From 3a318ab38c4959b21df3cce6b933b6d0abe5eb4b Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Fri, 26 May 2023 15:03:07 +0530 Subject: [PATCH] usb: dwc3: qcom: Cleanup layering violations in dwc3 qcom Implement host notifier in qcom to remove layering violations Signed-off-by: Krishna Kurapati --- drivers/usb/dwc3/dwc3-qcom.c | 56 +++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 959fc925ca7c..ce2f867d7c9a 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -91,6 +91,9 @@ struct dwc3_qcom { bool pm_suspended; struct icc_path *icc_path_ddr; struct icc_path *icc_path_apps; + + bool in_host_mode; + struct notifier_block xhci_nb; }; static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val) @@ -305,14 +308,6 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) icc_put(qcom->icc_path_apps); } -/* Only usable in contexts where the role can not change. */ -static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) -{ - struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); - - return dwc->xhci; -} - static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) { struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); @@ -432,7 +427,7 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) * The role is stable during suspend as role switching is done from a * freezable workqueue. */ - if (dwc3_qcom_is_host(qcom) && wakeup) { + if (qcom->in_host_mode && wakeup) { qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom); dwc3_qcom_enable_interrupts(qcom); } @@ -450,7 +445,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup) if (!qcom->is_suspended) return 0; - if (dwc3_qcom_is_host(qcom) && wakeup) + if (qcom->in_host_mode && wakeup) dwc3_qcom_disable_interrupts(qcom); for (i = 0; i < qcom->num_clocks; i++) { @@ -488,7 +483,7 @@ static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) * This is safe as role switching is done from a freezable workqueue * and the wakeup interrupts are disabled as part of resume. */ - if (dwc3_qcom_is_host(qcom)) + if (qcom->in_host_mode) pm_runtime_resume(&dwc->xhci->dev); return IRQ_HANDLED; @@ -785,6 +780,41 @@ dwc3_qcom_create_urs_usb_platdev(struct device *dev) return acpi_create_platform_device(adev, NULL); } +static int dwc3_xhci_event_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, xhci_nb); + struct usb_bus *ubus = ptr; + struct usb_hcd *hcd; + + if (event != USB_BUS_ADD && event != USB_BUS_REMOVE) + return NOTIFY_DONE; + + //TODO: Check whether event generated is for this qcom controller or not + + hcd = bus_to_hcd(ubus); + if (event == USB_BUS_ADD) { + /* + * Assuming both usb2 and usb3 roothubs wil + * be registered, wait for shared hcd to be + * registered to ensure that we are in host mode + * completely. + */ + if (!usb_hcd_is_primary_hcd(hcd)) + qcom->in_host_mode = true; + } else if (event == USB_BUS_REMOVE) { + /* + * While exiting host mode, primary hcd is + * removed at the end. Use it as indication + * that host stack has been removed successfully. + */ + if (usb_hcd_is_primary_hcd(hcd)) + qcom->in_host_mode = false; + } + + return 0; +} + static int dwc3_qcom_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -884,6 +914,9 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (ignore_pipe_clk) dwc3_qcom_select_utmi_clk(qcom); + qcom->xhci_nb.notifier_call = dwc3_xhci_event_notifier; + usb_register_notify(&qcom->xhci_nb); + if (np) ret = dwc3_qcom_of_register_core(pdev); else @@ -923,6 +956,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev) interconnect_exit: dwc3_qcom_interconnect_exit(qcom); depopulate: + usb_unregister_notify(&qcom->xhci_nb); if (np) of_platform_depopulate(&pdev->dev); else -- 2.40.0