aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2011-05-02 17:05:19 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-02 17:05:23 -0700
commitdbc265465a3fc8ac8d75d3ede7e84ea122a8fd0a (patch)
tree59e1ebdf34f49c48a5603ca541508492672eaecd /drivers/usb
parent71a9f9d268a5c2b0a80ae606cf8e502f3410a5df (diff)
parentb61d378f2da41c748aba6ca19d77e1e1c02bcea5 (diff)
Merge branch 'for-usb-next' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-next
* 'for-usb-next' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci: xhci 1.0: Set transfer burst last packet count field. xhci 1.0: Set transfer burst count field. xhci 1.0: Update TD size field format. xhci 1.0: Only interrupt on short packet for IN EPs. xhci: Remove sparse warning about cmd_status. usbcore: warm reset USB3 port in SS.Inactive state usbcore: Refine USB3.0 device suspend and resume xHCI: report USB3.0 portstatus comply with USB3.0 specification xHCI: Set link state support xHCI: Clear link state change support xHCI: warm reset support usb/ch9: use proper endianess for wBytesPerInterval xhci: Remove recursive call to xhci_handle_event xhci: Add an assertion to check for virt_dev=0 bug. xhci: Add rmb() between reading event validity & event data access. xhci: Make xHCI driver endian-safe
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/config.c2
-rw-r--r--drivers/usb/core/hub.c131
-rw-r--r--drivers/usb/host/xhci-dbg.c51
-rw-r--r--drivers/usb/host/xhci-hub.c165
-rw-r--r--drivers/usb/host/xhci-mem.c124
-rw-r--r--drivers/usb/host/xhci-ring.c477
-rw-r--r--drivers/usb/host/xhci.c124
-rw-r--r--drivers/usb/host/xhci.h136
8 files changed, 762 insertions, 448 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 83126b03e7c..c962608b4b9 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -129,7 +129,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
else
max_tx = 999999;
- if (desc->wBytesPerInterval > max_tx) {
+ if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to %d\n",
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 93720bdc9ef..79a58c3a2e2 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1,
*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 & USB_SS_PORT_STAT_MASK;
- if (*status & USB_SS_PORT_STAT_POWER)
- tmp |= USB_PORT_STAT_POWER;
- *status = tmp;
- }
-
ret = 0;
}
mutex_unlock(&hub->status_mutex);
@@ -2160,11 +2151,76 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
return status;
}
+/* Warm reset a USB3 protocol port */
+static int hub_port_warm_reset(struct usb_hub *hub, int port)
+{
+ int ret;
+ u16 portstatus, portchange;
+
+ if (!hub_is_superspeed(hub->hdev)) {
+ dev_err(hub->intfdev, "only USB3 hub support warm reset\n");
+ return -EINVAL;
+ }
+
+ /* Warm reset the port */
+ ret = set_port_feature(hub->hdev,
+ port, USB_PORT_FEAT_BH_PORT_RESET);
+ if (ret) {
+ dev_err(hub->intfdev, "cannot warm reset port %d\n", port);
+ return ret;
+ }
+
+ msleep(20);
+ ret = hub_port_status(hub, port, &portstatus, &portchange);
+
+ if (portchange & USB_PORT_STAT_C_RESET)
+ clear_port_feature(hub->hdev, port, USB_PORT_FEAT_C_RESET);
+
+ if (portchange & USB_PORT_STAT_C_BH_RESET)
+ clear_port_feature(hub->hdev, port,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+
+ if (portchange & USB_PORT_STAT_C_LINK_STATE)
+ clear_port_feature(hub->hdev, port,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+
+ return ret;
+}
+
+/* Check if a port is power on */
+static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
+{
+ int ret = 0;
+
+ if (hub_is_superspeed(hub->hdev)) {
+ if (portstatus & USB_SS_PORT_STAT_POWER)
+ ret = 1;
+ } else {
+ if (portstatus & USB_PORT_STAT_POWER)
+ ret = 1;
+ }
+
+ return ret;
+}
+
#ifdef CONFIG_PM
-#define MASK_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION | \
- USB_PORT_STAT_SUSPEND)
-#define WANT_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION)
+/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
+static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
+{
+ int ret = 0;
+
+ if (hub_is_superspeed(hub->hdev)) {
+ if ((portstatus & USB_PORT_STAT_LINK_STATE)
+ == USB_SS_PORT_LS_U3)
+ ret = 1;
+ } else {
+ if (portstatus & USB_PORT_STAT_SUSPEND)
+ ret = 1;
+ }
+
+ return ret;
+}
/* Determine whether the device on a port is ready for a normal resume,
* is ready for a reset-resume, or should be disconnected.
@@ -2174,7 +2230,9 @@ static int check_port_resume_type(struct usb_device *udev,
int status, unsigned portchange, unsigned portstatus)
{
/* Is the device still present? */
- if (status || (portstatus & MASK_BITS) != WANT_BITS) {
+ if (status || port_is_suspended(hub, portstatus) ||
+ !port_is_power_on(hub, portstatus) ||
+ !(portstatus & USB_PORT_STAT_CONNECTION)) {
if (status >= 0)
status = -ENODEV;
}
@@ -2285,14 +2343,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
}
/* see 7.1.7.6 */
- /* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0
- * external hub.
- * FIXME: this is a temporary workaround to make the system able
- * to suspend/resume.
- */
- if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev))
- status = clear_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_POWER);
+ if (hub_is_superspeed(hub->hdev))
+ status = set_port_feature(hub->hdev,
+ port1 | (USB_SS_PORT_LS_U3 << 3),
+ USB_PORT_FEAT_LINK_STATE);
else
status = set_port_feature(hub->hdev, port1,
USB_PORT_FEAT_SUSPEND);
@@ -2439,7 +2493,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
/* Skip the initial Clear-Suspend step for a remote wakeup */
status = hub_port_status(hub, port1, &portstatus, &portchange);
- if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND))
+ if (status == 0 && !port_is_suspended(hub, portstatus))
goto SuspendCleared;
// dev_dbg(hub->intfdev, "resume port %d\n", port1);
@@ -2447,8 +2501,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
set_bit(port1, hub->busy_bits);
/* see 7.1.7.7; affects power usage, but not budgeting */
- status = clear_port_feature(hub->hdev,
- port1, USB_PORT_FEAT_SUSPEND);
+ if (hub_is_superspeed(hub->hdev))
+ status = set_port_feature(hub->hdev,
+ port1 | (USB_SS_PORT_LS_U0 << 3),
+ USB_PORT_FEAT_LINK_STATE);
+ else
+ status = clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_SUSPEND);
if (status) {
dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
port1, status);
@@ -2470,9 +2529,15 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
SuspendCleared:
if (status == 0) {
- if (portchange & USB_PORT_STAT_C_SUSPEND)
- clear_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_C_SUSPEND);
+ if (hub_is_superspeed(hub->hdev)) {
+ if (portchange & USB_PORT_STAT_C_LINK_STATE)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ } else {
+ if (portchange & USB_PORT_STAT_C_SUSPEND)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_SUSPEND);
+ }
}
clear_bit(port1, hub->busy_bits);
@@ -3147,7 +3212,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* maybe switch power back on (e.g. root hub was reset) */
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
- && !(portstatus & USB_PORT_STAT_POWER))
+ && !port_is_power_on(hub, portstatus))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
if (portstatus & USB_PORT_STAT_ENABLE)
@@ -3490,6 +3555,16 @@ static void hub_events(void)
USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
}
+ /* Warm reset a USB3 protocol port if it's in
+ * SS.Inactive state.
+ */
+ if (hub_is_superspeed(hub->hdev) &&
+ (portstatus & USB_PORT_STAT_LINK_STATE)
+ == USB_SS_PORT_LS_SS_INACTIVE) {
+ dev_dbg(hub_dev, "warm reset port %d\n", i);
+ hub_port_warm_reset(hub, i);
+ }
+
if (connect_change)
hub_port_connect_change(hub, i,
portstatus, portchange);
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 0231814a97a..2e0486178db 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -147,7 +147,7 @@ static void xhci_print_op_regs(struct xhci_hcd *xhci)
static void xhci_print_ports(struct xhci_hcd *xhci)
{
- u32 __iomem *addr;
+ __le32 __iomem *addr;
int i, j;
int ports;
char *names[NUM_PORT_REGS] = {
@@ -253,27 +253,27 @@ void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
{
u64 address;
- u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK;
+ u32 type = le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK;
switch (type) {
case TRB_TYPE(TRB_LINK):
xhci_dbg(xhci, "Link TRB:\n");
xhci_print_trb_offsets(xhci, trb);
- address = trb->link.segment_ptr;
+ address = le64_to_cpu(trb->link.segment_ptr);
xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
- GET_INTR_TARGET(trb->link.intr_target));
+ GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target)));
xhci_dbg(xhci, "Cycle bit = %u\n",
- (unsigned int) (trb->link.control & TRB_CYCLE));
+ (unsigned int) (le32_to_cpu(trb->link.control) & TRB_CYCLE));
xhci_dbg(xhci, "Toggle cycle bit = %u\n",
- (unsigned int) (trb->link.control & LINK_TOGGLE));
+ (unsigned int) (le32_to_cpu(trb->link.control) & LINK_TOGGLE));
xhci_dbg(xhci, "No Snoop bit = %u\n",
- (unsigned int) (trb->link.control & TRB_NO_SNOOP));
+ (unsigned int) (le32_to_cpu(trb->link.control) & TRB_NO_SNOOP));
break;
case TRB_TYPE(TRB_TRANSFER):
- address = trb->trans_event.buffer;
+ address = le64_to_cpu(trb->trans_event.buffer);
/*
* FIXME: look at flags to figure out if it's an address or if
* the data is directly in the buffer field.
@@ -281,11 +281,12 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
break;
case TRB_TYPE(TRB_COMPLETION):
- address = trb->event_cmd.cmd_trb;
+ address = le64_to_cpu(trb->event_cmd.cmd_trb);
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
xhci_dbg(xhci, "Completion status = %u\n",
- (unsigned int) GET_COMP_CODE(trb->event_cmd.status));
- xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags);
+ (unsigned int) GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
+ xhci_dbg(xhci, "Flags = 0x%x\n",
+ (unsigned int) le32_to_cpu(trb->event_cmd.flags));
break;
default:
xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
@@ -311,16 +312,16 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
{
int i;
- u32 addr = (u32) seg->dma;
+ u64 addr = seg->dma;
union xhci_trb *trb = seg->trbs;
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
trb = &seg->trbs[i];
- xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
- lower_32_bits(trb->link.segment_ptr),
- upper_32_bits(trb->link.segment_ptr),
- (unsigned int) trb->link.intr_target,
- (unsigned int) trb->link.control);
+ xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr,
+ (u32)lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+ (u32)upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+ (unsigned int) le32_to_cpu(trb->link.intr_target),
+ (unsigned int) le32_to_cpu(trb->link.control));
addr += sizeof(*trb);
}
}
@@ -391,18 +392,18 @@ void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
{
- u32 addr = (u32) erst->erst_dma_addr;
+ u64 addr = erst->erst_dma_addr;
int i;
struct xhci_erst_entry *entry;
for (i = 0; i < erst->num_entries; ++i) {
entry = &erst->entries[i];
- xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
- (unsigned int) addr,
- lower_32_bits(entry->seg_addr),
- upper_32_bits(entry->seg_addr),
- (unsigned int) entry->seg_size,
- (unsigned int) entry->rsvd);
+ xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n",
+ addr,
+ lower_32_bits(le64_to_cpu(entry->seg_addr)),
+ upper_32_bits(le64_to_cpu(entry->seg_addr)),
+ (unsigned int) le32_to_cpu(entry->seg_size),
+ (unsigned int) le32_to_cpu(entry->rsvd));
addr += sizeof(*entry);
}
}
@@ -436,7 +437,7 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
{
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
- switch (GET_SLOT_STATE(slot_ctx->dev_state)) {
+ switch (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state))) {
case 0:
return "enabled/disabled";
case 1:
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index a78f2ebd11b..e3ddc6a95af 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -50,7 +50,7 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
temp |= 0x0008;
/* Bits 6:5 - no TTs in root ports */
/* Bit 7 - no port indicators */
- desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp);
+ desc->wHubCharacteristics = cpu_to_le16(temp);
}
/* Fill in the USB 2.0 roothub descriptor */
@@ -314,7 +314,7 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
}
static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
- u16 wIndex, u32 __iomem *addr, u32 port_status)
+ u16 wIndex, __le32 __iomem *addr, u32 port_status)
{
/* Don't allow the USB core to disable SuperSpeed ports. */
if (hcd->speed == HCD_USB3) {
@@ -331,7 +331,7 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
}
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
- u16 wIndex, u32 __iomem *addr, u32 port_status)
+ u16 wIndex, __le32 __iomem *addr, u32 port_status)
{
char *port_change_bit;
u32 status;
@@ -341,6 +341,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
status = PORT_RC;
port_change_bit = "reset";
break;
+ case USB_PORT_FEAT_C_BH_PORT_RESET:
+ status = PORT_WRC;
+ port_change_bit = "warm(BH) reset";
+ break;
case USB_PORT_FEAT_C_CONNECTION:
status = PORT_CSC;
port_change_bit = "connect";
@@ -357,6 +361,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
status = PORT_PLC;
port_change_bit = "suspend/resume";
break;
+ case USB_PORT_FEAT_C_PORT_LINK_STATE:
+ status = PORT_PLC;
+ port_change_bit = "link state";
+ break;
default:
/* Should never happen */
return;
@@ -376,9 +384,10 @@ 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;
+ __le32 __iomem **port_array;
int slot_id;
struct xhci_bus_state *bus_state;
+ u16 link_state = 0;
if (hcd->speed == HCD_USB3) {
ports = xhci->num_usb3_ports;
@@ -422,9 +431,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
- /* FIXME - should we return a port status value like the USB
- * 3.0 external hubs do?
- */
/* wPortChange bits */
if (temp & PORT_CSC)
status |= USB_PORT_STAT_C_CONNECTION << 16;
@@ -432,13 +438,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
status |= USB_PORT_STAT_C_ENABLE << 16;
if ((temp & PORT_OCC))
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
- /*
- * FIXME ignoring reset and USB 2.1/3.0 specific
- * changes
- */
- if ((temp & PORT_PLS_MASK) == XDEV_U3
- && (temp & PORT_POWER))
- status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if ((temp & PORT_RC))
+ status |= USB_PORT_STAT_C_RESET << 16;
+ /* USB3.0 only */
+ if (hcd->speed == HCD_USB3) {
+ if ((temp & PORT_PLC))
+ status |= USB_PORT_STAT_C_LINK_STATE << 16;
+ if ((temp & PORT_WRC))
+ status |= USB_PORT_STAT_C_BH_RESET << 16;
+ }
+
+ if (hcd->speed != HCD_USB3) {
+ if ((temp & PORT_PLS_MASK) == XDEV_U3
+ && (temp & PORT_POWER))
+ status |= USB_PORT_STAT_SUSPEND;
+ }
if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
if ((temp & PORT_RESET) || !(temp & PORT_PE))
goto error;
@@ -469,7 +483,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
&& (temp & PORT_POWER)
&& (bus_state->suspended_ports & (1 << wIndex))) {
bus_state->suspended_ports &= ~(1 << wIndex);
- bus_state->port_c_suspend |= 1 << wIndex;
+ if (hcd->speed != HCD_USB3)
+ bus_state->port_c_suspend |= 1 << wIndex;
}
if (temp & PORT_CONNECT) {
status |= USB_PORT_STAT_CONNECTION;
@@ -481,14 +496,28 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
status |= USB_PORT_STAT_OVERCURRENT;
if (temp & PORT_RESET)
status |= USB_PORT_STAT_RESET;
- if (temp & PORT_POWER)
- status |= USB_PORT_STAT_POWER;
+ if (temp & PORT_POWER) {
+ if (hcd->speed == HCD_USB3)
+ status |= USB_SS_PORT_STAT_POWER;
+ else
+ status |= USB_PORT_STAT_POWER;
+ }
+ /* Port Link State */
+ if (hcd->speed == HCD_USB3) {
+ /* resume state is a xHCI internal state.
+ * Do not report it to usb core.
+ */
+ if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
+ status |= (temp & PORT_PLS_MASK);
+ }
if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
break;
case SetPortFeature:
+ if (wValue == USB_PORT_FEAT_LINK_STATE)
+ link_state = (wIndex & 0xff00) >> 3;
wIndex &= 0xff;
if (!wIndex || wIndex > ports)
goto error;
@@ -537,6 +566,44 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
bus_state->suspended_ports |= 1 << wIndex;
break;
+ case USB_PORT_FEAT_LINK_STATE:
+ temp = xhci_readl(xhci, port_array[wIndex]);
+ /* Software should not attempt to set
+ * port link state above '5' (Rx.Detect) and the port
+ * must be enabled.
+ */
+ if ((temp & PORT_PE) == 0 ||
+ (link_state > USB_SS_PORT_LS_RX_DETECT)) {
+ xhci_warn(xhci, "Cannot set link state.\n");
+ goto error;
+ }
+
+ if (link_state == USB_SS_PORT_LS_U3) {
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+ wIndex + 1);
+ if (slot_id) {
+ /* unlock to execute stop endpoint
+ * commands */
+ spin_unlock_irqrestore(&xhci->lock,
+ flags);
+ xhci_stop_device(xhci, slot_id, 1);
+ spin_lock_irqsave(&xhci->lock, flags);
+ }
+ }
+
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | link_state;
+ xhci_writel(xhci, temp, port_array[wIndex]);
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ msleep(20); /* wait device to enter */
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ temp = xhci_readl(xhci, port_array[wIndex]);
+ if (link_state == USB_SS_PORT_LS_U3)
+ bus_state->suspended_ports |= 1 << wIndex;
+ break;
case USB_PORT_FEAT_POWER:
/*
* Turn on ports, even if there isn't per-port switching.
@@ -557,6 +624,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
break;
+ case USB_PORT_FEAT_BH_PORT_RESET:
+ temp |= PORT_WR;
+ xhci_writel(xhci, temp, port_array[wIndex]);
+
+ temp = xhci_readl(xhci, port_array[wIndex]);
+ break;
default:
goto error;
}
@@ -584,35 +657,27 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (temp & XDEV_U3) {
if ((temp & PORT_PE) == 0)
goto error;
- if (DEV_SUPERSPEED(temp)) {
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U0;
- 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,
- port_array[wIndex]);
- spin_unlock_irqrestore(&xhci->lock,
- flags);
- msleep(20);
- spin_lock_irqsave(&xhci->lock, flags);
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | XDEV_RESUME;
+ xhci_writel(xhci, temp,
+ port_array[wIndex]);
- 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,
- port_array[wIndex]);
- }
- bus_state->port_c_suspend |= 1 << wIndex;
+ spin_unlock_irqrestore(&xhci->lock,
+ flags);
+ msleep(20);
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ 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,
+ port_array[wIndex]);
}
+ bus_state->port_c_suspend |= 1 << wIndex;
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
wIndex + 1);
@@ -625,9 +690,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_SUSPEND:
bus_state->port_c_suspend &= ~(1 << wIndex);
case USB_PORT_FEAT_C_RESET:
+ case USB_PORT_FEAT_C_BH_PORT_RESET:
case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_OVER_CURRENT:
case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_PORT_LINK_STATE:
xhci_clear_port_change_bit(xhci, wValue, wIndex,
port_array[wIndex], temp);
break;
@@ -664,7 +731,7 @@ 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;
+ __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
if (hcd->speed == HCD_USB3) {
@@ -681,7 +748,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
memset(buf, 0, retval);
status = 0;
- mask = PORT_CSC | PORT_PEC | PORT_OCC;
+ mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC;
spin_lock_irqsave(&xhci->lock, flags);
/* For each port, did anything change? If so, set that bit in buf. */
@@ -709,7 +776,7 @@ 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;
+ __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
unsigned long flags;
@@ -779,7 +846,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
if (DEV_HIGHSPEED(t1)) {
/* enable remote wake up for USB 2.0 */
- u32 __iomem *addr;
+ __le32 __iomem *addr;
u32 tmp;
/* Add one to the port status register address to get
@@ -801,7 +868,7 @@ 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;
+ __le32 __iomem **port_array;
struct xhci_bus_state *bus_state;
u32 temp;
unsigned long flags;
@@ -875,7 +942,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
if (DEV_HIGHSPEED(temp)) {
/* disable remote wake up for USB 2.0 */
- u32 __iomem *addr;
+ __le32 __iomem *addr;
u32 tmp;
/* Add one to the port status register address to get
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 627f3438028..a4fc4d92938 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -89,16 +89,17 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
return;
prev->next = next;
if (link_trbs) {
- prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma;
+ prev->trbs[TRBS_PER_SEGMENT-1].link.
+ segment_ptr = cpu_to_le64(next->dma);
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
- val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
+ val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
val &= ~TRB_TYPE_BITMASK;
val |= TRB_TYPE(TRB_LINK);
/* Always set the chain bit with 0.95 hardware */
if (xhci_link_trb_quirk(xhci))
val |= TRB_CHAIN;
- prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
+ prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
(unsigned long long)prev->dma,
@@ -186,7 +187,8 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
if (link_trbs) {
/* See section 4.9.2.1 and 6.4.4.1 */
- prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE);
+ prev->trbs[TRBS_PER_SEGMENT-1].link.
+ control |= cpu_to_le32(LINK_TOGGLE);
xhci_dbg(xhci, "Wrote link toggle flag to"
" segment %p (virtual), 0x%llx (DMA)\n",
prev, (unsigned long long)prev->dma);
@@ -548,7 +550,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
addr = cur_ring->first_seg->dma |
SCT_FOR_CTX(SCT_PRI_TR) |
cur_ring->cycle_state;
- stream_info->stream_ctx_array[cur_stream].stream_ring = addr;
+ stream_info->stream_ctx_array[cur_stream].
+ stream_ring = cpu_to_le64(addr);
xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
cur_stream, (unsigned long long) addr);
@@ -614,10 +617,10 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
max_primary_streams = fls(stream_info->num_stream_ctxs) - 2;
xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n",
1 << (max_primary_streams + 1));
- ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
- ep_ctx->ep_info |= EP_MAXPSTREAMS(max_primary_streams);
- ep_ctx->ep_info |= EP_HAS_LSA;
- ep_ctx->deq = stream_info->ctx_array_dma;
+ ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK);
+ ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams)
+ | EP_HAS_LSA);
+ ep_ctx->deq = cpu_to_le64(stream_info->ctx_array_dma);
}
/*
@@ -630,10 +633,9 @@ void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
struct xhci_virt_ep *ep)
{
dma_addr_t addr;
- ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
- ep_ctx->ep_info &= ~EP_HAS_LSA;
+ ep_ctx->ep_info &= cpu_to_le32(~(EP_MAXPSTREAMS_MASK | EP_HAS_LSA));
addr = xhci_trb_virt_to_dma(ep->ring->deq_seg, ep->ring->dequeue);
- ep_ctx->deq = addr | ep->ring->cycle_state;
+ ep_ctx->deq = cpu_to_le64(addr | ep->ring->cycle_state);
}
/* Frees all stream contexts associated with the endpoint,
@@ -781,11 +783,11 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
dev->udev = udev;
/* Point to output device context in dcbaa. */
- xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;
+ xhci->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(dev->out_ctx->dma);
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
- slot_id,
- &xhci->dcbaa->dev_context_ptrs[slot_id],
- (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]);
+ slot_id,
+ &xhci->dcbaa->dev_context_ptrs[slot_id],
+ (unsigned long long) le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
return 1;
fail:
@@ -810,8 +812,9 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
* configured device has reset, so all control transfers should have
* been completed or cancelled before the reset.
*/
- ep0_ctx->deq = xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue);
- ep0_ctx->deq |= ep_ring->cycle_state;
+ ep0_ctx->deq = cpu_to_le64(xhci_trb_virt_to_dma(ep_ring->enq_seg,
+ ep_ring->enqueue)
+ | ep_ring->cycle_state);
}
/*
@@ -885,24 +888,22 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx);
/* 2) New slot context and endpoint 0 context are valid*/
- ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
+ ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
/* 3) Only the control endpoint is valid - one endpoint context */
- slot_ctx->dev_info |= LAST_CTX(1);
-
- slot_ctx->dev_info |= (u32) udev->route;
+ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route);
switch (udev->speed) {
case USB_SPEED_SUPER:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_SS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_SS);
break;
case USB_SPEED_HIGH:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_HS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_HS);
break;
case USB_SPEED_FULL:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_FS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_FS);
break;
case USB_SPEED_LOW:
- slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;
+ slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_LS);
break;
case USB_SPEED_WIRELESS:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
@@ -916,7 +917,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
port_num = xhci_find_real_port_number(xhci, udev);
if (!port_num)
return -EINVAL;
- slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(port_num);
+ slot_ctx->dev_info2 |= cpu_to_le32((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)
@@ -927,31 +928,31 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
/* Is this a LS/FS device under an external HS hub? */
if (udev->tt && udev->tt->hub->parent) {
- slot_ctx->tt_info = udev->tt->hub->slot_id;
- slot_ctx->tt_info |= udev->ttport << 8;
+ slot_ctx->tt_info = cpu_to_le32(udev->tt->hub->slot_id |
+ (udev->ttport << 8));
if (udev->tt->multi)
- slot_ctx->dev_info |= DEV_MTT;
+ slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
}
xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
/* Step 4 - ring already allocated */
/* Step 5 */
- ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
+ ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP));
/*
* XXX: Not sure about wireless USB devices.
*/
switch (udev->speed) {
case USB_SPEED_SUPER:
- ep0_ctx->ep_info2 |= MAX_PACKET(512);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512));
break;
case USB_SPEED_HIGH:
/* USB core guesses at a 64-byte max packet first for FS devices */
case USB_SPEED_FULL:
- ep0_ctx->ep_info2 |= MAX_PACKET(64);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64));
break;
case USB_SPEED_LOW:
- ep0_ctx->ep_info2 |= MAX_PACKET(8);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8));
break;
case USB_SPEED_WIRELESS:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
@@ -962,12 +963,10 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
BUG();
}
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
- ep0_ctx->ep_info2 |= MAX_BURST(0);
- ep0_ctx->ep_info2 |= ERROR_COUNT(3);
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3));
- ep0_ctx->deq =
- dev->eps[0].ring->first_seg->dma;
- ep0_ctx->deq |= dev->eps[0].ring->cycle_state;
+ ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma |
+ dev->eps[0].ring->cycle_state);
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
@@ -1131,10 +1130,10 @@ static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
return 0;
if (udev->speed == USB_SPEED_SUPER)
- return ep->ss_ep_comp.wBytesPerInterval;
+ return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
- max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
- max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
+ max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
+ max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize) & 0x1800) >> 11;
/* A 0 in max burst means 1 transfer per ESIT */
return max_packet * (max_burst + 1);
}
@@ -1183,10 +1182,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
- ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;
+ ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma | ep_ring->cycle_state);
- ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
- ep_ctx->ep_info |= EP_MULT(xhci_get_endpoint_mult(udev, ep));
+ ep_ctx->ep_info = cpu_to_le32(xhci_get_endpoint_interval(udev, ep)
+ | EP_MULT(xhci_get_endpoint_mult(udev, ep)));
/* FIXME dig Mult and streams info out of ep companion desc */
@@ -1194,22 +1193,22 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
* error count = 0 means infinite retries.
*/
if (!usb_endpoint_xfer_isoc(&ep->desc))
- ep_ctx->ep_info2 = ERROR_COUNT(3);
+ ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(3));
else
- ep_ctx->ep_info2 = ERROR_COUNT(1);
+ ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(1));
- ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
+ ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep));
/* Set the max packet size and max burst */
switch (udev->speed) {
case USB_SPEED_SUPER:
- max_packet = ep->desc.wMaxPacketSize;
- ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
+ max_packet = le16_to_cpu(ep->desc.wMaxPacketSize);
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
/* dig out max burst from ep companion desc */
max_packet = ep->ss_ep_comp.bMaxBurst;
if (!max_packet)
xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n");
- ep_ctx->ep_info2 |= MAX_BURST(max_packet);
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet));
break;
case USB_SPEED_HIGH:
/* bits 11:12 specify th