diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 102 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 11 |
2 files changed, 113 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 41aca003ee82..71121d99235d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -545,6 +545,103 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci, | |||
545 | */ | 545 | */ |
546 | } | 546 | } |
547 | 547 | ||
548 | /* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ | ||
549 | static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) | ||
550 | { | ||
551 | int i; | ||
552 | struct device *dev = xhci_to_hcd(xhci)->self.controller; | ||
553 | int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); | ||
554 | |||
555 | xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp); | ||
556 | |||
557 | if (!num_sp) | ||
558 | return 0; | ||
559 | |||
560 | xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags); | ||
561 | if (!xhci->scratchpad) | ||
562 | goto fail_sp; | ||
563 | |||
564 | xhci->scratchpad->sp_array = | ||
565 | pci_alloc_consistent(to_pci_dev(dev), | ||
566 | num_sp * sizeof(u64), | ||
567 | &xhci->scratchpad->sp_dma); | ||
568 | if (!xhci->scratchpad->sp_array) | ||
569 | goto fail_sp2; | ||
570 | |||
571 | xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags); | ||
572 | if (!xhci->scratchpad->sp_buffers) | ||
573 | goto fail_sp3; | ||
574 | |||
575 | xhci->scratchpad->sp_dma_buffers = | ||
576 | kzalloc(sizeof(dma_addr_t) * num_sp, flags); | ||
577 | |||
578 | if (!xhci->scratchpad->sp_dma_buffers) | ||
579 | goto fail_sp4; | ||
580 | |||
581 | xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma; | ||
582 | for (i = 0; i < num_sp; i++) { | ||
583 | dma_addr_t dma; | ||
584 | void *buf = pci_alloc_consistent(to_pci_dev(dev), | ||
585 | xhci->page_size, &dma); | ||
586 | if (!buf) | ||
587 | goto fail_sp5; | ||
588 | |||
589 | xhci->scratchpad->sp_array[i] = dma; | ||
590 | xhci->scratchpad->sp_buffers[i] = buf; | ||
591 | xhci->scratchpad->sp_dma_buffers[i] = dma; | ||
592 | } | ||
593 | |||
594 | return 0; | ||
595 | |||
596 | fail_sp5: | ||
597 | for (i = i - 1; i >= 0; i--) { | ||
598 | pci_free_consistent(to_pci_dev(dev), xhci->page_size, | ||
599 | xhci->scratchpad->sp_buffers[i], | ||
600 | xhci->scratchpad->sp_dma_buffers[i]); | ||
601 | } | ||
602 | kfree(xhci->scratchpad->sp_dma_buffers); | ||
603 | |||
604 | fail_sp4: | ||
605 | kfree(xhci->scratchpad->sp_buffers); | ||
606 | |||
607 | fail_sp3: | ||
608 | pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64), | ||
609 | xhci->scratchpad->sp_array, | ||
610 | xhci->scratchpad->sp_dma); | ||
611 | |||
612 | fail_sp2: | ||
613 | kfree(xhci->scratchpad); | ||
614 | xhci->scratchpad = NULL; | ||
615 | |||
616 | fail_sp: | ||
617 | return -ENOMEM; | ||
618 | } | ||
619 | |||
620 | static void scratchpad_free(struct xhci_hcd *xhci) | ||
621 | { | ||
622 | int num_sp; | ||
623 | int i; | ||
624 | struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); | ||
625 | |||
626 | if (!xhci->scratchpad) | ||
627 | return; | ||
628 | |||
629 | num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); | ||
630 | |||
631 | for (i = 0; i < num_sp; i++) { | ||
632 | pci_free_consistent(pdev, xhci->page_size, | ||
633 | xhci->scratchpad->sp_buffers[i], | ||
634 | xhci->scratchpad->sp_dma_buffers[i]); | ||
635 | } | ||
636 | kfree(xhci->scratchpad->sp_dma_buffers); | ||
637 | kfree(xhci->scratchpad->sp_buffers); | ||
638 | pci_free_consistent(pdev, num_sp * sizeof(u64), | ||
639 | xhci->scratchpad->sp_array, | ||
640 | xhci->scratchpad->sp_dma); | ||
641 | kfree(xhci->scratchpad); | ||
642 | xhci->scratchpad = NULL; | ||
643 | } | ||
644 | |||
548 | void xhci_mem_cleanup(struct xhci_hcd *xhci) | 645 | void xhci_mem_cleanup(struct xhci_hcd *xhci) |
549 | { | 646 | { |
550 | struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); | 647 | struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); |
@@ -593,6 +690,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) | |||
593 | 690 | ||
594 | xhci->page_size = 0; | 691 | xhci->page_size = 0; |
595 | xhci->page_shift = 0; | 692 | xhci->page_shift = 0; |
693 | scratchpad_free(xhci); | ||
596 | } | 694 | } |
597 | 695 | ||
598 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | 696 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) |
@@ -755,7 +853,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | |||
755 | for (i = 0; i < MAX_HC_SLOTS; ++i) | 853 | for (i = 0; i < MAX_HC_SLOTS; ++i) |
756 | xhci->devs[i] = 0; | 854 | xhci->devs[i] = 0; |
757 | 855 | ||
856 | if (scratchpad_alloc(xhci, flags)) | ||
857 | goto fail; | ||
858 | |||
758 | return 0; | 859 | return 0; |
860 | |||
759 | fail: | 861 | fail: |
760 | xhci_warn(xhci, "Couldn't initialize memory\n"); | 862 | xhci_warn(xhci, "Couldn't initialize memory\n"); |
761 | xhci_mem_cleanup(xhci); | 863 | xhci_mem_cleanup(xhci); |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 074728e10225..5a09b9a26e0d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -89,6 +89,7 @@ struct xhci_cap_regs { | |||
89 | #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) | 89 | #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) |
90 | /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ | 90 | /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ |
91 | /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ | 91 | /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ |
92 | #define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) | ||
92 | 93 | ||
93 | /* HCSPARAMS3 - hcs_params3 - bitmasks */ | 94 | /* HCSPARAMS3 - hcs_params3 - bitmasks */ |
94 | /* bits 0:7, Max U1 to U0 latency for the roothub ports */ | 95 | /* bits 0:7, Max U1 to U0 latency for the roothub ports */ |
@@ -951,6 +952,13 @@ struct xhci_erst { | |||
951 | unsigned int erst_size; | 952 | unsigned int erst_size; |
952 | }; | 953 | }; |
953 | 954 | ||
955 | struct xhci_scratchpad { | ||
956 | u64 *sp_array; | ||
957 | dma_addr_t sp_dma; | ||
958 | void **sp_buffers; | ||
959 | dma_addr_t *sp_dma_buffers; | ||
960 | }; | ||
961 | |||
954 | /* | 962 | /* |
955 | * Each segment table entry is 4*32bits long. 1K seems like an ok size: | 963 | * Each segment table entry is 4*32bits long. 1K seems like an ok size: |
956 | * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, | 964 | * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, |
@@ -1005,6 +1013,9 @@ struct xhci_hcd { | |||
1005 | struct xhci_ring *cmd_ring; | 1013 | struct xhci_ring *cmd_ring; |
1006 | struct xhci_ring *event_ring; | 1014 | struct xhci_ring *event_ring; |
1007 | struct xhci_erst erst; | 1015 | struct xhci_erst erst; |
1016 | /* Scratchpad */ | ||
1017 | struct xhci_scratchpad *scratchpad; | ||
1018 | |||
1008 | /* slot enabling and address device helpers */ | 1019 | /* slot enabling and address device helpers */ |
1009 | struct completion addr_dev; | 1020 | struct completion addr_dev; |
1010 | int slot_id; | 1021 | int slot_id; |