Commit a3395f0d authored by Anton Tikhomirov's avatar Anton Tikhomirov Committed by Greg Kroah-Hartman

USB: s3c-hsotg: Fix interrupt cleaning code

This commit does the following:
1) clears all pending interrupts before unmasking;
2) clears interrupts as soon as possible to avoid missing
   next coming that may occur during handling;
3) removes ineffective interrupt cleaning code.
Signed-off-by: default avatarAnton Tikhomirov <av.tikhomirov@samsung.com>
Reviewed-by: Kyoungil Kim<ki0351.kim@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: default avatarKukjin Kim <kgene.kim@samsung.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d00f5004
...@@ -1775,10 +1775,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, ...@@ -1775,10 +1775,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx); u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx);
u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx); u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx);
u32 ints; u32 ints;
u32 clear = 0;
ints = readl(hsotg->regs + epint_reg); ints = readl(hsotg->regs + epint_reg);
/* Clear endpoint interrupts */
writel(ints, hsotg->regs + epint_reg);
dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
__func__, idx, dir_in ? "in" : "out", ints); __func__, idx, dir_in ? "in" : "out", ints);
...@@ -1801,19 +1803,13 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, ...@@ -1801,19 +1803,13 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
s3c_hsotg_handle_outdone(hsotg, idx, false); s3c_hsotg_handle_outdone(hsotg, idx, false);
} }
clear |= S3C_DxEPINT_XferCompl;
} }
if (ints & S3C_DxEPINT_EPDisbld) { if (ints & S3C_DxEPINT_EPDisbld)
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
clear |= S3C_DxEPINT_EPDisbld;
}
if (ints & S3C_DxEPINT_AHBErr) { if (ints & S3C_DxEPINT_AHBErr)
dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
clear |= S3C_DxEPINT_AHBErr;
}
if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */ if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */
dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__);
...@@ -1829,14 +1825,10 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, ...@@ -1829,14 +1825,10 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
else else
s3c_hsotg_handle_outdone(hsotg, 0, true); s3c_hsotg_handle_outdone(hsotg, 0, true);
} }
clear |= S3C_DxEPINT_Setup;
} }
if (ints & S3C_DxEPINT_Back2BackSetup) { if (ints & S3C_DxEPINT_Back2BackSetup)
dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
clear |= S3C_DxEPINT_Back2BackSetup;
}
if (dir_in) { if (dir_in) {
/* not sure if this is important, but we'll clear it anyway /* not sure if this is important, but we'll clear it anyway
...@@ -1844,14 +1836,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, ...@@ -1844,14 +1836,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) { if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) {
dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
__func__, idx); __func__, idx);
clear |= S3C_DIEPMSK_INTknTXFEmpMsk;
} }
/* this probably means something bad is happening */ /* this probably means something bad is happening */
if (ints & S3C_DIEPMSK_INTknEPMisMsk) { if (ints & S3C_DIEPMSK_INTknEPMisMsk) {
dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
__func__, idx); __func__, idx);
clear |= S3C_DIEPMSK_INTknEPMisMsk;
} }
/* FIFO has space or is empty (see GAHBCFG) */ /* FIFO has space or is empty (see GAHBCFG) */
...@@ -1860,11 +1850,8 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, ...@@ -1860,11 +1850,8 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
__func__, idx); __func__, idx);
s3c_hsotg_trytx(hsotg, hs_ep); s3c_hsotg_trytx(hsotg, hs_ep);
clear |= S3C_DIEPMSK_TxFIFOEmpty;
} }
} }
writel(clear, hsotg->regs + epint_reg);
} }
/** /**
...@@ -2056,7 +2043,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2056,7 +2043,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
writel(otgint, hsotg->regs + S3C_GOTGINT); writel(otgint, hsotg->regs + S3C_GOTGINT);
writel(S3C_GINTSTS_OTGInt, hsotg->regs + S3C_GINTSTS);
} }
if (gintsts & S3C_GINTSTS_DisconnInt) { if (gintsts & S3C_GINTSTS_DisconnInt) {
...@@ -2072,8 +2058,9 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2072,8 +2058,9 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
} }
if (gintsts & S3C_GINTSTS_EnumDone) { if (gintsts & S3C_GINTSTS_EnumDone) {
s3c_hsotg_irq_enumdone(hsotg);
writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS); writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);
s3c_hsotg_irq_enumdone(hsotg);
} }
if (gintsts & S3C_GINTSTS_ConIDStsChng) { if (gintsts & S3C_GINTSTS_ConIDStsChng) {
...@@ -2101,10 +2088,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2101,10 +2088,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
if (daint_in & 1) if (daint_in & 1)
s3c_hsotg_epint(hsotg, ep, 1); s3c_hsotg_epint(hsotg, ep, 1);
} }
writel(daint, hsotg->regs + S3C_DAINT);
writel(gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt),
hsotg->regs + S3C_GINTSTS);
} }
if (gintsts & S3C_GINTSTS_USBRst) { if (gintsts & S3C_GINTSTS_USBRst) {
...@@ -2112,6 +2095,8 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2112,6 +2095,8 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
readl(hsotg->regs + S3C_GNPTXSTS)); readl(hsotg->regs + S3C_GNPTXSTS));
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
/* it seems after a reset we can end up with a situation /* it seems after a reset we can end up with a situation
...@@ -2123,8 +2108,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2123,8 +2108,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
s3c_hsotg_init_fifo(hsotg); s3c_hsotg_init_fifo(hsotg);
s3c_hsotg_enqueue_setup(hsotg); s3c_hsotg_enqueue_setup(hsotg);
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
} }
/* check both FIFOs */ /* check both FIFOs */
...@@ -2138,8 +2121,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2138,8 +2121,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
s3c_hsotg_irq_fifoempty(hsotg, false); s3c_hsotg_irq_fifoempty(hsotg, false);
writel(S3C_GINTSTS_NPTxFEmp, hsotg->regs + S3C_GINTSTS);
} }
if (gintsts & S3C_GINTSTS_PTxFEmp) { if (gintsts & S3C_GINTSTS_PTxFEmp) {
...@@ -2149,8 +2130,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2149,8 +2130,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp); s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
s3c_hsotg_irq_fifoempty(hsotg, true); s3c_hsotg_irq_fifoempty(hsotg, true);
writel(S3C_GINTSTS_PTxFEmp, hsotg->regs + S3C_GINTSTS);
} }
if (gintsts & S3C_GINTSTS_RxFLvl) { if (gintsts & S3C_GINTSTS_RxFLvl) {
...@@ -2159,7 +2138,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2159,7 +2138,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
* set. */ * set. */
s3c_hsotg_handle_rx(hsotg); s3c_hsotg_handle_rx(hsotg);
writel(S3C_GINTSTS_RxFLvl, hsotg->regs + S3C_GINTSTS);
} }
if (gintsts & S3C_GINTSTS_ModeMis) { if (gintsts & S3C_GINTSTS_ModeMis) {
...@@ -2193,19 +2171,17 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) ...@@ -2193,19 +2171,17 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
if (gintsts & S3C_GINTSTS_GOUTNakEff) { if (gintsts & S3C_GINTSTS_GOUTNakEff) {
dev_info(hsotg->dev, "GOUTNakEff triggered\n"); dev_info(hsotg->dev, "GOUTNakEff triggered\n");
s3c_hsotg_dump(hsotg);
writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL); writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);
writel(S3C_GINTSTS_GOUTNakEff, hsotg->regs + S3C_GINTSTS);
s3c_hsotg_dump(hsotg);
} }
if (gintsts & S3C_GINTSTS_GINNakEff) { if (gintsts & S3C_GINTSTS_GINNakEff) {
dev_info(hsotg->dev, "GINNakEff triggered\n"); dev_info(hsotg->dev, "GINNakEff triggered\n");
s3c_hsotg_dump(hsotg);
writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL); writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);
writel(S3C_GINTSTS_GINNakEff, hsotg->regs + S3C_GINTSTS);
s3c_hsotg_dump(hsotg);
} }
/* if we've had fifo events, we should try and go around the /* if we've had fifo events, we should try and go around the
...@@ -2585,6 +2561,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, ...@@ -2585,6 +2561,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG); writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG);
/* Clear any pending OTG interrupts */
writel(0xffffffff, hsotg->regs + S3C_GOTGINT);
/* Clear any pending interrupts */
writel(0xffffffff, hsotg->regs + S3C_GINTSTS);
writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt | writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt |
S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst | S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst |
S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt | S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment