Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6d3f802 authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa Committed by Mayank Rana
Browse files

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: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 6f504dca
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ Optional properties :
	  device provides both "USB" and "USB-HOST" events.
- qcom,num-gsi-evt-buffs: If present, specifies number of GSI based hardware accelerated
  event buffers. 1 event buffer is needed per h/w accelerated endpoint.
- 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".
@@ -89,6 +91,7 @@ Example MSM USB3.0 controller device node :
		qcom,usb-dbm = <&dbm_1p4>;
		qcom,lpm-to-suspend-delay-ms = <2>;
		qcom,num-gsi-evt-buffs = <0x2>;
		qcom,pm-qos-latency = <2>;

		qcom,msm_bus,name = "usb3";
		qcom,msm_bus,num_cases = <2>;
+92 −0
Original line number Diff line number Diff line
@@ -147,6 +147,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;
@@ -224,6 +227,9 @@ struct dwc3_msm {
	enum plug_orientation	typec_orientation;
	u32			num_gsi_event_buffers;
	struct dwc3_event_buffer **gsi_ev_buff;
	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 */
@@ -1964,6 +1970,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)
{
@@ -1977,6 +1985,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) {
		evt = dwc->ev_buf;
		if ((evt->flags & DWC3_EVENT_PENDING)) {
@@ -2259,6 +2270,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;
}
@@ -2715,6 +2730,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 ssize_t speed_show(struct device *dev, struct device_attribute *attr,
		char *buf)
@@ -2782,6 +2798,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) {
@@ -3060,6 +3077,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))
@@ -3127,6 +3151,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)
@@ -3233,6 +3258,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))

/**
@@ -3337,6 +3401,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__);

@@ -3347,6 +3421,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));
@@ -3430,9 +3508,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);