Re: 2.0 devices on 3.0 ports not recognized

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

 



On 11/13/2011 10:35 AM, Andrej Podzimek wrote:
Hello,

I am running kernel 3.0.8 on x86_64 (a Zotac mini-ITX motherboard with a
NEC USB 3.0 controller).

05:00.0 USB controller: NEC Corporation uPD720200 USB 3.0 Host
Controller (rev 03)

The problem is that USB 2.0 devices are not recognized at all when
connected to USB 3.0 ports. But USB 3.0 devices work just fine. For
instance, a Western Digital USB 3.0 hard disk appears in both lsusb (and
lsusb -t) and achieves transfer rates of more than 100 MB/s.

Bus 002 Device 008: ID 1058:0730 Western Digital Technologies, Inc.

/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 5000M
|__ Port 2: Dev 2, If 0, Class=hub, Driver=hub/4p, 5000M
|__ Port 4: Dev 8, If 0, Class=stor., Driver=usb-storage, 5000M

(There is a Hama USB 3.0 hub connected to one of the USB 3.0 ports.
Tried to connect my devices with/without the hub and also with/without a
5 meters long "active cable" for USB 3.0. The hard drive achieved the
same transfer rates in all configurations.)

When it comes to USB 2.0 devices in USB 3.0 ports, they are silently
ignored and nothing appears in dmesg. Two different flash drives, two
different UVC cameras and a HP DVD writer -- all of them work normally
on USB 2.0 ports, but don't seem to be recognized at all on USB 3.0.

(The motivation behind using USB 3.0 hubs for USB 2.0 devices is a
multi-seat configuration with a USB 3.0 hub for each user, aiming to
provide fast USB connectivity with just one cable.)

How can I diagnose these problems? Is this a known issue? A hint would
help me a lot. :-)


Do you connect your USB2.0 devices to USB3 root hub or via a USB3.0 external hub?

Please apply the two patches attached and see if they are useful.

Thanks,
Andiry

>From 4d30c1a8e4411f4602fe0d0507dc0f6d2ae153dd Mon Sep 17 00:00:00 2001
From: Andiry Xu <andiry.xu@xxxxxxx>
Date: Wed, 17 Aug 2011 05:54:25 +0800
Subject: [PATCH 4/9] xHCI: test and clear RWC bit

Introduce xhci_test_and_clear_bit() to clear RWC bit in PORTSC register.

Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
---
 drivers/usb/host/xhci-hub.c  |   22 ++++++++++++++++------
 drivers/usb/host/xhci-ring.c |    6 ++----
 drivers/usb/host/xhci.h      |    2 ++
 3 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index e80b42f..aec098a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -404,6 +404,20 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 	xhci_writel(xhci, temp, port_array[port_id]);
 }
 
+/* Test and clear port RWC bit */
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+				int port_id, u32 port_bit)
+{
+	u32 temp;
+
+	temp = xhci_readl(xhci, port_array[port_id]);
+	if (temp & port_bit) {
+		temp = xhci_port_state_to_neutral(temp);
+		temp |= port_bit;
+		xhci_writel(xhci, temp, port_array[port_id]);
+	}
+}
+
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 		u16 wIndex, char *buf, u16 wLength)
 {
@@ -924,12 +938,8 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 			spin_lock_irqsave(&xhci->lock, flags);
 
 			/* Clear PLC */
-			temp = xhci_readl(xhci, port_array[port_index]);
-			if (temp & PORT_PLC) {
-				temp = xhci_port_state_to_neutral(temp);
-				temp |= PORT_PLC;
-				xhci_writel(xhci, temp, port_array[port_index]);
-			}
+			xhci_test_and_clear_bit(xhci, port_array, port_index,
+						PORT_PLC);
 
 			slot_id = xhci_find_slot_id_by_port(hcd,
 					xhci, port_index + 1);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index ac45c53..68bda1b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1340,10 +1340,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
 			xhci_ring_device(xhci, slot_id);
 			xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
 			/* Clear PORT_PLC */
-			temp = xhci_readl(xhci, port_array[faked_port_index]);
-			temp = xhci_port_state_to_neutral(temp);
-			temp |= PORT_PLC;
-			xhci_writel(xhci, temp, port_array[faked_port_index]);
+			xhci_test_and_clear_bit(xhci, port_array,
+						faked_port_index, PORT_PLC);
 		} else {
 			xhci_dbg(xhci, "resume HS port %d\n", port_id);
 			bus_state->resume_done[faked_port_index] = jiffies +
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 59e83bf..2f49554 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1574,6 +1574,8 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
 /* xHCI roothub code */
 void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 				int port_id, u32 link_state);
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+				int port_id, u32 port_bit);
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
 		char *buf, u16 wLength);
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
-- 
1.7.4.1

>From 341f24b7da73da65cc3811951c1e6d2ed6f476c7 Mon Sep 17 00:00:00 2001
From: Andiry Xu <andiry.xu@xxxxxxx>
Date: Wed, 17 Aug 2011 06:12:51 +0800
Subject: [PATCH 5/9] xHCI: Clear PLC for USB2 root hub ports

When the link state changes, xHC will report a port status change event
and set the PORT_PLC bit, for both USB3 and USB2 root hub ports.

The PLC will be cleared by usbcore for USB3 root hub ports, but not for
USB2 ports, because they do not report USB_PORT_STAT_C_LINK_STATE in
wPortChange.

Clear it for USB2 root hub ports in handle_port_status().

Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
---
 drivers/usb/host/xhci-ring.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 68bda1b..4f5faa1 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1352,6 +1352,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
 		}
 	}
 
+	if (hcd->speed != HCD_USB3)
+		xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
+					PORT_PLC);
+
 cleanup:
 	/* Update event ring dequeue pointer before dropping the lock */
 	inc_deq(xhci, xhci->event_ring, true);
-- 
1.7.4.1


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

  Powered by Linux