summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/hcd.c35
-rw-r--r--drivers/usb/core/usb.c31
-rw-r--r--drivers/usb/host/xhci.c58
-rw-r--r--include/linux/usb.h7
-rw-r--r--include/linux/usb/hcd.h13
5 files changed, 144 insertions, 0 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 374e79dccc2c..5cc655908fda 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2226,6 +2226,41 @@ int usb_hcd_sec_event_ring_cleanup(struct usb_device *udev,
/*-------------------------------------------------------------------------*/
+dma_addr_t
+usb_hcd_get_sec_event_ring_dma_addr(struct usb_device *udev,
+ unsigned intr_num)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!HCD_RH_RUNNING(hcd))
+ return 0;
+
+ return hcd->driver->get_sec_event_ring_dma_addr(hcd, intr_num);
+}
+
+dma_addr_t
+usb_hcd_get_dcba_dma_addr(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!HCD_RH_RUNNING(hcd))
+ return 0;
+
+ return hcd->driver->get_dcba_dma_addr(hcd, udev);
+}
+
+dma_addr_t
+usb_hcd_get_xfer_ring_dma_addr(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!HCD_RH_RUNNING(hcd))
+ return 0;
+
+ return hcd->driver->get_xfer_ring_dma_addr(hcd, udev, ep);
+}
+
#ifdef CONFIG_PM
int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 3b14f3919d0a..b43d542e3bd4 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -689,6 +689,37 @@ int usb_sec_event_ring_cleanup(struct usb_device *dev,
}
EXPORT_SYMBOL(usb_sec_event_ring_cleanup);
+dma_addr_t
+usb_get_sec_event_ring_dma_addr(struct usb_device *dev,
+ unsigned intr_num)
+{
+ if (dev->state == USB_STATE_NOTATTACHED)
+ return 0;
+
+ return usb_hcd_get_sec_event_ring_dma_addr(dev, intr_num);
+}
+EXPORT_SYMBOL(usb_get_sec_event_ring_dma_addr);
+
+dma_addr_t
+usb_get_dcba_dma_addr(struct usb_device *dev)
+{
+ if (dev->state == USB_STATE_NOTATTACHED)
+ return 0;
+
+ return usb_hcd_get_dcba_dma_addr(dev);
+}
+EXPORT_SYMBOL(usb_get_dcba_dma_addr);
+
+dma_addr_t usb_get_xfer_ring_dma_addr(struct usb_device *dev,
+ struct usb_host_endpoint *ep)
+{
+ if (dev->state == USB_STATE_NOTATTACHED)
+ return 0;
+
+ return usb_hcd_get_xfer_ring_dma_addr(dev, ep);
+}
+EXPORT_SYMBOL(usb_get_xfer_ring_dma_addr);
+
/*-------------------------------------------------------------------*/
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 8bc1ff067ebe..42f74d55e3bd 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4968,6 +4968,61 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
}
EXPORT_SYMBOL_GPL(xhci_gen_setup);
+dma_addr_t xhci_get_sec_event_ring_dma_addr(struct usb_hcd *hcd,
+ unsigned intr_num)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ 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)
+ return xhci->sec_event_ring[intr_num]->first_seg->dma;
+
+ return 0;
+}
+
+dma_addr_t xhci_get_dcba_dma_addr(struct usb_hcd *hcd,
+ struct usb_device *udev)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ if (!(xhci->xhc_state & XHCI_STATE_HALTED) && xhci->dcbaa)
+ return xhci->dcbaa->dev_context_ptrs[udev->slot_id];
+
+ return 0;
+}
+
+dma_addr_t xhci_get_xfer_ring_dma_addr(struct usb_hcd *hcd,
+ struct usb_device *udev, struct usb_host_endpoint *ep)
+{
+ int ret;
+ unsigned int ep_index;
+ struct xhci_virt_device *virt_dev;
+
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ 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)
+ return virt_dev->eps[ep_index].ring->first_seg->dma;
+
+ return 0;
+}
+
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
@@ -5029,6 +5084,9 @@ static const struct hc_driver xhci_hc_driver = {
.find_raw_port_number = xhci_find_raw_port_number,
.sec_event_ring_setup = xhci_sec_event_ring_setup,
.sec_event_ring_cleanup = xhci_sec_event_ring_cleanup,
+ .get_sec_event_ring_dma_addr = xhci_get_sec_event_ring_dma_addr,
+ .get_xfer_ring_dma_addr = xhci_get_xfer_ring_dma_addr,
+ .get_dcba_dma_addr = xhci_get_dcba_dma_addr,
};
void xhci_init_driver(struct hc_driver *drv,
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a2e367de268d..246945be000c 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -739,6 +739,13 @@ extern int usb_sec_event_ring_setup(struct usb_device *dev,
extern int usb_sec_event_ring_cleanup(struct usb_device *dev,
unsigned intr_num);
+extern dma_addr_t
+usb_get_sec_event_ring_dma_addr(struct usb_device *dev,
+ unsigned intr_num);
+extern dma_addr_t usb_get_dcba_dma_addr(struct usb_device *dev);
+extern dma_addr_t usb_get_xfer_ring_dma_addr(struct usb_device *dev,
+ struct usb_host_endpoint *ep);
+
/* Sets up a group of bulk endpoints to support multiple stream IDs. */
extern int usb_alloc_streams(struct usb_interface *interface,
struct usb_host_endpoint **eps, unsigned int num_eps,
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 56c7fba6dcdf..3740366d9fc5 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -398,6 +398,12 @@ struct hc_driver {
int (*sec_event_ring_setup)(struct usb_hcd *hcd, unsigned intr_num);
int (*sec_event_ring_cleanup)(struct usb_hcd *hcd, unsigned intr_num);
+ dma_addr_t (*get_sec_event_ring_dma_addr)(struct usb_hcd *hcd,
+ unsigned intr_num);
+ dma_addr_t (*get_xfer_ring_dma_addr)(struct usb_hcd *hcd,
+ struct usb_device *udev, struct usb_host_endpoint *ep);
+ dma_addr_t (*get_dcba_dma_addr)(struct usb_hcd *hcd,
+ struct usb_device *udev);
};
static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
@@ -440,6 +446,13 @@ extern int usb_hcd_sec_event_ring_setup(struct usb_device *udev,
unsigned intr_num);
extern int usb_hcd_sec_event_ring_cleanup(struct usb_device *udev,
unsigned intr_num);
+extern dma_addr_t
+usb_hcd_get_sec_event_ring_dma_addr(struct usb_device *udev,
+ unsigned intr_num);
+extern dma_addr_t usb_hcd_get_dcba_dma_addr(struct usb_device *udev);
+extern dma_addr_t
+usb_hcd_get_xfer_ring_dma_addr(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name);