Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 235439
b: refs/heads/master
c: f6ff0ac
h: refs/heads/master
i:
  235437: aee8296
  235435: b417c0f
  235431: b4c928f
  235423: 0a1a97b
v: v3
  • Loading branch information
Sarah Sharp committed Mar 14, 2011
1 parent 9c81808 commit 1b27a41
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 89 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5233630fcdd6f7d415dcbed264031439cab73f9d
refs/heads/master: f6ff0ac878eb420011fa2448851dd48c3a7e7b31
97 changes: 52 additions & 45 deletions trunk/drivers/usb/host/xhci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
PORT_RC | PORT_PLC | PORT_PE)

static void xhci_hub_descriptor(struct xhci_hcd *xhci,
static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
struct usb_hub_descriptor *desc)
{
int ports;
u16 temp;

ports = HCS_MAX_PORTS(xhci->hcs_params1);
if (hcd->speed == HCD_USB3)
ports = xhci->num_usb3_ports;
else
ports = xhci->num_usb2_ports;

/* FIXME: return a USB 3.0 hub descriptor if this request was for the
* USB3 roothub.
*/

/* USB 3.0 hubs have a different descriptor, but we fake this for now */
desc->bDescriptorType = 0x29;
Expand Down Expand Up @@ -134,18 +141,22 @@ u32 xhci_port_state_to_neutral(u32 state)

/*
* find slot id based on port number.
* @port: The one-based port number from one of the two split roothubs.
*/
int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
u16 port)
{
int slot_id;
int i;
enum usb_device_speed speed;

slot_id = 0;
for (i = 0; i < MAX_HC_SLOTS; i++) {
if (!xhci->devs[i])
continue;
if (xhci->devs[i]->port == port) {
speed = xhci->devs[i]->udev->speed;
if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3))
&& xhci->devs[i]->port == port) {
slot_id = i;
break;
}
Expand Down Expand Up @@ -226,11 +237,11 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
return;
}

