From 18e5c7eddd16b6d0e561a8aa7394a841fb04ecfa Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 22 Mar 2016 19:34:20 -0700 Subject: [PATCH] usb: xhci: Add helper APIs to return xhci dma addresses Add APIs to get physical and mapped DMA addresses of secondary event ring, transfer ring and device context base addresses which are required to pass to remote entity. The remote entity uses these addresses to in order to program the xHC from its context. This commit also squashes in the following change: usb: Add support to handle USB SMMU S1 address Change-Id: Ie0756d646a396a11b41b93e886bca9aff636ee5d Signed-off-by: Hemant Kumar Signed-off-by: Jack Pham --- drivers/usb/host/xhci.c | 83 ++++++++++++++++++++++++++++++++++++ include/linux/usb/xhci-sec.h | 19 ++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8081fee0e45d..9cf78e8f4e41 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -5300,6 +5300,89 @@ static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd, spin_unlock_irqrestore(&xhci->lock, flags); } +phys_addr_t xhci_get_sec_event_ring_phys_addr(struct usb_device *udev, + unsigned int intr_num, dma_addr_t *dma) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct device *dev = hcd->self.sysdev; + struct sg_table sgt; + phys_addr_t pa; + + if (udev->state == USB_STATE_NOTATTACHED || !HCD_RH_RUNNING(hcd)) + return 0; + + if (intr_num >= xhci->max_interrupters) { + xhci_err(xhci, "intr num %d >= max intrs %d\n", intr_num, + xhci->max_interrupters); + return 0; + } + + if (!(xhci->xhc_state & XHCI_STATE_HALTED) && + xhci->sec_event_ring && xhci->sec_event_ring[intr_num] + && xhci->sec_event_ring[intr_num]->first_seg) { + + dma_get_sgtable(dev, &sgt, + xhci->sec_event_ring[intr_num]->first_seg->trbs, + xhci->sec_event_ring[intr_num]->first_seg->dma, + TRB_SEGMENT_SIZE); + + *dma = xhci->sec_event_ring[intr_num]->first_seg->dma; + + pa = page_to_phys(sg_page(sgt.sgl)); + sg_free_table(&sgt); + + return pa; + } + + return 0; +} +EXPORT_SYMBOL(xhci_get_sec_event_ring_phys_addr); + +phys_addr_t xhci_get_xfer_ring_phys_addr(struct usb_device *udev, + struct usb_host_endpoint *ep, dma_addr_t *dma) +{ + int ret; + unsigned int ep_index; + struct xhci_virt_device *virt_dev; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct device *dev = hcd->self.sysdev; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct sg_table sgt; + phys_addr_t pa; + + if (udev->state == USB_STATE_NOTATTACHED || !HCD_RH_RUNNING(hcd)) + return 0; + + ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); + if (ret <= 0) { + xhci_err(xhci, "%s: invalid args\n", __func__); + return 0; + } + + virt_dev = xhci->devs[udev->slot_id]; + ep_index = xhci_get_endpoint_index(&ep->desc); + + if (virt_dev->eps[ep_index].ring && + virt_dev->eps[ep_index].ring->first_seg) { + + dma_get_sgtable(dev, &sgt, + virt_dev->eps[ep_index].ring->first_seg->trbs, + virt_dev->eps[ep_index].ring->first_seg->dma, + TRB_SEGMENT_SIZE); + + *dma = virt_dev->eps[ep_index].ring->first_seg->dma; + + pa = page_to_phys(sg_page(sgt.sgl)); + sg_free_table(&sgt); + + return pa; + } + + return 0; +} +EXPORT_SYMBOL(xhci_get_xfer_ring_phys_addr); + static const struct hc_driver xhci_hc_driver = { .description = "xhci-hcd", .product_desc = "xHCI Host Controller", diff --git a/include/linux/usb/xhci-sec.h b/include/linux/usb/xhci-sec.h index 47cb4e0cf458..878d45d372c9 100644 --- a/include/linux/usb/xhci-sec.h +++ b/include/linux/usb/xhci-sec.h @@ -8,11 +8,15 @@ #ifndef __LINUX_XHCI_SEC_H #define __LINUX_XHCI_SEC_H -struct usb_device; +#include #if IS_ENABLED(CONFIG_USB_XHCI_HCD) int xhci_sec_event_ring_setup(struct usb_device *udev, unsigned int intr_num); int xhci_sec_event_ring_cleanup(struct usb_device *udev, unsigned int intr_num); +phys_addr_t xhci_get_sec_event_ring_phys_addr(struct usb_device *udev, + unsigned int intr_num, dma_addr_t *dma); +phys_addr_t xhci_get_xfer_ring_phys_addr(struct usb_device *udev, + struct usb_host_endpoint *ep, dma_addr_t *dma); #else static inline int xhci_sec_event_ring_setup(struct usb_device *udev, unsigned int intr_num); @@ -25,6 +29,19 @@ static inline int xhci_sec_event_ring_cleanup(struct usb_device *udev, { return -ENODEV; } + +static inline phys_addr_t xhci_get_sec_event_ring_phys_addr( + struct usb_device *udev, unsigned int intr_num, + dma_addr_t *dma) +{ + return NULL; +} + +static inline phys_addr_t xhci_get_xfer_ring_phys_addr(struct usb_device *udev, + struct usb_host_endpoint *ep, dma_addr_t *dma) +{ + return NULL; +} #endif #endif /* __LINUX_XHCI_SEC_H */