return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
}
+/*
+ * find slot id based on port number.
+ */
+static int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port)
+{
+ int slot_id;
+ int i;
+
+ slot_id = 0;
+ for (i = 0; i < MAX_HC_SLOTS; i++) {
+ if (!xhci->devs[i])
+ continue;
+ if (xhci->devs[i]->port == port) {
+ slot_id = i;
+ break;
+ }
+ }
+
+ return slot_id;
+}
+
+/*
+ * Stop device
+ * It issues stop endpoint command for EP 0 to 30. And wait the last command
+ * to complete.
+ * suspend will set to 1, if suspend bit need to set in command.
+ */
+static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
+{
+ struct xhci_virt_device *virt_dev;
+ struct xhci_command *cmd;
+ unsigned long flags;
+ int timeleft;
+ int ret;
+ int i;
+
+ ret = 0;
+ virt_dev = xhci->devs[slot_id];
+ cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
+ if (!cmd) {
+ xhci_dbg(xhci, "Couldn't allocate command structure.\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ for (i = LAST_EP_INDEX; i > 0; i--) {
+ if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
+ xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
+ }
+ cmd->command_trb = xhci->cmd_ring->enqueue;
+ list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
+ xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ /* Wait for last stop endpoint command to finish */
+ timeleft = wait_for_completion_interruptible_timeout(
+ cmd->completion,
+ USB_CTRL_SET_TIMEOUT);
+ if (timeleft <= 0) {
+ xhci_warn(xhci, "%s while waiting for stop endpoint command\n",
+ timeleft == 0 ? "Timeout" : "Signal");
+ spin_lock_irqsave(&xhci->lock, flags);
+ /* The timeout might have raced with the event ring handler, so
+ * only delete from the list if the item isn't poisoned.
+ */
+ if (cmd->cmd_list.next != LIST_POISON1)
+ list_del(&cmd->cmd_list);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ ret = -ETIME;
+ goto command_cleanup;
+ }
+
+command_cleanup:
+ xhci_free_command(xhci, cmd);
+ return ret;
+}
+
+/*
+ * Ring device, it rings the all doorbells unconditionally.
+ */
+static void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
+{
+ int i;
+
+ for (i = 0; i < LAST_EP_INDEX + 1; i++)
+ if (xhci->devs[slot_id]->eps[i].ring &&
+ xhci->devs[slot_id]->eps[i].ring->dequeue)
+ xhci_ring_ep_doorbell(xhci, slot_id, i, 0);
+
+ return;
+}
+
static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
u32 __iomem *addr, u32 port_status)
{
status = PORT_PEC;
port_change_bit = "enable/disable";
break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ status = PORT_PLC;
+ port_change_bit = "suspend/resume";
+ break;
default:
/* Should never happen */
return;
u32 temp, status;
int retval = 0;
u32 __iomem *addr;
+ int slot_id;
ports = HCS_MAX_PORTS(xhci->hcs_params1);
if ((temp & PORT_OCC))
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
/*
- * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific
+ * 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_PLS_MASK) == XDEV_U0
+ && (temp & PORT_POWER)
+ && (xhci->suspended_ports[wIndex >> 5] &
+ (1 << (wIndex & 31)))) {
+ xhci->suspended_ports[wIndex >> 5] &=
+ ~(1 << (wIndex & 31));
+ xhci->port_c_suspend[wIndex >> 5] |=
+ 1 << (wIndex & 31);
+ }
if (temp & PORT_CONNECT) {
status |= USB_PORT_STAT_CONNECTION;
status |= xhci_port_speed(temp);
status |= USB_PORT_STAT_RESET;
if (temp & PORT_POWER)
status |= USB_PORT_STAT_POWER;
+ if (xhci->port_c_suspend[wIndex >> 5] & (1 << (wIndex & 31)))
+ 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;
temp = xhci_readl(xhci, addr);
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ temp = xhci_readl(xhci, addr);
+ /* 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.
+ */
+ if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
+ || (temp & PORT_PLS_MASK) >= XDEV_U3) {
+ xhci_warn(xhci, "USB core suspending device "
+ "not in U0/U1/U2.\n");
+ goto error;
+ }
+
+ slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
+ if (!slot_id) {
+ xhci_warn(xhci, "slot_id is zero\n");
+ goto error;
+ }
+ /* 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 | XDEV_U3;
+ xhci_writel(xhci, temp, addr);
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ msleep(10); /* wait device to enter */
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ temp = xhci_readl(xhci, addr);
+ xhci->suspended_ports[wIndex >> 5] |=
+ 1 << (wIndex & (31));
+ break;
case USB_PORT_FEAT_POWER:
/*
* Turn on ports, even if there isn't per-port switching.
temp = xhci_readl(xhci, addr);
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ temp = xhci_readl(xhci, addr);
+ xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
+ xhci_dbg(xhci, "PORTSC %04x\n", temp);
+ if (temp & PORT_RESET)
+ goto error;
+ 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, addr);
+ xhci_readl(xhci, addr);
+ } else {
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | XDEV_RESUME;
+ xhci_writel(xhci, temp, addr);
+
+ spin_unlock_irqrestore(&xhci->lock,
+ flags);
+ msleep(20);
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ temp = xhci_readl(xhci, addr);
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | XDEV_U0;
+ xhci_writel(xhci, temp, addr);
+ }
+ xhci->port_c_suspend[wIndex >> 5] |=
+ 1 << (wIndex & 31);
+ }
+
+ slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
+ if (!slot_id) {
+ xhci_dbg(xhci, "slot_id is zero\n");
+ goto error;
+ }
+ xhci_ring_device(xhci, slot_id);
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ xhci->port_c_suspend[wIndex >> 5] &=
+ ~(1 << (wIndex & 31));
case USB_PORT_FEAT_C_RESET:
case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_OVER_CURRENT:
#include <linux/slab.h>
#include "xhci.h"
+static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ struct xhci_event_cmd *event);
+
/*
* Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
* address of the TRB.
xhci_readl(xhci, &xhci->dba->doorbell[0]);
}
-static void ring_ep_doorbell(struct xhci_hcd *xhci,
+void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
unsigned int slot_id,
unsigned int ep_index,
unsigned int stream_id)
/* A ring has pending URBs if its TD list is not empty */
if (!(ep->ep_state & EP_HAS_STREAMS)) {
if (!(list_empty(&ep->ring->td_list)))
- ring_ep_doorbell(xhci, slot_id, ep_index, 0);
+ xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0);
return;
}
stream_id++) {
struct xhci_stream_info *stream_info = ep->stream_info;
if (!list_empty(&stream_info->stream_rings[stream_id]->td_list))
- ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
+ xhci_ring_ep_doorbell(xhci, slot_id, ep_index,
+ stream_id);
}
}
* bit cleared) so that the HW will skip over them.
*/
static void handle_stopped_endpoint(struct xhci_hcd *xhci,
- union xhci_trb *trb)
+ union xhci_trb *trb, struct xhci_event_cmd *event)
{
unsigned int slot_id;
unsigned int ep_index;
+ struct xhci_virt_device *virt_dev;
struct xhci_ring *ep_ring;
struct xhci_virt_ep *ep;
struct list_head *entry;
struct xhci_dequeue_state deq_state;
+ if (unlikely(TRB_TO_SUSPEND_PORT(
+ xhci->cmd_ring->dequeue->generic.field[3]))) {
+ slot_id = TRB_TO_SLOT_ID(
+ xhci->cmd_ring->dequeue->generic.field[3]);
+ virt_dev = xhci->devs[slot_id];
+ if (virt_dev)
+ handle_cmd_in_cmd_wait_list(xhci, virt_dev,
+ event);
+ else
+ xhci_warn(xhci, "Stop endpoint command "
+ "completion for disabled slot %u\n",
+ slot_id);
+ return;
+ }
+
memset(&deq_state, 0, sizeof(deq_state));
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
complete(&xhci->addr_dev);
break;
case TRB_TYPE(TRB_STOP_RING):
- handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue);
+ handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue, event);
break;
case TRB_TYPE(TRB_SET_DEQ):
handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue);
*/
wmb();
start_trb->field[3] |= start_cycle;
- ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
+ xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
}
/*
wmb();
start_trb->field[3] |= start_cycle;
- ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
+ xhci_ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
return 0;
}
false);
}
+/*
+ * Suspend is set to indicate "Stop Endpoint Command" is being issued to stop
+ * activity on an endpoint that is about to be suspended.
+ */
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
- unsigned int ep_index)
+ unsigned int ep_index, int suspend)
{
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
u32 type = TRB_TYPE(TRB_STOP_RING);
+ u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend);
return queue_command(xhci, 0, 0, 0,
- trb_slot_id | trb_ep_index | type, false);
+ trb_slot_id | trb_ep_index | type | trb_suspend, false);
}
/* Set Transfer Ring Dequeue Pointer command.
* A read gives the current link PM state of the port,
* a write with Link State Write Strobe set sets the link state.
*/
+#define PORT_PLS_MASK (0xf << 5)
+#define XDEV_U0 (0x0 << 5)
+#define XDEV_U3 (0x3 << 5)
+#define XDEV_RESUME (0xf << 5)
/* true: port has power (see HCC_PPC) */
#define PORT_POWER (1 << 9)
/* bits 10:13 indicate device speed:
#define MAX_EXIT (0xffff)
/* Root hub port number that is needed to access the USB device */
#define ROOT_HUB_PORT(p) (((p) & 0xff) << 16)
+#define DEVINFO_TO_ROOT_HUB_PORT(p) (((p) >> 16) & 0xff)
/* Maximum number of ports under a hub device */
#define XHCI_MAX_PORTS(p) (((p) & 0xff) << 24)
/* Status of the last command issued for this device */
u32 cmd_status;
struct list_head cmd_list;
+ u8 port;
};
#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1)
#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16)
+#define SUSPEND_PORT_FOR_TRB(p) (((p) & 1) << 23)
+#define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23)
+#define LAST_EP_INDEX 30
+
/* Set TR Dequeue Pointer command TRB fields */
#define TRB_TO_STREAM_ID(p) ((((p) & (0xffff << 16)) >> 16))
#define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16)
#define XHCI_LINK_TRB_QUIRK (1 << 0)
#define XHCI_RESET_EP_QUIRK (1 << 1)
#define XHCI_NEC_HOST (1 << 2)
+ u32 port_c_suspend[8]; /* port suspend change*/
+ u32 suspended_ports[8]; /* which ports are
+ suspended */
};
/* For testing purposes */
int xhci_queue_vendor_command(struct xhci_hcd *xhci,
u32 field1, u32 field2, u32 field3, u32 field4);
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
- unsigned int ep_index);
+ unsigned int ep_index, int suspend);
int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index);
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state);
void xhci_stop_endpoint_command_watchdog(unsigned long arg);
+void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
+ unsigned int ep_index, unsigned int stream_id);
/* xHCI roothub code */
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,