From: Dinh Nguyen <dinguyen@xxxxxxxxxx> Update dwc2_handle_common_intr() to handle both hcd and gadget interrupts. Signed-off-by: Dinh Nguyen <dinguyen@xxxxxxxxxx> --- drivers/usb/dwc2/core_intr.c | 116 +++++++++++++++++++++++++- drivers/usb/dwc2/gadget.c | 188 ------------------------------------------ 2 files changed, 114 insertions(+), 190 deletions(-) diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index c93918b..7500621 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -337,6 +337,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) } /* Change to L0 state */ hsotg->lx_state = DWC2_L0; + call_gadget(hsotg, resume); } else { if (hsotg->lx_state != DWC2_L1) { u32 pcgcctl = readl(hsotg->regs + PCGCTL); @@ -397,6 +398,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n", !!(dsts & DSTS_SUSPSTS), hsotg->hw_params.power_optimized); + + call_gadget(hsotg, suspend); } else { if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) { dev_dbg(hsotg->dev, "a_peripheral->a_host\n"); @@ -421,6 +424,11 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \ GINTSTS_USBSUSP | GINTSTS_PRTINT) +/* IRQ flags which will trigger a retry around the IRQ loop */ +#define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ + GINTSTS_PTXFEMP | \ + GINTSTS_RXFLVL) + /* * This function returns the Core Interrupt register */ @@ -441,7 +449,7 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg) gintsts, gintmsk); if (gahbcfg & GAHBCFG_GLBL_INTR_EN) - return gintsts & gintmsk & gintmsk_common; + return gintsts & gintmsk; else return 0; } @@ -463,7 +471,8 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) { struct dwc2_hsotg *hsotg = dev; u32 gintsts; - irqreturn_t retval = IRQ_NONE; + int retry_count = 8; + irqreturn_t retval = IRQ_HANDLED; if (!dwc2_is_controller_alive(hsotg)) { dev_warn(hsotg->dev, "Controller is dead\n"); @@ -472,16 +481,90 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) spin_lock(&hsotg->lock); +irq_retry: gintsts = dwc2_read_common_intr(hsotg); if (gintsts & ~GINTSTS_PRTINT) retval = IRQ_HANDLED; + if (gintsts & GINTSTS_ENUMDONE) { + writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); + s3c_hsotg_irq_enumdone(hsotg); + } + if (gintsts & GINTSTS_MODEMIS) dwc2_handle_mode_mismatch_intr(hsotg); if (gintsts & GINTSTS_OTGINT) dwc2_handle_otg_intr(hsotg); if (gintsts & GINTSTS_CONIDSTSCHNG) dwc2_handle_conn_id_status_change_intr(hsotg); + + if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { + u32 daint = readl(hsotg->regs + DAINT); + u32 daint_out = daint >> DAINT_OUTEP_SHIFT; + u32 daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); + int ep; + + dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); + for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { + if (daint_out & 1) + s3c_hsotg_epint(hsotg, ep, 0); + } + + for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) { + if (daint_in & 1) + s3c_hsotg_epint(hsotg, ep, 1); + } + } + + if (gintsts & GINTSTS_USBRST) { + u32 usb_status = readl(hsotg->regs + GOTGCTL); + + dev_dbg(hsotg->dev, "%s: USBRST\n", __func__); + dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", + readl(hsotg->regs + GNPTXSTS)); + + writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); + + if (usb_status & GOTGCTL_BSESVLD) { + if (time_after(jiffies, hsotg->s3c_hsotg->last_rst + + msecs_to_jiffies(200))) { + kill_all_requests(hsotg, &hsotg->eps[0], + -ECONNRESET, true); + s3c_hsotg_core_init(hsotg); + hsotg->s3c_hsotg->last_rst = jiffies; + } + } + } + + if (gintsts & GINTSTS_NPTXFEMP) { + dev_dbg(hsotg->dev, "NPTXFEMP\n"); + + /* + * Disable the interrupt to stop it happening again + * unless one of these endpoint routines decides that + * it needs re-enabling + */ + s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); + s3c_hsotg_irq_fifoempty(hsotg, false); + } + + if (gintsts & GINTSTS_PTXFEMP) { + dev_dbg(hsotg->dev, "PTXFEMP\n"); + + /* See note in GINTSTS_NPTxFEmp */ + s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); + s3c_hsotg_irq_fifoempty(hsotg, true); + } + + if (gintsts & GINTSTS_RXFLVL) { + /* + * note, since GINTSTS_RXFLVL doubles as FIFO-not-empty, + * we need to retry s3c_hsotg_handle_rx if this is still + * set. + */ + s3c_hsotg_handle_rx(hsotg); + } + if (gintsts & GINTSTS_DISCONNINT) dwc2_handle_disconnect_intr(hsotg); if (gintsts & GINTSTS_SESSREQINT) @@ -491,6 +574,28 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) if (gintsts & GINTSTS_USBSUSP) dwc2_handle_usb_suspend_intr(hsotg); + if (gintsts & GINTSTS_ERLYSUSP) { + dev_dbg(hsotg->dev, "GINTSTS_ERLYSUSP\n"); + writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); + } + + /* + * these next two seem to crop-up occasionally causing the core + * to shutdown the USB transfer, so try clearing them and logging + * the occurrence. + */ + if (gintsts & GINTSTS_GOUTNAKEFF) { + dev_dbg(hsotg->dev, "GOUTNAKEFF triggered\n"); + writel(DCTL_CGOUTNAK, hsotg->regs + DCTL); + s3c_hsotg_dump(hsotg); + } + + if (gintsts & GINTSTS_GINNAKEFF) { + dev_dbg(hsotg->dev, "GINNAKEFF triggered\n"); + writel(DCTL_CGNPINNAK, hsotg->regs + DCTL); + s3c_hsotg_dump(hsotg); + } + if (gintsts & GINTSTS_PRTINT) { /* * The port interrupt occurs while in device mode with HPRT0 @@ -504,6 +609,13 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) } } + /* + * if we've had fifo events, we should try and go around the + * loop again to see if there's any point in returning yet. + */ + if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) + goto irq_retry; + spin_unlock(&hsotg->lock); out: return retval; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index e74656c..9bfd906 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2231,194 +2231,6 @@ void s3c_hsotg_core_init(struct dwc2_hsotg *dwc2) } /** - * s3c_hsotg_irq - handle device interrupt - * @irq: The IRQ number triggered - * @pw: The pw value when registered the handler. - */ -static irqreturn_t s3c_hsotg_irq(int irq, void *pw) -{ - struct s3c_hsotg *hsotg = pw; - int retry_count = 8; - u32 gintsts; - u32 gintmsk; - - spin_lock(&hsotg->lock); -irq_retry: - gintsts = readl(hsotg->regs + GINTSTS); - gintmsk = readl(hsotg->regs + GINTMSK); - - dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", - __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); - - gintsts &= gintmsk; - - if (gintsts & GINTSTS_OTGINT) { - u32 otgint = readl(hsotg->regs + GOTGINT); - - dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); - - writel(otgint, hsotg->regs + GOTGINT); - } - - if (gintsts & GINTSTS_SESSREQINT) { - dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); - writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); - } - - if (gintsts & GINTSTS_ENUMDONE) { - writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); - - s3c_hsotg_irq_enumdone(hsotg); - } - - if (gintsts & GINTSTS_CONIDSTSCHNG) { - dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", - readl(hsotg->regs + DSTS), - readl(hsotg->regs + GOTGCTL)); - - writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); - } - - if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { - u32 daint = readl(hsotg->regs + DAINT); - u32 daintmsk = readl(hsotg->regs + DAINTMSK); - u32 daint_out, daint_in; - int ep; - - daint &= daintmsk; - daint_out = daint >> DAINT_OUTEP_SHIFT; - daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); - - dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); - - for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { - if (daint_out & 1) - s3c_hsotg_epint(hsotg, ep, 0); - } - - for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) { - if (daint_in & 1) - s3c_hsotg_epint(hsotg, ep, 1); - } - } - - if (gintsts & GINTSTS_USBRST) { - - u32 usb_status = readl(hsotg->regs + GOTGCTL); - - dev_info(hsotg->dev, "%s: USBRst\n", __func__); - dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", - readl(hsotg->regs + GNPTXSTS)); - - writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); - - if (usb_status & GOTGCTL_BSESVLD) { - if (time_after(jiffies, hsotg->last_rst + - msecs_to_jiffies(200))) { - - kill_all_requests(hsotg, &hsotg->eps[0], - -ECONNRESET, true); - - s3c_hsotg_core_init(hsotg); - hsotg->last_rst = jiffies; - } - } - } - - /* check both FIFOs */ - - if (gintsts & GINTSTS_NPTXFEMP) { - dev_dbg(hsotg->dev, "NPTxFEmp\n"); - - /* - * Disable the interrupt to stop it happening again - * unless one of these endpoint routines decides that - * it needs re-enabling - */ - - s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); - s3c_hsotg_irq_fifoempty(hsotg, false); - } - - if (gintsts & GINTSTS_PTXFEMP) { - dev_dbg(hsotg->dev, "PTxFEmp\n"); - - /* See note in GINTSTS_NPTxFEmp */ - - s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); - s3c_hsotg_irq_fifoempty(hsotg, true); - } - - if (gintsts & GINTSTS_RXFLVL) { - /* - * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, - * we need to retry s3c_hsotg_handle_rx if this is still - * set. - */ - - s3c_hsotg_handle_rx(hsotg); - } - - if (gintsts & GINTSTS_MODEMIS) { - dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); - writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS); - } - - if (gintsts & GINTSTS_USBSUSP) { - dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); - writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); - - call_gadget(hsotg, suspend); - } - - if (gintsts & GINTSTS_WKUPINT) { - dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); - writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS); - - call_gadget(hsotg, resume); - } - - if (gintsts & GINTSTS_ERLYSUSP) { - dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); - writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); - } - - /* - * these next two seem to crop-up occasionally causing the core - * to shutdown the USB transfer, so try clearing them and logging - * the occurrence. - */ - - if (gintsts & GINTSTS_GOUTNAKEFF) { - dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - - writel(DCTL_CGOUTNAK, hsotg->regs + DCTL); - - s3c_hsotg_dump(hsotg); - } - - if (gintsts & GINTSTS_GINNAKEFF) { - dev_info(hsotg->dev, "GINNakEff triggered\n"); - - writel(DCTL_CGNPINNAK, hsotg->regs + DCTL); - - s3c_hsotg_dump(hsotg); - } - - /* - * if we've had fifo events, we should try and go around the - * loop again to see if there's any point in returning yet. - */ - - if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) - goto irq_retry; - - spin_unlock(&hsotg->lock); - - return IRQ_HANDLED; -} - -/** * s3c_hsotg_ep_enable - enable the given endpoint * @ep: The USB endpint to configure * @desc: The USB endpoint descriptor to configure with. -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html