diff options
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 102 |
1 files changed, 102 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); |