diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-26 21:00:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-26 21:00:28 -0400 |
commit | bcba282ab399eec1c8b8dcb49c43a33813971913 (patch) | |
tree | de81927192d6b02071479aa08a78466878d115c1 | |
parent | fb740f9bab3b3c049d6207b148e45de05163b6e5 (diff) | |
parent | b4731977243c1ae9cfd8b3971ffc15425b7d7545 (diff) |
Merge tag 'usb-4.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB fixes from Greg KH:
"Here are some USB driver fixes for 4.3-rc3.
There's the usual assortment of new device ids, combined with xhci and
gadget driver fixes. Full details in the shortlog. All of these have
been in linux-next with no reported problems"
* tag 'usb-4.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (34 commits)
MAINTAINERS: remove amd5536udc USB gadget driver maintainer
USB: whiteheat: fix potential null-deref at probe
xhci: init command timeout timer earlier to avoid deleting it uninitialized
xhci: change xhci 1.0 only restrictions to support xhci 1.1
usb: xhci: exit early in xhci_setup_device() if we're halted or dying
usb: xhci: stop everything on the first call to xhci_stop
usb: xhci: Clear XHCI_STATE_DYING on start
usb: xhci: lock mutex on xhci_stop
xhci: Move xhci_pme_quirk() behind #ifdef CONFIG_PM
xhci: give command abortion one more chance before killing xhci
usb: Use the USB_SS_MULT() macro to get the burst multiplier.
usb: dwc3: gadget: Fix BUG in RT config
usb: musb: fix cppi channel teardown for isoch transfer
usb: phy: isp1301: Export I2C module alias information
usb: gadget: drop null test before destroy functions
usb: gadget: dummy_hcd: in transfer(), return data sent, not limit
usb: gadget: dummy_hcd: fix rescan logic for transfer
usb: gadget: dummy_hcd: fix unneeded else-if condition
usb: gadget: dummy_hcd: emulate sending zlp in packet logic
usb: musb: dsps: fix polling in device-only mode
...
29 files changed, 288 insertions, 177 deletions
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index d71ef07bca5d..a057b75ba4b5 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -6,6 +6,7 @@ Required properties: "lsi,zevio-usb" "qcom,ci-hdrc" "chipidea,usb2" + "xlnx,zynq-usb-2.20a" - reg: base address and length of the registers - interrupts: interrupt for the USB controller diff --git a/MAINTAINERS b/MAINTAINERS index a3077df7e68a..9f6685f6c5a9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -615,9 +615,8 @@ F: Documentation/hwmon/fam15h_power F: drivers/hwmon/fam15h_power.c AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER -M: Thomas Dahlmann <dahlmann.thomas@arcor.de> L: linux-geode@lists.infradead.org (moderated for non-subscribers) -S: Supported +S: Orphan F: drivers/usb/gadget/udc/amd5536udc.* AMD GEODE PROCESSOR/CHIPSET SUPPORT diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 867e9f3f3859..dcc50c878159 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -61,7 +61,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = { { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data}, { .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data}, { .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data}, - { .compatible = "fsl,imx6sx-usb", .data = &imx6sl_usb_data}, + { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index 9eae1a16cef9..4456d2cf80ff 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -12,6 +12,7 @@ #include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_platform.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/usb/chipidea.h> @@ -30,18 +31,36 @@ static const struct ci_hdrc_platform_data ci_default_pdata = { .flags = CI_HDRC_DISABLE_STREAMING, }; +static struct ci_hdrc_platform_data ci_zynq_pdata = { + .capoffset = DEF_CAPOFFSET, +}; + +static const struct of_device_id ci_hdrc_usb2_of_match[] = { + { .compatible = "chipidea,usb2"}, + { .compatible = "xlnx,zynq-usb-2.20a", .data = &ci_zynq_pdata}, + { } +}; +MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match); + static int ci_hdrc_usb2_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ci_hdrc_usb2_priv *priv; struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev); int ret; + const struct of_device_id *match; if (!ci_pdata) { ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL); *ci_pdata = ci_default_pdata; /* struct copy */ } + match = of_match_device(ci_hdrc_usb2_of_match, &pdev->dev); + if (match && match->data) { + /* struct copy */ + *ci_pdata = *(struct ci_hdrc_platform_data *)match->data; + } + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -96,12 +115,6 @@ static int ci_hdrc_usb2_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id ci_hdrc_usb2_of_match[] = { - { .compatible = "chipidea,usb2" }, - { } -}; -MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match); - static struct platform_driver ci_hdrc_usb2_driver = { .probe = ci_hdrc_usb2_probe, .remove = ci_hdrc_usb2_remove, diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index a637da25dda0..8223fe73ea85 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -656,6 +656,44 @@ __acquires(hwep->lock) return 0; } +static int _ep_set_halt(struct usb_ep *ep, int value, bool check_transfer) +{ + struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep); + int direction, retval = 0; + unsigned long flags; + + if (ep == NULL || hwep->ep.desc == NULL) + return -EINVAL; + + if (usb_endpoint_xfer_isoc(hwep->ep.desc)) + return -EOPNOTSUPP; + + spin_lock_irqsave(hwep->lock, flags); + + if (value && hwep->dir == TX && check_transfer && + !list_empty(&hwep->qh.queue) && + !usb_endpoint_xfer_control(hwep->ep.desc)) { + spin_unlock_irqrestore(hwep->lock, flags); + return -EAGAIN; + } + + direction = hwep->dir; + do { + retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value); + + if (!value) + hwep->wedge = 0; + + if (hwep->type == USB_ENDPOINT_XFER_CONTROL) + hwep->dir = (hwep->dir == TX) ? RX : TX; + + } while (hwep->dir != direction); + + spin_unlock_irqrestore(hwep->lock, flags); + return retval; +} + + /** * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts * @gadget: gadget @@ -1051,7 +1089,7 @@ __acquires(ci->lock) num += ci->hw_ep_max / 2; spin_unlock(&ci->lock); - err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep); + err = _ep_set_halt(&ci->ci_hw_ep[num].ep, 1, false); spin_lock(&ci->lock); if (!err) isr_setup_status_phase(ci); @@ -1117,8 +1155,8 @@ delegate: if (err < 0) { spin_unlock(&ci->lock); - if (usb_ep_set_halt(&hwep->ep)) - dev_err(ci->dev, "error: ep_set_halt\n"); + if (_ep_set_halt(&hwep->ep, 1, false)) + dev_err(ci->dev, "error: _ep_set_halt\n"); spin_lock(&ci->lock); } } @@ -1149,9 +1187,9 @@ __acquires(ci->lock) err = isr_setup_status_phase(ci); if (err < 0) { spin_unlock(&ci->lock); - if (usb_ep_set_halt(&hwep->ep)) + if (_ep_set_halt(&hwep->ep, 1, false)) dev_err(ci->dev, - "error: ep_set_halt\n"); + "error: _ep_set_halt\n"); spin_lock(&ci->lock); } } @@ -1397,41 +1435,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) */ static int ep_set_halt(struct usb_ep *ep, int value) { - struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep); - int direction, retval = 0; - unsigned long flags; - - if (ep == NULL || hwep->ep.desc == NULL) - return -EINVAL; - - if (usb_endpoint_xfer_isoc(hwep->ep.desc)) - return -EOPNOTSUPP; - - spin_lock_irqsave(hwep->lock, flags); - -#ifndef STALL_IN - /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ - if (value && hwep->type == USB_ENDPOINT_XFER_BULK && hwep->dir == TX && - !list_empty(&hwep->qh.queue)) { - spin_unlock_irqrestore(hwep->lock, flags); - return -EAGAIN; - } -#endif - - direction = hwep->dir; - do { - retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value); - - if (!value) - hwep->wedge = 0; - - if (hwep->type == USB_ENDPOINT_XFER_CONTROL) - hwep->dir = (hwep->dir == TX) ? RX : TX; - - } while (hwep->dir != direction); - - spin_unlock_irqrestore(hwep->lock, flags); - return retval; + return _ep_set_halt(ep, value, true); } /** diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index b2a540b43f97..b9ddf0c1ffe5 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -112,7 +112,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, cfgno, inum, asnum, ep->desc.bEndpointAddress); ep->ss_ep_comp.bmAttributes = 16; } else if (usb_endpoint_xfer_isoc(&ep->desc) && - desc->bmAttributes > 2) { + USB_SS_MULT(desc->bmAttributes) > 3) { dev_warn(ddev, "Isoc endpoint has Mult of %d in " "config %d interface %d altsetting %d ep %d: " "setting to 3\n", desc->bmAttributes + 1, @@ -121,7 +121,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, } if (usb_endpoint_xfer_isoc(&ep->desc)) - max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) * + max_tx = (desc->bMaxBurst + 1) * + (USB_SS_MULT(desc->bmAttributes)) * usb_endpoint_maxp(&ep->desc); else if (usb_endpoint_xfer_int(&ep->desc)) max_tx = usb_endpoint_maxp(&ep->desc) * diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index a5a1b7c45743..22e9606d8e08 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -514,8 +514,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) goto err1; } - dwc3_omap_enable_irqs(omap); - ret = dwc3_omap_extcon_register(omap); if (ret < 0) goto err2; @@ -526,6 +524,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) goto err3; } + dwc3_omap_enable_irqs(omap); + return 0; err3: diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0c25704dcb6b..1e8bdf817811 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2665,8 +2665,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) int i; irqreturn_t ret = IRQ_NONE; - spin_lock(&dwc->lock); - for (i = 0; i < dwc->num_event_buffers; i++) { irqreturn_t status; @@ -2675,8 +2673,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) ret = status; } - spin_unlock(&dwc->lock); - return ret; } diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 978435a51038..6399c106a3a5 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -186,6 +186,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget) list_for_each_entry (ep, &gadget->ep_list, ep_list) { ep->claimed = false; + ep->driver_data = NULL; } gadget->in_epnum = 0; gadget->out_epnum = 0; diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c index fdacddb18c00..175ca93fe5e2 100644 --- a/drivers/usb/gadget/udc/amd5536udc.c +++ b/drivers/usb/gadget/udc/amd5536udc.c @@ -3138,8 +3138,8 @@ static void udc_pci_remove(struct pci_dev *pdev) writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); if (dev->irq_registered) free_irq(pdev->irq, dev); - if (dev->regs) - iounmap(dev->regs); + if (dev->virt_addr) + iounmap(dev->virt_addr); if (dev->mem_region) release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); @@ -3226,17 +3226,13 @@ static int udc_pci_probe( /* init */ dev = kzalloc(sizeof(struct udc), GFP_KERNEL); - if (!dev) { - retval = -ENOMEM; - goto finished; - } + if (!dev) + return -ENOMEM; /* pci setup */ if (pci_enable_device(pdev) < 0) { - kfree(dev); - dev = NULL; retval = -ENODEV; - goto finished; + goto err_pcidev; } dev->active = 1; @@ -3246,28 +3242,22 @@ static int udc_pci_probe( if (!request_mem_region(resource, len, name)) { dev_dbg(&pdev->dev, "pci device used already\n"); - kfree(dev); - dev = NULL; retval = -EBUSY; - goto finished; + goto err_memreg; } dev->mem_region = 1; dev->virt_addr = ioremap_nocache(resource, len); if (dev->virt_addr == NULL) { dev_dbg(&pdev->dev, "start address cannot be mapped\n"); - kfree(dev); - dev = NULL; retval = -EFAULT; - goto finished; + goto err_ioremap; } if (!pdev->irq) { dev_err(&pdev->dev, "irq not set\n"); - kfree(dev); - dev = NULL; retval = -ENODEV; - goto finished; + goto err_irq; } spin_lock_init(&dev->lock); @@ -3283,10 +3273,8 @@ static int udc_pci_probe( if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq); - kfree(dev); - dev = NULL; retval = -EBUSY; - goto finished; + goto err_irq; } dev->irq_registered = 1; @@ -3314,8 +3302,17 @@ static int udc_pci_probe( return 0; finished: - if (dev) - udc_pci_remove(pdev); + udc_pci_remove(pdev); + return retval; + +err_irq: + iounmap(dev->virt_addr); +err_ioremap: + release_mem_region(resource, len); +err_memreg: + pci_disable_device(pdev); +err_pcidev: + kfree(dev); return retval; } diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 3dfada8d6061..f0f2b066ac08 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2002,6 +2002,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ep->udc = udc; INIT_LIST_HEAD(&ep->queue); + if (ep->index == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = ep->can_isoc; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + if (i) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 5c8f4effb62a..ccb9c213cc9f 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -324,8 +324,7 @@ static void bdc_mem_free(struct bdc *bdc) bdc->scratchpad.buff, bdc->scratchpad.sp_dma); /* Destroy the dma pools */ - if (bdc->bd_table_pool) - dma_pool_destroy(bdc->bd_table_pool); + dma_pool_destroy(bdc->bd_table_pool); /* Free the bdc_ep array */ kfree(bdc->bdc_ep_array); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 1379ad40d864..27af0f008b57 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1348,6 +1348,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, { struct dummy *dum = dum_hcd->dum; struct dummy_request *req; + int sent = 0; top: /* if there's no request queued, the device is NAKing; return */ @@ -1385,12 +1386,15 @@ top: if (len == 0) break; - /* use an extra pass for the final short packet */ - if (len > ep->ep.maxpacket) { - rescan = 1; - len -= (len % ep->ep.maxpacket); + /* send multiple of maxpacket first, then remainder */ + if (len >= ep->ep.maxpacket) { + is_short = 0; + if (len % ep->ep.maxpacket) + rescan = 1; + len -= len % ep->ep.maxpacket; + } else { + is_short = 1; } - is_short = (len % ep->ep.maxpacket) != 0; len = dummy_perform_transfer(urb, req, len); @@ -1399,6 +1403,7 @@ top: req->req.status = len; } else { limit -= len; + sent += len; urb->actual_length += len; req->req.actual += len; } @@ -1421,7 +1426,7 @@ top: *status = -EOVERFLOW; else *status = 0; - } else if (!to_host) { + } else { *status = 0; if (host_len > dev_len) req->req.status = -EOVERFLOW; @@ -1429,15 +1434,24 @@ top: req->req.status = 0; } - /* many requests terminate without a short packet */ + /* + * many requests terminate without a short packet. + * send a zlp if demanded by flags. + */ } else { - if (req->req.length == req->req.actual - && !req->req.zero) - req->req.status = 0; - if (urb->transfer_buffer_length == urb->actual_length - && !(urb->transfer_flags - & URB_ZERO_PACKET)) - *status = 0; + if (req->req.length == req->req.actual) { + if (req->req.zero && to_host) + rescan = 1; + else + req->req.status = 0; + } + if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_flags & URB_ZERO_PACKET && + !to_host) + rescan = 1; + else + *status = 0; + } } /* device side completion --> continuable */ @@ -1460,7 +1474,7 @@ top: if (rescan) goto top; } - return limit; + return sent; } static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep) @@ -1890,7 +1904,7 @@ restart: default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer(dum_hcd, urb, ep, limit, &status); + total -= transfer(dum_hcd, urb, ep, limit, &status); break; } diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index 8aa2593c2c36..b9429bc42511 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -2117,8 +2117,7 @@ static int gr_remove(struct platform_device *pdev) return -EBUSY; gr_dfs_delete(dev); - if (dev->desc_pool) - dma_pool_destroy(dev->desc_pool); + dma_pool_destroy(dev->desc_pool); platform_set_drvdata(pdev, NULL); gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req); diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 4c489692745e..dafe74eb9ade 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1767,8 +1767,7 @@ static int mv_u3d_remove(struct platform_device *dev) usb_del_gadget_udc(&u3d->gadget); /* free memory allocated in probe */ - if (u3d->trb_pool) - dma_pool_destroy(u3d->trb_pool); + dma_pool_destroy(u3d->trb_pool); if (u3d->ep_context) dma_free_coherent(&dev->dev, u3d->ep_context_size, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 339af51df57d..81b6229c7805 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2100,8 +2100,7 @@ static int mv_udc_remove(struct platform_device *pdev) } /* free memory allocated in probe */ - if (udc->dtd_pool) - dma_pool_destroy(udc->dtd_pool); + dma_pool_destroy(udc->dtd_pool); if (udc->ep_dqh) dma_free_coherent(&pdev->dev, udc->ep_dqh_size, diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 9a8c936cd42c..41f841fa6c4d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1498,10 +1498,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, * use Event Data TRBs, and we don't chain in a link TRB on short * transfers, we're basically dividing by 1. * - * xHCI 1.0 specification indicates that the Average TRB Length should - * be set to 8 for control endpoints. + * xHCI 1.0 and 1.1 specification indicates that the Average TRB Length + * should be set to 8 for control endpoints. */ - if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100) + if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100) ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8)); else ep_ctx->tx_info |= @@ -1792,8 +1792,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) int size; int i, j, num_ports; - if (timer_pending(&xhci->cmd_timer)) - del_timer_sync(&xhci->cmd_timer); + del_timer_sync(&xhci->cmd_timer); /* Free the Event Ring Segment Table and the actual Event Ring */ size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); @@ -2321,6 +2320,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) INIT_LIST_HEAD(&xhci->cmd_list); + /* init command timeout timer */ + setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout, + (unsigned long)xhci); + page_size = readl(&xhci->op_regs->page_size); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Supported page size register = 0x%x", page_size); @@ -2505,10 +2508,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) "Wrote ERST address to ir_set 0."); xhci_print_ir_set(xhci, 0); - /* init command timeout timer */ - setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout, - (unsigned long)xhci); - /* * XXX: Might need to set the Interrupter Moderation Register to * something other than the default (~1ms minimum between interrupts). diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 5590eac2b22d..c79d33676672 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -180,51 +180,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) "QUIRK: Resetting on resume"); } -/* - * In some Intel xHCI controllers, in order to get D3 working, - * through a vendor specific SSIC CONFIG register at offset 0x883c, - * SSIC PORT need to be marked as "unused" before putting xHCI - * into D3. After D3 exit, the SSIC port need to be marked as "used". - * Without this change, xHCI might not enter D3 state. - * Make sure PME works on some Intel xHCI controllers by writing 1 to clear - * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 - */ -static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - u32 val; - void __iomem *reg; - - if (pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { - - reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2; - - /* Notify SSIC that SSIC profile programming is not done */ - val = readl(reg) & ~PROG_DONE; - writel(val, reg); - - /* Mark SSIC port as unused(suspend) or used(resume) */ - val = readl(reg); - if (suspend) - val |= SSIC_PORT_UNUSED; - else - val &= ~SSIC_PORT_UNUSED; - writel(val, reg); - - /* Notify SSIC that SSIC profile programming is done */ - val = readl(reg) | PROG_DONE; - writel(val, reg); - readl(reg); - } - - reg = (void __iomem *) xhci->cap_regs + 0x80a4; - val = readl(reg); - writel(val | BIT(28), reg); - readl(reg); -} - #ifdef CONFIG_ACPI static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { @@ -345,6 +300,51 @@ static void xhci_pci_remove(struct pci_dev *dev) } #ifdef CONFIG_PM +/* + * In some Intel xHCI controllers, in order to get D3 working, + * through a vendor specific SSIC CONFIG register at offset 0x883c, + * SSIC PORT need to be marked as "unused" before putting xHCI + * into D3. After D3 exit, the SSIC port need to be marked as "used". + * Without this change, xHCI might not enter D3 state. + * Make sure PME works on some Intel xHCI controllers by writing 1 to clear + * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 + */ +static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + u32 val; + void __iomem *reg; + + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { + + reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2; + + /* Notify SSIC that SSIC profile programming is not done */ + val = readl(reg) & ~PROG_DONE; + writel(val, reg); + + /* Mark SSIC port as unused(suspend) or used(resume) */ + val = readl(reg); + if (suspend) + val |= SSIC_PORT_UNUSED; + else + val &= ~SSIC_PORT_UNUSED; + writel(val, reg); + + /* Notify SSIC that SSIC profile programming is done */ + val = readl(reg) | PROG_DONE; + writel(val, reg); + readl(reg); + } + + reg = (void __iomem *) xhci->cap_regs + 0x80a4; + val = readl(reg); + writel(val | BIT(28), reg); + readl(reg); +} + static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a47a1e897086..43291f93afeb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -302,6 +302,15 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->cmd_ring, CMD_RING_RUNNING, 0, 5 * 1000 * 1000); if (ret < 0) { + /* we are about to kill xhci, give it one more chance */ + xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, + &xhci->op_regs->cmd_ring); + udelay(1000); + ret = xhci_handshake(&xhci->op_regs->cmd_ring, + CMD_RING_RUNNING, 0, 3 * 1000 * 1000); + if (ret == 0) + return 0; + xhci_err(xhci, "Stopped the command ring failed, " "maybe the host is dead\n"); xhci->xhc_state |= XHCI_STATE_DYING; @@ -3461,8 +3470,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (start_cycle == 0) field |= 0x1; - /* xHCI 1.0 6.4.1.2.1: Transfer Type field */ - if (xhci->hci_version == 0x100) { + /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */ + if (xhci->hci_version >= 0x100) { if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) field |= TRB_TX_TYPE(TRB_DATA_IN); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6b0f4a47e402..9957bd96d4bc 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -146,7 +146,8 @@ static int xhci_start(struct xhci_hcd *xhci) "waited %u microseconds.\n", XHCI_MAX_HALT_USEC); if (!ret) - xhci->xhc_state &= ~XHCI_STATE_HALTED; + xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING); + return ret; } @@ -654,15 +655,6 @@ int xhci_run(struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(xhci_run); -static void xhci_only_stop_hcd(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - spin_lock_irq(&xhci->lock); - xhci_halt(xhci); - spin_unlock_irq(&xhci->lock); |