Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 151411
b: refs/heads/master
c: 3ffbba9
h: refs/heads/master
i:
  151409: 071b852
  151407: 619e49d
v: v3
  • Loading branch information
Sarah Sharp authored and Greg Kroah-Hartman committed Jun 16, 2009
1 parent aee16f4 commit a522628
Show file tree
Hide file tree
Showing 7 changed files with 591 additions and 30 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c6515272b858742962c1de0f3bf497a048b9abd7
refs/heads/master: 3ffbba9511b4148cbe1f6b6238686adaeaca8feb
79 changes: 79 additions & 0 deletions trunk/drivers/usb/host/xhci-dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,82 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]);
xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val);
}

void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep)
{
int i, j;
int last_ep_ctx = 31;
/* Fields are 32 bits wide, DMA addresses are in bytes */
int field_size = 32 / 8;

xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - drop flags\n",
(unsigned int) &ctx->drop_flags,
dma, ctx->drop_flags);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - add flags\n",
(unsigned int) &ctx->add_flags,
dma, ctx->add_flags);
dma += field_size;
for (i = 0; i > 6; ++i) {
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - rsvd[%d]\n",
(unsigned int) &ctx->rsvd[i],
dma, ctx->rsvd[i], i);
dma += field_size;
}

xhci_dbg(xhci, "Slot Context:\n");
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - dev_info\n",
(unsigned int) &ctx->slot.dev_info,
dma, ctx->slot.dev_info);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - dev_info2\n",
(unsigned int) &ctx->slot.dev_info2,
dma, ctx->slot.dev_info2);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - tt_info\n",
(unsigned int) &ctx->slot.tt_info,
dma, ctx->slot.tt_info);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - dev_state\n",
(unsigned int) &ctx->slot.dev_state,
dma, ctx->slot.dev_state);
dma += field_size;
for (i = 0; i > 4; ++i) {
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - rsvd[%d]\n",
(unsigned int) &ctx->slot.reserved[i],
dma, ctx->slot.reserved[i], i);
dma += field_size;
}

if (last_ep < 31)
last_ep_ctx = last_ep + 1;
for (i = 0; i < last_ep_ctx; ++i) {
xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - ep_info\n",
(unsigned int) &ctx->ep[i].ep_info,
dma, ctx->ep[i].ep_info);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - ep_info2\n",
(unsigned int) &ctx->ep[i].ep_info2,
dma, ctx->ep[i].ep_info2);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - deq[0]\n",
(unsigned int) &ctx->ep[i].deq[0],
dma, ctx->ep[i].deq[0]);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - deq[1]\n",
(unsigned int) &ctx->ep[i].deq[1],
dma, ctx->ep[i].deq[1]);
dma += field_size;
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - tx_info\n",
(unsigned int) &ctx->ep[i].tx_info,
dma, ctx->ep[i].tx_info);
dma += field_size;
for (j = 0; j < 3; ++j) {
xhci_dbg(xhci, "@%08x (virt) @%08x (dma) %#08x - rsvd[%d]\n",
(unsigned int) &ctx->ep[i].reserved[j],
dma, ctx->ep[i].reserved[j], j);
dma += field_size;
}
}
}
201 changes: 201 additions & 0 deletions trunk/drivers/usb/host/xhci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,16 @@ void event_ring_work(unsigned long arg)
xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);
xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
for (i = 0; i < MAX_HC_SLOTS; ++i) {
if (xhci->devs[i]) {
for (j = 0; j < 31; ++j) {
if (xhci->devs[i]->ep_rings[j]) {
xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j);
xhci_debug_segment(xhci, xhci->devs[i]->ep_rings[j]->deq_seg);
}
}
}
}

if (xhci->noops_submitted != NUM_TEST_NOOPS)
if (setup_one_noop(xhci))
Expand Down Expand Up @@ -499,6 +509,197 @@ void xhci_shutdown(struct usb_hcd *hcd)

/*-------------------------------------------------------------------------*/

/*
* At this point, the struct usb_device is about to go away, the device has
* disconnected, and all traffic has been stopped and the endpoints have been
* disabled. Free any HC data structures associated with that device.
*/
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned long flags;

if (udev->slot_id == 0)
return;

spin_lock_irqsave(&xhci->lock, flags);
if (queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
return;
}
ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
/*
* Event command completion handler will free any data structures
* associated with the slot
*/
}

