diff options
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 90 |
1 files changed, 49 insertions, 41 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ad244637e6..9758e1ed73 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -184,15 +184,11 @@ out: return ret; } -static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) +static int ehci_td_buffer(struct qTD *td, dma_addr_t addr, size_t sz) { - uint32_t addr, delta, next; + uint32_t delta, next; int idx; - addr = (uint32_t) buf; - td->qtd_dma = addr; - td->length = sz; - idx = 0; while (idx < 5) { td->qt_buffer[idx] = cpu_to_hc32(addr); @@ -213,8 +209,11 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) return 0; } -static int ehci_prepare_qtd(struct qTD *td, uint32_t token, - void *buffer, size_t length) +static int ehci_prepare_qtd(struct device_d *dev, + struct qTD *td, uint32_t token, + void *buffer, size_t length, + dma_addr_t *buffer_dma, + enum dma_data_direction dma_direction) { int ret; @@ -226,7 +225,12 @@ static int ehci_prepare_qtd(struct qTD *td, uint32_t token, td->qt_token = cpu_to_hc32(token); if (length) { - ret = ehci_td_buffer(td, buffer, length); + *buffer_dma = dma_map_single(dev, buffer, length, + dma_direction); + if (dma_mapping_error(dev, *buffer_dma)) + return -EFAULT; + + ret = ehci_td_buffer(td, *buffer_dma, length); if (ret) return ret; } @@ -257,12 +261,15 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, { struct usb_host *host = dev->host; struct ehci_host *ehci = to_ehci(host); + const bool dir_in = usb_pipein(pipe); + dma_addr_t buffer_dma, req_dma; struct QH *qh; struct qTD *td; uint32_t *tdp; uint32_t endpt, token, usbsts; uint32_t c, toggle; - int ret = 0, i; + int ret = 0; + dev_dbg(ehci->dev, "pipe=%lx, buffer=%p, length=%d, req=%p\n", pipe, buffer, length, req); @@ -320,9 +327,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, if (req != NULL) { td = &ehci->td[0]; - ret = ehci_prepare_qtd(td, QT_TOKEN_DT(0) | QT_TOKEN_IOC(0) | + ret = ehci_prepare_qtd(ehci->dev, + td, QT_TOKEN_DT(0) | QT_TOKEN_IOC(0) | QT_TOKEN_PID(QT_TOKEN_PID_SETUP), - req, sizeof(*req)); + req, sizeof(*req), + &req_dma, DMA_TO_DEVICE); if (ret) { dev_dbg(ehci->dev, "unable construct SETUP td\n"); return ret; @@ -334,14 +343,25 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, } if (length > 0 || req == NULL) { + enum dma_data_direction dir; + unsigned int pid; + td = &ehci->td[1]; - ret = ehci_prepare_qtd(td, QT_TOKEN_DT(toggle) | + if (dir_in) { + dir = DMA_FROM_DEVICE; + pid = QT_TOKEN_PID_IN; + } else { + dir = DMA_TO_DEVICE; + pid = QT_TOKEN_PID_OUT; + } + + ret = ehci_prepare_qtd(ehci->dev, + td, QT_TOKEN_DT(toggle) | QT_TOKEN_IOC(req == NULL) | - QT_TOKEN_PID(usb_pipein(pipe) ? - QT_TOKEN_PID_IN : - QT_TOKEN_PID_OUT), - buffer, length); + QT_TOKEN_PID(pid), + buffer, length, + &buffer_dma, dir); if (ret) { dev_err(ehci->dev, "unable construct DATA td\n"); return ret; @@ -353,29 +373,19 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, if (req) { td = &ehci->td[2]; - ehci_prepare_qtd(td, QT_TOKEN_DT(1) | QT_TOKEN_IOC(1) | - QT_TOKEN_PID(usb_pipein(pipe) ? + ehci_prepare_qtd(ehci->dev, + td, QT_TOKEN_DT(1) | QT_TOKEN_IOC(1) | + QT_TOKEN_PID(dir_in ? QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN), - NULL, 0); + NULL, 0, + NULL, DMA_NONE); *tdp = cpu_to_hc32((uint32_t)td); tdp = &td->qt_next; } ehci->qh_list->qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH); - /* Flush dcache */ - if (IS_ENABLED(CONFIG_MMU)) { - for (i = 0; i < NUM_TD; i ++) { - struct qTD *qtd = &ehci->td[i]; - if (!qtd->qtd_dma) - continue; - dma_sync_single_for_device((unsigned long)qtd->qtd_dma, - qtd->length, - DMA_BIDIRECTIONAL); - } - } - usbsts = ehci_readl(&ehci->hcor->or_usbsts); ehci_writel(&ehci->hcor->or_usbsts, (usbsts & 0x3f)); @@ -394,15 +404,13 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, return -ETIMEDOUT; } - if (IS_ENABLED(CONFIG_MMU)) { - for (i = 0; i < NUM_TD; i ++) { - struct qTD *qtd = &ehci->td[i]; - if (!qtd->qtd_dma) - continue; - dma_sync_single_for_cpu((unsigned long)qtd->qtd_dma, - qtd->length, DMA_BIDIRECTIONAL); - } - } + if (req) + dma_unmap_single(ehci->dev, req_dma, sizeof(*req), + DMA_TO_DEVICE); + + if (length) + dma_unmap_single(ehci->dev, buffer_dma, length, + dir_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); ret = ehci_enable_async_schedule(ehci, false); if (ret < 0) { |