aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2014-05-20 21:09:15 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-27 19:51:50 -0400
commitaf376a461cf075de6358255579c8d42bb1246e18 (patch)
treeb1f6e07252726796e18689c44ac11cd6096fc4c0 /drivers/usb/core/hub.c
parent6908058469e3253637894d1cb3e2581870c77e1d (diff)
usb: refactor port handling in hub_events()
In preparation for synchronizing port handling with pm_runtime transitions refactor port handling into its own subroutine. We expect that clearing some status flags will be required regardless of the port state, so handle those first and group all non-trivial actions at the bottom of the routine. This also splits off the bottom half of hub_port_connect_change() into hub_port_reconnect() in prepartion for introducing a port->status_lock. hub_port_reconnect() will expect the port lock to not be held while hub_port_connect_change() expects to enter with it held. Other cleanups include: 1/ reflowing to 80 columns 2/ replacing redundant usages of 'hub->hdev' with 'hdev' 3/ consolidate clearing of ->change_bits() in hub_port_connect_change 4/ consolidate calls to usb_reset_device Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c374
1 files changed, 185 insertions, 189 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index e492bca74425..782ce2e31c7f 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4413,66 +4413,15 @@ hub_power_remaining (struct usb_hub *hub)
4413 return remaining; 4413 return remaining;
4414} 4414}
4415 4415
4416/* Handle physical or logical connection change events. 4416static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
4417 * This routine is called when: 4417 u16 portchange)
4418 * a port connection-change occurs;
4419 * a port enable-change occurs (often caused by EMI);
4420 * usb_reset_and_verify_device() encounters changed descriptors (as from
4421 * a firmware download)
4422 * caller already locked the hub
4423 */
4424static void hub_port_connect_change(struct usb_hub *hub, int port1,
4425 u16 portstatus, u16 portchange)
4426{ 4418{
4419 int status, i;
4420 unsigned unit_load;
4427 struct usb_device *hdev = hub->hdev; 4421 struct usb_device *hdev = hub->hdev;
4428 struct usb_hcd *hcd = bus_to_hcd(hdev->bus); 4422 struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
4429 struct usb_port *port_dev = hub->ports[port1 - 1]; 4423 struct usb_port *port_dev = hub->ports[port1 - 1];
4430 struct usb_device *udev; 4424 struct usb_device *udev = port_dev->child;
4431 int status, i;
4432 unsigned unit_load;
4433
4434 dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n",
4435 portstatus, portchange, portspeed(hub, portstatus));
4436
4437 if (hub->has_indicators) {
4438 set_port_led(hub, port1, HUB_LED_AUTO);
4439 hub->indicator[port1-1] = INDICATOR_AUTO;
4440 }
4441
4442#ifdef CONFIG_USB_OTG
4443 /* during HNP, don't repeat the debounce */
4444 if (hdev->bus->is_b_host)
4445 portchange &= ~(USB_PORT_STAT_C_CONNECTION |
4446 USB_PORT_STAT_C_ENABLE);
4447#endif
4448
4449 /* Try to resuscitate an existing device */
4450 udev = port_dev->child;
4451 if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
4452 udev->state != USB_STATE_NOTATTACHED) {
4453 usb_lock_device(udev);
4454 if (portstatus & USB_PORT_STAT_ENABLE) {
4455 status = 0; /* Nothing to do */
4456
4457#ifdef CONFIG_PM_RUNTIME
4458 } else if (udev->state == USB_STATE_SUSPENDED &&
4459 udev->persist_enabled) {
4460 /* For a suspended device, treat this as a
4461 * remote wakeup event.
4462 */
4463 status = usb_remote_wakeup(udev);
4464#endif
4465
4466 } else {
4467 status = -ENODEV; /* Don't resuscitate */
4468 }
4469 usb_unlock_device(udev);
4470
4471 if (status == 0) {
4472 clear_bit(port1, hub->change_bits);
4473 return;
4474 }
4475 }
4476 4425
4477 /* Disconnect any existing devices under this port */ 4426 /* Disconnect any existing devices under this port */
4478 if (udev) { 4427 if (udev) {
@@ -4481,7 +4430,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
4481 usb_phy_notify_disconnect(hcd->phy, udev->speed); 4430 usb_phy_notify_disconnect(hcd->phy, udev->speed);
4482 usb_disconnect(&port_dev->child); 4431 usb_disconnect(&port_dev->child);
4483 } 4432 }
4484 clear_bit(port1, hub->change_bits);
4485 4433
4486 /* We can forget about a "removed" device when there's a physical 4434 /* We can forget about a "removed" device when there's a physical
4487 * disconnect or the connect status changes. 4435 * disconnect or the connect status changes.
@@ -4663,6 +4611,65 @@ done:
4663 hub_port_disable(hub, port1, 1); 4611 hub_port_disable(hub, port1, 1);
4664 if (hcd->driver->relinquish_port && !hub->hdev->parent) 4612 if (hcd->driver->relinquish_port && !hub->hdev->parent)
4665 hcd->driver->relinquish_port(hcd, port1); 4613 hcd->driver->relinquish_port(hcd, port1);
4614
4615}
4616
4617/* Handle physical or logical connection change events.
4618 * This routine is called when:
4619 * a port connection-change occurs;
4620 * a port enable-change occurs (often caused by EMI);
4621 * usb_reset_and_verify_device() encounters changed descriptors (as from
4622 * a firmware download)
4623 * caller already locked the hub
4624 */
4625static void hub_port_connect_change(struct usb_hub *hub, int port1,
4626 u16 portstatus, u16 portchange)
4627{
4628 struct usb_port *port_dev = hub->ports[port1 - 1];
4629 struct usb_device *udev = port_dev->child;
4630 int status = -ENODEV;
4631
4632 dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
4633 portchange, portspeed(hub, portstatus));
4634
4635 if (hub->has_indicators) {
4636 set_port_led(hub, port1, HUB_LED_AUTO);
4637 hub->indicator[port1-1] = INDICATOR_AUTO;
4638 }
4639
4640#ifdef CONFIG_USB_OTG
4641 /* during HNP, don't repeat the debounce */
4642 if (hub->hdev->bus->is_b_host)
4643 portchange &= ~(USB_PORT_STAT_C_CONNECTION |
4644 USB_PORT_STAT_C_ENABLE);
4645#endif
4646
4647 /* Try to resuscitate an existing device */
4648 if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
4649 udev->state != USB_STATE_NOTATTACHED) {
4650 if (portstatus & USB_PORT_STAT_ENABLE) {
4651 status = 0; /* Nothing to do */
4652#ifdef CONFIG_PM_RUNTIME
4653 } else if (udev->state == USB_STATE_SUSPENDED &&
4654 udev->persist_enabled) {
4655 /* For a suspended device, treat this as a
4656 * remote wakeup event.
4657 */
4658 usb_lock_device(udev);
4659 status = usb_remote_wakeup(udev);
4660 usb_unlock_device(udev);
4661#endif
4662 } else {
4663 /* Don't resuscitate */;
4664 }
4665
4666 }
4667 clear_bit(port1, hub->change_bits);
4668
4669 if (status == 0)
4670 return;
4671
4672 hub_port_connect(hub, port1, portstatus, portchange);
4666} 4673}
4667 4674
4668/* Returns 1 if there was a remote wakeup and a connect status change. */ 4675/* Returns 1 if there was a remote wakeup and a connect status change. */
@@ -4705,6 +4712,121 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
4705 return connect_change; 4712 return connect_change;
4706} 4713}
4707 4714
4715static void port_event(struct usb_hub *hub, int port1)
4716{
4717 int connect_change, reset_device = 0;
4718 struct usb_port *port_dev = hub->ports[port1 - 1];
4719 struct usb_device *udev = port_dev->child;
4720 struct usb_device *hdev = hub->hdev;
4721 u16 portstatus, portchange;
4722
4723 connect_change = test_bit(port1, hub->change_bits);
4724 clear_bit(port1, hub->event_bits);
4725 clear_bit(port1, hub->wakeup_bits);
4726
4727 if (hub_port_status(hub, port1, &portstatus, &portchange) < 0)
4728 return;
4729
4730 if (portchange & USB_PORT_STAT_C_CONNECTION) {
4731 usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
4732 connect_change = 1;
4733 }
4734
4735 if (portchange & USB_PORT_STAT_C_ENABLE) {
4736 if (!connect_change)
4737 dev_dbg(&port_dev->dev, "enable change, status %08x\n",
4738 portstatus);
4739 usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
4740
4741 /*
4742 * EM interference sometimes causes badly shielded USB devices
4743 * to be shutdown by the hub, this hack enables them again.
4744 * Works at least with mouse driver.
4745 */
4746 if (!(portstatus & USB_PORT_STAT_ENABLE)
4747 && !connect_change && udev) {
4748 dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n");
4749 connect_change = 1;
4750 }
4751 }
4752
4753 if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
4754 u16 status = 0, unused;
4755
4756 dev_dbg(&port_dev->dev, "over-current change\n");
4757 usb_clear_port_feature(hdev, port1,
4758 USB_PORT_FEAT_C_OVER_CURRENT);
4759 msleep(100); /* Cool down */
4760 hub_power_on(hub, true);
4761 hub_port_status(hub, port1, &status, &unused);
4762 if (status & USB_PORT_STAT_OVERCURRENT)
4763 dev_err(&port_dev->dev, "over-current condition\n");
4764 }
4765
4766 if (portchange & USB_PORT_STAT_C_RESET) {
4767 dev_dbg(&port_dev->dev, "reset change\n");
4768 usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET);
4769 }
4770 if ((portchange & USB_PORT_STAT_C_BH_RESET)
4771 && hub_is_superspeed(hdev)) {
4772 dev_dbg(&port_dev->dev, "warm reset change\n");
4773 usb_clear_port_feature(hdev, port1,
4774 USB_PORT_FEAT_C_BH_PORT_RESET);
4775 }
4776 if (portchange & USB_PORT_STAT_C_LINK_STATE) {
4777 dev_dbg(&port_dev->dev, "link state change\n");
4778 usb_clear_port_feature(hdev, port1,
4779 USB_PORT_FEAT_C_PORT_LINK_STATE);
4780 }
4781 if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
4782 dev_warn(&port_dev->dev, "config error\n");
4783 usb_clear_port_feature(hdev, port1,
4784 USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
4785 }
4786
4787 if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))
4788 connect_change = 1;
4789
4790 /*
4791 * Warm reset a USB3 protocol port if it's in
4792 * SS.Inactive state.
4793 */
4794 if (hub_port_warm_reset_required(hub, portstatus)) {
4795 dev_dbg(&port_dev->dev, "do warm reset\n");
4796 if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
4797 || udev->state == USB_STATE_NOTATTACHED) {
4798 if (hub_port_reset(hub, port1, NULL,
4799 HUB_BH_RESET_TIME, true) < 0)
4800 hub_port_disable(hub, port1, 1);
4801 } else
4802 reset_device = 1;
4803 }
4804
4805 /*
4806 * On disconnect USB3 protocol ports transit from U0 to
4807 * SS.Inactive to Rx.Detect. If this happens a warm-
4808 * reset is not needed, but a (re)connect may happen
4809 * before khubd runs and sees the disconnect, and the
4810 * device may be an unknown state.
4811 *
4812 * If the port went through SS.Inactive without khubd
4813 * seeing it the C_LINK_STATE change flag will be set,
4814 * and we reset the dev to put it in a known state.
4815 */
4816 if (reset_device || (udev && hub_is_superspeed(hub->hdev)
4817 && (portchange & USB_PORT_STAT_C_LINK_STATE)
4818 && (portstatus & USB_PORT_STAT_CONNECTION))) {
4819 usb_lock_device(udev);
4820 usb_reset_device(udev);
4821 usb_unlock_device(udev);
4822 connect_change = 0;
4823 }
4824
4825 if (connect_change)
4826 hub_port_connect_change(hub, port1, portstatus, portchange);
4827}
4828
4829
4708static void hub_events(void) 4830static void hub_events(void)
4709{ 4831{
4710 struct list_head *tmp; 4832 struct list_head *tmp;
@@ -4714,10 +4836,7 @@ static void hub_events(void)
4714 struct device *hub_dev; 4836 struct device *hub_dev;
4715 u16 hubstatus; 4837 u16 hubstatus;
4716 u16 hubchange; 4838 u16 hubchange;
4717 u16 portstatus;
4718 u16 portchange;
4719 int i, ret; 4839 int i, ret;
4720 int connect_change, wakeup_change;
4721 4840
4722 /* 4841 /*
4723 * We restart the list every time to avoid a deadlock with 4842 * We restart the list every time to avoid a deadlock with
@@ -4791,135 +4910,12 @@ static void hub_events(void)
4791 4910
4792 /* deal with port status changes */ 4911 /* deal with port status changes */
4793 for (i = 1; i <= hdev->maxchild; i++) { 4912 for (i = 1; i <= hdev->maxchild; i++) {
4794 struct usb_port *port_dev = hub->ports[i - 1]; 4913 if (!test_bit(i, hub->busy_bits)
4795 struct usb_device *udev = port_dev->child; 4914 && (test_bit(i, hub->event_bits)
4796 4915 || test_bit(i, hub->change_bits)
4797 if (test_bit(i, hub->busy_bits)) 4916 || test_bit(i, hub->wakeup_bits)))
4798 continue; 4917 port_event(hub, i);
4799 connect_change = test_bit(i, hub->change_bits); 4918 }
4800 wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
4801 if (!test_and_clear_bit(i, hub->event_bits) &&
4802 !connect_change && !wakeup_change)
4803 continue;
4804
4805 ret = hub_port_status(hub, i,
4806 &portstatus, &portchange);
4807 if (ret < 0)
4808 continue;
4809
4810 if (portchange & USB_PORT_STAT_C_CONNECTION) {
4811 usb_clear_port_feature(hdev, i,
4812 USB_PORT_FEAT_C_CONNECTION);
4813 connect_change = 1;
4814 }
4815
4816 if (portchange & USB_PORT_STAT_C_ENABLE) {
4817 if (!connect_change)
4818 dev_dbg(&port_dev->dev,
4819 "enable change, status %08x\n",
4820 portstatus);
4821 usb_clear_port_feature(hdev, i,
4822 USB_PORT_FEAT_C_ENABLE);
4823
4824 /*
4825 * EM interference sometimes causes badly
4826 * shielded USB devices to be shutdown by
4827 * the hub, this hack enables them again.
4828 * Works at least with mouse driver.
4829 */
4830 if (!(portstatus & USB_PORT_STAT_ENABLE)
4831 && !connect_change && udev) {
4832 dev_err(&port_dev->dev,
4833 "disabled by hub (EMI?), re-enabling...\n");
4834 connect_change = 1;
4835 }
4836 }
4837
4838 if (hub_handle_remote_wakeup(hub, i,
4839 portstatus, portchange))
4840 connect_change = 1;
4841
4842 if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
4843 u16 status = 0;
4844 u16 unused;
4845
4846 dev_dbg(&port_dev->dev, "over-current change\n");
4847 usb_clear_port_feature(hdev, i,
4848 USB_PORT_FEAT_C_OVER_CURRENT);
4849 msleep(100); /* Cool down */
4850 hub_power_on(hub, true);
4851 hub_port_status(hub, i, &status, &unused);
4852 if (status & USB_PORT_STAT_OVERCURRENT)
4853 dev_err(&port_dev->dev,
4854 "over-current condition\n");
4855 }
4856
4857 if (portchange & USB_PORT_STAT_C_RESET) {
4858 dev_dbg(&port_dev->dev, "reset change\n");
4859 usb_clear_port_feature(hdev, i,
4860 USB_PORT_FEAT_C_RESET);
4861 }
4862 if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
4863 hub_is_superspeed(hub->hdev)) {
4864 dev_dbg(&port_dev->dev, "warm reset change\n");
4865 usb_clear_port_feature(hdev, i,
4866 USB_PORT_FEAT_C_BH_PORT_RESET);
4867 }
4868 if (portchange & USB_PORT_STAT_C_LINK_STATE) {
4869 usb_clear_port_feature(hub->hdev, i,
4870 USB_PORT_FEAT_C_PORT_LINK_STATE);
4871 }
4872 if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
4873 dev_warn(&port_dev->dev, "config error\n");
4874 usb_clear_port_feature(hub->hdev, i,
4875 USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
4876 }
4877
4878 /* Warm reset a USB3 protocol port if it's in
4879 * SS.Inactive state.
4880 */
4881 if (hub_port_warm_reset_required(hub, portstatus)) {
4882 int status;
4883
4884 dev_dbg(&port_dev->dev, "warm reset\n");
4885 if (!udev ||
4886 !(portstatus & USB_PORT_STAT_CONNECTION) ||
4887 udev->state == USB_STATE_NOTATTACHED) {
4888 status = hub_port_reset(hub, i,
4889 NULL, HUB_BH_RESET_TIME,
4890 true);
4891 if (status < 0)
4892 hub_port_disable(hub, i, 1);
4893 } else {
4894 usb_lock_device(udev);
4895 status = usb_reset_device(udev);
4896 usb_unlock_device(udev);
4897 connect_change = 0;
4898 }
4899 /*
4900 * On disconnect USB3 protocol ports transit from U0 to
4901 * SS.Inactive to Rx.Detect. If this happens a warm-
4902 * reset is not needed, but a (re)connect may happen
4903 * before khubd runs and sees the disconnect, and the
4904 * device may be an unknown state.
4905 *
4906 * If the port went through SS.Inactive without khubd
4907 * seeing it the C_LINK_STATE change flag will be set,
4908 * and we reset the dev to put it in a known state.
4909 */
4910 } else if (udev && hub_is_superspeed(hub->hdev) &&
4911 (portchange & USB_PORT_STAT_C_LINK_STATE) &&
4912 (portstatus & USB_PORT_STAT_CONNECTION)) {
4913 usb_lock_device(udev);
4914 usb_reset_device(udev);
4915 usb_unlock_device(udev);
4916 connect_change = 0;
4917 }
4918
4919 if (connect_change)
4920 hub_port_connect_change(hub, i,
4921 portstatus, portchange);
4922 } /* end for i */
4923 4919
4924 /* deal with hub status changes */ 4920 /* deal with hub status changes */
4925 if (test_and_clear_bit(0, hub->event_bits) == 0) 4921 if (test_and_clear_bit(0, hub->event_bits) == 0)