/*
* Returns 0 if the xHC ran out of device slots, the Enable Slot command
* timed out, or allocating memory failed. Returns 1 on success.
*/
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned long flags;
int timeleft;
int ret;

spin_lock_irqsave(&xhci->lock, flags);
ret = queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
return 0;
}
ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);

/* XXX: how much time for xHC slot assignment? */
timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
USB_CTRL_SET_TIMEOUT);
if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for a slot\n",
timeleft == 0 ? "Timeout" : "Signal");
/* FIXME cancel the enable slot request */
return 0;
}

spin_lock_irqsave(&xhci->lock, flags);
if (!xhci->slot_id) {
xhci_err(xhci, "Error while assigning device slot ID\n");
spin_unlock_irqrestore(&xhci->lock, flags);
return 0;
}
if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_KERNEL)) {
/* Disable slot, if we can do it without mem alloc */
xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
if (!queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id))
ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
return 0;
}
udev->slot_id = xhci->slot_id;
/* Is this a LS or FS device under a HS hub? */
/* Hub or peripherial? */
spin_unlock_irqrestore(&xhci->lock, flags);
return 1;
}

/*
* Issue an Address Device command (which will issue a SetAddress request to
* the device).
* We should be protected by the usb_address0_mutex in khubd's hub_port_init, so
* we should only issue and wait on one address command at the same time.
*
* We add one to the device address issued by the hardware because the USB core
* uses address 1 for the root hubs (even though they're not really devices).
*/
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
{
unsigned long flags;
int timeleft;
struct xhci_virt_device *virt_dev;
int ret = 0;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
u32 temp;

if (!udev->slot_id) {
xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
return -EINVAL;
}

spin_lock_irqsave(&xhci->lock, flags);
virt_dev = xhci->devs[udev->slot_id];

/* If this is a Set Address to an unconfigured device, setup ep 0 */
if (!udev->config)
xhci_setup_addressable_virt_dev(xhci, udev);
/* Otherwise, assume the core has the device configured how it wants */

ret = queue_address_device(xhci, virt_dev->in_ctx_dma, udev->slot_id);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
return ret;
}
ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);

/* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
USB_CTRL_SET_TIMEOUT);
/* FIXME: From section 4.3.4: "Software shall be responsible for timing
* the SetAddress() "recovery interval" required by USB and aborting the
* command on a timeout.
*/
if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for a slot\n",
timeleft == 0 ? "Timeout" : "Signal");
/* FIXME cancel the address device command */
return -ETIME;
}

spin_lock_irqsave(&xhci->lock, flags);
switch (virt_dev->cmd_status) {
case COMP_CTX_STATE:
case COMP_EBADSLT:
xhci_err(xhci, "Setup ERROR: address device command for slot %d.\n",
udev->slot_id);
ret = -EINVAL;
break;
case COMP_TX_ERR:
dev_warn(&udev->dev, "Device not responding to set address.\n");
ret = -EPROTO;
break;
case COMP_SUCCESS:
xhci_dbg(xhci, "Successful Address Device command\n");
break;
default:
xhci_err(xhci, "ERROR: unexpected command completion "
"code 0x%x.\n", virt_dev->cmd_status);
ret = -EINVAL;
break;
}
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
return ret;
}
temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]);
xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp);
temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]);
xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp);
xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%08x = %#08x\n",
udev->slot_id,
(unsigned int) &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id],
xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]);
xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%08x = %#08x\n",
udev->slot_id,
(unsigned int) &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1],
xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]);
xhci_dbg(xhci, "Output Context DMA address = %#08x\n",
virt_dev->out_ctx_dma);
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2);
xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2);
/*
* USB core uses address 1 for the roothubs, so we add one to the
* address given back to us by the HC.
*/
udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1;
/* FIXME: Zero the input context control for later use? */
spin_unlock_irqrestore(&xhci->lock, flags);

xhci_dbg(xhci, "Device address = %d\n", udev->devnum);
/* XXX Meh, not sure if anyone else but choose_address uses this. */
set_bit(udev->devnum, udev->bus->devmap.devicemap);

return 0;
}

int xhci_get_frame(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
Expand Down
Loading

0 comments on commit a522628

Please sign in to comment.