From e3d9558082061481af96b588583e0cf220c2943c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 5 Jun 2014 14:23:04 -0700 Subject: usb: fix ->update_hub_device() vs hdev->maxchild Commit d8521afe3586 "usb: assign default peer ports for root hubs" delayed marking a hub valid (set hdev->maxchild) until it had been fully configured and to enable the publishing of valid hubs to be serialized by usb_port_peer_mutex. However, xhci_update_hub_device() in some cases depends on hdev->maxchild already being set. Do the minimal fix and move it after the setting of hdev->maxchild. Cc: Mathias Nyman Reported-by: Valdis Kletnieks Tested-by: Valdis Kletnieks Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 879b66e13370..ec6f05cbbae3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1526,18 +1526,6 @@ static int hub_configure(struct usb_hub *hub, dev_dbg(hub_dev, "%umA bus power budget for each child\n", hub->mA_per_port); - /* Update the HCD's internal representation of this hub before khubd - * starts getting port status changes for devices under the hub. - */ - if (hcd->driver->update_hub_device) { - ret = hcd->driver->update_hub_device(hcd, hdev, - &hub->tt, GFP_KERNEL); - if (ret < 0) { - message = "can't update HCD hub info"; - goto fail; - } - } - ret = hub_hub_status(hub, &hubstatus, &hubchange); if (ret < 0) { message = "can't get hub status"; @@ -1593,6 +1581,18 @@ static int hub_configure(struct usb_hub *hub, if (ret < 0) goto fail; + /* Update the HCD's internal representation of this hub before khubd + * starts getting port status changes for devices under the hub. + */ + if (hcd->driver->update_hub_device) { + ret = hcd->driver->update_hub_device(hcd, hdev, + &hub->tt, GFP_KERNEL); + if (ret < 0) { + message = "can't update HCD hub info"; + goto fail; + } + } + usb_hub_adjust_deviceremovable(hdev, hub->descriptor); hub_activate(hub, HUB_INIT); -- cgit v1.2.3 From be3de32107091c266b00a48265fe7e06233af4f0 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 10 Jun 2014 11:27:41 +0300 Subject: xhci: Fix sleeping with IRQs disabled in xhci_stop_device() xhci_stop_device() allocates and issues stop commands for each active endpoint. This is done with spinlock held and interrupt disabled so we can't sleep during memory allocation. Use GFP_NOWAIT instead Regression from commit ddba5cd0aeff5bbed92ebdf4b1223300b0541e78 "xhci: Use command structures when queuing commands on the command ring" for 3.16-rc1 Fixes: ddba5cd0aeff ("xhci: Use command structures when queuing commands") Reported-by: Dan Williams Reported-by: Johannes Berg Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 6231ce6aa0c3..2b998c60faf2 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -287,7 +287,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) { struct xhci_command *command; command = xhci_alloc_command(xhci, false, false, - GFP_NOIO); + GFP_NOWAIT); if (!command) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_free_command(xhci, cmd); -- cgit v1.2.3 From b658b8f5c09d3d1db9641c9d520b36b3e4c0d744 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 17 Jun 2014 16:16:22 -0700 Subject: usb: improve "not suspended yet" message in hub_suspend() Reading through a recent bug report [1], Alan notes: "Dan, the warning message in hub_suspend() should mention that the child device isn't suspended yet." ...update the warning from: "usb usb3-port4: not suspended yet" ...to: "usb usb3-port4: device 3-4: not suspended yet" [1]: http://marc.info/?l=linux-usb&m=140290586301336&w=2 Reported-by: Alan Stern Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ec6f05cbbae3..78c3cd20d7ae 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3458,7 +3458,8 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev = port_dev->child; if (udev && udev->can_submit) { - dev_warn(&port_dev->dev, "not suspended yet\n"); + dev_warn(&port_dev->dev, "device %s not suspended yet\n", + dev_name(&udev->dev)); if (PMSG_IS_AUTO(msg)) return -EBUSY; } -- cgit v1.2.3 From 6c79fe4afcb0450bd638f6e959e512aad270ff2f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 17 Jun 2014 16:16:27 -0700 Subject: usb: quiet peer failure warning, disable poweroff In the case where platform firmware has specified conflicting values for port locations it is confusing and otherwise not helpful to throw a backtrace. Instead, include enough information to determine that firmware has done something wrong and globally disable port poweroff. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 62036faf56c0..9347ade7d5fe 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -21,6 +21,8 @@ #include "hub.h" +static int usb_port_block_power_off; + static const struct attribute_group *port_dev_group[]; static ssize_t connect_type_show(struct device *dev, @@ -142,6 +144,9 @@ static int usb_port_runtime_suspend(struct device *dev) == PM_QOS_FLAGS_ALL) return -EAGAIN; + if (usb_port_block_power_off) + return -EBUSY; + usb_autopm_get_interface(intf); retval = usb_hub_set_port_power(hdev, hub, port1, false); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); @@ -190,11 +195,19 @@ static int link_peers(struct usb_port *left, struct usb_port *right) if (left->peer || right->peer) { struct usb_port *lpeer = left->peer; struct usb_port *rpeer = right->peer; - - WARN(1, "failed to peer %s and %s (%s -> %p) (%s -> %p)\n", - dev_name(&left->dev), dev_name(&right->dev), - dev_name(&left->dev), lpeer, - dev_name(&right->dev), rpeer); + char *method; + + if (left->location && left->location == right->location) + method = "location"; + else + method = "default"; + + pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", + dev_name(&left->dev), dev_name(&right->dev), method, + dev_name(&left->dev), + lpeer ? dev_name(&lpeer->dev) : "none", + dev_name(&right->dev), + rpeer ? dev_name(&rpeer->dev) : "none"); return -EBUSY; } @@ -251,6 +264,7 @@ static void link_peers_report(struct usb_port *left, struct usb_port *right) dev_warn(&left->dev, "failed to peer to %s (%d)\n", dev_name(&right->dev), rc); pr_warn_once("usb: port power management may be unreliable\n"); + usb_port_block_power_off = 1; } } -- cgit v1.2.3 From e3d105055525d9ea9f8e9cb0db8237df3df1bb9f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 17 Jun 2014 16:16:32 -0700 Subject: usb: fix hub-port pm_runtime_enable() vs runtime pm transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 9262c19d14c4 "usb: disable port power control if not supported in wHubCharacteristics" gated enabling runtime pm for usb_port devices on whether the parent hub supports power control, which causes a regression. The port must still be allowed to carry out runtime pm callbacks and receive a -EAGAIN or -EBUSY result. Otherwise the usb_port device will transition to the pm error state and trigger the same for the child usb_device. Prior to the offending commit usb_hub_create_port_device() arranged for runtime pm to be disabled is dev_pm_qos_expose_flags() failed. Instead, force the default state of PM_QOS_FLAG_NO_POWER_OFF flag to be set prior to enabling runtime pm. If that policy can not be set then fail registration. Report: http://marc.info/?l=linux-usb&m=140290586301336&w=2 Fixes: 9262c19d14c4 ("usb: disable port power control if not supported in wHubCharacteristics") Reported-by: Bjørn Mork Reported-by: Alan Stern Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 6 +++++ drivers/usb/core/hub.h | 2 ++ drivers/usb/core/port.c | 65 ++++++++++++++++++++++++++++++++++--------------- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 78c3cd20d7ae..21b99b4b4082 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1577,6 +1577,12 @@ static int hub_configure(struct usb_hub *hub, } } hdev->maxchild = i; + for (i = 0; i < hdev->maxchild; i++) { + struct usb_port *port_dev = hub->ports[i]; + + pm_runtime_put(&port_dev->dev); + } + mutex_unlock(&usb_port_peer_mutex); if (ret < 0) goto fail; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 0a7cdc0ef0a9..326308e53961 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -84,6 +84,7 @@ struct usb_hub { * @dev: generic device interface * @port_owner: port's owner * @peer: related usb2 and usb3 ports (share the same connector) + * @req: default pm qos request for hubs without port power control * @connect_type: port's connect type * @location: opaque representation of platform connector location * @status_lock: synchronize port_event() vs usb_port_{suspend|resume} @@ -95,6 +96,7 @@ struct usb_port { struct device dev; struct usb_dev_state *port_owner; struct usb_port *peer; + struct dev_pm_qos_request *req; enum usb_port_connect_type connect_type; usb_port_location_t location; struct mutex status_lock; diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 9347ade7d5fe..fe1b6d0967e3 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -68,6 +68,7 @@ static void usb_port_device_release(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); + kfree(port_dev->req); kfree(port_dev); } @@ -400,9 +401,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) int retval; port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); - if (!port_dev) { - retval = -ENOMEM; - goto exit; + if (!port_dev) + return -ENOMEM; + + port_dev->req = kzalloc(sizeof(*(port_dev->req)), GFP_KERNEL); + if (!port_dev->req) { + kfree(port_dev); + return -ENOMEM; } hub->ports[port1 - 1] = port_dev; @@ -418,31 +423,53 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) port1); mutex_init(&port_dev->status_lock); retval = device_register(&port_dev->dev); - if (retval) - goto error_register; + if (retval) { + put_device(&port_dev->dev); + return retval; + } + + /* Set default policy of port-poweroff disabled. */ + retval = dev_pm_qos_add_request(&port_dev->dev, port_dev->req, + DEV_PM_QOS_FLAGS, PM_QOS_FLAG_NO_POWER_OFF); + if (retval < 0) { + device_unregister(&port_dev->dev); + return retval; + } find_and_link_peer(hub, port1); + /* + * Enable runtime pm and hold a refernce that hub_configure() + * will drop once the PM_QOS_NO_POWER_OFF flag state has been set + * and the hub has been fully registered (hdev->maxchild set). + */ pm_runtime_set_active(&port_dev->dev); + pm_runtime_get_noresume(&port_dev->dev); + pm_runtime_enable(&port_dev->dev); + device_enable_async_suspend(&port_dev->dev); /* - * Do not enable port runtime pm if the hub does not support - * power switching. Also, userspace must have final say of - * whether a port is permitted to power-off. Do not enable - * runtime pm if we fail to expose pm_qos_no_power_off. + * Keep hidden the ability to enable port-poweroff if the hub + * does not support power switching. */ - if (hub_is_port_power_switchable(hub) - && dev_pm_qos_expose_flags(&port_dev->dev, - PM_QOS_FLAG_NO_POWER_OFF) == 0) - pm_runtime_enable(&port_dev->dev); + if (!hub_is_port_power_switchable(hub)) + return 0; - device_enable_async_suspend(&port_dev->dev); - return 0; + /* Attempt to let userspace take over the policy. */ + retval = dev_pm_qos_expose_flags(&port_dev->dev, + PM_QOS_FLAG_NO_POWER_OFF); + if (retval < 0) { + dev_warn(&port_dev->dev, "failed to expose pm_qos_no_poweroff\n"); + return 0; + } -error_register: - put_device(&port_dev->dev); -exit: - return retval; + /* Userspace owns the policy, drop the kernel 'no_poweroff' request. */ + retval = dev_pm_qos_remove_request(port_dev->req); + if (retval >= 0) { + kfree(port_dev->req); + port_dev->req = NULL; + } + return 0; } void usb_hub_remove_port_device(struct usb_hub *hub, int port1) -- cgit v1.2.3 From b0a50e92bda3c4aeb8017d4e6c6e92146ebd5c9b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 Jun 2014 11:00:27 -0400 Subject: USB: EHCI: avoid BIOS handover on the HASEE E200 Leandro Liptak reports that his HASEE E200 computer hangs when we ask the BIOS to hand over control of the EHCI host controller. This definitely sounds like a bug in the BIOS, but at the moment there is no way to fix it. This patch works around the problem by avoiding the handoff whenever the motherboard and BIOS version match those of Leandro's computer. Signed-off-by: Alan Stern Reported-by: Leandro Liptak Tested-by: Leandro Liptak CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 4a6d3dd68572..2f3acebb577a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -656,6 +656,14 @@ static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), }, }, + { + /* HASEE E200 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "HASEE"), + DMI_MATCH(DMI_BOARD_NAME, "E210"), + DMI_MATCH(DMI_BIOS_VERSION, "6.00"), + }, + }, { } }; @@ -665,9 +673,14 @@ static void ehci_bios_handoff(struct pci_dev *pdev, { int try_handoff = 1, tried_handoff = 0; - /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying - * the handoff on its unused controller. Skip it. */ - if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { + /* + * The Pegatron Lucid tablet sporadically waits for 98 seconds trying + * the handoff on its unused controller. Skip it. + * + * The HASEE E200 hangs when the semaphore is set (bugzilla #77021). + */ + if (pdev->vendor == 0x8086 && (pdev->device == 0x283a || + pdev->device == 0x27cc)) { if (dmi_check_system(ehci_dmi_nohandoff_table)) try_handoff = 0; } -- cgit v1.2.3 From 32b36eeae6a859670d2939a7d6136cb5e9ed64f8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 Jun 2014 11:11:34 -0400 Subject: USB: usbtest: add a timeout for scatter-gather tests In usbtest, tests 5 - 8 use the scatter-gather library in usbcore without any sort of timeout. If there's a problem in the gadget or host controller being tested, the test can hang. This patch adds a 10-second timeout to the tests, so that they will fail gracefully with an ETIMEDOUT error instead of hanging. Signed-off-by: Alan Stern Reported-by: Huang Rui Tested-by: Huang Rui CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbtest.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 51a6da256772..829f446064ea 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -7,7 +7,7 @@ #include #include #include - +#include #include #define SIMPLE_IO_TIMEOUT 10000 /* in milliseconds */ @@ -484,6 +484,14 @@ alloc_sglist(int nents, int max, int vary) return sg; } +static void sg_timeout(unsigned long _req) +{ + struct usb_sg_request *req = (struct usb_sg_request *) _req; + + req->status = -ETIMEDOUT; + usb_sg_cancel(req); +} + static int perform_sglist( struct usbtest_dev *tdev, unsigned iterations, @@ -495,6 +503,9 @@ static int perform_sglist( { struct usb_device *udev = testdev_to_usbdev(tdev); int retval = 0; + struct timer_list sg_timer; + + setup_timer_on_stack(&sg_timer, sg_timeout, (unsigned long) req); while (retval == 0 && iterations-- > 0) { retval = usb_sg_init(req, udev, pipe, @@ -505,7 +516,10 @@ static int perform_sglist( if (retval) break; + mod_timer(&sg_timer, jiffies + + msecs_to_jiffies(SIMPLE_IO_TIMEOUT)); usb_sg_wait(req); + del_timer_sync(&sg_timer); retval = req->status; /* FIXME check resulting data pattern */ -- cgit v1.2.3