diff options
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 549 |
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 + |