From da518c8f5afdf23b4d25a8e12c4abf184c90e99d Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 15 Dec 2016 13:48:39 +0530 Subject: [PATCH 1/2] USB: dwc3-msm: Add support for voting for PM_QOS_LATENCY Add required changes to enable to vote for PM_QOS_LATENCY based on number of interrupts fired during certain duration. Change-Id: I92ace85ee7fd40c3f33f1b9f7bdd32469d990d84 Signed-off-by: Vijayavardhan Vennapusa --- .../devicetree/bindings/usb/msm-ssusb.txt | 3 + drivers/usb/dwc3/dwc3-msm.c | 92 +++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index 1c870acbd034..fa6ee8969946 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -60,6 +60,8 @@ Optional properties : should point to external connector device, which provide "USB-HOST" cable events. A single phandle may be specified if a single connector device provides both "USB" and "USB-HOST" events. +- qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs, + which is used as a vote by driver to get max performance in perf mode. Sub nodes: - Sub node for "DWC3- USB3 controller". @@ -84,6 +86,7 @@ Example MSM USB3.0 controller device node : qcom,dwc-usb3-msm-tx-fifo-size = <29696>; qcom,usb-dbm = <&dbm_1p4>; qcom,lpm-to-suspend-delay-ms = <2>; + qcom,pm-qos-latency = <2>; qcom,msm_bus,name = "usb3"; qcom,msm_bus,num_cases = <2>; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index cd55d908ea61..52756d655ed5 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -143,6 +143,9 @@ enum plug_orientation { #define B_SESS_VLD 1 #define B_SUSPEND 2 +#define PM_QOS_SAMPLE_SEC 2 +#define PM_QOS_THRESHOLD 400 + struct dwc3_msm { struct device *dev; void __iomem *base; @@ -219,6 +222,9 @@ struct dwc3_msm { unsigned int lpm_to_suspend_delay; bool init; enum plug_orientation typec_orientation; + int pm_qos_latency; + struct pm_qos_request pm_qos_req_dma; + struct delayed_work perf_vote_work; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -1911,6 +1917,8 @@ static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) } } +static void msm_dwc3_perf_vote_update(struct dwc3_msm *mdwc, + bool perf_mode); static int dwc3_msm_suspend(struct dwc3_msm *mdwc) { @@ -1925,6 +1933,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) return 0; } + cancel_delayed_work_sync(&mdwc->perf_vote_work); + msm_dwc3_perf_vote_update(mdwc, false); + if (!mdwc->in_host_mode) { /* pending device events unprocessed */ for (i = 0; i < dwc->num_event_buffers; i++) { @@ -2203,6 +2214,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) */ dwc3_pwr_event_handler(mdwc); + if (pm_qos_request_active(&mdwc->pm_qos_req_dma)) + schedule_delayed_work(&mdwc->perf_vote_work, + msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); + dbg_event(0xFF, "Ctl Res", atomic_read(&dwc->in_lpm)); return 0; @@ -2661,6 +2676,7 @@ static ssize_t mode_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(mode); +static void msm_dwc3_perf_vote_work(struct work_struct *w); static int dwc3_msm_probe(struct platform_device *pdev) { @@ -2696,6 +2712,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) INIT_WORK(&mdwc->bus_vote_w, dwc3_msm_bus_vote_w); INIT_WORK(&mdwc->vbus_draw_work, dwc3_msm_vbus_draw_work); INIT_DELAYED_WORK(&mdwc->sm_work, dwc3_otg_sm_work); + INIT_DELAYED_WORK(&mdwc->perf_vote_work, msm_dwc3_perf_vote_work); mdwc->dwc3_wq = alloc_ordered_workqueue("dwc3_wq", 0); if (!mdwc->dwc3_wq) { @@ -2971,6 +2988,13 @@ static int dwc3_msm_probe(struct platform_device *pdev) if (ret) goto put_dwc3; + ret = of_property_read_u32(node, "qcom,pm-qos-latency", + &mdwc->pm_qos_latency); + if (ret) { + dev_dbg(&pdev->dev, "setting pm-qos-latency to zero.\n"); + mdwc->pm_qos_latency = 0; + } + /* Update initial VBUS/ID state from extcon */ if (mdwc->extcon_vbus && extcon_get_cable_state_(mdwc->extcon_vbus, EXTCON_USB)) @@ -3036,6 +3060,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) clk_prepare_enable(mdwc->xo_clk); } + cancel_delayed_work_sync(&mdwc->perf_vote_work); cancel_delayed_work_sync(&mdwc->sm_work); if (mdwc->hs_phy) @@ -3121,6 +3146,45 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, return NOTIFY_DONE; } +static void msm_dwc3_perf_vote_update(struct dwc3_msm *mdwc, bool perf_mode) +{ + static bool curr_perf_mode; + int latency = mdwc->pm_qos_latency; + + if ((curr_perf_mode == perf_mode) || !latency) + return; + + if (perf_mode) + pm_qos_update_request(&mdwc->pm_qos_req_dma, latency); + else + pm_qos_update_request(&mdwc->pm_qos_req_dma, + PM_QOS_DEFAULT_VALUE); + + curr_perf_mode = perf_mode; + pr_debug("%s: latency updated to: %d\n", __func__, + perf_mode ? latency : PM_QOS_DEFAULT_VALUE); +} + +static void msm_dwc3_perf_vote_work(struct work_struct *w) +{ + struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, + perf_vote_work.work); + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + static unsigned long last_irq_cnt; + bool in_perf_mode = false; + + if (dwc->irq_cnt - last_irq_cnt >= PM_QOS_THRESHOLD) + in_perf_mode = true; + + pr_debug("%s: in_perf_mode:%u, interrupts in last sample:%lu\n", + __func__, in_perf_mode, (dwc->irq_cnt - last_irq_cnt)); + + last_irq_cnt = dwc->irq_cnt; + msm_dwc3_perf_vote_update(mdwc, in_perf_mode); + schedule_delayed_work(&mdwc->perf_vote_work, + msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); +} + #define VBUS_REG_CHECK_DELAY (msecs_to_jiffies(1000)) /** @@ -3226,6 +3290,16 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) atomic_read(&mdwc->dev->power.usage_count)); pm_runtime_mark_last_busy(mdwc->dev); pm_runtime_put_sync_autosuspend(mdwc->dev); +#ifdef CONFIG_SMP + mdwc->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ; + mdwc->pm_qos_req_dma.irq = dwc->irq; +#endif + pm_qos_add_request(&mdwc->pm_qos_req_dma, + PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); + /* start in perf mode for better performance initially */ + msm_dwc3_perf_vote_update(mdwc, true); + schedule_delayed_work(&mdwc->perf_vote_work, + msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); } else { dev_dbg(mdwc->dev, "%s: turn off host\n", __func__); @@ -3237,6 +3311,10 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) return ret; } + cancel_delayed_work_sync(&mdwc->perf_vote_work); + msm_dwc3_perf_vote_update(mdwc, false); + pm_qos_remove_request(&mdwc->pm_qos_req_dma); + pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "StopHost gsync", atomic_read(&mdwc->dev->power.usage_count)); @@ -3318,9 +3396,23 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); usb_gadget_vbus_connect(&dwc->gadget); +#ifdef CONFIG_SMP + mdwc->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ; + mdwc->pm_qos_req_dma.irq = dwc->irq; +#endif + pm_qos_add_request(&mdwc->pm_qos_req_dma, + PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); + /* start in perf mode for better performance initially */ + msm_dwc3_perf_vote_update(mdwc, true); + schedule_delayed_work(&mdwc->perf_vote_work, + msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); } else { dev_dbg(mdwc->dev, "%s: turn off gadget %s\n", __func__, dwc->gadget.name); + cancel_delayed_work_sync(&mdwc->perf_vote_work); + msm_dwc3_perf_vote_update(mdwc, false); + pm_qos_remove_request(&mdwc->pm_qos_req_dma); + usb_gadget_vbus_disconnect(&dwc->gadget); usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); From d6592bed8dedc0adb568e9753b0df95b1ce409ef Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Tue, 20 Dec 2016 17:06:41 +0530 Subject: [PATCH 2/2] ARM: dts: msm: Allow only wfi based on USB irq load for msmfalcon Add pm-qos latency(i.e CPU-CLUSTER-WFI-LEVEL latency + 1) to be voted by USB driver to allow only WFI during peak data transfers for msmfalcon to improve performance. Change-Id: I40a86a062910253401dc4a59f7ae84c518eebb5e Signed-off-by: Vijayavardhan Vennapusa --- arch/arm/boot/dts/qcom/msmfalcon-common.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/qcom/msmfalcon-common.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-common.dtsi index 50513ceabbeb..e03a60d96827 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-common.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-common.dtsi @@ -36,6 +36,7 @@ qcom,dwc-usb3-msm-tx-fifo-size = <21288>; extcon = <&pmfalcon_pdphy>; + qcom,pm-qos-latency = <41>; /* CPU-CLUSTER-WFI-LVL latency +1 */ clocks = <&clock_gcc GCC_USB30_MASTER_CLK>, <&clock_gcc GCC_CFG_NOC_USB3_AXI_CLK>,