summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorArvid Brodin <arvid.brodin@enea.com>2011-08-21 08:29:28 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-23 00:32:46 +0200
commit6477acc0814fc7aadfe3d723d2596fb4eb6d1732 (patch)
tree58246dfcdaf790e3f29c99f95a38faa0639a2bfd /drivers/usb
parentusb/isp1760: Fix missing endpoint unlink when no mem during enqueue (diff)
downloadlinux-6477acc0814fc7aadfe3d723d2596fb4eb6d1732.tar.xz
linux-6477acc0814fc7aadfe3d723d2596fb4eb6d1732.zip
usb/isp1760: Fix problems that trigger WARNING at line 1136.
1) A bug in the usage of time_after() in errata2_function(). 2) Clear done_maps just prior to starting a new transfer in start_bus_transfer(), instead of just after, when done_map bits might have been validly set by the started transfer. Signed-off-by: Arvid Brodin <arvid.brodin@enea.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/isp1760-hcd.c38
1 files changed, 20 insertions, 18 deletions
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 1eb69e050941..11367b45d511 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -732,28 +732,29 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
WARN_ON(slots[slot].qh);
WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
- slots[slot].qtd = qtd;
- slots[slot].qh = qh;
- qh->slot = slot;
- qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since
- interrupt routine may preempt and expects this value. */
- slots[slot].timestamp = jiffies;
- ptd_write(hcd->regs, ptd_offset, slot, ptd);
-
/* Make sure done map has not triggered from some unlinked transfer */
if (ptd_offset == ATL_PTD_OFFSET) {
priv->atl_done_map |= reg_read32(hcd->regs,
HC_ATL_PTD_DONEMAP_REG);
- priv->atl_done_map &= ~(1 << qh->slot);
+ priv->atl_done_map &= ~(1 << slot);
+ } else {
+ priv->int_done_map |= reg_read32(hcd->regs,
+ HC_INT_PTD_DONEMAP_REG);
+ priv->int_done_map &= ~(1 << slot);
+ }
+ qh->slot = slot;
+ qtd->status = QTD_XFER_STARTED;
+ slots[slot].timestamp = jiffies;
+ slots[slot].qtd = qtd;
+ slots[slot].qh = qh;
+ ptd_write(hcd->regs, ptd_offset, slot, ptd);
+
+ if (ptd_offset == ATL_PTD_OFFSET) {
skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
skip_map &= ~(1 << qh->slot);
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
} else {
- priv->int_done_map |= reg_read32(hcd->regs,
- HC_INT_PTD_DONEMAP_REG);
- priv->int_done_map &= ~(1 << qh->slot);
-
skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
skip_map &= ~(1 << qh->slot);
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
@@ -1266,7 +1267,7 @@ leave:
* not to cause too much lag when this HW bug occurs, while still hopefully
* ensuring that the check does not falsely trigger.
*/
-#define SLOT_TIMEOUT 180
+#define SLOT_TIMEOUT 300
#define SLOT_CHECK_PERIOD 200
static struct timer_list errata2_timer;
@@ -1281,16 +1282,17 @@ void errata2_function(unsigned long data)
spin_lock_irqsave(&priv->lock, spinflags);
for (slot = 0; slot < 32; slot++)
- if ((priv->atl_slots[slot].qh || priv->atl_slots[slot].qtd) &&
- time_after(jiffies + SLOT_TIMEOUT * HZ / 1000,
- priv->atl_slots[slot].timestamp)) {
+ if (priv->atl_slots[slot].qh && time_after(jiffies,
+ priv->atl_slots[slot].timestamp +
+ SLOT_TIMEOUT * HZ / 1000)) {
ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
if (!FROM_DW0_VALID(ptd.dw0) &&
!FROM_DW3_ACTIVE(ptd.dw3))
priv->atl_done_map |= 1 << slot;
}
- handle_done_ptds(hcd);
+ if (priv->atl_done_map)
+ handle_done_ptds(hcd);
spin_unlock_irqrestore(&priv->lock, spinflags);