summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r--drivers/usb/host/xhci-hcd.c549
1 files changed, 345 insertions, 204 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 2b808cc875..32a6ccd5cd 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -23,16 +23,49 @@
#include "xhci.h"
+
+static struct xhci_input_control_ctx *
+xhci_get_input_control_ctx(struct xhci_container_ctx *ctx)
+{
+ if (ctx->type != XHCI_CTX_TYPE_INPUT)
+ return NULL;
+
+ return (struct xhci_input_control_ctx *)ctx->bytes;
+}
+
+static struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx)
+{
+ if (ctx->type == XHCI_CTX_TYPE_DEVICE)
+ return (struct xhci_slot_ctx *)ctx->bytes;
+
+ return (struct xhci_slot_ctx *)
+ (ctx->bytes + HCC_CTX_SIZE(xhci->hcc_params));
+}
+
+static struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx,
+ unsigned int ep_index)
+{
+ /* increment ep index by offset of start of ep ctx array */
+ ep_index++;
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ ep_index++;
+
+ return (struct xhci_ep_ctx *)
+ (ctx->bytes + (ep_index * HCC_CTX_SIZE(xhci->hcc_params)));
+}
+
/*
* xHCI ring handling
*/
static int xhci_ring_is_last_trb(struct xhci_ring *ring, union xhci_trb *trb)
{
- if (ring->type == TYPE_EVENT)
- return trb == &ring->trbs[NUM_EVENT_TRBS];
- else
- return TRB_TYPE_LINK(le32_to_cpu(trb->link.control));
+ if (ring->type == TYPE_EVENT)
+ return trb == &ring->trbs[NUM_EVENT_TRBS];
+ else
+ return TRB_TYPE_LINK(le32_to_cpu(trb->link.control));
}
static int xhci_ring_increment(struct xhci_ring *ring, bool enqueue)
@@ -41,7 +74,7 @@ static int xhci_ring_increment(struct xhci_ring *ring, bool enqueue)
(*queue)++;
- if (!xhci_ring_is_last_trb(ring, *queue))
+ if (!xhci_ring_is_last_trb(ring, *queue))
return 0;
if (ring->type == TYPE_EVENT) {
@@ -139,15 +172,15 @@ static unsigned int xhci_get_endpoint_index(u8 epaddress, u8 epattributes)
{
u8 epnum = epaddress & USB_ENDPOINT_NUMBER_MASK;
u8 xfer = epattributes & USB_ENDPOINT_XFERTYPE_MASK;
- unsigned int index;
+ unsigned int index;
- if (xfer == USB_ENDPOINT_XFER_CONTROL)
- index = (unsigned int)(epnum * 2);
- else
- index = (unsigned int)(epnum * 2) +
- ((epaddress & USB_DIR_IN) ? 1 : 0) - 1;
+ if (xfer == USB_ENDPOINT_XFER_CONTROL)
+ index = (unsigned int)(epnum * 2);
+ else
+ index = (unsigned int)(epnum * 2) +
+ ((epaddress & USB_DIR_IN) ? 1 : 0) - 1;
- return index;
+ return index;
}
static u8 xhci_get_endpoint_type(u8 epaddress, u8 epattributes)
@@ -341,15 +374,15 @@ int xhci_issue_command(struct xhci_hcd *xhci, union xhci_trb *trb)
static void xhci_set_event_dequeue(struct xhci_hcd *xhci)
{
- u64 reg64;
+ u64 reg64;
- reg64 = xhci_read_64(&xhci->ir_set->erst_dequeue);
- reg64 &= ERST_PTR_MASK;
- /*
+ reg64 = xhci_read_64(&xhci->ir_set->erst_dequeue);
+ reg64 &= ERST_PTR_MASK;
+ /*
* Don't clear the EHB bit (which is RW1C) because
- * there might be more events to service.
- */
- reg64 &= ~ERST_EHB;
+ * there might be more events to service.
+ */
+ reg64 &= ~ERST_EHB;
reg64 |= (dma_addr_t)xhci->event_ring.dequeue &
~(dma_addr_t)ERST_PTR_MASK;
@@ -426,29 +459,48 @@ static struct xhci_virtual_device *xhci_find_virtdev(struct xhci_hcd *xhci,
return NULL;
}
+static struct xhci_container_ctx *
+xhci_alloc_container_ctx(struct xhci_hcd *xhci, int type)
+{
+ struct xhci_container_ctx *ctx;
+
+ if ((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT))
+ return NULL;
+
+ ctx = xzalloc(sizeof(*ctx));
+ ctx->type = type;
+ ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
+ if (type == XHCI_CTX_TYPE_INPUT)
+ ctx->size += HCC_CTX_SIZE(xhci->hcc_params);
+
+ ctx->bytes = dma_alloc_coherent(ctx->size, &ctx->dma);
+ if (WARN_ON(!ctx->bytes)) {
+ kfree(ctx);
+ return NULL;
+ }
+ return ctx;
+}
+
+static void xhci_free_container_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx)
+{
+ if (!ctx)
+ return;
+ dma_free_coherent(ctx->bytes, ctx->dma, ctx->size);
+ kfree(ctx);
+}
+
static struct xhci_virtual_device *xhci_alloc_virtdev(struct xhci_hcd *xhci,
struct usb_device *udev)
{
struct xhci_virtual_device *vdev;
- size_t sz_ctx, sz_ictx, sz_dctx;
- void *p;
vdev = xzalloc(sizeof(*vdev));
vdev->udev = udev;
list_add_tail(&vdev->list, &xhci->vdev_list);
- sz_ctx = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
- /* Device Context: 64B aligned */
- sz_dctx = ALIGN(sz_ctx, 64);
- /* Input Control Context: 64B aligned */
- sz_ictx = ALIGN(sz_ctx + HCC_CTX_SIZE(xhci->hcc_params), 64);
-
- vdev->dma_size = sz_ictx + sz_dctx;
- p = vdev->dma = dma_alloc_coherent(vdev->dma_size, DMA_ADDRESS_BROKEN);
- memset(vdev->dma, 0, vdev->dma_size);
-
- vdev->out_ctx = p; p += sz_dctx;
- vdev->in_ctx = p; p += sz_ictx;
+ vdev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE);
+ vdev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT);
return vdev;
}
@@ -463,7 +515,8 @@ static void xhci_free_virtdev(struct xhci_virtual_device *vdev)
xhci_put_endpoint_ring(xhci, vdev->ep[i]);
list_del(&vdev->list);
- dma_free_coherent(vdev->dma, 0, vdev->dma_size);
+ xhci_free_container_ctx(xhci, vdev->out_ctx);
+ xhci_free_container_ctx(xhci, vdev->in_ctx);
free(vdev);
}
@@ -487,26 +540,43 @@ static int xhci_virtdev_issue_transfer(struct xhci_virtual_device *vdev,
static void xhci_virtdev_zero_in_ctx(struct xhci_virtual_device *vdev)
{
+ struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+ struct xhci_input_control_ctx *in_icc;
+ struct xhci_slot_ctx *in_slot;
+ struct xhci_ep_ctx *in_ep;
int i;
- /* When a device's add flag and drop flag are zero, any subsequent
- * configure endpoint command will leave that endpoint's state
- * untouched. Make sure we don't leave any old state in the input
- * endpoint contexts.
- */
- vdev->in_ctx->icc.drop_flags = 0;
- vdev->in_ctx->icc.add_flags = 0;
- vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
- /* Endpoint 0 is always valid */
- vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(1));
+ in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+ in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+
+ /* When a device's add flag and drop flag are zero, any subsequent
+ * configure endpoint command will leave that endpoint's state
+ * untouched. Make sure we don't leave any old state in the input
+ * endpoint contexts.
+ */
+ in_icc->drop_flags = 0;
+ in_icc->add_flags = 0;
+ in_slot->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+ /* Endpoint 0 is always valid */
+ in_slot->dev_info |= cpu_to_le32(LAST_CTX(1));
for (i = 1; i < 31; i++) {
- vdev->in_ctx->ep[i].ep_info = 0;
- vdev->in_ctx->ep[i].ep_info2 = 0;
- vdev->in_ctx->ep[i].deq = 0;
- vdev->in_ctx->ep[i].tx_info = 0;
+ in_ep = xhci_get_ep_ctx(xhci, vdev->in_ctx, i);
+
+ in_ep->ep_info = 0;
+ in_ep->ep_info2 = 0;
+ in_ep->deq = 0;
+ in_ep->tx_info = 0;
}
}
+static void xhci_init_event_cmd_trb(union xhci_trb *trb,
+ u64 cmd_trb, u32 status, u32 flags)
+{
+ xhci_write_64(cmd_trb, &trb->event_cmd.cmd_trb);
+ writel(status, &trb->event_cmd.status);
+ writel(flags, &trb->event_cmd.flags);
+}
+
static int xhci_virtdev_disable_slot(struct xhci_virtual_device *vdev)
{
struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
@@ -514,15 +584,17 @@ static int xhci_virtdev_disable_slot(struct xhci_virtual_device *vdev)
int ret;
/* Issue Disable Slot Command */
- memset(&trb, 0, sizeof(union xhci_trb));
- trb.event_cmd.flags = TRB_TYPE(TRB_DISABLE_SLOT) |
- SLOT_ID_FOR_TRB(vdev->slot_id);
+ xhci_init_event_cmd_trb(&trb,
+ 0,
+ 0,
+ TRB_TYPE(TRB_DISABLE_SLOT) |
+ SLOT_ID_FOR_TRB(vdev->slot_id));
xhci_print_trb(xhci, &trb, "Request DisableSlot");
xhci_issue_command(xhci, &trb);
ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
xhci_print_trb(xhci, &trb, "Response DisableSlot");
- /* Clear Device Context Base Address Array */
+ /* Clear Device Context Base Address Array */
xhci->dcbaa[vdev->slot_id] = 0;
return ret;
@@ -536,8 +608,10 @@ static int xhci_virtdev_enable_slot(struct xhci_virtual_device *vdev)
int ret;
/* Issue Enable Slot Command */
- memset(&trb, 0, sizeof(union xhci_trb));
- trb.event_cmd.flags = TRB_TYPE(TRB_ENABLE_SLOT);
+ xhci_init_event_cmd_trb(&trb,
+ 0,
+ 0,
+ TRB_TYPE(TRB_ENABLE_SLOT));
xhci_print_trb(xhci, &trb, "Request EnableSlot");
xhci_issue_command(xhci, &trb);
ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -559,42 +633,47 @@ static int xhci_virtdev_enable_slot(struct xhci_virtual_device *vdev)
int xhci_virtdev_reset(struct xhci_virtual_device *vdev)
{
struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+ struct xhci_slot_ctx *out_slot;
union xhci_trb trb;
int ret;
+ out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
/* If device is not setup, there is no point in resetting it */
- if (GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)) ==
+ if (GET_SLOT_STATE(le32_to_cpu(out_slot->dev_state)) ==
SLOT_STATE_DISABLED)
- return 0;
+ return 0;
- memset(&trb, 0, sizeof(union xhci_trb));
- trb.event_cmd.flags = TRB_TYPE(TRB_RESET_DEV) |
- SLOT_ID_FOR_TRB(vdev->slot_id);
+ xhci_init_event_cmd_trb(&trb,
+ 0,
+ 0,
+ TRB_TYPE(TRB_RESET_DEV) |
+ SLOT_ID_FOR_TRB(vdev->slot_id));
xhci_print_trb(xhci, &trb, "Request Reset");
xhci_issue_command(xhci, &trb);
ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
xhci_print_trb(xhci, &trb, "Response Reset");
- /*
+ /*
* The Reset Device command can't fail, according to the 0.95/0.96 spec,
- * unless we tried to reset a slot ID that wasn't enabled,
- * or the device wasn't in the addressed or configured state.
- */
- switch (GET_COMP_CODE(trb.event_cmd.status)) {
- case COMP_CMD_ABORT:
- case COMP_CMD_STOP:
- dev_warn(xhci->dev, "Timeout waiting for reset device command\n");
- ret = -ETIMEDOUT;
+ * unless we tried to reset a slot ID that wasn't enabled,
+ * or the device wasn't in the addressed or configured state.
+ */
+ switch (GET_COMP_CODE(trb.event_cmd.status)) {
+ case COMP_CMD_ABORT:
+ case COMP_CMD_STOP:
+ dev_warn(xhci->dev, "Timeout waiting for reset device command\n");
+ ret = -ETIMEDOUT;
+ break;
+ case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
+ case COMP_CTX_STATE: /* 0.96 completion code for same thing */
+ /* Don't treat this as an error. May change my mind later. */
+ ret = 0;
+ case COMP_SUCCESS:
break;
- case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
- case COMP_CTX_STATE: /* 0.96 completion code for same thing */
- /* Don't treat this as an error. May change my mind later. */
- ret = 0;
- case COMP_SUCCESS:
- break;
- default:
- ret = -EINVAL;
- }
+ default:
+ ret = -EINVAL;
+ }
return ret;
}
@@ -608,31 +687,38 @@ static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
{
struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
struct usb_hub_descriptor *desc = buffer;
+ struct xhci_input_control_ctx *in_icc;
+ struct xhci_slot_ctx *in_slot, *out_slot;
union xhci_trb trb;
u32 dev_info, dev_info2, tt_info;
u8 maxchild;
u16 hubchar;
+ u32 flags;
int ret;
+ out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
/* Need at least first byte of wHubCharacteristics */
if (length < 4)
return 0;
/* Skip already configured hub device */
- if (vdev->out_ctx->slot.dev_info & DEV_HUB)
+ if (out_slot->dev_info & DEV_HUB)
return 0;
maxchild = desc->bNbrPorts;
hubchar = le16_to_cpu(desc->wHubCharacteristics);
+ in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+ in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+
/* update slot context */
- memcpy(&vdev->in_ctx->slot, &vdev->out_ctx->slot,
- sizeof(struct xhci_slot_ctx));
- vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
- vdev->in_ctx->icc.drop_flags = 0;
- vdev->in_ctx->slot.dev_state = 0;
- dev_info = le32_to_cpu(vdev->in_ctx->slot.dev_info);
- dev_info2 = le32_to_cpu(vdev->in_ctx->slot.dev_info2);
- tt_info = le32_to_cpu(vdev->in_ctx->slot.tt_info);
+ memcpy(in_slot, out_slot, sizeof(struct xhci_slot_ctx));
+ in_icc->add_flags |= cpu_to_le32(SLOT_FLAG);
+ in_icc->drop_flags = 0;
+ in_slot->dev_state = 0;
+ dev_info = le32_to_cpu(in_slot->dev_info);
+ dev_info2 = le32_to_cpu(in_slot->dev_info2);
+ tt_info = le32_to_cpu(in_slot->tt_info);
dev_info |= DEV_HUB;
/* HS Multi-TT in bDeviceProtocol */
@@ -651,21 +737,23 @@ static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
if (xhci->hci_version < 0x100 ||
vdev->udev->speed == USB_SPEED_HIGH) {
u32 think_time = (hubchar & HUB_CHAR_TTTT) >> 5;
- tt_info |= TT_THINK_TIME(think_time);
+ tt_info |= TT_THINK_TIME(think_time);
}
- }
- vdev->in_ctx->slot.dev_info = cpu_to_le32(dev_info);
- vdev->in_ctx->slot.dev_info2 = cpu_to_le32(dev_info2);
- vdev->in_ctx->slot.tt_info = cpu_to_le32(tt_info);
-
- /* Issue Configure Endpoint or Evaluate Context Command */
- memset(&trb, 0, sizeof(union xhci_trb));
- xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
- trb.event_cmd.flags = SLOT_ID_FOR_TRB(vdev->slot_id);
+ }
+ in_slot->dev_info = cpu_to_le32(dev_info);
+ in_slot->dev_info2 = cpu_to_le32(dev_info2);
+ in_slot->tt_info = cpu_to_le32(tt_info);
+
+ /* Issue Configure Endpoint or Evaluate Context Command */
+ flags = SLOT_ID_FOR_TRB(vdev->slot_id);
if (xhci->hci_version > 0x95)
- trb.event_cmd.flags |= TRB_TYPE(TRB_CONFIG_EP);
+ flags |= TRB_TYPE(TRB_CONFIG_EP);
else
- trb.event_cmd.flags |= TRB_TYPE(TRB_EVAL_CONTEXT);
+ flags |= TRB_TYPE(TRB_EVAL_CONTEXT);
+ xhci_init_event_cmd_trb(&trb,
+ vdev->in_ctx->dma,
+ 0,
+ flags);
xhci_print_trb(xhci, &trb, "Request ConfigureEndpoint");
xhci_issue_command(xhci, &trb);
ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -696,6 +784,8 @@ static int xhci_virtdev_update_hub_status(struct xhci_virtual_device *vhub,
static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
{
struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+ struct xhci_input_control_ctx *in_icc;
+ struct xhci_slot_ctx *in_slot;
struct usb_device *udev = vdev->udev;
union xhci_trb trb;
u32 add_flags = 0, last_ctx;
@@ -712,10 +802,12 @@ static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
ep->bmAttributes);
u8 epi = xhci_get_endpoint_index(ep->bEndpointAddress,
ep->bmAttributes);
- struct xhci_ep_ctx *ctx = &vdev->in_ctx->ep[epi];
+ struct xhci_ep_ctx *ctx;
u32 mps, interval, mult, esit, max_packet, max_burst;
u32 ep_info, ep_info2, tx_info;
+ ctx = xhci_get_ep_ctx(xhci, vdev->in_ctx, epi);
+
vdev->ep[epi] = xhci_get_endpoint_ring(xhci);
if (!vdev->ep[epi])
return -ENOMEM;
@@ -782,25 +874,29 @@ static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
last_ctx = fls(add_flags) - 1;
- /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
- vdev->in_ctx->icc.add_flags = cpu_to_le32(add_flags);
- vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
- vdev->in_ctx->icc.add_flags &= cpu_to_le32(~EP0_FLAG);
- vdev->in_ctx->icc.drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
+ in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+ in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+
+ /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
+ in_icc->add_flags = cpu_to_le32(add_flags);
+ in_icc->add_flags |= cpu_to_le32(SLOT_FLAG);
+ in_icc->add_flags &= cpu_to_le32(~EP0_FLAG);
+ in_icc->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
/* Don't issue the command if there's no endpoints to update. */
- if (vdev->in_ctx->icc.add_flags == cpu_to_le32(SLOT_FLAG) &&
- vdev->in_ctx->icc.drop_flags == 0)
+ if (in_icc->add_flags == cpu_to_le32(SLOT_FLAG) &&
+ in_icc->drop_flags == 0)
return 0;
- vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
- vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
+ in_slot->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+ in_slot->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
- /* Issue Configure Endpoint Command */
- memset(&trb, 0, sizeof(union xhci_trb));
- xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
- trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) |
- SLOT_ID_FOR_TRB(vdev->slot_id);
+ /* Issue Configure Endpoint Command */
+ xhci_init_event_cmd_trb(&trb,
+ vdev->in_ctx->dma,
+ 0,
+ TRB_TYPE(TRB_CONFIG_EP) |
+ SLOT_ID_FOR_TRB(vdev->slot_id));
xhci_print_trb(xhci, &trb, "Request ConfigureEndpoint");
xhci_issue_command(xhci, &trb);
ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -816,11 +912,12 @@ static int xhci_virtdev_deconfigure(struct xhci_virtual_device *vdev)
union xhci_trb trb;
int ret;
- /* Issue Deconfigure Endpoint Command */
- memset(&trb, 0, sizeof(union xhci_trb));
- xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
- trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) | TRB_DC |
- SLOT_ID_FOR_TRB(vdev->slot_id);
+ /* Issue Deconfigure Endpoint Command */
+ xhci_init_event_cmd_trb(&trb,
+ vdev->in_ctx->dma,
+ 0,
+ TRB_TYPE(TRB_CONFIG_EP) | TRB_DC |
+ SLOT_ID_FOR_TRB(vdev->slot_id));
xhci_print_trb(xhci, &trb, "Request DeconfigureEndpoint");
xhci_issue_command(xhci, &trb);
ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -834,23 +931,30 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
{
struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
struct usb_device *top_dev;
+ struct xhci_slot_ctx *in_slot;
+ struct xhci_ep_ctx *in_ep;
int max_packets;
u32 route = 0, dev_info, dev_info2, tt_info, ep_info2, tx_info;
bool on_hs_hub = false;
int hs_slot_id = 0;
+ in_ep = xhci_get_ep_ctx(xhci, vdev->in_ctx, 0);
+ in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+
/*
* Find the root hub port this device is under, also determine SlotID
* of possible external HS hub a LS/FS device could be connected to.
*/
for (top_dev = vdev->udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent) {
- if (top_dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB)
- route = (route << 4) | (top_dev->portnr & 0xf);
- if (top_dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB &&
- top_dev->parent->speed != USB_SPEED_LOW &&
+ if (top_dev->parent->descriptor->bDeviceClass != USB_CLASS_HUB)
+ continue;
+
+ route = (route << 4) | (top_dev->portnr & 0xf);
+
+ if (top_dev->parent->speed != USB_SPEED_LOW &&
top_dev->parent->speed != USB_SPEED_FULL) {
- on_hs_hub |= true;
+ on_hs_hub = true;
if (!hs_slot_id) {
struct xhci_virtual_device *vhub =
xhci_find_virtdev(xhci, top_dev->parent);
@@ -893,9 +997,9 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
tt_info |= (top_dev->portnr << 8) | hs_slot_id;
}
- vdev->in_ctx->slot.dev_info = cpu_to_le32(dev_info);
- vdev->in_ctx->slot.dev_info2 = cpu_to_le32(dev_info2);
- vdev->in_ctx->slot.tt_info = cpu_to_le32(tt_info);
+ in_slot->dev_info = cpu_to_le32(dev_info);
+ in_slot->dev_info2 = cpu_to_le32(dev_info2);
+ in_slot->tt_info = cpu_to_le32(tt_info);
/* 4.3.3 4) Initalize Transfer Ring */
vdev->ep[0] = xhci_get_endpoint_ring(xhci);
@@ -907,13 +1011,13 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
ep_info2 = EP_TYPE(CTRL_EP) | MAX_BURST(0) | ERROR_COUNT(3);
ep_info2 |= MAX_PACKET(max_packets);
tx_info = AVG_TRB_LENGTH_FOR_EP(8);
- vdev->in_ctx->ep[0].ep_info2 = cpu_to_le32(ep_info2);
- vdev->in_ctx->ep[0].tx_info = cpu_to_le32(tx_info);
- vdev->in_ctx->ep[0].deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
- vdev->ep[0]->cycle_state);
+ in_ep->ep_info2 = cpu_to_le32(ep_info2);
+ in_ep->tx_info = cpu_to_le32(tx_info);
+ in_ep->deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
+ vdev->ep[0]->cycle_state);
- /* 4.3.3 6+7) Initalize and Set Device Context Base Address Array */
- xhci->dcbaa[vdev->slot_id] = cpu_to_le64((dma_addr_t)vdev->out_ctx);
+ /* 4.3.3 6+7) Initalize and Set Device Context Base Address Array */
+ xhci->dcbaa[vdev->slot_id] = cpu_to_le64(vdev->out_ctx->dma);
return 0;
}
@@ -922,43 +1026,53 @@ static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
enum xhci_setup_dev setup)
{
struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+ static struct xhci_input_control_ctx *in_icc;
+ struct xhci_slot_ctx *in_slot;
+ struct xhci_ep_ctx *in_ep;
union xhci_trb trb;
+ u32 flags;
int ret;
+ in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+ in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+
/*
* If this is the first Set Address since device
* plug-in then initialize Slot Context
*/
- if (!vdev->in_ctx->slot.dev_info)
+ if (!in_slot->dev_info)
xhci_virtdev_init(vdev);
else {
+ in_ep = xhci_get_ep_ctx(xhci, vdev->in_ctx, 0);
+
/* Otherwise, update Control Ring Dequeue pointer */
- vdev->in_ctx->ep[0].deq =
- cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
- vdev->ep[0]->cycle_state);
+ in_ep->deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
+ vdev->ep[0]->cycle_state);
/*
* FS devices have MaxPacketSize0 of 8 or 64, we start
* with 64. If assumtion was wrong, fix it up here.
*/
if (vdev->udev->speed == USB_SPEED_FULL &&
vdev->udev->maxpacketsize == PACKET_SIZE_8) {
- u32 info = le32_to_cpu(vdev->in_ctx->ep[0].ep_info2);
+ u32 info = le32_to_cpu(in_ep->ep_info2);
info &= ~MAX_PACKET_MASK;
info |= MAX_PACKET(8);
- vdev->in_ctx->ep[0].ep_info2 = cpu_to_le32(info);
+ in_ep->ep_info2 = cpu_to_le32(info);
}
}
- vdev->in_ctx->icc.add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
- vdev->in_ctx->icc.drop_flags = 0;
+ in_icc->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
+ in_icc->drop_flags = 0;
- /* Issue Address Device Command */
- memset(&trb, 0, sizeof(union xhci_trb));
- xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
- trb.event_cmd.flags = TRB_TYPE(TRB_ADDR_DEV) |
+ /* Issue Address Device Command */
+ flags = TRB_TYPE(TRB_ADDR_DEV) |
SLOT_ID_FOR_TRB(vdev->slot_id);
if (setup == SETUP_CONTEXT_ONLY)
- trb.event_cmd.flags |= TRB_BSR;
+ flags |= TRB_BSR;
+ xhci_init_event_cmd_trb(&trb,
+ vdev->in_ctx->dma,
+ 0,
+ flags);
xhci_print_trb(xhci, &trb, "Request AddressDevice");
xhci_issue_command(xhci, &trb);
ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -970,12 +1084,12 @@ static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
static int xhci_virtdev_set_address(struct xhci_virtual_device *vdev)
{
- return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ADDRESS);
+ return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ADDRESS);
}
static int xhci_virtdev_enable(struct xhci_virtual_device *vdev)
{
- return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ONLY);
+ return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ONLY);
}
static int xhci_virtdev_attach(struct xhci_hcd *xhci, struct usb_device *udev)
@@ -1008,45 +1122,57 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
{
struct usb_host *host = udev->host;
struct xhci_hcd *xhci = to_xhci_hcd(host);
+ enum dma_data_direction dma_direction;
struct xhci_virtual_device *vdev;
+ struct xhci_slot_ctx *out_slot;
+ dma_addr_t buffer_dma;
union xhci_trb trb;
- u8 epaddr = (usb_pipein(pipe) ? USB_DIR_IN : USB_DIR_OUT) |
- usb_pipeendpoint(pipe);
- u8 epi = xhci_get_endpoint_index(epaddr, usb_pipetype(pipe));
+ u8 epaddr = usb_pipeendpoint(pipe);
+ u8 epi;
+ u32 flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
int ret;
+ if (usb_pipein(pipe)) {
+ epaddr |= USB_DIR_IN;
+ flags |= TRB_ISP;
+ dma_direction = DMA_FROM_DEVICE;
+ } else {
+ epaddr |= USB_DIR_OUT;
+ dma_direction = DMA_TO_DEVICE;
+ }
+
+ epi = xhci_get_endpoint_index(epaddr, usb_pipetype(pipe));
vdev = xhci_find_virtdev(xhci, udev);
if (!vdev)
return -ENODEV;
+ out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
dev_dbg(xhci->dev, "%s udev %p vdev %p slot %u state %u epi %u in_ctx %p out_ctx %p\n",
__func__, udev, vdev, vdev->slot_id,
- GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)), epi,
- vdev->in_ctx, vdev->out_ctx);
+ GET_SLOT_STATE(le32_to_cpu(out_slot->dev_state)), epi,
+ vdev->in_ctx->bytes, vdev->out_ctx->bytes);
/* pass ownership of data buffer to device */
- dma_sync_single_for_device((unsigned long)buffer, length,
- usb_pipein(pipe) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ buffer_dma = dma_map_single(xhci->dev, buffer, length,
+ dma_direction);
+ if (dma_mapping_error(xhci->dev, buffer_dma))
+ return -EFAULT;
/* Normal TRB */
- memset(&trb, 0, sizeof(union xhci_trb));
- trb.event_cmd.cmd_trb = cpu_to_le64((dma_addr_t)buffer);
/* FIXME: TD remainder */
- trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
- trb.event_cmd.flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
- if (usb_pipein(pipe))
- trb.event_cmd.flags |= TRB_ISP;
+ xhci_init_event_cmd_trb(&trb,
+ buffer_dma,
+ TRB_LEN(length) | TRB_INTR_TARGET(0),
+ flags);
xhci_print_trb(xhci, &trb, "Request Normal");
xhci_virtdev_issue_transfer(vdev, epi, &trb, true);
ret = xhci_wait_for_event(xhci, TRB_TRANSFER, &trb);
xhci_print_trb(xhci, &trb, "Response Normal");
/* Regain ownership of data buffer from device */
- dma_sync_single_for_cpu((unsigned long)buffer, length,
- usb_pipein(pipe) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
+ dma_unmap_single(xhci->dev, buffer_dma, length,
+ dma_direction);
switch (ret) {
case -COMP_SHORT_TX:
udev->status = 0;
@@ -1070,8 +1196,12 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
struct usb_host *host = udev->host;
struct xhci_hcd *xhci = to_xhci_hcd(host);
struct xhci_virtual_device *vdev;
+ struct xhci_slot_ctx *out_slot;
+ dma_addr_t buffer_dma = 0;
union xhci_trb trb;
u16 typeReq = (req->requesttype << 8) | req->request;
+ u64 field[2];
+ u32 flags;
int ret;
dev_dbg(xhci->dev, "%s req %u (%#x), type %u (%#x), value %u (%#x), index %u (%#x), length %u (%#x)\n",
@@ -1091,10 +1221,12 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
if (!vdev)
return -ENODEV;
+ out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
dev_dbg(xhci->dev, "%s udev %p vdev %p slot %u state %u epi %u in_ctx %p out_ctx %p\n",
__func__, udev, vdev, vdev->slot_id,
- GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)), 0,
- vdev->in_ctx, vdev->out_ctx);
+ GET_SLOT_STATE(le32_to_cpu(out_slot->dev_state)), 0,
+ vdev->in_ctx->bytes, vdev->out_ctx->bytes);
if (req->request == USB_REQ_SET_ADDRESS)
return xhci_virtdev_set_address(vdev);
@@ -1104,53 +1236,59 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
return ret;
}
- /* Pass ownership of data buffer to device */
- dma_sync_single_for_device((unsigned long)buffer, length,
- (req->requesttype & USB_DIR_IN) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
+ if (length > 0) {
+ /* Pass ownership of data buffer to device */
+ buffer_dma = dma_map_single(xhci->dev, buffer, length,
+ (req->requesttype & USB_DIR_IN) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ if (dma_mapping_error(xhci->dev, buffer_dma))
+ return -EFAULT;
+ }
/* Setup TRB */
- memset(&trb, 0, sizeof(union xhci_trb));
- trb.generic.field[0] = le16_to_cpu(req->value) << 16 |
+ field[0] = le16_to_cpu(req->value) << 16 |
req->request << 8 | req->requesttype;
- trb.generic.field[1] = le16_to_cpu(req->length) << 16 |
+ field[1] = le16_to_cpu(req->length) << 16 |
le16_to_cpu(req->index);
- trb.event_cmd.status = TRB_LEN(8) | TRB_INTR_TARGET(0);
- trb.event_cmd.flags = TRB_TYPE(TRB_SETUP) | TRB_IDT;
- if (xhci->hci_version == 0x100 && length > 0) {
+ flags = TRB_TYPE(TRB_SETUP) | TRB_IDT;
+ if (xhci->hci_version >= 0x100 && length > 0) {
if (req->requesttype & USB_DIR_IN)
- trb.event_cmd.flags |= TRB_TX_TYPE(TRB_DATA_IN);
+ flags |= TRB_TX_TYPE(TRB_DATA_IN);
else
- trb.event_cmd.flags |= TRB_TX_TYPE(TRB_DATA_OUT);
+ flags |= TRB_TX_TYPE(TRB_DATA_OUT);
}
+ xhci_init_event_cmd_trb(&trb,
+ field[1] << 32 | field[0],
+ TRB_LEN(8) | TRB_INTR_TARGET(0),
+ flags);
xhci_print_trb(xhci, &trb, "Request Setup ");
xhci_virtdev_issue_transfer(vdev, 0, &trb, false);
/* Data TRB */
if (length > 0) {
- memset(&trb, 0, sizeof(union xhci_trb));
- trb.event_cmd.cmd_trb = cpu_to_le64((dma_addr_t)buffer);
/* FIXME: TD remainder */
- trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
- trb.event_cmd.flags = TRB_TYPE(TRB_DATA) | TRB_IOC;
+ flags = TRB_TYPE(TRB_DATA) | TRB_IOC;
if (req->requesttype & USB_DIR_IN)
- trb.event_cmd.flags |= TRB_ISP | TRB_DIR_IN;
+ flags |= TRB_ISP | TRB_DIR_IN;
+ xhci_init_event_cmd_trb(&trb,
+ buffer_dma,
+ TRB_LEN(length) | TRB_INTR_TARGET(0),
+ flags);
xhci_print_trb(xhci, &trb, "Request Data ");
xhci_virtdev_issue_transfer(vdev, 0, &trb, false);
}
/* Status TRB */
- memset(&trb, 0, sizeof(union xhci_trb));
- trb.event_cmd.status = TRB_INTR_TARGET(0);
- if (length > 0 && req->requesttype & USB_DIR_IN)
- trb.event_cmd.flags = 0;
- else
- trb.event_cmd.flags = TRB_DIR_IN;
- trb.event_cmd.flags |= TRB_TYPE(TRB_STATUS) | TRB_IOC;
+ flags = TRB_TYPE(TRB_STATUS) | TRB_IOC;
+ if (!(length > 0 && req->requesttype & USB_DIR_IN))
+ flags |= TRB_DIR_IN;
+ xhci_init_event_cmd_trb(&trb,
+ 0,
+ TRB_INTR_TARGET(0),
+ flags);
xhci_print_trb(xhci, &trb, "Request Status");
xhci_virtdev_issue_transfer(vdev, 0, &trb, true);
- if (length > 0 && req->requesttype & USB_DIR_IN) {
+ if (length > 0) {
ret = xhci_wait_for_event(xhci, TRB_TRANSFER, &trb);
xhci_print_trb(xhci, &trb, "Response Data ");
if (ret == -COMP_SHORT_TX)
@@ -1163,10 +1301,13 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
xhci_print_trb(xhci, &trb, "Response Status");
dma_regain:
- /* Regain ownership of data buffer from device */
- dma_sync_single_for_cpu((unsigned long)buffer, length,
- (req->requesttype & USB_DIR_IN) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ if (length > 0) {
+ /* Regain ownership of data buffer from device */
+ dma_unmap_single(xhci->dev, buffer_dma, length,
+ (req->requesttype & USB_DIR_IN) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
+
if (ret < 0)
return ret;
@@ -1224,8 +1365,7 @@ static void xhci_dma_alloc(struct xhci_hcd *xhci)
num_ep = max(MAX_EP_RINGS, MIN_EP_RINGS + num_ep);
xhci->dma_size += num_ep * sz_ep;
- p = xhci->dma = dma_alloc_coherent(xhci->dma_size, DMA_ADDRESS_BROKEN);
- memset(xhci->dma, 0, xhci->dma_size);
+ p = dma_alloc_coherent(xhci->dma_size, DMA_ADDRESS_BROKEN);
xhci->sp = p; p += sz_sp;
xhci->dcbaa = p; p += sz_dca;
@@ -1261,7 +1401,7 @@ static void xhci_dma_alloc(struct xhci_hcd *xhci)
static int xhci_halt(struct xhci_hcd *xhci)
{
u32 reg = readl(&xhci->op_regs->status);
- u32 mask = ~XHCI_IRQS;
+ u32 mask = (u32)~XHCI_IRQS;
if (!(reg & STS_HALT))
mask &= ~CMD_RUN;
@@ -1291,7 +1431,7 @@ static int xhci_reset(struct xhci_hcd *xhci)
return ret;
}
- return 0;
+ return 0;
}
static int xhci_start(struct xhci_hcd *xhci)
@@ -1305,8 +1445,8 @@ static int xhci_start(struct xhci_hcd *xhci)
ret = xhci_handshake(&xhci->op_regs->status,
STS_HALT, 0, XHCI_MAX_HALT_USEC);
- if (ret) {
- dev_err(xhci->dev, "failed to start\n");
+ if (ret) {
+ dev_err(xhci->dev, "failed to start\n");
return ret;
}
@@ -1314,7 +1454,7 @@ static int xhci_start(struct xhci_hcd *xhci)
for (i = 0; i < xhci->num_usb_ports; i++)
xhci_hub_port_power(xhci, i, false);
- return 0;
+ return 0;
}
static int xhci_init(struct usb_host *host)
@@ -1472,6 +1612,7 @@ int xhci_register(struct device_d *dev, struct xhci_data *data)
xhci = xzalloc(sizeof(*xhci));
host = &xhci->host;
INIT_LIST_HEAD(&xhci->vdev_list);
+ INIT_LIST_HEAD(&xhci->rings_list);
xhci->dev = dev;
xhci->cap_regs = data->regs;
xhci->op_regs = (void __iomem *)xhci->cap_regs +