diff options
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 174 |
1 files changed, 173 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 6ff2e298bff8..8cd55f03ea26 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -103,7 +103,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, | |||
103 | } | 103 | } |
104 | 104 | ||
105 | /* XXX: Do we need the hcd structure in all these functions? */ | 105 | /* XXX: Do we need the hcd structure in all these functions? */ |
106 | static void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) | 106 | void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) |
107 | { | 107 | { |
108 | struct xhci_segment *seg; | 108 | struct xhci_segment *seg; |
109 | struct xhci_segment *first_seg; | 109 | struct xhci_segment *first_seg; |
@@ -257,6 +257,8 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, | |||
257 | if (!dev->ep_rings[0]) | 257 | if (!dev->ep_rings[0]) |
258 | goto fail; | 258 | goto fail; |
259 | 259 | ||
260 | init_completion(&dev->cmd_completion); | ||
261 | |||
260 | /* | 262 | /* |
261 | * Point to output device context in dcbaa; skip the output control | 263 | * Point to output device context in dcbaa; skip the output control |
262 | * context, which is eight 32 bit fields (or 32 bytes long) | 264 | * context, which is eight 32 bit fields (or 32 bytes long) |
@@ -366,6 +368,176 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud | |||
366 | return 0; | 368 | return 0; |
367 | } | 369 | } |
368 | 370 | ||
371 | /* Return the polling or NAK interval. | ||
372 | * | ||
373 | * The polling interval is expressed in "microframes". If xHCI's Interval field | ||
374 | * is set to N, it will service the endpoint every 2^(Interval)*125us. | ||
375 | * | ||
376 | * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval | ||
377 | * is set to 0. | ||
378 | */ | ||
379 | static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, | ||
380 | struct usb_host_endpoint *ep) | ||
381 | { | ||
382 | unsigned int interval = 0; | ||
383 | |||
384 | switch (udev->speed) { | ||
385 | case USB_SPEED_HIGH: | ||
386 | /* Max NAK rate */ | ||
387 | if (usb_endpoint_xfer_control(&ep->desc) || | ||
388 | usb_endpoint_xfer_bulk(&ep->desc)) | ||
389 | interval = ep->desc.bInterval; | ||
390 | /* Fall through - SS and HS isoc/int have same decoding */ | ||
391 | case USB_SPEED_SUPER: | ||
392 | if (usb_endpoint_xfer_int(&ep->desc) || | ||
393 | usb_endpoint_xfer_isoc(&ep->desc)) { | ||
394 | if (ep->desc.bInterval == 0) | ||
395 | interval = 0; | ||
396 | else | ||
397 | interval = ep->desc.bInterval - 1; | ||
398 | if (interval > 15) | ||
399 | interval = 15; | ||
400 | if (interval != ep->desc.bInterval + 1) | ||
401 | dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n", | ||
402 | ep->desc.bEndpointAddress, 1 << interval); | ||
403 | } | ||
404 | break; | ||
405 | /* Convert bInterval (in 1-255 frames) to microframes and round down to | ||
406 | * nearest power of 2. | ||
407 | */ | ||
408 | case USB_SPEED_FULL: | ||
409 | case USB_SPEED_LOW: | ||
410 | if (usb_endpoint_xfer_int(&ep->desc) || | ||
411 | usb_endpoint_xfer_isoc(&ep->desc)) { | ||
412 | interval = fls(8*ep->desc.bInterval) - 1; | ||
413 | if (interval > 10) | ||
414 | interval = 10; | ||
415 | if (interval < 3) | ||
416 | interval = 3; | ||
417 | if ((1 << interval) != 8*ep->desc.bInterval) | ||
418 | dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n", | ||
419 | ep->desc.bEndpointAddress, 1 << interval); | ||
420 | } | ||
421 | break; | ||
422 | default: | ||
423 | BUG(); | ||
424 | } | ||
425 | return EP_INTERVAL(interval); | ||
426 | } | ||
427 | |||
428 | static inline u32 xhci_get_endpoint_type(struct usb_device *udev, | ||
429 | struct usb_host_endpoint *ep) | ||
430 | { | ||
431 | int in; | ||
432 | u32 type; | ||
433 | |||
434 | in = usb_endpoint_dir_in(&ep->desc); | ||
435 | if (usb_endpoint_xfer_control(&ep->desc)) { | ||
436 | type = EP_TYPE(CTRL_EP); | ||
437 | } else if (usb_endpoint_xfer_bulk(&ep->desc)) { | ||
438 | if (in) | ||
439 | type = EP_TYPE(BULK_IN_EP); | ||
440 | else | ||
441 | type = EP_TYPE(BULK_OUT_EP); | ||
442 | } else if (usb_endpoint_xfer_isoc(&ep->desc)) { | ||
443 | if (in) | ||
444 | type = EP_TYPE(ISOC_IN_EP); | ||
445 | else | ||
446 | type = EP_TYPE(ISOC_OUT_EP); | ||
447 | } else if (usb_endpoint_xfer_int(&ep->desc)) { | ||
448 | if (in) | ||
449 | type = EP_TYPE(INT_IN_EP); | ||
450 | else | ||
451 | type = EP_TYPE(INT_OUT_EP); | ||
452 | } else { | ||
453 | BUG(); | ||
454 | } | ||
455 | return type; | ||
456 | } | ||
457 | |||
458 | int xhci_endpoint_init(struct xhci_hcd *xhci, | ||
459 | struct xhci_virt_device *virt_dev, | ||
460 | struct usb_device *udev, | ||
461 | struct usb_host_endpoint *ep) | ||
462 | { | ||
463 | unsigned int ep_index; | ||
464 | struct xhci_ep_ctx *ep_ctx; | ||
465 | struct xhci_ring *ep_ring; | ||
466 | unsigned int max_packet; | ||
467 | unsigned int max_burst; | ||
468 | |||
469 | ep_index = xhci_get_endpoint_index(&ep->desc); | ||
470 | ep_ctx = &virt_dev->in_ctx->ep[ep_index]; | ||
471 | |||
472 | /* Set up the endpoint ring */ | ||
473 | virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, GFP_KERNEL); | ||
474 | if (!virt_dev->new_ep_rings[ep_index]) | ||
475 | return -ENOMEM; | ||
476 | ep_ring = virt_dev->new_ep_rings[ep_index]; | ||
477 | ep_ctx->deq[1] = 0; | ||
478 | ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state; | ||
479 | |||
480 | ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep); | ||
481 | |||
482 | /* FIXME dig Mult and streams info out of ep companion desc */ | ||
483 | |||
484 | /* Allow 3 retries for everything but isoc */ | ||
485 | if (!usb_endpoint_xfer_isoc(&ep->desc)) | ||
486 | ep_ctx->ep_info2 = ERROR_COUNT(3); | ||
487 | else | ||
488 | ep_ctx->ep_info2 = ERROR_COUNT(0); | ||
489 | |||
490 | ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep); | ||
491 | |||
492 | /* Set the max packet size and max burst */ | ||
493 | switch (udev->speed) { | ||
494 | case USB_SPEED_SUPER: | ||
495 | max_packet = ep->desc.wMaxPacketSize; | ||
496 | ep_ctx->ep_info2 |= MAX_PACKET(max_packet); | ||
497 | /* FIXME dig out burst from ep companion desc */ | ||
498 | break; | ||
499 | case USB_SPEED_HIGH: | ||
500 | /* bits 11:12 specify the number of additional transaction | ||
501 | * opportunities per microframe (USB 2.0, section 9.6.6) | ||
502 | */ | ||
503 | if (usb_endpoint_xfer_isoc(&ep->desc) || | ||
504 | usb_endpoint_xfer_int(&ep->desc)) { | ||
505 | max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11; | ||
506 | ep_ctx->ep_info2 |= MAX_BURST(max_burst); | ||
507 | } | ||
508 | /* Fall through */ | ||
509 | case USB_SPEED_FULL: | ||
510 | case USB_SPEED_LOW: | ||
511 | max_packet = ep->desc.wMaxPacketSize & 0x3ff; | ||
512 | ep_ctx->ep_info2 |= MAX_PACKET(max_packet); | ||
513 | break; | ||
514 | default: | ||
515 | BUG(); | ||
516 | } | ||
517 | /* FIXME Debug endpoint context */ | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | void xhci_endpoint_zero(struct xhci_hcd *xhci, | ||
522 | struct xhci_virt_device *virt_dev, | ||
523 | struct usb_host_endpoint *ep) | ||
524 | { | ||
525 | unsigned int ep_index; | ||
526 | struct xhci_ep_ctx *ep_ctx; | ||
527 | |||
528 | ep_index = xhci_get_endpoint_index(&ep->desc); | ||
529 | ep_ctx = &virt_dev->in_ctx->ep[ep_index]; | ||
530 | |||
531 | ep_ctx->ep_info = 0; | ||
532 | ep_ctx->ep_info2 = 0; | ||
533 | ep_ctx->deq[1] = 0; | ||
534 | ep_ctx->deq[0] = 0; | ||
535 | ep_ctx->tx_info = 0; | ||
536 | /* Don't free the endpoint ring until the set interface or configuration | ||
537 | * request succeeds. | ||
538 | */ | ||
539 | } | ||
540 | |||
369 | void xhci_mem_cleanup(struct xhci_hcd *xhci) | 541 | void xhci_mem_cleanup(struct xhci_hcd *xhci) |
370 | { | 542 | { |
371 | struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); | 543 | struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); |