Re: [PATCH v3] usb/isp1760: Implement solution for erratum 2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greg, is that patch on your list or did it get lost?

* Sebastian Andrzej Siewior | 2011-02-08 21:07:40 [+0100]:

>The document says:
>|2.1 Problem description
>|    When at least two USB devices are simultaneously running, it is observed that
>|    sometimes the INT corresponding to one of the USB devices stops occurring. This may
>|    be observed sometimes with USB-to-serial or USB-to-network devices.
>|    The problem is not noticed when only USB mass storage devices are running.
>|2.2 Implication
>|    This issue is because of the clearing of the respective Done Map bit on reading the ATL
>|    PTD Done Map register when an INT is generated by another PTD completion, but is not
>|    found set on that read access. In this situation, the respective Done Map bit will remain
>|    reset and no further INT will be asserted so the data transfer corresponding to that USB
>|    device will stop.
>|2.3 Workaround
>|    An SOF INT can be used instead of an ATL INT with polling on Done bits. A time-out can
>|    be implemented and if a certain Done bit is never set, verification of the PTD completion
>|    can be done by reading PTD contents (valid bit).
>|    This is a proven workaround implemented in software.
>
>Russell King run into this with an USB-to-serial converter. This patch
>implements his suggestion to enable the high frequent SOF interrupt only
>at the time we have ATL packages queued. It goes even one step further
>and enables the SOF interrupt only if we have more than one ATL packet
>queued at the same time.
>
>Cc: <stable@xxxxxxxxxx> # [2.6.35.x, 2.6.36.x, 2.6.37.x]
>Tested-by: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx>
>Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
>---
>v1..v2: use the register offset instead of the value.
>v2..v3: change patch title
>
> drivers/usb/host/isp1760-hcd.c |   22 ++++++++++++++++------
> drivers/usb/host/isp1760-hcd.h |    1 +
> 2 files changed, 17 insertions(+), 6 deletions(-)
>
>diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
>index bdba8c5..c470cc8 100644
>--- a/drivers/usb/host/isp1760-hcd.c
>+++ b/drivers/usb/host/isp1760-hcd.c
>@@ -33,6 +33,7 @@ struct isp1760_hcd {
> 	struct inter_packet_info atl_ints[32];
> 	struct inter_packet_info int_ints[32];
> 	struct memory_chunk memory_pool[BLOCKS];
>+	u32 atl_queued;
> 
> 	/* periodic schedule support */
> #define	DEFAULT_I_TDPS		1024
>@@ -850,6 +851,11 @@ static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
> 	skip_map &= ~queue_entry;
> 	isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
> 
>+	priv->atl_queued++;
>+	if (priv->atl_queued == 2)
>+		isp1760_writel(INTERRUPT_ENABLE_SOT_MASK,
>+				hcd->regs + HC_INTERRUPT_ENABLE);
>+
> 	buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
> 	buffstatus |= ATL_BUFFER;
> 	isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
>@@ -992,6 +998,7 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
> 		u32 dw3;
> 
> 		status = 0;
>+		priv->atl_queued--;
> 
> 		queue_entry = __ffs(done_map);
> 		done_map &= ~(1 << queue_entry);
>@@ -1054,11 +1061,6 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
> 			 * device is not able to send data fast enough.
> 			 * This happens mostly on slower hardware.
> 			 */
>-			printk(KERN_NOTICE "Reloading ptd %p/%p... qh %p read: "
>-					"%d of %zu done: %08x cur: %08x\n", qtd,
>-					urb, qh, PTD_XFERRED_LENGTH(dw3),
>-					qtd->length, done_map,
>-					(1 << queue_entry));
> 
> 			/* RL counter = ERR counter */
> 			dw3 &= ~(0xf << 19);
>@@ -1086,6 +1088,11 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
> 			priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
> 					atl_regs, sizeof(ptd));
> 
>+			priv->atl_queued++;
>+			if (priv->atl_queued == 2)
>+				isp1760_writel(INTERRUPT_ENABLE_SOT_MASK,
>+				    usb_hcd->regs + HC_INTERRUPT_ENABLE);
>+
> 			buffstatus = isp1760_readl(usb_hcd->regs +
> 					HC_BUFFER_STATUS_REG);
> 			buffstatus |= ATL_BUFFER;
>@@ -1191,6 +1198,9 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
> 		skip_map = isp1760_readl(usb_hcd->regs +
> 				HC_ATL_PTD_SKIPMAP_REG);
> 	}
>+	if (priv->atl_queued <= 1)
>+		isp1760_writel(INTERRUPT_ENABLE_MASK,
>+				usb_hcd->regs + HC_INTERRUPT_ENABLE);
> }
> 
> static void do_intl_int(struct usb_hcd *usb_hcd)
>@@ -1770,7 +1780,7 @@ static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd)
> 		goto leave;
> 
> 	isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG);
>-	if (imask & HC_ATL_INT)
>+	if (imask & (HC_ATL_INT | HC_SOT_INT))
> 		do_atl_int(usb_hcd);
> 
> 	if (imask & HC_INTL_INT)
>diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
>index 6931ef5..612bce5 100644
>--- a/drivers/usb/host/isp1760-hcd.h
>+++ b/drivers/usb/host/isp1760-hcd.h
>@@ -69,6 +69,7 @@ void deinit_kmem_cache(void);
> 
> #define HC_INTERRUPT_ENABLE	0x314
> #define INTERRUPT_ENABLE_MASK	(HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
>+#define INTERRUPT_ENABLE_SOT_MASK	(HC_INTL_INT | HC_SOT_INT | HC_EOT_INT)
> 
> #define HC_ISO_INT		(1 << 9)
> #define HC_ATL_INT		(1 << 8)
>-- 
>1.7.3.2

Sebastian
--
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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux