diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r-- | drivers/usb/host/xhci.c | 99 |
1 files changed, 62 insertions, 37 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index caab2400d8..e7b8344181 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0-or-later /* * USB HOST XHCI Controller stack * @@ -24,13 +24,13 @@ #include <init.h> #include <io.h> #include <linux/err.h> -#include <usb/usb.h> -#include <usb/xhci.h> +#include <linux/usb/usb.h> +#include <linux/usb/xhci.h> #include <asm/unaligned.h> #include "xhci.h" -static struct descriptor { +static const struct descriptor { struct usb_hub_descriptor hub; struct usb_device_descriptor device; struct usb_config_descriptor config; @@ -151,6 +151,8 @@ static int xhci_start(struct xhci_ctrl *ctrl) u32 temp; int ret; + dev_dbg(ctrl->dev, "Starting the controller\n"); + temp = xhci_readl(&hcor->or_usbcmd); temp |= (CMD_RUN); xhci_writel(&hcor->or_usbcmd, temp); @@ -441,9 +443,12 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change) in_ctx = virt_dev->in_ctx; xhci_flush_cache((uintptr_t)in_ctx->bytes, in_ctx->size); - xhci_queue_command(ctrl, in_ctx->bytes, udev->slot_id, 0, + xhci_queue_command(ctrl, in_ctx->dma, udev->slot_id, 0, ctx_change ? TRB_EVAL_CONTEXT : TRB_CONFIG_EP); - event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT); + if (!event) + return -ETIMEDOUT; + BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != udev->slot_id); @@ -566,8 +571,7 @@ static int xhci_set_configuration(struct usb_device *udev) cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) | EP_INTERVAL(interval) | EP_MULT(mult)); - ep_ctx[ep_index]->ep_info2 = - cpu_to_le32(ep_type << EP_TYPE_SHIFT); + ep_ctx[ep_index]->ep_info2 = cpu_to_le32(EP_TYPE(ep_type)); ep_ctx[ep_index]->ep_info2 |= cpu_to_le32(MAX_PACKET (get_unaligned(&endpt_desc->wMaxPacketSize))); @@ -579,8 +583,8 @@ static int xhci_set_configuration(struct usb_device *udev) cpu_to_le32(MAX_BURST(max_burst) | ERROR_COUNT(err_count)); - trb_64 = (uintptr_t) - virt_dev->eps[ep_index].ring->enqueue; + trb_64 = xhci_trb_virt_to_dma(virt_dev->eps[ep_index].ring->enq_seg, + virt_dev->eps[ep_index].ring->enqueue); ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 | virt_dev->eps[ep_index].ring->cycle_state); @@ -628,8 +632,12 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr) ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); ctrl_ctx->drop_flags = 0; - xhci_queue_command(ctrl, (void *)ctrl_ctx, slot_id, 0, TRB_ADDR_DEV); - event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + xhci_queue_command(ctrl, virt_dev->in_ctx->dma, + slot_id, 0, TRB_ADDR_DEV); + event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT); + if (!event) + return -ETIMEDOUT; + BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != slot_id); switch (GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))) { @@ -703,8 +711,11 @@ static int _xhci_alloc_device(struct usb_device *udev) return 0; } - xhci_queue_command(ctrl, NULL, 0, 0, TRB_ENABLE_SLOT); - event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + xhci_queue_command(ctrl, 0, 0, 0, TRB_ENABLE_SLOT); + event = xhci_wait_for_event(ctrl, TRB_COMPLETION, XHCI_TIMEOUT_DEFAULT); + if (!event) + return -ETIMEDOUT; + BUG_ON(GET_COMP_CODE(le32_to_cpu(event->event_cmd.status)) != COMP_SUCCESS); @@ -764,8 +775,7 @@ int xhci_check_maxpacket(struct usb_device *udev) ctrl->devs[slot_id]->out_ctx, ep_index); in_ctx = ctrl->devs[slot_id]->in_ctx; ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); - ep_ctx->ep_info2 &= cpu_to_le32(~((0xffff & MAX_PACKET_MASK) - << MAX_PACKET_SHIFT)); + ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET(MAX_PACKET_MASK)); ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); /* @@ -860,7 +870,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe, { uint8_t tmpbuf[4]; u16 typeReq; - void *srcptr = NULL; + const void *srcptr = NULL; int len, srclen; uint32_t reg; volatile uint32_t *status_reg; @@ -928,7 +938,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe, case USB_DT_HUB: case USB_DT_SS_HUB: dev_dbg(&udev->dev, "USB_DT_HUB config\n"); - srcptr = &descriptor.hub; + srcptr = &ctrl->hub_desc; srclen = 0x8; break; default: @@ -1088,8 +1098,10 @@ unknown: static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer, int length, int interval) { - if (usb_pipetype(pipe) != PIPE_INTERRUPT) + if (usb_pipetype(pipe) != PIPE_INTERRUPT) { + dev_err(&udev->dev, "non-interrupt pipe (type=%lu)", usb_pipetype(pipe)); return -EINVAL; + } /* * xHCI uses normal TRBs for both bulk and interrupt. When the @@ -1097,7 +1109,7 @@ static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe, * (at most) one TD. A TD (comprised of sg list entries) can * take several service intervals to transmit. */ - return xhci_bulk_tx(udev, pipe, length, buffer); + return xhci_bulk_tx(udev, pipe, length, buffer, 0); } /** @@ -1112,10 +1124,12 @@ static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe, static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer, int length, int timeout_ms) { - if (usb_pipetype(pipe) != PIPE_BULK) + if (usb_pipetype(pipe) != PIPE_BULK) { + dev_err(&udev->dev, "non-bulk pipe (type=%lu)", usb_pipetype(pipe)); return -EINVAL; + } - return xhci_bulk_tx(udev, pipe, length, buffer); + return xhci_bulk_tx(udev, pipe, length, buffer, timeout_ms); } /** @@ -1131,13 +1145,16 @@ static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe, */ static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer, int length, - struct devrequest *setup, int root_portnr) + struct devrequest *setup, int root_portnr, + unsigned int timeout_ms) { struct xhci_ctrl *ctrl = xhci_get_ctrl(udev); int ret = 0; - if (usb_pipetype(pipe) != PIPE_CONTROL) + if (usb_pipetype(pipe) != PIPE_CONTROL) { + dev_err(&udev->dev, "non-control pipe (type=%lu)", usb_pipetype(pipe)); return -EINVAL; + } if (usb_pipedevice(pipe) == ctrl->rootdev) return xhci_submit_root(udev, pipe, buffer, setup); @@ -1155,7 +1172,7 @@ static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe, } } - return xhci_ctrl_tx(udev, pipe, setup, length, buffer); + return xhci_ctrl_tx(udev, pipe, setup, length, buffer, timeout_ms); } static int xhci_lowlevel_init(struct xhci_ctrl *ctrl) @@ -1180,21 +1197,23 @@ static int xhci_lowlevel_init(struct xhci_ctrl *ctrl) /* initializing xhci data structures */ if (xhci_mem_init(ctrl, hccr, hcor) < 0) return -ENOMEM; + ctrl->hub_desc = descriptor.hub; reg = xhci_readl(&hccr->cr_hcsparams1); - descriptor.hub.bNbrPorts = ((reg & HCS_MAX_PORTS_MASK) >> - HCS_MAX_PORTS_SHIFT); + ctrl->hub_desc.bNbrPorts = HCS_MAX_PORTS(reg); + + dev_dbg(ctrl->dev, "Register 0x%x NbrPorts %d\n", reg, ctrl->hub_desc.bNbrPorts); /* Port Indicators */ reg = xhci_readl(&hccr->cr_hccparams); if (HCS_INDICATOR(reg)) - put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics) - | 0x80, &descriptor.hub.wHubCharacteristics); + put_unaligned(get_unaligned(&ctrl->hub_desc.wHubCharacteristics) + | 0x80, &ctrl->hub_desc.wHubCharacteristics); /* Port Power Control */ if (HCC_PPC(reg)) - put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics) - | 0x01, &descriptor.hub.wHubCharacteristics); + put_unaligned(get_unaligned(&ctrl->hub_desc.wHubCharacteristics) + | 0x01, &ctrl->hub_desc.wHubCharacteristics); if (xhci_start(ctrl)) { xhci_reset(ctrl); @@ -1217,6 +1236,8 @@ static int xhci_lowlevel_stop(struct xhci_ctrl *ctrl) xhci_reset(ctrl); + dev_dbg(ctrl->dev, "Disabling event ring interrupts\n"); + temp = xhci_readl(&ctrl->hcor->or_usbsts); xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT); temp = xhci_readl(&ctrl->ir_set->irq_pending); @@ -1239,7 +1260,7 @@ static int xhci_submit_control_msg(struct usb_device *udev, } return _xhci_submit_control_msg(udev, pipe, buffer, length, setup, - root_portnr); + root_portnr, timeout_ms); } static int xhci_submit_bulk_msg(struct usb_device *udev, @@ -1343,7 +1364,7 @@ static __maybe_unused int xhci_get_max_xfer_size(size_t *size) int xhci_register(struct xhci_ctrl *ctrl) { struct usb_host *host; - struct device_d *dev = ctrl->dev; + struct device *dev = ctrl->dev; int ret; dev_dbg(dev, "%s: hccr=%p, hcor=%p\n", __func__, ctrl->hccr, ctrl->hcor); @@ -1358,7 +1379,11 @@ int xhci_register(struct xhci_ctrl *ctrl) */ host->no_desc_before_addr = true; - host->hw_dev = dev; + /* + * If xHCI doesn't have its own DT node, it'll be a child of a + * physical USB host controller device that should be used for DMA + */ + host->hw_dev = dev_of_node(dev) ? dev : dev->parent; host->submit_int_msg = xhci_submit_int_msg; host->submit_control_msg = xhci_submit_control_msg; host->submit_bulk_msg = xhci_submit_bulk_msg; @@ -1393,7 +1418,7 @@ int xhci_deregister(struct xhci_ctrl *ctrl) * xHCI platform driver */ -static int xhci_probe(struct device_d *dev) +static int xhci_probe(struct device *dev) { struct resource *iores; struct xhci_ctrl *ctrl; @@ -1414,14 +1439,14 @@ static int xhci_probe(struct device_d *dev) return xhci_register(ctrl); } -static void xhci_remove(struct device_d *dev) +static void xhci_remove(struct device *dev) { struct xhci_ctrl *ctrl = dev->priv; xhci_deregister(ctrl); } -static struct driver_d xhci_driver = { +static struct driver xhci_driver = { .name = "xHCI", .probe = xhci_probe, .remove = xhci_remove, |