Commit 28c2d2ef authored by Sarah Sharp's avatar Sarah Sharp Committed by Greg Kroah-Hartman

USB: xhci: Always align output device contexts to 64 bytes.

Make sure the xHCI output device context is 64-byte aligned.  Previous
code was using the same structure for both the output device context and
the input control context.  Since the structure had 32 bytes of flags
before the device context, the output device context wouldn't be 64-byte
aligned.  Define a new structure to use for the output device context and
clean up the debugging for these two structures.

The copy of the device context in the input control context does *not*
need to be 64-byte aligned.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 254c80a3
...@@ -393,78 +393,103 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) ...@@ -393,78 +393,103 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
upper_32_bits(val)); upper_32_bits(val));
} }
void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) dma_addr_t xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_slot_ctx *slot, dma_addr_t dma)
{ {
int i, j;
int last_ep_ctx = 31;
/* Fields are 32 bits wide, DMA addresses are in bytes */ /* Fields are 32 bits wide, DMA addresses are in bytes */
int field_size = 32 / 8; int field_size = 32 / 8;
int i;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
&ctx->drop_flags, (unsigned long long)dma,
ctx->drop_flags);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
&ctx->add_flags, (unsigned long long)dma,
ctx->add_flags);
dma += field_size;
for (i = 0; i < 6; ++i) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
&ctx->rsvd[i], (unsigned long long)dma,
ctx->rsvd[i], i);
dma += field_size;
}
xhci_dbg(xhci, "Slot Context:\n"); xhci_dbg(xhci, "Slot Context:\n");
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n",
&ctx->slot.dev_info, &slot->dev_info,
(unsigned long long)dma, ctx->slot.dev_info); (unsigned long long)dma, slot->dev_info);
dma += field_size; dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n",
&ctx->slot.dev_info2, &slot->dev_info2,
(unsigned long long)dma, ctx->slot.dev_info2); (unsigned long long)dma, slot->dev_info2);
dma += field_size; dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n",
&ctx->slot.tt_info, &slot->tt_info,
(unsigned long long)dma, ctx->slot.tt_info); (unsigned long long)dma, slot->tt_info);
dma += field_size; dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n",
&ctx->slot.dev_state, &slot->dev_state,
(unsigned long long)dma, ctx->slot.dev_state); (unsigned long long)dma, slot->dev_state);
dma += field_size; dma += field_size;
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
&ctx->slot.reserved[i], (unsigned long long)dma, &slot->reserved[i], (unsigned long long)dma,
ctx->slot.reserved[i], i); slot->reserved[i], i);
dma += field_size; dma += field_size;
} }
return dma;
}
dma_addr_t xhci_dbg_ep_ctx(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep, 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;
if (last_ep < 31) if (last_ep < 31)
last_ep_ctx = last_ep + 1; last_ep_ctx = last_ep + 1;
for (i = 0; i < last_ep_ctx; ++i) { for (i = 0; i < last_ep_ctx; ++i) {
xhci_dbg(xhci, "Endpoint %02d Context:\n", i); xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
&ctx->ep[i].ep_info, &ep[i].ep_info,
(unsigned long long)dma, ctx->ep[i].ep_info); (unsigned long long)dma, ep[i].ep_info);
dma += field_size; dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n",
&ctx->ep[i].ep_info2, &ep[i].ep_info2,
(unsigned long long)dma, ctx->ep[i].ep_info2); (unsigned long long)dma, ep[i].ep_info2);
dma += field_size; dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n",
&ctx->ep[i].deq, &ep[i].deq,
(unsigned long long)dma, ctx->ep[i].deq); (unsigned long long)dma, ep[i].deq);
dma += 2*field_size; dma += 2*field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n",
&ctx->ep[i].tx_info, &ep[i].tx_info,
(unsigned long long)dma, ctx->ep[i].tx_info); (unsigned long long)dma, ep[i].tx_info);
dma += field_size; dma += field_size;
for (j = 0; j < 3; ++j) { for (j = 0; j < 3; ++j) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
&ctx->ep[i].reserved[j], &ep[i].reserved[j],
(unsigned long long)dma, (unsigned long long)dma,
ctx->ep[i].reserved[j], j); ep[i].reserved[j], j);
dma += field_size; dma += field_size;
} }
} }
return dma;
}
void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep)
{
int i;
/* Fields are 32 bits wide, DMA addresses are in bytes */
int field_size = 32 / 8;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
&ctx->drop_flags, (unsigned long long)dma,
ctx->drop_flags);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
&ctx->add_flags, (unsigned long long)dma,
ctx->add_flags);
dma += field_size;
for (i = 0; i < 6; ++i) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
&ctx->rsvd[i], (unsigned long long)dma,
ctx->rsvd[i], i);
dma += field_size;
}
dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma);
dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep);
}
void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep)
{
dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma);
dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep);
} }
...@@ -1013,7 +1013,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -1013,7 +1013,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
} }
xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); xhci_dbg(xhci, "Output context after successful config ep cmd:\n");
xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma,
LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info));
xhci_zero_in_ctx(virt_dev); xhci_zero_in_ctx(virt_dev);
...@@ -1265,7 +1265,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -1265,7 +1265,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); 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_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(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); xhci_dbg_device_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 * USB core uses address 1 for the roothubs, so we add one to the
* address given back to us by the HC. * address given back to us by the HC.
...@@ -1274,9 +1274,6 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -1274,9 +1274,6 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
/* Zero the input context control for later use */ /* Zero the input context control for later use */
virt_dev->in_ctx->add_flags = 0; virt_dev->in_ctx->add_flags = 0;
virt_dev->in_ctx->drop_flags = 0; virt_dev->in_ctx->drop_flags = 0;
/* Mirror flags in the output context for future ep enable/disable */
virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
virt_dev->out_ctx->drop_flags = 0;
xhci_dbg(xhci, "Device address = %d\n", udev->devnum); xhci_dbg(xhci, "Device address = %d\n", udev->devnum);
/* XXX Meh, not sure if anyone else but choose_address uses this. */ /* XXX Meh, not sure if anyone else but choose_address uses this. */
......
...@@ -235,7 +235,10 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, ...@@ -235,7 +235,10 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
return 0; return 0;
dev = xhci->devs[slot_id]; dev = xhci->devs[slot_id];
/* Allocate the (output) device context that will be used in the HC */ /* Allocate the (output) device context that will be used in the HC.
* The structure is 32 bytes smaller than the input context, but that's
* fine.
*/
dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
if (!dev->out_ctx) if (!dev->out_ctx)
goto fail; goto fail;
...@@ -260,16 +263,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, ...@@ -260,16 +263,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
init_completion(&dev->cmd_completion); init_completion(&dev->cmd_completion);
/* /* Point to output device context in dcbaa. */
* Point to output device context in dcbaa; skip the output control xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx_dma;
* context, which is eight 32 bit fields (or 32 bytes long)
*/
xhci->dcbaa->dev_context_ptrs[slot_id] =
(u32) dev->out_ctx_dma + (32);
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
slot_id, slot_id,
&xhci->dcbaa->dev_context_ptrs[slot_id], &xhci->dcbaa->dev_context_ptrs[slot_id],
(unsigned long long)dev->out_ctx_dma); (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]);
return 1; return 1;
fail: fail:
......
...@@ -584,15 +584,29 @@ struct xhci_ep_ctx { ...@@ -584,15 +584,29 @@ struct xhci_ep_ctx {
/** /**
* struct xhci_device_control * struct xhci_device_control
* Input/Output context; see section 6.2.5. * Input context; see section 6.2.5.
* *
* @drop_context: set the bit of the endpoint context you want to disable * @drop_context: set the bit of the endpoint context you want to disable
* @add_context: set the bit of the endpoint context you want to enable * @add_context: set the bit of the endpoint context you want to enable
*/ */
struct xhci_device_control { struct xhci_device_control {
/* Input control context */
u32 drop_flags; u32 drop_flags;
u32 add_flags; u32 add_flags;
u32 rsvd[6]; u32 rsvd[6];
/* Copy of device context */
struct xhci_slot_ctx slot;
struct xhci_ep_ctx ep[31];
};
/**
* struct xhci_device_ctx
* Device context; see section 6.2.1.
*
* @slot: slot context for the device.
* @ep: array of endpoint contexts for the device.
*/
struct xhci_device_ctx {
struct xhci_slot_ctx slot; struct xhci_slot_ctx slot;
struct xhci_ep_ctx ep[31]; struct xhci_ep_ctx ep[31];
}; };
...@@ -612,7 +626,7 @@ struct xhci_virt_device { ...@@ -612,7 +626,7 @@ struct xhci_virt_device {
* track of input and output contexts separately because * track of input and output contexts separately because
* these commands might fail and we don't trust the hardware. * these commands might fail and we don't trust the hardware.
*/ */
struct xhci_device_control *out_ctx; struct xhci_device_ctx *out_ctx;
dma_addr_t out_ctx_dma; dma_addr_t out_ctx_dma;
/* Used for addressing devices and configuration changes */ /* Used for addressing devices and configuration changes */
struct xhci_device_control *in_ctx; struct xhci_device_control *in_ctx;
...@@ -1126,6 +1140,7 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); ...@@ -1126,6 +1140,7 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep); void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep);
void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep);
/* xHCI memory managment */ /* xHCI memory managment */
void xhci_mem_cleanup(struct xhci_hcd *xhci); void xhci_mem_cleanup(struct xhci_hcd *xhci);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment