Hi Paul, There's a lot more work that needs to be done than just this patch. I've been working on getting that done on the 'hubs-v3' branch in my repository. I've built on top of John's patch and modified it based on community feedback. It's on my todo list for this weekend to get the final feedback integrated and try to push out a new RFC next week. Greg, NAK on this patch for now. Sarah Sharp On Fri, Feb 25, 2011 at 01:39:20PM -0800, Paul Zimmerman wrote: > From: John Youn <johnyoun@xxxxxxxxxxxx> > > Make the following changes to work with SuperSpeed hubs: > - Add new constants in header > - Add check for superspeed hubs > - Skip some things not needed for superspeed hub > - Set the hub depth after enumeration to address downstream ports > - Modify the port status and port changed bits from the hub > > Signed-off-by: John Youn <johnyoun@xxxxxxxxxxxx> > Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx> > --- > > Hi Sarah, > > Can we finally get John's hub patches queued for .39? There are SuperSpeed > hubs in the market now (e.g. > http://www.amazon.com/SuperSpeed-USB-3-0-7-Port-Hub/dp/B003NE5I9I) so I > think we should have the support in the kernel. It also makes it easier > for us not needing to patch the kernel every time a new version is > released. > > I seem to recall some objections to a couple of things in the patch, but I > don't remember what those were now. > > The diffs are against Greg's for-linus branch. > > -Paul > > > drivers/usb/core/hub.c | 60 +++++++++++++++++++++++++++++++++++++++++++-- > include/linux/usb/ch11.h | 30 +++++++++++++++++++++++ > 2 files changed, 87 insertions(+), 3 deletions(-) > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c > index 0f299b7..fb8e96b 100644 > --- a/drivers/usb/core/hub.c > +++ b/drivers/usb/core/hub.c > @@ -82,6 +82,10 @@ struct usb_hub { > void **port_owners; > }; > > +static inline int hub_is_superspeed(struct usb_device *hdev) > +{ > + return (hdev->descriptor.bDeviceProtocol == 3); > +} > > /* Protect struct usb_device->state and ->children members > * Note: Both are also protected by ->dev.sem, except that ->state can > @@ -176,10 +180,17 @@ static int get_hub_descriptor(struct usb_device *hdev, void *data, int size) > { > int i, ret; > > + unsigned dtype = USB_DT_HUB; > + > + if (hub_is_superspeed(hdev)) { > + dtype = USB_DT_SS_HUB; > + size = 12; > + } > + > for (i = 0; i < 3; i++) { > ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), > USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, > - USB_DT_HUB << 8, 0, data, size, > + dtype << 8, 0, data, size, > USB_CTRL_GET_TIMEOUT); > if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2)) > return ret; > @@ -365,6 +376,17 @@ static int hub_port_status(struct usb_hub *hub, int port1, > } else { > *status = le16_to_cpu(hub->status->port.wPortStatus); > *change = le16_to_cpu(hub->status->port.wPortChange); > + > + if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev)) { > + /* Translate the USB 3 port status */ > + u16 tmp = *status & USB3_PORT_STAT_MASK; > + if (*status & USB3_PORT_STAT_POWER) > + tmp |= USB_PORT_STAT_POWER; > + if ((*status & USB3_PORT_STAT_SPEED) == USB3_PORT_STAT_SPEED_SUPER) > + tmp |= USB_PORT_STAT_SUPER_SPEED; > + *status = tmp; > + } > + > ret = 0; > } > mutex_unlock(&hub->status_mutex); > @@ -607,7 +629,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) > if (hdev->children[port1-1] && set_state) > usb_set_device_state(hdev->children[port1-1], > USB_STATE_NOTATTACHED); > - if (!hub->error) > + if (!hub->error && !hub_is_superspeed(hdev)) > ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); > if (ret) > dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", > @@ -795,6 +817,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) > clear_port_feature(hub->hdev, port1, > USB_PORT_FEAT_C_ENABLE); > } > + if (portchange & USB_PORT_STAT_C_LINK_STATE) { > + need_debounce_delay = true; > + clear_port_feature(hub->hdev, port1, > + USB_PORT_FEAT_C_PORT_LINK_STATE); > + } > > /* We can forget about a "removed" device when there's a > * physical disconnect or the connect status changes. > @@ -964,6 +991,18 @@ static int hub_configure(struct usb_hub *hub, > goto fail; > } > > + if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) { > + ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), > + HUB_SET_DEPTH, USB_RT_HUB, > + hdev->level - 1, 0, NULL, 0, > + USB_CTRL_SET_TIMEOUT); > + > + if (ret < 0) { > + message = "can't set hub depth"; > + goto fail; > + } > + } > + > /* Request the entire hub descriptor. > * hub->descriptor can handle USB_MAXCHILDREN ports, > * but the hub can/will return fewer bytes here. > @@ -991,7 +1030,8 @@ static int hub_configure(struct usb_hub *hub, > > wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); > > - if (wHubCharacteristics & HUB_CHAR_COMPOUND) { > + /* FIXME for USB 3.0, skip for now */ > + if ((wHubCharacteristics & HUB_CHAR_COMPOUND) && !(hub_is_superspeed(hdev))) { > int i; > char portstr [USB_MAXCHILDREN + 1]; > > @@ -3423,6 +3463,20 @@ static void hub_events(void) > clear_port_feature(hdev, i, > USB_PORT_FEAT_C_RESET); > } > + if (portchange & USB_PORT_STAT_C_LINK_STATE) { > + dev_dbg (hub_dev, > + "link state change on port %d\n", > + i); > + clear_port_feature(hub->hdev, i, > + USB_PORT_FEAT_C_PORT_LINK_STATE); > + } > + if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { > + dev_dbg (hub_dev, > + "config error on port %d\n", > + i); > + clear_port_feature(hub->hdev, i, > + USB_PORT_FEAT_C_PORT_CONFIG_ERROR); > + } > > if (connect_change) > hub_port_connect_change(hub, i, > diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h > index 10ec069..3edf7bc 100644 > --- a/include/linux/usb/ch11.h > +++ b/include/linux/usb/ch11.h > @@ -26,6 +26,7 @@ > #define HUB_RESET_TT 9 > #define HUB_GET_TT_STATE 10 > #define HUB_STOP_TT 11 > +#define HUB_SET_DEPTH 12 > > /* > * Hub class additional requests defined by USB 3.0 spec > @@ -61,6 +62,12 @@ > #define USB_PORT_FEAT_TEST 21 > #define USB_PORT_FEAT_INDICATOR 22 > #define USB_PORT_FEAT_C_PORT_L1 23 > +#define USB_PORT_FEAT_C_PORT_LINK_STATE 25 > +#define USB_PORT_FEAT_C_PORT_CONFIG_ERROR 26 > +#define USB_PORT_FEAT_PORT_REMOTE_WAKE_MASK 27 > +#define USB_PORT_FEAT_BH_PORT_RESET 28 > +#define USB_PORT_FEAT_C_BH_PORT_RESET 29 > +#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30 > > /* > * Port feature selectors added by USB 3.0 spec. > @@ -131,6 +138,21 @@ struct usb_port_status { > #define USB_SS_PORT_LS_LOOPBACK 0x0160 > > /* > + * USB 3.0 wPortStatus bit fields > + * See USB 3.0 spec Table 10-10 > + */ > +/* Bits that are the same from USB 2.0 */ > +#define USB3_PORT_STAT_MASK (USB_PORT_STAT_CONNECTION | \ > + USB_PORT_STAT_ENABLE | \ > + USB_PORT_STAT_OVERCURRENT | \ > + USB_PORT_STAT_RESET) > +/* 3.0 specific bits */ > +#define USB3_PORT_STAT_LINK_STATE 0x01e0 > +#define USB3_PORT_STAT_POWER 0x0200 > +#define USB3_PORT_STAT_SPEED 0x1c00 > +#define USB3_PORT_STAT_SPEED_SUPER 0x0 > + > +/* > * wPortChange bit field > * See USB 2.0 spec Table 11-22 > * Bits 0 to 4 shown, bits 5 to 15 are reserved > @@ -141,6 +163,13 @@ struct usb_port_status { > #define USB_PORT_STAT_C_OVERCURRENT 0x0008 > #define USB_PORT_STAT_C_RESET 0x0010 > #define USB_PORT_STAT_C_L1 0x0020 > +/* > + * USB 3.0 wPortChange bit fields > + * See USB 3.0 spec Table 10-11 > + */ > +#define USB_PORT_STAT_C_BH_RESET 0x0020 > +#define USB_PORT_STAT_C_LINK_STATE 0x0040 > +#define USB_PORT_STAT_C_CONFIG_ERROR 0x0080 > > /* > * wHubCharacteristics (masks) > @@ -175,6 +204,7 @@ struct usb_hub_status { > */ > > #define USB_DT_HUB (USB_TYPE_CLASS | 0x09) > +#define USB_DT_SS_HUB (USB_TYPE_CLASS | 0x0a) > #define USB_DT_HUB_NONVAR_SIZE 7 > > struct usb_hub_descriptor { > -- > 1.6.5.1.69.g36942 > > > -- 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