diff options
author | John Youn <johnyoun@synopsys.com> | 2009-07-27 15:05:15 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-28 17:31:13 -0400 |
commit | d115b04818e57bdbc7ccde4d0660b15e33013dc8 (patch) | |
tree | 48b699c9b81fb0570d03009f353225faad238c64 /drivers/usb/host/xhci-mem.c | |
parent | 28c2d2efb48dec2f0b050affae6d5787d6449e47 (diff) |
USB: xhci: Support for 64-byte contexts
Adds support for controllers that use 64-byte contexts. The following context
data structures are affected by this: Device, Input, Input Control, Endpoint,
and Slot. To accommodate the use of either 32 or 64-byte contexts, a Device or
Input context can only be accessed through functions which look-up and return
pointers to their contained contexts.
Signed-off-by: John Youn <johnyoun@synopsys.com>
Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 121 |
1 files changed, 87 insertions, 34 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8d6bdf2f8015..e6b9a1c6002d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -189,6 +189,63 @@ fail: | |||
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | #define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) | ||
193 | |||
194 | struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, | ||
195 | int type, gfp_t flags) | ||
196 | { | ||
197 | struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags); | ||
198 | if (!ctx) | ||
199 | return NULL; | ||
200 | |||
201 | BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)); | ||
202 | ctx->type = type; | ||
203 | ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024; | ||
204 | if (type == XHCI_CTX_TYPE_INPUT) | ||
205 | ctx->size += CTX_SIZE(xhci->hcc_params); | ||
206 | |||
207 | ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma); | ||
208 | memset(ctx->bytes, 0, ctx->size); | ||
209 | return ctx; | ||
210 | } | ||
211 | |||
212 | void xhci_free_container_ctx(struct xhci_hcd *xhci, | ||
213 | struct xhci_container_ctx *ctx) | ||
214 | { | ||
215 | dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); | ||
216 | kfree(ctx); | ||
217 | } | ||
218 | |||
219 | struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, | ||
220 | struct xhci_container_ctx *ctx) | ||
221 | { | ||
222 | BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT); | ||
223 | return (struct xhci_input_control_ctx *)ctx->bytes; | ||
224 | } | ||
225 | |||
226 | struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, | ||
227 | struct xhci_container_ctx *ctx) | ||
228 | { | ||
229 | if (ctx->type == XHCI_CTX_TYPE_DEVICE) | ||
230 | return (struct xhci_slot_ctx *)ctx->bytes; | ||
231 | |||
232 | return (struct xhci_slot_ctx *) | ||
233 | (ctx->bytes + CTX_SIZE(xhci->hcc_params)); | ||
234 | } | ||
235 | |||
236 | struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, | ||
237 | struct xhci_container_ctx *ctx, | ||
238 | unsigned int ep_index) | ||
239 | { | ||
240 | /* increment ep index by offset of start of ep ctx array */ | ||
241 | ep_index++; | ||
242 | if (ctx->type == XHCI_CTX_TYPE_INPUT) | ||
243 | ep_index++; | ||
244 | |||
245 | return (struct xhci_ep_ctx *) | ||
246 | (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); | ||
247 | } | ||
248 | |||
192 | /* All the xhci_tds in the ring's TD list should be freed at this point */ | 249 | /* All the xhci_tds in the ring's TD list should be freed at this point */ |
193 | void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) | 250 | void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) |
194 | { | 251 | { |
@@ -209,11 +266,10 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) | |||
209 | xhci_ring_free(xhci, dev->ep_rings[i]); | 266 | xhci_ring_free(xhci, dev->ep_rings[i]); |
210 | 267 | ||
211 | if (dev->in_ctx) | 268 | if (dev->in_ctx) |
212 | dma_pool_free(xhci->device_pool, | 269 | xhci_free_container_ctx(xhci, dev->in_ctx); |
213 | dev->in_ctx, dev->in_ctx_dma); | ||
214 | if (dev->out_ctx) | 270 | if (dev->out_ctx) |
215 | dma_pool_free(xhci->device_pool, | 271 | xhci_free_container_ctx(xhci, dev->out_ctx); |
216 | dev->out_ctx, dev->out_ctx_dma); | 272 | |
217 | kfree(xhci->devs[slot_id]); | 273 | kfree(xhci->devs[slot_id]); |
218 | xhci->devs[slot_id] = 0; | 274 | xhci->devs[slot_id] = 0; |
219 | } | 275 | } |
@@ -221,7 +277,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) | |||
221 | int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, | 277 | int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, |
222 | struct usb_device *udev, gfp_t flags) | 278 | struct usb_device *udev, gfp_t flags) |
223 | { | 279 | { |
224 | dma_addr_t dma; | ||
225 | struct xhci_virt_device *dev; | 280 | struct xhci_virt_device *dev; |
226 | 281 | ||
227 | /* Slot ID 0 is reserved */ | 282 | /* Slot ID 0 is reserved */ |
@@ -235,26 +290,21 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, | |||
235 | return 0; | 290 | return 0; |
236 | dev = xhci->devs[slot_id]; | 291 | dev = xhci->devs[slot_id]; |
237 | 292 | ||
238 | /* Allocate the (output) device context that will be used in the HC. | 293 | /* Allocate the (output) device context that will be used in the HC. */ |
239 | * The structure is 32 bytes smaller than the input context, but that's | 294 | dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); |
240 | * fine. | ||
241 | */ | ||
242 | dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); | ||
243 | if (!dev->out_ctx) | 295 | if (!dev->out_ctx) |
244 | goto fail; | 296 | goto fail; |
245 | dev->out_ctx_dma = dma; | 297 | |
246 | xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, | 298 | xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, |
247 | (unsigned long long)dma); | 299 | (unsigned long long)dev->out_ctx->dma); |
248 | memset(dev->out_ctx, 0, sizeof(*dev->out_ctx)); | ||
249 | 300 | ||
250 | /* Allocate the (input) device context for address device command */ | 301 | /* Allocate the (input) device context for address device command */ |
251 | dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); | 302 | dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); |
252 | if (!dev->in_ctx) | 303 | if (!dev->in_ctx) |
253 | goto fail; | 304 | goto fail; |
254 | dev->in_ctx_dma = dma; | 305 | |
255 | xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, | 306 | xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, |
256 | (unsigned long long)dma); | 307 | (unsigned long long)dev->in_ctx->dma); |
257 | memset(dev->in_ctx, 0, sizeof(*dev->in_ctx)); | ||
258 | 308 | ||
259 | /* Allocate endpoint 0 ring */ | 309 | /* Allocate endpoint 0 ring */ |
260 | dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags); | 310 | dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags); |
@@ -264,7 +314,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, | |||
264 | init_completion(&dev->cmd_completion); | 314 | init_completion(&dev->cmd_completion); |
265 | 315 | ||
266 | /* Point to output device context in dcbaa. */ | 316 | /* Point to output device context in dcbaa. */ |
267 | xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx_dma; | 317 | xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; |
268 | xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", | 318 | xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", |
269 | slot_id, | 319 | slot_id, |
270 | &xhci->dcbaa->dev_context_ptrs[slot_id], | 320 | &xhci->dcbaa->dev_context_ptrs[slot_id], |
@@ -282,6 +332,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud | |||
282 | struct xhci_virt_device *dev; | 332 | struct xhci_virt_device *dev; |
283 | struct xhci_ep_ctx *ep0_ctx; | 333 | struct xhci_ep_ctx *ep0_ctx; |
284 | struct usb_device *top_dev; | 334 | struct usb_device *top_dev; |
335 | struct xhci_slot_ctx *slot_ctx; | ||
336 | struct xhci_input_control_ctx *ctrl_ctx; | ||
285 | 337 | ||
286 | dev = xhci->devs[udev->slot_id]; | 338 | dev = xhci->devs[udev->slot_id]; |
287 | /* Slot ID 0 is reserved */ | 339 | /* Slot ID 0 is reserved */ |
@@ -290,27 +342,29 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud | |||
290 | udev->slot_id); | 342 | udev->slot_id); |
291 | return -EINVAL; | 343 | return -EINVAL; |
292 | } | 344 | } |
293 | ep0_ctx = &dev->in_ctx->ep[0]; | 345 | ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); |
346 | ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); | ||
347 | slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); | ||
294 | 348 | ||
295 | /* 2) New slot context and endpoint 0 context are valid*/ | 349 | /* 2) New slot context and endpoint 0 context are valid*/ |
296 | dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG; | 350 | ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG; |
297 | 351 | ||
298 | /* 3) Only the control endpoint is valid - one endpoint context */ | 352 | /* 3) Only the control endpoint is valid - one endpoint context */ |
299 | dev->in_ctx->slot.dev_info |= LAST_CTX(1); | 353 | slot_ctx->dev_info |= LAST_CTX(1); |
300 | 354 | ||
301 | switch (udev->speed) { | 355 | switch (udev->speed) { |
302 | case USB_SPEED_SUPER: | 356 | case USB_SPEED_SUPER: |
303 | dev->in_ctx->slot.dev_info |= (u32) udev->route; | 357 | slot_ctx->dev_info |= (u32) udev->route; |
304 | dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS; | 358 | slot_ctx->dev_info |= (u32) SLOT_SPEED_SS; |
305 | break; | 359 | break; |
306 | case USB_SPEED_HIGH: | 360 | case USB_SPEED_HIGH: |
307 | dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS; | 361 | slot_ctx->dev_info |= (u32) SLOT_SPEED_HS; |
308 | break; | 362 | break; |
309 | case USB_SPEED_FULL: | 363 | case USB_SPEED_FULL: |
310 | dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS; | 364 | slot_ctx->dev_info |= (u32) SLOT_SPEED_FS; |
311 | break; | 365 | break; |
312 | case USB_SPEED_LOW: | 366 | case USB_SPEED_LOW: |
313 | dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS; | 367 | slot_ctx->dev_info |= (u32) SLOT_SPEED_LS; |
314 | break; | 368 | break; |
315 | case USB_SPEED_VARIABLE: | 369 | case USB_SPEED_VARIABLE: |
316 | xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); | 370 | xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); |
@@ -324,7 +378,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud | |||
324 | for (top_dev = udev; top_dev->parent && top_dev->parent->parent; | 378 | for (top_dev = udev; top_dev->parent && top_dev->parent->parent; |
325 | top_dev = top_dev->parent) | 379 | top_dev = top_dev->parent) |
326 | /* Found device below root hub */; | 380 | /* Found device below root hub */; |
327 | dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); | 381 | slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); |
328 | xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum); | 382 | xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum); |
329 | 383 | ||
330 | /* Is this a LS/FS device under a HS hub? */ | 384 | /* Is this a LS/FS device under a HS hub? */ |
@@ -334,8 +388,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud | |||
334 | */ | 388 | */ |
335 | if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) && | 389 | if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) && |
336 | udev->tt) { | 390 | udev->tt) { |
337 | dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id; | 391 | slot_ctx->tt_info = udev->tt->hub->slot_id; |
338 | dev->in_ctx->slot.tt_info |= udev->ttport << 8; | 392 | slot_ctx->tt_info |= udev->ttport << 8; |
339 | } | 393 | } |
340 | xhci_dbg(xhci, "udev->tt = %p\n", udev->tt); | 394 | xhci_dbg(xhci, "udev->tt = %p\n", udev->tt); |
341 | xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); | 395 | xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); |
@@ -466,7 +520,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, | |||
466 | unsigned int max_burst; | 520 | unsigned int max_burst; |
467 | 521 | ||
468 | ep_index = xhci_get_endpoint_index(&ep->desc); | 522 | ep_index = xhci_get_endpoint_index(&ep->desc); |
469 | ep_ctx = &virt_dev->in_ctx->ep[ep_index]; | 523 | ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); |
470 | 524 | ||
471 | /* Set up the endpoint ring */ | 525 | /* Set up the endpoint ring */ |
472 | virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags); | 526 | virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags); |
@@ -533,7 +587,7 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci, | |||
533 | struct xhci_ep_ctx *ep_ctx; | 587 | struct xhci_ep_ctx *ep_ctx; |
534 | 588 | ||
535 | ep_index = xhci_get_endpoint_index(&ep->desc); | 589 | ep_index = xhci_get_endpoint_index(&ep->desc); |
536 | ep_ctx = &virt_dev->in_ctx->ep[ep_index]; | 590 | ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); |
537 | 591 | ||
538 | ep_ctx->ep_info = 0; | 592 | ep_ctx->ep_info = 0; |
539 | ep_ctx->ep_info2 = 0; | 593 | ep_ctx->ep_info2 = 0; |
@@ -753,11 +807,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | |||
753 | */ | 807 | */ |
754 | xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, | 808 | xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, |
755 | SEGMENT_SIZE, 64, xhci->page_size); | 809 | SEGMENT_SIZE, 64, xhci->page_size); |
810 | |||
756 | /* See Table 46 and Note on Figure 55 */ | 811 | /* See Table 46 and Note on Figure 55 */ |
757 | /* FIXME support 64-byte contexts */ | ||
758 | xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, | 812 | xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, |
759 | sizeof(struct xhci_device_control), | 813 | 2112, 64, xhci->page_size); |
760 | 64, xhci->page_size); | ||
761 | if (!xhci->segment_pool || !xhci->device_pool) | 814 | if (!xhci->segment_pool || !xhci->device_pool) |
762 | goto fail; | 815 | goto fail; |
763 | 816 | ||