xhci: Index with a port array instead of PORTSC addresses.
In the upcoming patches, the roothub emulation code will need to return port status and port change buffers based on whether they are called with the xHCI USB 2.0 or USB 3.0 roothub. To facilitate that, make the roothub code index into an array of port addresses with wIndex, rather than calculating the address using the offset and the address of the PORTSC registers. Later we can set the port array to be the array of USB 3.0 port addresses, or the USB 2.0 port addresses, depending on the roothub passed in. Create a temporary (statically sized) port array and fill it in with both USB 3.0 and USB 2.0 port addresses. This is inefficient to do for every roothub call, but this is needed for git bisect compatibility. The temporary port array will be deleted in a subsequent patch. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
This commit is contained in:
parent
ff9d78b36f
commit
5308a91b9f
2 changed files with 95 additions and 53 deletions
|
@ -288,10 +288,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
unsigned long flags;
|
||||
u32 temp, temp1, status;
|
||||
int retval = 0;
|
||||
u32 __iomem *addr;
|
||||
u32 __iomem *port_array[15 + USB_MAXCHILDREN];
|
||||
int i;
|
||||
int slot_id;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
switch (typeReq) {
|
||||
|
@ -307,8 +315,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
goto error;
|
||||
wIndex--;
|
||||
status = 0;
|
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
|
||||
/* wPortChange bits */
|
||||
|
@ -336,7 +343,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp1 = xhci_port_state_to_neutral(temp);
|
||||
temp1 &= ~PORT_PLS_MASK;
|
||||
temp1 |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp1, addr);
|
||||
xhci_writel(xhci, temp1, port_array[wIndex]);
|
||||
|
||||
xhci_dbg(xhci, "set port %d resume\n",
|
||||
wIndex + 1);
|
||||
|
@ -379,12 +386,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
if (!wIndex || wIndex > ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
/* In spec software should not attempt to suspend
|
||||
* a port unless the port reports that it is in the
|
||||
* enabled (PED = ‘1’,PLS < ‘3’) state.
|
||||
|
@ -409,13 +415,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U3;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[wIndex]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(10); /* wait device to enter */
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci->suspended_ports |= 1 << wIndex;
|
||||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
|
@ -425,34 +431,34 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
* However, khubd will ignore the roothub events until
|
||||
* the roothub is registered.
|
||||
*/
|
||||
xhci_writel(xhci, temp | PORT_POWER, addr);
|
||||
xhci_writel(xhci, temp | PORT_POWER,
|
||||
port_array[wIndex]);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
break;
|
||||
case USB_PORT_FEAT_RESET:
|
||||
temp = (temp | PORT_RESET);
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[wIndex]);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
temp = xhci_readl(xhci, addr); /* unblock any posted writes */
|
||||
/* unblock any posted writes */
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
break;
|
||||
case ClearPortFeature:
|
||||
if (!wIndex || wIndex > ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS*(wIndex & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
|
||||
xhci_dbg(xhci, "PORTSC %04x\n", temp);
|
||||
if (temp & PORT_RESET)
|
||||
|
@ -464,24 +470,28 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_readl(xhci, addr);
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
xhci_readl(xhci, port_array[wIndex]);
|
||||
} else {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock,
|
||||
flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci,
|
||||
port_array[wIndex]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
}
|
||||
xhci->port_c_suspend |= 1 << wIndex;
|
||||
}
|
||||
|
@ -500,10 +510,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
case USB_PORT_FEAT_C_OVER_CURRENT:
|
||||
case USB_PORT_FEAT_C_ENABLE:
|
||||
xhci_clear_port_change_bit(xhci, wValue, wIndex,
|
||||
addr, temp);
|
||||
port_array[wIndex], temp);
|
||||
break;
|
||||
case USB_PORT_FEAT_ENABLE:
|
||||
xhci_disable_port(xhci, wIndex, addr, temp);
|
||||
xhci_disable_port(xhci, wIndex,
|
||||
port_array[wIndex], temp);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
|
@ -534,9 +545,16 @@ 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 *addr;
|
||||
u32 __iomem *port_array[15 + USB_MAXCHILDREN];
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
/* Initial status is no changes */
|
||||
retval = (ports + 8) / 8;
|
||||
|
@ -548,9 +566,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
|||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* For each port, did anything change? If so, set that bit in buf. */
|
||||
for (i = 0; i < ports; i++) {
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS*i;
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[i]);
|
||||
if ((temp & mask) != 0 ||
|
||||
(xhci->port_c_suspend & 1 << i) ||
|
||||
(xhci->resume_done[i] && time_after_eq(
|
||||
|
@ -569,10 +585,19 @@ 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;
|
||||
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];
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
|
@ -593,13 +618,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
xhci->bus_suspended = 0;
|
||||
while (port_index--) {
|
||||
/* suspend the port if the port is not suspended */
|
||||
u32 __iomem *addr;
|
||||
u32 t1, t2;
|
||||
int slot_id;
|
||||
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS * (port_index & 0xff);
|
||||
t1 = xhci_readl(xhci, addr);
|
||||
t1 = xhci_readl(xhci, port_array[port_index]);
|
||||
t2 = xhci_port_state_to_neutral(t1);
|
||||
|
||||
if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
|
||||
|
@ -628,15 +650,17 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
|
||||
t1 = xhci_port_state_to_neutral(t1);
|
||||
if (t1 != t2)
|
||||
xhci_writel(xhci, t2, addr);
|
||||
xhci_writel(xhci, t2, port_array[port_index]);
|
||||
|
||||
if (DEV_HIGHSPEED(t1)) {
|
||||
/* enable remote wake up for USB 2.0 */
|
||||
u32 __iomem *addr;
|
||||
u32 tmp;
|
||||
|
||||
addr = &xhci->op_regs->port_power_base +
|
||||
NUM_PORT_REGS * (port_index & 0xff);
|
||||
/* Add one to the port status register address to get
|
||||
* the port power control register address.
|
||||
*/
|
||||
addr = port_array[port_index] + 1;
|
||||
tmp = xhci_readl(xhci, addr);
|
||||
tmp |= PORT_RWE;
|
||||
xhci_writel(xhci, tmp, addr);
|
||||
|
@ -652,11 +676,20 @@ 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 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 (time_before(jiffies, xhci->next_statechange))
|
||||
msleep(5);
|
||||
|
@ -676,13 +709,10 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|||
while (port_index--) {
|
||||
/* Check whether need resume ports. If needed
|
||||
resume port and disable remote wakeup */
|
||||
u32 __iomem *addr;
|
||||
u32 temp;
|
||||
int slot_id;
|
||||
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS * (port_index & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[port_index]);
|
||||
if (DEV_SUPERSPEED(temp))
|
||||
temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
|
||||
else
|
||||
|
@ -693,36 +723,38 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
} else {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_readl(xhci, port_array[port_index]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
}
|
||||
slot_id = xhci_find_slot_id_by_port(xhci, port_index + 1);
|
||||
if (slot_id)
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
} else
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
|
||||
if (DEV_HIGHSPEED(temp)) {
|
||||
/* disable remote wake up for USB 2.0 */
|
||||
u32 __iomem *addr;
|
||||
u32 tmp;
|
||||
|
||||
addr = &xhci->op_regs->port_power_base +
|
||||
NUM_PORT_REGS * (port_index & 0xff);
|
||||
/* Add one to the port status register address to get
|
||||
* the port power control register address.
|
||||
*/
|
||||
addr = port_array[port_index] + 1;
|
||||
tmp = xhci_readl(xhci, addr);
|
||||
tmp &= ~PORT_RWE;
|
||||
xhci_writel(xhci, tmp, addr);
|
||||
|
|
|
@ -1161,9 +1161,11 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||
u32 port_id;
|
||||
u32 temp, temp1;
|
||||
u32 __iomem *addr;
|
||||
int max_ports;
|
||||
int slot_id;
|
||||
unsigned int faked_port_index;
|
||||
u32 __iomem *port_array[15 + USB_MAXCHILDREN];
|
||||
int i;
|
||||
|
||||
/* Port status change events always have a successful completion code */
|
||||
if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
|
||||
|
@ -1179,8 +1181,16 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * (port_id - 1);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
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];
|
||||
}
|
||||
|
||||
faked_port_index = port_id;
|
||||
temp = xhci_readl(xhci, port_array[faked_port_index]);
|
||||
if (hcd->state == HC_STATE_SUSPENDED) {
|
||||
xhci_dbg(xhci, "resume root hub\n");
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
|
@ -1200,7 +1210,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[faked_port_index]);
|
||||
slot_id = xhci_find_slot_id_by_port(xhci, port_id);
|
||||
if (!slot_id) {
|
||||
xhci_dbg(xhci, "slot_id is zero\n");
|
||||
|
@ -1209,10 +1219,10 @@ 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, addr);
|
||||
temp = xhci_readl(xhci, port_array[faked_port_index]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp |= PORT_PLC;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_writel(xhci, temp, port_array[faked_port_index]);
|
||||
} else {
|
||||
xhci_dbg(xhci, "resume HS port %d\n", port_id);
|
||||
xhci->resume_done[port_id - 1] = jiffies +
|
||||
|
|
Reference in a new issue