static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
u32 __iomem *addr, u32 port_status)
static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
u16 wIndex, u32 __iomem *addr, u32 port_status)
{
/* Don't allow the USB core to disable SuperSpeed ports. */
if (xhci->port_array[wIndex] == 0x03) {
if (hcd->speed == HCD_USB3) {
xhci_dbg(xhci, "Ignoring request to disable "
"SuperSpeed port.\n");
return;
Expand Down Expand Up @@ -289,18 +300,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
unsigned long flags;
u32 temp, temp1, status;
int retval = 0;
u32 __iomem *port_array[15 + USB_MAXCHILDREN];
int i;
u32 __iomem **port_array;
int slot_id;
struct xhci_bus_state *bus_state;

ports = HCS_MAX_PORTS(xhci->hcs_params1);
for (i = 0; i < ports; i++) {
if (i < xhci->num_usb3_ports)
port_array[i] = xhci->usb3_ports[i];
else
port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports];
if (hcd->speed == HCD_USB3) {
ports = xhci->num_usb3_ports;
port_array = xhci->usb3_ports;
} else {
ports = xhci->num_usb2_ports;
port_array = xhci->usb2_ports;
}
bus_state = &xhci->bus_state[hcd_index(hcd)];

Expand All @@ -311,7 +320,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
memset(buf, 0, 4);
break;
case GetHubDescriptor:
xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf);
xhci_hub_descriptor(hcd, xhci,
(struct usb_hub_descriptor *) buf);
break;
case GetPortStatus:
if (!wIndex || wIndex > ports)
Expand Down Expand Up @@ -518,7 +528,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
port_array[wIndex], temp);
break;
case USB_PORT_FEAT_ENABLE:
xhci_disable_port(xhci, wIndex,
xhci_disable_port(hcd, xhci, wIndex,
port_array[wIndex], temp);
break;
default:
Expand Down Expand Up @@ -550,16 +560,15 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
int i, retval;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int ports;
u32 __iomem *port_array[15 + USB_MAXCHILDREN];
u32 __iomem **port_array;
struct xhci_bus_state *bus_state;

ports = HCS_MAX_PORTS(xhci->hcs_params1);
for (i = 0; i < ports; i++) {
if (i < xhci->num_usb3_ports)
port_array[i] = xhci->usb3_ports[i];
else
port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports];
if (hcd->speed == HCD_USB3) {
ports = xhci->num_usb3_ports;
port_array = xhci->usb3_ports;
} else {
ports = xhci->num_usb2_ports;
port_array = xhci->usb2_ports;
}
bus_state = &xhci->bus_state[hcd_index(hcd)];

Expand Down Expand Up @@ -592,19 +601,18 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int max_ports, port_index;
u32 __iomem *port_array[15 + USB_MAXCHILDREN];
int i;
u32 __iomem **port_array;
struct xhci_bus_state *bus_state;
unsigned long flags;

xhci_dbg(xhci, "suspend root hub\n");
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
for (i = 0; i < max_ports; i++) {
if (i < xhci->num_usb3_ports)
port_array[i] = xhci->usb3_ports[i];
else
port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports];
if (hcd->speed == HCD_USB3) {
max_ports = xhci->num_usb3_ports;
port_array = xhci->usb3_ports;
xhci_dbg(xhci, "suspend USB 3.0 root hub\n");
} else {
max_ports = xhci->num_usb2_ports;
port_array = xhci->usb2_ports;
xhci_dbg(xhci, "suspend USB 2.0 root hub\n");
}
bus_state = &xhci->bus_state[hcd_index(hcd)];

Expand Down Expand Up @@ -685,20 +693,19 @@ int xhci_bus_resume(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int max_ports, port_index;
u32 __iomem *port_array[15 + USB_MAXCHILDREN];
int i;
u32 __iomem **port_array;
struct xhci_bus_state *bus_state;
u32 temp;
unsigned long flags;

xhci_dbg(xhci, "resume root hub\n");
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
for (i = 0; i < max_ports; i++) {
if (i < xhci->num_usb3_ports)
port_array[i] = xhci->usb3_ports[i];
else
port_array[i] =
xhci->usb2_ports[i - xhci->num_usb3_ports];
if (hcd->speed == HCD_USB3) {
max_ports = xhci->num_usb3_ports;
port_array = xhci->usb3_ports;
xhci_dbg(xhci, "resume USB 3.0 root hub\n");
} else {
max_ports = xhci->num_usb2_ports;
port_array = xhci->usb2_ports;
xhci_dbg(xhci, "resume USB 2.0 root hub\n");
}
bus_state = &xhci->bus_state[hcd_index(hcd)];

Expand Down
66 changes: 62 additions & 4 deletions trunk/drivers/usb/host/xhci-mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,14 +814,64 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
ep0_ctx->deq |= ep_ring->cycle_state;
}

/*
* The xHCI roothub may have ports of differing speeds in any order in the port
* status registers. xhci->port_array provides an array of the port speed for
* each offset into the port status registers.
*
* The xHCI hardware wants to know the roothub port number that the USB device
* is attached to (or the roothub port its ancestor hub is attached to). All we
* know is the index of that port under either the USB 2.0 or the USB 3.0
* roothub, but that doesn't give us the real index into the HW port status
* registers. Scan through the xHCI roothub port array, looking for the Nth
* entry of the correct port speed. Return the port number of that entry.
*/
static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
struct usb_device *udev)
{
struct usb_device *top_dev;
unsigned int num_similar_speed_ports;
unsigned int faked_port_num;
int i;

for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent)
/* Found device below root hub */;
faked_port_num = top_dev->portnum;
for (i = 0, num_similar_speed_ports = 0;
i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
u8 port_speed = xhci->port_array[i];

/*
* Skip ports that don't have known speeds, or have duplicate
* Extended Capabilities port speed entries.
*/
if (port_speed == 0 || port_speed == -1)
continue;

/*
* USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and
* 1.1 ports are under the USB 2.0 hub. If the port speed
* matches the device speed, it's a similar speed port.
*/
if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER))
num_similar_speed_ports++;
if (num_similar_speed_ports == faked_port_num)
/* Roothub ports are numbered from 1 to N */
return i+1;
}
return 0;
}

/* Setup an xHCI virtual device for a Set Address command */
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev)
{
struct xhci_virt_device *dev;
struct xhci_ep_ctx *ep0_ctx;
struct usb_device *top_dev;
struct xhci_slot_ctx *slot_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
u32 port_num;
struct usb_device *top_dev;

dev = xhci->devs[udev->slot_id];
/* Slot ID 0 is reserved */
Expand Down Expand Up @@ -863,12 +913,17 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
BUG();
}
/* Find the root hub port this device is under */
port_num = xhci_find_real_port_number(xhci, udev);
if (!port_num)
return -EINVAL;
slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(port_num);
/* Set the port number in the virtual_device to the faked port number */
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent)
/* Found device below root hub */;
slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
dev->port = top_dev->portnum;
xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
xhci_dbg(xhci, "Set root hub portnum to %d\n", port_num);
xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->port);

/* Is this a LS/FS device under an external HS hub? */
if (udev->tt && udev->tt->hub->parent) {
Expand Down Expand Up @@ -1452,6 +1507,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->page_size = 0;
xhci->page_shift = 0;
xhci->bus_state[0].bus_suspended = 0;
xhci->bus_state[1].bus_suspended = 0;
}

static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
Expand Down Expand Up @@ -1970,8 +2026,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
init_completion(&xhci->addr_dev);
for (i = 0; i < MAX_HC_SLOTS; ++i)
xhci->devs[i] = NULL;
for (i = 0; i < USB_MAXCHILDREN; ++i)
for (i = 0; i < USB_MAXCHILDREN; ++i) {
xhci->bus_state[0].resume_done[i] = 0;
xhci->bus_state[1].resume_done[i] = 0;
}

if (scratchpad_alloc(xhci, flags))
goto fail;
Expand Down
Loading

0 comments on commit 1b27a41

Please sign in to comment.