diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
| -rw-r--r-- | drivers/usb/core/hub.c | 1369 | 
1 files changed, 789 insertions, 580 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dde4c83516a..0e950ad8cb2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -33,21 +33,9 @@  #include "hub.h" -/* if we are in debug mode, always announce new devices */ -#ifdef DEBUG -#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES -#define CONFIG_USB_ANNOUNCE_NEW_DEVICES -#endif -#endif -  #define USB_VENDOR_GENESYS_LOGIC		0x05e3  #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND	0x01 -static inline int hub_is_superspeed(struct usb_device *hdev) -{ -	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); -} -  /* Protect struct usb_device->state and ->children members   * Note: Both are also protected by ->dev.sem, except that ->state can   * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -62,6 +50,9 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);  static struct task_struct *khubd_task; +/* synchronize hub-port add/remove and peering operations */ +DEFINE_MUTEX(usb_port_peer_mutex); +  /* cycle leds on hubs that aren't blinking for attention */  static bool blinkenlights = 0;  module_param (blinkenlights, bool, S_IRUGO); @@ -120,7 +111,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus)  	if (hub_is_superspeed(hub->hdev))  		return "5.0 Gb/s";  	if (portstatus & USB_PORT_STAT_HIGH_SPEED) -    		return "480 Mb/s"; +		return "480 Mb/s";  	else if (portstatus & USB_PORT_STAT_LOW_SPEED)  		return "1.5 Mb/s";  	else @@ -148,19 +139,27 @@ static int usb_device_supports_lpm(struct usb_device *udev)  		return 0;  	} -	/* All USB 3.0 must support LPM, but we need their max exit latency -	 * information from the SuperSpeed Extended Capabilities BOS descriptor. +	/* +	 * According to the USB 3.0 spec, all USB 3.0 devices must support LPM. +	 * However, there are some that don't, and they set the U1/U2 exit +	 * latencies to zero.  	 */  	if (!udev->bos->ss_cap) { -		dev_warn(&udev->dev, "No LPM exit latency info found.  " -				"Power management will be impacted.\n"); +		dev_info(&udev->dev, "No LPM exit latency info found, disabling LPM.\n");  		return 0;  	} -	if (udev->parent->lpm_capable) -		return 1; -	dev_warn(&udev->dev, "Parent hub missing LPM exit latency info.  " -			"Power management will be impacted.\n"); +	if (udev->bos->ss_cap->bU1devExitLat == 0 && +			udev->bos->ss_cap->bU2DevExitLat == 0) { +		if (udev->parent) +			dev_info(&udev->dev, "LPM exit latency is zeroed, disabling LPM.\n"); +		else +			dev_info(&udev->dev, "We don't know the algorithms for LPM for this host, disabling LPM.\n"); +		return 0; +	} + +	if (!udev->parent || udev->parent->lpm_capable) +		return 1;  	return 0;  } @@ -310,9 +309,9 @@ static void usb_set_lpm_parameters(struct usb_device *udev)  		return;  	udev_u1_del = udev->bos->ss_cap->bU1devExitLat; -	udev_u2_del = udev->bos->ss_cap->bU2DevExitLat; +	udev_u2_del = le16_to_cpu(udev->bos->ss_cap->bU2DevExitLat);  	hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat; -	hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat; +	hub_u2_del = le16_to_cpu(udev->parent->bos->ss_cap->bU2DevExitLat);  	usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,  			hub, &udev->parent->u1_params, hub_u1_del); @@ -411,30 +410,35 @@ static int set_port_feature(struct usb_device *hdev, int port1, int feature)  		NULL, 0, 1000);  } +static char *to_led_name(int selector) +{ +	switch (selector) { +	case HUB_LED_AMBER: +		return "amber"; +	case HUB_LED_GREEN: +		return "green"; +	case HUB_LED_OFF: +		return "off"; +	case HUB_LED_AUTO: +		return "auto"; +	default: +		return "??"; +	} +} +  /*   * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7   * for info about using port indicators   */ -static void set_port_led( -	struct usb_hub *hub, -	int port1, -	int selector -) +static void set_port_led(struct usb_hub *hub, int port1, int selector)  { -	int status = set_port_feature(hub->hdev, (selector << 8) | port1, +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	int status; + +	status = set_port_feature(hub->hdev, (selector << 8) | port1,  			USB_PORT_FEAT_INDICATOR); -	if (status < 0) -		dev_dbg (hub->intfdev, -			"port %d indicator %s status %d\n", -			port1, -			({ char *s; switch (selector) { -			case HUB_LED_AMBER: s = "amber"; break; -			case HUB_LED_GREEN: s = "green"; break; -			case HUB_LED_OFF: s = "off"; break; -			case HUB_LED_AUTO: s = "auto"; break; -			default: s = "??"; break; -			}; s; }), -			status); +	dev_dbg(&port_dev->dev, "indicator %s status %d\n", +		to_led_name(selector), status);  }  #define	LED_CYCLE_PERIOD	((2*HZ)/3) @@ -506,7 +510,8 @@ static void led_work (struct work_struct *work)  		changed++;  	}  	if (changed) -		schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +		queue_delayed_work(system_power_efficient_wq, +				&hub->leds, LED_CYCLE_PERIOD);  }  /* use a short timeout for hub/port status fetches */ @@ -741,16 +746,20 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,  			   int port1, bool set)  {  	int ret; -	struct usb_port *port_dev = hub->ports[port1 - 1];  	if (set)  		ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);  	else  		ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); -	if (!ret) -		port_dev->power_is_on = set; -	return ret; +	if (ret) +		return ret; + +	if (set) +		set_bit(port1, hub->power_bits); +	else +		clear_bit(port1, hub->power_bits); +	return 0;  }  /** @@ -808,16 +817,9 @@ int usb_hub_clear_tt_buffer(struct urb *urb)  }  EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); -/* If do_delay is false, return the number of milliseconds the caller - * needs to delay. - */ -static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) +static void hub_power_on(struct usb_hub *hub, bool do_delay)  {  	int port1; -	unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; -	unsigned delay; -	u16 wHubCharacteristics = -			le16_to_cpu(hub->descriptor->wHubCharacteristics);  	/* Enable power on each port.  Some hubs have reserved values  	 * of LPSM (> 2) in their descriptors, even though they are @@ -825,23 +827,19 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)  	 * but only emulate it.  In all cases, the ports won't work  	 * unless we send these messages to the hub.  	 */ -	if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) +	if (hub_is_port_power_switchable(hub))  		dev_dbg(hub->intfdev, "enabling power on all ports\n");  	else  		dev_dbg(hub->intfdev, "trying to enable port power on "  				"non-switchable hub\n");  	for (port1 = 1; port1 <= hub->hdev->maxchild; port1++) -		if (hub->ports[port1 - 1]->power_is_on) +		if (test_bit(port1, hub->power_bits))  			set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);  		else  			usb_clear_port_feature(hub->hdev, port1,  						USB_PORT_FEAT_POWER); - -	/* Wait at least 100 msec for power to become stable */ -	delay = max(pgood_delay, (unsigned) 100);  	if (do_delay) -		msleep(delay); -	return delay; +		msleep(hub_power_on_good_delay(hub));  }  static int hub_hub_status(struct usb_hub *hub, @@ -857,7 +855,7 @@ static int hub_hub_status(struct usb_hub *hub,  				"%s failed (err = %d)\n", __func__, ret);  	} else {  		*status = le16_to_cpu(hub->status->hub.wHubStatus); -		*change = le16_to_cpu(hub->status->hub.wHubChange);  +		*change = le16_to_cpu(hub->status->hub.wHubChange);  		ret = 0;  	}  	mutex_unlock(&hub->status_mutex); @@ -891,6 +889,25 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)  	if (!hub_is_superspeed(hub->hdev))  		return -EINVAL; +	ret = hub_port_status(hub, port1, &portstatus, &portchange); +	if (ret < 0) +		return ret; + +	/* +	 * USB controller Advanced Micro Devices, Inc. [AMD] FCH USB XHCI +	 * Controller [1022:7814] will have spurious result making the following +	 * usb 3.0 device hotplugging route to the 2.0 root hub and recognized +	 * as high-speed device if we set the usb 3.0 port link state to +	 * Disabled. Since it's already in USB_SS_PORT_LS_RX_DETECT state, we +	 * check the state here to avoid the bug. +	 */ +	if ((portstatus & USB_PORT_STAT_LINK_STATE) == +				USB_SS_PORT_LS_RX_DETECT) { +		dev_dbg(&hub->ports[port1 - 1]->dev, +			 "Not disabling port; link state is RxDetect\n"); +		return ret; +	} +  	ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);  	if (ret)  		return ret; @@ -909,20 +926,20 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)  		msleep(HUB_DEBOUNCE_STEP);  	}  	if (total_time >= HUB_DEBOUNCE_TIMEOUT) -		dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", -				port1, total_time); +		dev_warn(&hub->ports[port1 - 1]->dev, +				"Could not disable after %d ms\n", total_time);  	return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT);  }  static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)  { +	struct usb_port *port_dev = hub->ports[port1 - 1];  	struct usb_device *hdev = hub->hdev;  	int ret = 0; -	if (hub->ports[port1 - 1]->child && set_state) -		usb_set_device_state(hub->ports[port1 - 1]->child, -				USB_STATE_NOTATTACHED); +	if (port_dev->child && set_state) +		usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);  	if (!hub->error) {  		if (hub_is_superspeed(hub->hdev))  			ret = hub_usb3_port_disable(hub, port1); @@ -931,8 +948,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)  					USB_PORT_FEAT_ENABLE);  	}  	if (ret && ret != -ENODEV) -		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", -				port1, ret); +		dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);  	return ret;  } @@ -943,7 +959,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)   */  static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)  { -	dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); +	dev_dbg(&hub->ports[port1 - 1]->dev, "logical disconnect\n");  	hub_port_disable(hub, port1, 1);  	/* FIXME let caller ask to power down the port: @@ -956,7 +972,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)  	 */  	set_bit(port1, hub->change_bits); - 	kick_khubd(hub); +	kick_khubd(hub);  }  /** @@ -1046,9 +1062,12 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  		 * for HUB_POST_RESET, but it's easier not to.  		 */  		if (type == HUB_INIT) { -			delay = hub_power_on(hub, false); -			PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2); -			schedule_delayed_work(&hub->init_work, +			unsigned delay = hub_power_on_good_delay(hub); + +			hub_power_on(hub, false); +			INIT_DELAYED_WORK(&hub->init_work, hub_init_func2); +			queue_delayed_work(system_power_efficient_wq, +					&hub->init_work,  					msecs_to_jiffies(delay));  			/* Suppress autosuspend until init is done */ @@ -1080,21 +1099,23 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  	}   init2: -	/* Check each port and set hub->change_bits to let khubd know +	/* +	 * Check each port and set hub->change_bits to let khubd know  	 * which ports need attention.  	 */  	for (port1 = 1; port1 <= hdev->maxchild; ++port1) { -		struct usb_device *udev = hub->ports[port1 - 1]->child; +		struct usb_port *port_dev = hub->ports[port1 - 1]; +		struct usb_device *udev = port_dev->child;  		u16 portstatus, portchange;  		portstatus = portchange = 0;  		status = hub_port_status(hub, port1, &portstatus, &portchange);  		if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) -			dev_dbg(hub->intfdev, -					"port %d: status %04x change %04x\n", -					port1, portstatus, portchange); +			dev_dbg(&port_dev->dev, "status %04x change %04x\n", +					portstatus, portchange); -		/* After anything other than HUB_RESUME (i.e., initialization +		/* +		 * After anything other than HUB_RESUME (i.e., initialization  		 * or any sort of reset), every port should be disabled.  		 * Unconnected ports should likewise be disabled (paranoia),  		 * and so should ports for which we have no usb_device. @@ -1107,16 +1128,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  			/*  			 * USB3 protocol ports will automatically transition  			 * to Enabled state when detect an USB3.0 device attach. -			 * Do not disable USB3 protocol ports. +			 * Do not disable USB3 protocol ports, just pretend +			 * power was lost  			 */ -			if (!hub_is_superspeed(hdev)) { +			portstatus &= ~USB_PORT_STAT_ENABLE; +			if (!hub_is_superspeed(hdev))  				usb_clear_port_feature(hdev, port1,  						   USB_PORT_FEAT_ENABLE); -				portstatus &= ~USB_PORT_STAT_ENABLE; -			} else { -				/* Pretend that power was lost for USB3 devs */ -				portstatus &= ~USB_PORT_STAT_ENABLE; -			}  		}  		/* Clear status-change flags; we'll debounce later */ @@ -1130,6 +1148,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  			usb_clear_port_feature(hub->hdev, port1,  					USB_PORT_FEAT_C_ENABLE);  		} +		if (portchange & USB_PORT_STAT_C_RESET) { +			need_debounce_delay = true; +			usb_clear_port_feature(hub->hdev, port1, +					USB_PORT_FEAT_C_RESET); +		}  		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&  				hub_is_superspeed(hub->hdev)) {  			need_debounce_delay = true; @@ -1147,7 +1170,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  			/* Tell khubd to disconnect the device or  			 * check for a new connection  			 */ -			if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) +			if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || +			    (portstatus & USB_PORT_STAT_OVERCURRENT))  				set_bit(port1, hub->change_bits);  		} else if (portstatus & USB_PORT_STAT_ENABLE) { @@ -1167,15 +1191,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  				set_bit(port1, hub->change_bits);  		} else if (udev->persist_enabled) { -			struct usb_port *port_dev = hub->ports[port1 - 1]; -  #ifdef CONFIG_PM  			udev->reset_resume = 1;  #endif  			/* Don't set the change_bits when the device  			 * was powered off.  			 */ -			if (port_dev->power_is_on) +			if (test_bit(port1, hub->power_bits))  				set_bit(port1, hub->change_bits);  		} else { @@ -1198,8 +1220,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  		/* Don't do a long sleep inside a workqueue routine */  		if (type == HUB_INIT2) { -			PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3); -			schedule_delayed_work(&hub->init_work, +			INIT_DELAYED_WORK(&hub->init_work, hub_init_func3); +			queue_delayed_work(system_power_efficient_wq, +					&hub->init_work,  					msecs_to_jiffies(delay));  			return;		/* Continues at init3: below */  		} else { @@ -1213,7 +1236,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  	if (status < 0)  		dev_err(hub->intfdev, "activate --> %d\n", status);  	if (hub->has_indicators && blinkenlights) -		schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +		queue_delayed_work(system_power_efficient_wq, +				&hub->leds, LED_CYCLE_PERIOD);  	/* Scan all ports that need attention */  	kick_khubd(hub); @@ -1268,12 +1292,22 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)  		flush_work(&hub->tt.clear_work);  } +static void hub_pm_barrier_for_all_ports(struct usb_hub *hub) +{ +	int i; + +	for (i = 0; i < hub->hdev->maxchild; ++i) +		pm_runtime_barrier(&hub->ports[i]->dev); +} +  /* caller has locked the hub device */  static int hub_pre_reset(struct usb_interface *intf)  {  	struct usb_hub *hub = usb_get_intfdata(intf);  	hub_quiesce(hub, HUB_PRE_RESET); +	hub->in_reset = 1; +	hub_pm_barrier_for_all_ports(hub);  	return 0;  } @@ -1282,6 +1316,8 @@ static int hub_post_reset(struct usb_interface *intf)  {  	struct usb_hub *hub = usb_get_intfdata(intf); +	hub->in_reset = 0; +	hub_pm_barrier_for_all_ports(hub);  	hub_activate(hub, HUB_POST_RESET);  	return 0;  } @@ -1299,6 +1335,7 @@ static int hub_configure(struct usb_hub *hub,  	char *message = "out of memory";  	unsigned unit_load;  	unsigned full_load; +	unsigned maxchild;  	hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);  	if (!hub->buffer) { @@ -1337,12 +1374,11 @@ static int hub_configure(struct usb_hub *hub,  		goto fail;  	} -	hdev->maxchild = hub->descriptor->bNbrPorts; -	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, -		(hdev->maxchild == 1) ? "" : "s"); +	maxchild = hub->descriptor->bNbrPorts; +	dev_info(hub_dev, "%d port%s detected\n", maxchild, +			(maxchild == 1) ? "" : "s"); -	hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *), -			     GFP_KERNEL); +	hub->ports = kzalloc(maxchild * sizeof(struct usb_port *), GFP_KERNEL);  	if (!hub->ports) {  		ret = -ENOMEM;  		goto fail; @@ -1361,13 +1397,13 @@ static int hub_configure(struct usb_hub *hub,  	if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&  			!(hub_is_superspeed(hdev))) {  		int	i; -		char	portstr [USB_MAXCHILDREN + 1]; +		char	portstr[USB_MAXCHILDREN + 1]; -		for (i = 0; i < hdev->maxchild; i++) +		for (i = 0; i < maxchild; i++)  			portstr[i] = hub->descriptor->u.hs.DeviceRemovable  				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))  				? 'F' : 'R'; -		portstr[hdev->maxchild] = 0; +		portstr[maxchild] = 0;  		dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);  	} else  		dev_dbg(hub_dev, "standalone hub\n"); @@ -1429,32 +1465,32 @@ static int hub_configure(struct usb_hub *hub,  	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */  	switch (wHubCharacteristics & HUB_CHAR_TTTT) { -		case HUB_TTTT_8_BITS: -			if (hdev->descriptor.bDeviceProtocol != 0) { -				hub->tt.think_time = 666; -				dev_dbg(hub_dev, "TT requires at most %d " -						"FS bit times (%d ns)\n", -					8, hub->tt.think_time); -			} -			break; -		case HUB_TTTT_16_BITS: -			hub->tt.think_time = 666 * 2; -			dev_dbg(hub_dev, "TT requires at most %d " -					"FS bit times (%d ns)\n", -				16, hub->tt.think_time); -			break; -		case HUB_TTTT_24_BITS: -			hub->tt.think_time = 666 * 3; -			dev_dbg(hub_dev, "TT requires at most %d " -					"FS bit times (%d ns)\n", -				24, hub->tt.think_time); -			break; -		case HUB_TTTT_32_BITS: -			hub->tt.think_time = 666 * 4; +	case HUB_TTTT_8_BITS: +		if (hdev->descriptor.bDeviceProtocol != 0) { +			hub->tt.think_time = 666;  			dev_dbg(hub_dev, "TT requires at most %d "  					"FS bit times (%d ns)\n", -				32, hub->tt.think_time); -			break; +				8, hub->tt.think_time); +		} +		break; +	case HUB_TTTT_16_BITS: +		hub->tt.think_time = 666 * 2; +		dev_dbg(hub_dev, "TT requires at most %d " +				"FS bit times (%d ns)\n", +			16, hub->tt.think_time); +		break; +	case HUB_TTTT_24_BITS: +		hub->tt.think_time = 666 * 3; +		dev_dbg(hub_dev, "TT requires at most %d " +				"FS bit times (%d ns)\n", +			24, hub->tt.think_time); +		break; +	case HUB_TTTT_32_BITS: +		hub->tt.think_time = 666 * 4; +		dev_dbg(hub_dev, "TT requires at most %d " +				"FS bit times (%d ns)\n", +			32, hub->tt.think_time); +		break;  	}  	/* probe() zeroes hub->indicator[] */ @@ -1479,7 +1515,7 @@ static int hub_configure(struct usb_hub *hub,  		if (hcd->power_budget > 0)  			hdev->bus_mA = hcd->power_budget;  		else -			hdev->bus_mA = full_load * hdev->maxchild; +			hdev->bus_mA = full_load * maxchild;  		if (hdev->bus_mA >= full_load)  			hub->mA_per_port = full_load;  		else { @@ -1494,7 +1530,7 @@ static int hub_configure(struct usb_hub *hub,  			hub->descriptor->bHubContrCurrent);  		hub->limited_power = 1; -		if (remaining < hdev->maxchild * unit_load) +		if (remaining < maxchild * unit_load)  			dev_warn(hub_dev,  					"insufficient power available "  					"to use all downstream ports\n"); @@ -1509,18 +1545,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"; @@ -1560,15 +1584,37 @@ static int hub_configure(struct usb_hub *hub,  	/* maybe cycle the hub leds */  	if (hub->has_indicators && blinkenlights) -		hub->indicator [0] = INDICATOR_CYCLE; +		hub->indicator[0] = INDICATOR_CYCLE; -	for (i = 0; i < hdev->maxchild; i++) { +	mutex_lock(&usb_port_peer_mutex); +	for (i = 0; i < maxchild; i++) {  		ret = usb_hub_create_port_device(hub, i + 1);  		if (ret < 0) {  			dev_err(hub->intfdev,  				"couldn't create port%d device.\n", i + 1); -			hdev->maxchild = i; -			goto fail_keep_maxchild; +			break; +		} +	} +	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; + +	/* 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;  		}  	} @@ -1578,8 +1624,6 @@ static int hub_configure(struct usb_hub *hub,  	return 0;  fail: -	hdev->maxchild = 0; -fail_keep_maxchild:  	dev_err (hub_dev, "config failed, %s (err %d)\n",  			message, ret);  	/* hub_disconnect() frees urb and descriptor */ @@ -1600,7 +1644,7 @@ static void hub_disconnect(struct usb_interface *intf)  {  	struct usb_hub *hub = usb_get_intfdata(intf);  	struct usb_device *hdev = interface_to_usbdev(intf); -	int i; +	int port1;  	/* Take the hub off the event list and don't let it be added again */  	spin_lock_irq(&hub_event_lock); @@ -1615,11 +1659,19 @@ static void hub_disconnect(struct usb_interface *intf)  	hub->error = 0;  	hub_quiesce(hub, HUB_DISCONNECT); -	usb_set_intfdata (intf, NULL); +	mutex_lock(&usb_port_peer_mutex); -	for (i = 0; i < hdev->maxchild; i++) -		usb_hub_remove_port_device(hub, i + 1); -	hub->hdev->maxchild = 0; +	/* Avoid races with recursively_mark_NOTATTACHED() */ +	spin_lock_irq(&device_state_lock); +	port1 = hdev->maxchild; +	hdev->maxchild = 0; +	usb_set_intfdata(intf, NULL); +	spin_unlock_irq(&device_state_lock); + +	for (; port1 > 0; --port1) +		usb_hub_remove_port_device(hub, port1); + +	mutex_unlock(&usb_port_peer_mutex);  	if (hub->hdev->speed == USB_SPEED_HIGH)  		highspeed_hubs--; @@ -1679,8 +1731,19 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)  	 */  	pm_runtime_set_autosuspend_delay(&hdev->dev, 0); -	/* Hubs have proper suspend/resume support. */ -	usb_enable_autosuspend(hdev); +	/* +	 * Hubs have proper suspend/resume support, except for root hubs +	 * where the controller driver doesn't have bus_suspend and +	 * bus_resume methods. +	 */ +	if (hdev->parent) {		/* normal device */ +		usb_enable_autosuspend(hdev); +	} else {			/* root hub */ +		const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver; + +		if (drv->bus_suspend && drv->bus_resume) +			usb_enable_autosuspend(hdev); +	}  	if (hdev->level == MAX_TOPO_LEVEL) {  		dev_err(&intf->dev, @@ -1788,7 +1851,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)   * to one of these "claimed" ports, the program will "own" the device.   */  static int find_port_owner(struct usb_device *hdev, unsigned port1, -		struct dev_state ***ppowner) +		struct usb_dev_state ***ppowner)  {  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); @@ -1806,10 +1869,10 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,  /* In the following three functions, the caller must hold hdev's lock */  int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, -		       struct dev_state *owner) +		       struct usb_dev_state *owner)  {  	int rc; -	struct dev_state **powner; +	struct usb_dev_state **powner;  	rc = find_port_owner(hdev, port1, &powner);  	if (rc) @@ -1819,12 +1882,13 @@ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,  	*powner = owner;  	return rc;  } +EXPORT_SYMBOL_GPL(usb_hub_claim_port);  int usb_hub_release_port(struct usb_device *hdev, unsigned port1, -			 struct dev_state *owner) +			 struct usb_dev_state *owner)  {  	int rc; -	struct dev_state **powner; +	struct usb_dev_state **powner;  	rc = find_port_owner(hdev, port1, &powner);  	if (rc) @@ -1834,8 +1898,9 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1,  	*powner = NULL;  	return rc;  } +EXPORT_SYMBOL_GPL(usb_hub_release_port); -void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner) +void usb_hub_release_all_ports(struct usb_device *hdev, struct usb_dev_state *owner)  {  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);  	int n; @@ -1978,7 +2043,7 @@ static void choose_devnum(struct usb_device *udev)  		if (devnum >= 128)  			devnum = find_next_zero_bit(bus->devmap.devicemap,  						    128, 1); -		bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); +		bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);  	}  	if (devnum < 128) {  		set_bit(devnum, bus->devmap.devicemap); @@ -2010,6 +2075,18 @@ static void hub_free_dev(struct usb_device *udev)  		hcd->driver->free_dev(hcd, udev);  } +static void hub_disconnect_children(struct usb_device *udev) +{ +	struct usb_hub *hub = usb_hub_to_struct_hub(udev); +	int i; + +	/* Free up all the children before we remove this device */ +	for (i = 0; i < udev->maxchild; i++) { +		if (hub->ports[i]->child) +			usb_disconnect(&hub->ports[i]->child); +	} +} +  /**   * usb_disconnect - disconnect a device (usbcore-internal)   * @pdev: pointer to device being disconnected @@ -2018,8 +2095,8 @@ static void hub_free_dev(struct usb_device *udev)   * Something got disconnected. Get rid of it and all of its children.   *   * If *pdev is a normal device then the parent hub must already be locked. - * If *pdev is a root hub then this routine will acquire the - * usb_bus_list_lock on behalf of the caller. + * If *pdev is a root hub then the caller must hold the usb_bus_list_lock, + * which protects the set of root hubs as well as the list of buses.   *   * Only hub drivers (including virtual root hub drivers for host   * controllers) should ever call this. @@ -2028,9 +2105,10 @@ static void hub_free_dev(struct usb_device *udev)   */  void usb_disconnect(struct usb_device **pdev)  { -	struct usb_device	*udev = *pdev; -	struct usb_hub		*hub = usb_hub_to_struct_hub(udev); -	int			i; +	struct usb_port *port_dev = NULL; +	struct usb_device *udev = *pdev; +	struct usb_hub *hub; +	int port1;  	/* mark the device as inactive, so any further urb submissions for  	 * this device (and any of its children) will fail immediately. @@ -2042,11 +2120,7 @@ void usb_disconnect(struct usb_device **pdev)  	usb_lock_device(udev); -	/* Free up all the children before we remove this device */ -	for (i = 0; i < udev->maxchild; i++) { -		if (hub->ports[i]->child) -			usb_disconnect(&hub->ports[i]->child); -	} +	hub_disconnect_children(udev);  	/* deallocate hcd/hardware state ... nuking all pending urbs and  	 * cleaning up all state associated with the current configuration @@ -2057,16 +2131,19 @@ void usb_disconnect(struct usb_device **pdev)  	usb_hcd_synchronize_unlinks(udev);  	if (udev->parent) { -		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); -		struct usb_port	*port_dev = hub->ports[udev->portnum - 1]; +		port1 = udev->portnum; +		hub = usb_hub_to_struct_hub(udev->parent); +		port_dev = hub->ports[port1 - 1];  		sysfs_remove_link(&udev->dev.kobj, "port");  		sysfs_remove_link(&port_dev->dev.kobj, "device"); -		if (!port_dev->did_runtime_put) -			pm_runtime_put(&port_dev->dev); -		else -			port_dev->did_runtime_put = false; +		/* +		 * As usb_port_runtime_resume() de-references udev, make +		 * sure no resumes occur during removal +		 */ +		if (!test_and_set_bit(port1, hub->child_usage_bits)) +			pm_runtime_get_sync(&port_dev->dev);  	}  	usb_remove_ep_devs(&udev->ep0); @@ -2088,6 +2165,9 @@ void usb_disconnect(struct usb_device **pdev)  	*pdev = NULL;  	spin_unlock_irq(&device_state_lock); +	if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits)) +		pm_runtime_put(&port_dev->dev); +  	hub_free_dev(udev);  	put_device(&udev->dev); @@ -2228,18 +2308,13 @@ static int usb_enumerate_device(struct usb_device *udev)  			return err;  		}  	} -	if (udev->wusb == 1 && udev->authorized == 0) { -		udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); -		udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); -		udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); -	} -	else { -		/* read the standard strings and cache them if present */ -		udev->product = usb_cache_string(udev, udev->descriptor.iProduct); -		udev->manufacturer = usb_cache_string(udev, -						      udev->descriptor.iManufacturer); -		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); -	} + +	/* read the standard strings and cache them if present */ +	udev->product = usb_cache_string(udev, udev->descriptor.iProduct); +	udev->manufacturer = usb_cache_string(udev, +					      udev->descriptor.iManufacturer); +	udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); +  	err = usb_enumerate_device_otg(udev);  	if (err < 0)  		return err; @@ -2280,6 +2355,22 @@ static void set_usb_port_removable(struct usb_device *udev)  		udev->removable = USB_DEVICE_REMOVABLE;  	else  		udev->removable = USB_DEVICE_FIXED; + +	/* +	 * Platform firmware may have populated an alternative value for +	 * removable.  If the parent port has a known connect_type use +	 * that instead. +	 */ +	switch (hub->ports[udev->portnum - 1]->connect_type) { +	case USB_PORT_CONNECT_TYPE_HOT_PLUG: +		udev->removable = USB_DEVICE_REMOVABLE; +		break; +	case USB_PORT_CONNECT_TYPE_HARD_WIRED: +		udev->removable = USB_DEVICE_FIXED; +		break; +	default: /* use what was set above */ +		break; +	}  }  /** @@ -2349,11 +2440,7 @@ int usb_new_device(struct usb_device *udev)  	device_enable_async_suspend(&udev->dev); -	/* -	 * check whether the hub marks this port as non-removable. Do it -	 * now so that platform-specific data can override it in -	 * device_add() -	 */ +	/* check whether the hub or firmware marks this port as non-removable */  	if (udev->parent)  		set_usb_port_removable(udev); @@ -2370,7 +2457,8 @@ int usb_new_device(struct usb_device *udev)  	/* Create link files between child device and usb port device. */  	if (udev->parent) {  		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); -		struct usb_port	*port_dev = hub->ports[udev->portnum - 1]; +		int port1 = udev->portnum; +		struct usb_port	*port_dev = hub->ports[port1 - 1];  		err = sysfs_create_link(&udev->dev.kobj,  				&port_dev->dev.kobj, "port"); @@ -2384,7 +2472,8 @@ int usb_new_device(struct usb_device *udev)  			goto fail;  		} -		pm_runtime_get_sync(&port_dev->dev); +		if (!test_and_set_bit(port1, hub->child_usage_bits)) +			pm_runtime_get_sync(&port_dev->dev);  	}  	(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); @@ -2421,16 +2510,6 @@ int usb_deauthorize_device(struct usb_device *usb_dev)  	usb_dev->authorized = 0;  	usb_set_configuration(usb_dev, -1); -	kfree(usb_dev->product); -	usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); -	kfree(usb_dev->manufacturer); -	usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); -	kfree(usb_dev->serial); -	usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - -	usb_destroy_configuration(usb_dev); -	usb_dev->descriptor.bNumConfigurations = 0; -  out_unauthorized:  	usb_unlock_device(usb_dev);  	return 0; @@ -2458,17 +2537,7 @@ int usb_authorize_device(struct usb_device *usb_dev)  		goto error_device_descriptor;  	} -	kfree(usb_dev->product); -	usb_dev->product = NULL; -	kfree(usb_dev->manufacturer); -	usb_dev->manufacturer = NULL; -	kfree(usb_dev->serial); -	usb_dev->serial = NULL; -  	usb_dev->authorized = 1; -	result = usb_enumerate_device(usb_dev); -	if (result < 0) -		goto error_enumerate;  	/* Choose and set the configuration.  This registers the interfaces  	 * with the driver core and lets interface drivers bind to them.  	 */ @@ -2484,12 +2553,11 @@ int usb_authorize_device(struct usb_device *usb_dev)  	}  	dev_info(&usb_dev->dev, "authorized to connect\n"); -error_enumerate:  error_device_descriptor:  	usb_autosuspend_device(usb_dev);  error_autoresume:  out_authorized: -	usb_unlock_device(usb_dev);	// complements locktree +	usb_unlock_device(usb_dev);	/* complements locktree */  	return result;  } @@ -2517,10 +2585,25 @@ static unsigned hub_is_wusb(struct usb_hub *hub)  #define HUB_LONG_RESET_TIME	200  #define HUB_RESET_TIMEOUT	800 +/* + * "New scheme" enumeration causes an extra state transition to be + * exposed to an xhci host and causes USB3 devices to receive control + * commands in the default state.  This has been seen to cause + * enumeration failures, so disable this enumeration scheme for USB3 + * devices. + */ +static bool use_new_scheme(struct usb_device *udev, int retry) +{ +	if (udev->speed == USB_SPEED_SUPER) +		return false; + +	return USE_NEW_SCHEME(retry); +} +  static int hub_port_reset(struct usb_hub *hub, int port1,  			struct usb_device *udev, unsigned int delay, bool warm); -/* Is a USB 3.0 port in the Inactive or Complinance Mode state? +/* Is a USB 3.0 port in the Inactive or Compliance Mode state?   * Port worm reset is required to recover   */  static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) @@ -2558,9 +2641,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,  		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)  			delay = HUB_LONG_RESET_TIME; -		dev_dbg (hub->intfdev, -			"port %d not %sreset yet, waiting %dms\n", -			port1, warm ? "warm " : "", delay); +		dev_dbg(&hub->ports[port1 - 1]->dev, +				"not %sreset yet, waiting %dms\n", +				warm ? "warm " : "", delay);  	}  	if ((portstatus & USB_PORT_STAT_RESET)) @@ -2644,6 +2727,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  {  	int i, status;  	u16 portchange, portstatus; +	struct usb_port *port_dev = hub->ports[port1 - 1];  	if (!hub_is_superspeed(hub->hdev)) {  		if (warm) { @@ -2677,9 +2761,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  		if (status == -ENODEV) {  			;	/* The hub is gone */  		} else if (status) { -			dev_err(hub->intfdev, -					"cannot %sreset port %d (err = %d)\n", -					warm ? "warm " : "", port1, status); +			dev_err(&port_dev->dev, +					"cannot %sreset (err = %d)\n", +					warm ? "warm " : "", status);  		} else {  			status = hub_port_wait_reset(hub, port1, udev, delay,  								warm); @@ -2712,21 +2796,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  			 * hot or warm reset failed.  Try another warm reset.  			 */  			if (!warm) { -				dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n", -						port1); +				dev_dbg(&port_dev->dev, +						"hot reset failed, warm reset\n");  				warm = true;  			}  		} -		dev_dbg (hub->intfdev, -			"port %d not enabled, trying %sreset again...\n", -			port1, warm ? "warm " : ""); +		dev_dbg(&port_dev->dev, +				"not enabled, trying %sreset again...\n", +				warm ? "warm " : "");  		delay = HUB_LONG_RESET_TIME;  	} -	dev_err (hub->intfdev, -		"Cannot enable port %i.  Maybe the USB cable is bad?\n", -		port1); +	dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");  done:  	if (!hub_is_superspeed(hub->hdev)) @@ -2751,6 +2833,20 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)  	return ret;  } +static void usb_lock_port(struct usb_port *port_dev) +		__acquires(&port_dev->status_lock) +{ +	mutex_lock(&port_dev->status_lock); +	__acquire(&port_dev->status_lock); +} + +static void usb_unlock_port(struct usb_port *port_dev) +		__releases(&port_dev->status_lock) +{ +	mutex_unlock(&port_dev->status_lock); +	__release(&port_dev->status_lock); +} +  #ifdef	CONFIG_PM  /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */ @@ -2777,6 +2873,8 @@ static int check_port_resume_type(struct usb_device *udev,  		struct usb_hub *hub, int port1,  		int status, unsigned portchange, unsigned portstatus)  { +	struct usb_port *port_dev = hub->ports[port1 - 1]; +  	/* Is the device still present? */  	if (status || port_is_suspended(hub, portstatus) ||  			!port_is_power_on(hub, portstatus) || @@ -2796,9 +2894,8 @@ static int check_port_resume_type(struct usb_device *udev,  	}  	if (status) { -		dev_dbg(hub->intfdev, -				"port %d status %04x.%04x after resume, %d\n", -				port1, portchange, portstatus, status); +		dev_dbg(&port_dev->dev, "status %04x.%04x after resume, %d\n", +				portchange, portstatus, status);  	} else if (udev->reset_resume) {  		/* Late port handoff can set status-change bits */ @@ -2972,6 +3069,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  	int		status;  	bool		really_suspend = true; +	usb_lock_port(port_dev); +  	/* enable remote wakeup when appropriate; this lets the device  	 * wake up the upstream hub (including maybe the root hub).  	 * @@ -3029,8 +3128,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  		status = 0;  	}  	if (status) { -		dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", -				port1, status); +		dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);  		/* Try to enable USB3 LPM and LTM again */  		usb_unlocked_enable_lpm(udev); @@ -3061,12 +3159,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  		usb_set_device_state(udev, USB_STATE_SUSPENDED);  	} -	if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) { +	if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled +			&& test_and_clear_bit(port1, hub->child_usage_bits))  		pm_runtime_put_sync(&port_dev->dev); -		port_dev->did_runtime_put = true; -	}  	usb_mark_last_busy(hub->hdev); + +	usb_unlock_port(port_dev);  	return status;  } @@ -3104,12 +3203,22 @@ static int finish_port_resume(struct usb_device *udev)  	 * operation is carried out here, after the port has been  	 * resumed.  	 */ -	if (udev->reset_resume) +	if (udev->reset_resume) { +		/* +		 * If the device morphs or switches modes when it is reset, +		 * we don't want to perform a reset-resume.  We'll fail the +		 * resume, which will cause a logical disconnect, and then +		 * the device will be rediscovered. +		 */   retry_reset_resume: -		status = usb_reset_and_verify_device(udev); +		if (udev->quirks & USB_QUIRK_RESET) +			status = -ENODEV; +		else +			status = usb_reset_and_verify_device(udev); +	} - 	/* 10.5.4.5 says be sure devices in the tree are still there. - 	 * For now let's assume the device didn't go crazy on resume, +	/* 10.5.4.5 says be sure devices in the tree are still there. +	 * For now let's assume the device didn't go crazy on resume,  	 * and device drivers will know about any resume quirks.  	 */  	if (status == 0) { @@ -3196,9 +3305,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  	int		status;  	u16		portchange, portstatus; -	if (port_dev->did_runtime_put) { +	if (!test_and_set_bit(port1, hub->child_usage_bits)) {  		status = pm_runtime_get_sync(&port_dev->dev); -		port_dev->did_runtime_put = false;  		if (status < 0) {  			dev_dbg(&udev->dev, "can't resume usb port, status %d\n",  					status); @@ -3206,15 +3314,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		}  	} +	usb_lock_port(port_dev); +  	/* Skip the initial Clear-Suspend step for a remote wakeup */  	status = hub_port_status(hub, port1, &portstatus, &portchange);  	if (status == 0 && !port_is_suspended(hub, portstatus))  		goto SuspendCleared; -	// dev_dbg(hub->intfdev, "resume port %d\n", port1); - -	set_bit(port1, hub->busy_bits); -  	/* see 7.1.7.7; affects power usage, but not budgeting */  	if (hub_is_superspeed(hub->hdev))  		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0); @@ -3222,8 +3328,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		status = usb_clear_port_feature(hub->hdev,  				port1, USB_PORT_FEAT_SUSPEND);  	if (status) { -		dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", -				port1, status); +		dev_dbg(&port_dev->dev, "can't resume, status %d\n", status);  	} else {  		/* drive resume for at least 20 msec */  		dev_dbg(&udev->dev, "usb %sresume\n", @@ -3254,8 +3359,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		}  	} -	clear_bit(port1, hub->busy_bits); -  	status = check_port_resume_type(udev,  			hub, port1, status, portchange, portstatus);  	if (status == 0) @@ -3273,16 +3376,18 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		usb_unlocked_enable_lpm(udev);  	} +	usb_unlock_port(port_dev); +  	return status;  }  #ifdef	CONFIG_PM_RUNTIME -/* caller has locked udev */  int usb_remote_wakeup(struct usb_device *udev)  {  	int	status = 0; +	usb_lock_device(udev);  	if (udev->state == USB_STATE_SUSPENDED) {  		dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");  		status = usb_autoresume_device(udev); @@ -3291,9 +3396,59 @@ int usb_remote_wakeup(struct usb_device *udev)  			usb_autosuspend_device(udev);  		}  	} +	usb_unlock_device(udev);  	return status;  } +/* Returns 1 if there was a remote wakeup and a connect status change. */ +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, +		u16 portstatus, u16 portchange) +		__must_hold(&port_dev->status_lock) +{ +	struct usb_port *port_dev = hub->ports[port - 1]; +	struct usb_device *hdev; +	struct usb_device *udev; +	int connect_change = 0; +	int ret; + +	hdev = hub->hdev; +	udev = port_dev->child; +	if (!hub_is_superspeed(hdev)) { +		if (!(portchange & USB_PORT_STAT_C_SUSPEND)) +			return 0; +		usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); +	} else { +		if (!udev || udev->state != USB_STATE_SUSPENDED || +				 (portstatus & USB_PORT_STAT_LINK_STATE) != +				 USB_SS_PORT_LS_U0) +			return 0; +	} + +	if (udev) { +		/* TRSMRCY = 10 msec */ +		msleep(10); + +		usb_unlock_port(port_dev); +		ret = usb_remote_wakeup(udev); +		usb_lock_port(port_dev); +		if (ret < 0) +			connect_change = 1; +	} else { +		ret = -ENODEV; +		hub_port_disable(hub, port, 1); +	} +	dev_dbg(&port_dev->dev, "resume, status %d\n", ret); +	return connect_change; +} + +#else + +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, +		u16 portstatus, u16 portchange) +{ +	return 0; +} +  #endif  static int check_ports_changed(struct usb_hub *hub) @@ -3324,11 +3479,12 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)  	 */  	hub->wakeup_enabled_descendants = 0;  	for (port1 = 1; port1 <= hdev->maxchild; port1++) { -		struct usb_device	*udev; +		struct usb_port *port_dev = hub->ports[port1 - 1]; +		struct usb_device *udev = port_dev->child; -		udev = hub->ports[port1 - 1]->child;  		if (udev && udev->can_submit) { -			dev_warn(&intf->dev, "port %d nyet suspended\n", port1); +			dev_warn(&port_dev->dev, "device %s not suspended yet\n", +					dev_name(&udev->dev));  			if (PMSG_IS_AUTO(msg))  				return -EBUSY;  		} @@ -3426,6 +3582,9 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)  	unsigned long long u2_pel;  	int ret; +	if (udev->state != USB_STATE_CONFIGURED) +		return 0; +  	/* Convert SEL and PEL stored in ns to us */  	u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);  	u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000); @@ -3844,6 +4003,12 @@ EXPORT_SYMBOL_GPL(usb_disable_ltm);  void usb_enable_ltm(struct usb_device *udev) { }  EXPORT_SYMBOL_GPL(usb_enable_ltm); +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, +		u16 portstatus, u16 portchange) +{ +	return 0; +} +  #endif	/* CONFIG_PM */ @@ -3852,7 +4017,7 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm);   * Between connect detection and reset signaling there must be a delay   * of 100ms at least for debounce and power-settling.  The corresponding   * timer shall restart whenever the downstream port detects a disconnect. - *  + *   * Apparently there are some bluetooth and irda-dongles and a number of   * low-speed devices for which this debounce period may last over a second.   * Not covered by the spec - but easy to deal with. @@ -3865,9 +4030,10 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm);  int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)  {  	int ret; -	int total_time, stable_time = 0;  	u16 portchange, portstatus;  	unsigned connection = 0xffff; +	int total_time, stable_time = 0; +	struct usb_port *port_dev = hub->ports[port1 - 1];  	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {  		ret = hub_port_status(hub, port1, &portstatus, &portchange); @@ -3896,9 +4062,8 @@ int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)  		msleep(HUB_DEBOUNCE_STEP);  	} -	dev_dbg (hub->intfdev, -		"debounce: port %d: total %dms stable %dms status 0x%x\n", -		port1, total_time, stable_time, portstatus); +	dev_dbg(&port_dev->dev, "debounce total %dms stable %dms status 0x%x\n", +			total_time, stable_time, portstatus);  	if (stable_time < HUB_DEBOUNCE_STABLE)  		return -ETIMEDOUT; @@ -3946,21 +4111,61 @@ static int hub_set_address(struct usb_device *udev, int devnum)  	return retval;  } +/* + * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM + * when they're plugged into a USB 2.0 port, but they don't work when LPM is + * enabled. + * + * Only enable USB 2.0 Link PM if the port is internal (hardwired), or the + * device says it supports the new USB 2.0 Link PM errata by setting the BESL + * support bit in the BOS descriptor. + */ +static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) +{ +	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); +	int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; + +	if (!udev->usb2_hw_lpm_capable) +		return; + +	if (hub) +		connect_type = hub->ports[udev->portnum - 1]->connect_type; + +	if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || +			connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { +		udev->usb2_hw_lpm_allowed = 1; +		usb_set_usb2_hardware_lpm(udev, 1); +	} +} + +static int hub_enable_device(struct usb_device *udev) +{ +	struct usb_hcd *hcd = bus_to_hcd(udev->bus); + +	if (!hcd->driver->enable_device) +		return 0; +	if (udev->state == USB_STATE_ADDRESS) +		return 0; +	if (udev->state != USB_STATE_DEFAULT) +		return -EINVAL; + +	return hcd->driver->enable_device(hcd, udev); +} +  /* Reset device, (re)assign address, get device descriptor.   * Device connection must be stable, no more debouncing needed.   * Returns device in USB_STATE_ADDRESS, except on error.   *   * If this is called for an already-existing device (as part of - * usb_reset_and_verify_device), the caller must own the device lock.  For a - * newly detected device that is not accessible through any global - * pointers, it's not necessary to lock the device. + * usb_reset_and_verify_device), the caller must own the device lock and + * the port lock.  For a newly detected device that is not accessible + * through any global pointers, it's not necessary to lock the device, + * but it is still necessary to lock the port.   */  static int  hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		int retry_counter)  { -	static DEFINE_MUTEX(usb_address0_mutex); -  	struct usb_device	*hdev = hub->hdev;  	struct usb_hcd		*hcd = bus_to_hcd(hdev->bus);  	int			i, j, retval; @@ -3983,7 +4188,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	if (oldspeed == USB_SPEED_LOW)  		delay = HUB_LONG_RESET_TIME; -	mutex_lock(&usb_address0_mutex); +	mutex_lock(&hdev->bus->usb_address0_mutex);  	/* Reset the device; full speed may morph to high speed */  	/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ @@ -4052,13 +4257,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		udev->tt = &hub->tt;  		udev->ttport = port1;  	} -  +  	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?  	 * Because device hardware and firmware is sometimes buggy in  	 * this area, and this is how Linux has done it for ages.  	 * Change it cautiously.  	 * -	 * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing +	 * NOTE:  If use_new_scheme() is true we will start by issuing  	 * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,  	 * so it may help with some non-standards-compliant devices.  	 * Otherwise we start with SET_ADDRESS and then try to read the @@ -4066,10 +4271,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	 * value.  	 */  	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { -		if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { +		bool did_new_scheme = false; + +		if (use_new_scheme(udev, retry_counter)) {  			struct usb_device_descriptor *buf;  			int r = 0; +			did_new_scheme = true; +			retval = hub_enable_device(udev); +			if (retval < 0) { +				dev_err(&udev->dev, +					"hub failed to enable device, error %d\n", +					retval); +				goto fail; +			} +  #define GET_DESCRIPTOR_BUFSIZE	64  			buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);  			if (!buf) { @@ -4127,11 +4343,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  #undef GET_DESCRIPTOR_BUFSIZE  		} - 		/* - 		 * If device is WUSB, we already assigned an - 		 * unauthorized address in the Connect Ack sequence; - 		 * authorization will assign the final address. - 		 */ +		/* +		 * If device is WUSB, we already assigned an +		 * unauthorized address in the Connect Ack sequence; +		 * authorization will assign the final address. +		 */  		if (udev->wusb == 0) {  			for (j = 0; j < SET_ADDRESS_TRIES; ++j) {  				retval = hub_set_address(udev, devnum); @@ -4158,9 +4374,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  			 *  - read ep0 maxpacket even for high and low speed,  			 */  			msleep(10); -			if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) +			/* use_new_scheme() checks the speed which may have +			 * changed since the initial look so we cache the result +			 * in did_new_scheme +			 */ +			if (did_new_scheme)  				break; -  		} +		}  		retval = usb_get_device_descriptor(udev, 8);  		if (retval < 8) { @@ -4216,7 +4436,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);  		usb_ep0_reinit(udev);  	} -   +  	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);  	if (retval < (signed)sizeof(udev->descriptor)) {  		if (retval != -ENODEV) @@ -4239,12 +4459,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	/* notify HCD that we have a device connected and addressed */  	if (hcd->driver->update_device)  		hcd->driver->update_device(hcd, udev); +	hub_set_initial_usb2_lpm_policy(udev);  fail:  	if (retval) {  		hub_port_disable(hub, port1, 0);  		update_devnum(udev, devnum);	/* for disconnect processing */  	} -	mutex_unlock(&usb_address0_mutex); +	mutex_unlock(&hdev->bus->usb_address0_mutex);  	return retval;  } @@ -4266,7 +4487,8 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)  		/* hub LEDs are probably harder to miss than syslog */  		if (hub->has_indicators) {  			hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; -			schedule_delayed_work (&hub->leds, 0); +			queue_delayed_work(system_power_efficient_wq, +					&hub->leds, 0);  		}  	}  	kfree(qual); @@ -4284,9 +4506,10 @@ hub_power_remaining (struct usb_hub *hub)  	remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;  	for (port1 = 1; port1 <= hdev->maxchild; ++port1) { -		struct usb_device	*udev = hub->ports[port1 - 1]->child; -		int			delta; -		unsigned		unit_load; +		struct usb_port *port_dev = hub->ports[port1 - 1]; +		struct usb_device *udev = port_dev->child; +		unsigned unit_load; +		int delta;  		if (!udev)  			continue; @@ -4306,91 +4529,35 @@ hub_power_remaining (struct usb_hub *hub)  		else  			delta = 8;  		if (delta > hub->mA_per_port) -			dev_warn(&udev->dev, -				 "%dmA is over %umA budget for port %d!\n", -				 delta, hub->mA_per_port, port1); +			dev_warn(&port_dev->dev, "%dmA is over %umA budget!\n", +					delta, hub->mA_per_port);  		remaining -= delta;  	}  	if (remaining < 0) {  		dev_warn(hub->intfdev, "%dmA over power budget!\n", -			- remaining); +			-remaining);  		remaining = 0;  	}  	return remaining;  } -/* Handle physical or logical connection change events. - * This routine is called when: - * 	a port connection-change occurs; - *	a port enable-change occurs (often caused by EMI); - *	usb_reset_and_verify_device() encounters changed descriptors (as from - *		a firmware download) - * caller already locked the hub - */ -static void hub_port_connect_change(struct usb_hub *hub, int port1, -					u16 portstatus, u16 portchange) +static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, +		u16 portchange)  { -	struct usb_device *hdev = hub->hdev; -	struct device *hub_dev = hub->intfdev; -	struct usb_hcd *hcd = bus_to_hcd(hdev->bus); -	unsigned wHubCharacteristics = -			le16_to_cpu(hub->descriptor->wHubCharacteristics); -	struct usb_device *udev;  	int status, i;  	unsigned unit_load; - -	dev_dbg (hub_dev, -		"port %d, status %04x, change %04x, %s\n", -		port1, portstatus, portchange, portspeed(hub, portstatus)); - -	if (hub->has_indicators) { -		set_port_led(hub, port1, HUB_LED_AUTO); -		hub->indicator[port1-1] = INDICATOR_AUTO; -	} - -#ifdef	CONFIG_USB_OTG -	/* during HNP, don't repeat the debounce */ -	if (hdev->bus->is_b_host) -		portchange &= ~(USB_PORT_STAT_C_CONNECTION | -				USB_PORT_STAT_C_ENABLE); -#endif - -	/* Try to resuscitate an existing device */ -	udev = hub->ports[port1 - 1]->child; -	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && -			udev->state != USB_STATE_NOTATTACHED) { -		usb_lock_device(udev); -		if (portstatus & USB_PORT_STAT_ENABLE) { -			status = 0;		/* Nothing to do */ - -#ifdef CONFIG_PM_RUNTIME -		} else if (udev->state == USB_STATE_SUSPENDED && -				udev->persist_enabled) { -			/* For a suspended device, treat this as a -			 * remote wakeup event. -			 */ -			status = usb_remote_wakeup(udev); -#endif - -		} else { -			status = -ENODEV;	/* Don't resuscitate */ -		} -		usb_unlock_device(udev); - -		if (status == 0) { -			clear_bit(port1, hub->change_bits); -			return; -		} -	} +	struct usb_device *hdev = hub->hdev; +	struct usb_hcd *hcd = bus_to_hcd(hdev->bus); +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	struct usb_device *udev = port_dev->child;  	/* Disconnect any existing devices under this port */  	if (udev) {  		if (hcd->phy && !hdev->parent &&  				!(portstatus & USB_PORT_STAT_CONNECTION))  			usb_phy_notify_disconnect(hcd->phy, udev->speed); -		usb_disconnect(&hub->ports[port1 - 1]->child); +		usb_disconnect(&port_dev->child);  	} -	clear_bit(port1, hub->change_bits);  	/* We can forget about a "removed" device when there's a physical  	 * disconnect or the connect status changes. @@ -4404,8 +4571,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		status = hub_port_debounce_be_stable(hub, port1);  		if (status < 0) {  			if (status != -ENODEV && printk_ratelimit()) -				dev_err(hub_dev, "connect-debounce failed, " -						"port %d disabled\n", port1); +				dev_err(&port_dev->dev, +						"connect-debounce failed\n");  			portstatus &= ~USB_PORT_STAT_CONNECTION;  		} else {  			portstatus = status; @@ -4419,12 +4586,12 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  			test_bit(port1, hub->removed_bits)) {  		/* maybe switch power back on (e.g. root hub was reset) */ -		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 +		if (hub_is_port_power_switchable(hub)  				&& !port_is_power_on(hub, portstatus))  			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);  		if (portstatus & USB_PORT_STAT_ENABLE) -  			goto done; +			goto done;  		return;  	}  	if (hub_is_superspeed(hub->hdev)) @@ -4440,14 +4607,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		 */  		udev = usb_alloc_dev(hdev, hdev->bus, port1);  		if (!udev) { -			dev_err (hub_dev, -				"couldn't allocate port %d usb_device\n", -				port1); +			dev_err(&port_dev->dev, +					"couldn't allocate usb_device\n");  			goto done;  		}  		usb_set_device_state(udev, USB_STATE_POWERED); - 		udev->bus_mA = hub->mA_per_port; +		udev->bus_mA = hub->mA_per_port;  		udev->level = hdev->level + 1;  		udev->wusb = hub_is_wusb(hub); @@ -4464,7 +4630,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		}  		/* reset (non-USB 3.0 devices) and get descriptor */ +		usb_lock_port(port_dev);  		status = hub_port_init(hub, udev, port1, i); +		usb_unlock_port(port_dev);  		if (status < 0)  			goto loop; @@ -4495,13 +4663,15 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  				if (hub->has_indicators) {  					hub->indicator[port1-1] =  						INDICATOR_AMBER_BLINK; -					schedule_delayed_work (&hub->leds, 0); +					queue_delayed_work( +						system_power_efficient_wq, +						&hub->leds, 0);  				}  				status = -ENOTCONN;	/* Don't retry */  				goto loop_disable;  			}  		} -  +  		/* check for devices running slower than they could */  		if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200  				&& udev->speed == USB_SPEED_FULL @@ -4514,6 +4684,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		 */  		status = 0; +		mutex_lock(&usb_port_peer_mutex); +  		/* We mustn't add new devices if the parent hub has  		 * been disconnected; we would race with the  		 * recursively_mark_NOTATTACHED() routine. @@ -4522,16 +4694,19 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		if (hdev->state == USB_STATE_NOTATTACHED)  			status = -ENOTCONN;  		else -			hub->ports[port1 - 1]->child = udev; +			port_dev->child = udev;  		spin_unlock_irq(&device_state_lock); +		mutex_unlock(&usb_port_peer_mutex);  		/* Run it through the hoops (find a driver, etc) */  		if (!status) {  			status = usb_new_device(udev);  			if (status) { +				mutex_lock(&usb_port_peer_mutex);  				spin_lock_irq(&device_state_lock); -				hub->ports[port1 - 1]->child = NULL; +				port_dev->child = NULL;  				spin_unlock_irq(&device_state_lock); +				mutex_unlock(&usb_port_peer_mutex);  			}  		} @@ -4540,7 +4715,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		status = hub_power_remaining(hub);  		if (status) -			dev_dbg(hub_dev, "%dmA power budget left\n", status); +			dev_dbg(hub->intfdev, "%dmA power budget left\n", status);  		return; @@ -4558,56 +4733,200 @@ loop:  			!hcd->driver->port_handed_over ||  			!(hcd->driver->port_handed_over)(hcd, port1)) {  		if (status != -ENOTCONN && status != -ENODEV) -			dev_err(hub_dev, "unable to enumerate USB device on port %d\n", -					port1); +			dev_err(&port_dev->dev, +					"unable to enumerate USB device\n");  	} -  +  done:  	hub_port_disable(hub, port1, 1);  	if (hcd->driver->relinquish_port && !hub->hdev->parent)  		hcd->driver->relinquish_port(hcd, port1); +  } -/* Returns 1 if there was a remote wakeup and a connect status change. */ -static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, -		u16 portstatus, u16 portchange) +/* Handle physical or logical connection change events. + * This routine is called when: + *	a port connection-change occurs; + *	a port enable-change occurs (often caused by EMI); + *	usb_reset_and_verify_device() encounters changed descriptors (as from + *		a firmware download) + * caller already locked the hub + */ +static void hub_port_connect_change(struct usb_hub *hub, int port1, +					u16 portstatus, u16 portchange) +		__must_hold(&port_dev->status_lock)  { -	struct usb_device *hdev; -	struct usb_device *udev; -	int connect_change = 0; -	int ret; +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	struct usb_device *udev = port_dev->child; +	int status = -ENODEV; -	hdev = hub->hdev; -	udev = hub->ports[port - 1]->child; -	if (!hub_is_superspeed(hdev)) { -		if (!(portchange & USB_PORT_STAT_C_SUSPEND)) -			return 0; -		usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); -	} else { -		if (!udev || udev->state != USB_STATE_SUSPENDED || -				 (portstatus & USB_PORT_STAT_LINK_STATE) != -				 USB_SS_PORT_LS_U0) -			return 0; +	dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, +			portchange, portspeed(hub, portstatus)); + +	if (hub->has_indicators) { +		set_port_led(hub, port1, HUB_LED_AUTO); +		hub->indicator[port1-1] = INDICATOR_AUTO;  	} -	if (udev) { -		/* TRSMRCY = 10 msec */ -		msleep(10); +#ifdef	CONFIG_USB_OTG +	/* during HNP, don't repeat the debounce */ +	if (hub->hdev->bus->is_b_host) +		portchange &= ~(USB_PORT_STAT_C_CONNECTION | +				USB_PORT_STAT_C_ENABLE); +#endif + +	/* Try to resuscitate an existing device */ +	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && +			udev->state != USB_STATE_NOTATTACHED) { +		if (portstatus & USB_PORT_STAT_ENABLE) { +			status = 0;		/* Nothing to do */ +#ifdef CONFIG_PM_RUNTIME +		} else if (udev->state == USB_STATE_SUSPENDED && +				udev->persist_enabled) { +			/* For a suspended device, treat this as a +			 * remote wakeup event. +			 */ +			usb_unlock_port(port_dev); +			status = usb_remote_wakeup(udev); +			usb_lock_port(port_dev); +#endif +		} else { +			/* Don't resuscitate */; +		} +	} +	clear_bit(port1, hub->change_bits); + +	/* successfully revalidated the connection */ +	if (status == 0) +		return; + +	usb_unlock_port(port_dev); +	hub_port_connect(hub, port1, portstatus, portchange); +	usb_lock_port(port_dev); +} + +static void port_event(struct usb_hub *hub, int port1) +		__must_hold(&port_dev->status_lock) +{ +	int connect_change, reset_device = 0; +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	struct usb_device *udev = port_dev->child; +	struct usb_device *hdev = hub->hdev; +	u16 portstatus, portchange; + +	connect_change = test_bit(port1, hub->change_bits); +	clear_bit(port1, hub->event_bits); +	clear_bit(port1, hub->wakeup_bits); + +	if (hub_port_status(hub, port1, &portstatus, &portchange) < 0) +		return; + +	if (portchange & USB_PORT_STAT_C_CONNECTION) { +		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); +		connect_change = 1; +	} + +	if (portchange & USB_PORT_STAT_C_ENABLE) { +		if (!connect_change) +			dev_dbg(&port_dev->dev, "enable change, status %08x\n", +					portstatus); +		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); + +		/* +		 * EM interference sometimes causes badly shielded USB devices +		 * to be shutdown by the hub, this hack enables them again. +		 * Works at least with mouse driver. +		 */ +		if (!(portstatus & USB_PORT_STAT_ENABLE) +		    && !connect_change && udev) { +			dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n"); +			connect_change = 1; +		} +	} +	if (portchange & USB_PORT_STAT_C_OVERCURRENT) { +		u16 status = 0, unused; + +		dev_dbg(&port_dev->dev, "over-current change\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_OVER_CURRENT); +		msleep(100);	/* Cool down */ +		hub_power_on(hub, true); +		hub_port_status(hub, port1, &status, &unused); +		if (status & USB_PORT_STAT_OVERCURRENT) +			dev_err(&port_dev->dev, "over-current condition\n"); +	} + +	if (portchange & USB_PORT_STAT_C_RESET) { +		dev_dbg(&port_dev->dev, "reset change\n"); +		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET); +	} +	if ((portchange & USB_PORT_STAT_C_BH_RESET) +	    && hub_is_superspeed(hdev)) { +		dev_dbg(&port_dev->dev, "warm reset change\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_BH_PORT_RESET); +	} +	if (portchange & USB_PORT_STAT_C_LINK_STATE) { +		dev_dbg(&port_dev->dev, "link state change\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_PORT_LINK_STATE); +	} +	if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { +		dev_warn(&port_dev->dev, "config error\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_PORT_CONFIG_ERROR); +	} + +	/* skip port actions that require the port to be powered on */ +	if (!pm_runtime_active(&port_dev->dev)) +		return; + +	if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange)) +		connect_change = 1; + +	/* +	 * Warm reset a USB3 protocol port if it's in +	 * SS.Inactive state. +	 */ +	if (hub_port_warm_reset_required(hub, portstatus)) { +		dev_dbg(&port_dev->dev, "do warm reset\n"); +		if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) +				|| udev->state == USB_STATE_NOTATTACHED) { +			if (hub_port_reset(hub, port1, NULL, +					HUB_BH_RESET_TIME, true) < 0) +				hub_port_disable(hub, port1, 1); +		} else +			reset_device = 1; +	} + +	/* +	 * On disconnect USB3 protocol ports transit from U0 to +	 * SS.Inactive to Rx.Detect. If this happens a warm- +	 * reset is not needed, but a (re)connect may happen +	 * before khubd runs and sees the disconnect, and the +	 * device may be an unknown state. +	 * +	 * If the port went through SS.Inactive without khubd +	 * seeing it the C_LINK_STATE change flag will be set, +	 * and we reset the dev to put it in a known state. +	 */ +	if (reset_device || (udev && hub_is_superspeed(hub->hdev) +				&& (portchange & USB_PORT_STAT_C_LINK_STATE) +				&& (portstatus & USB_PORT_STAT_CONNECTION))) { +		usb_unlock_port(port_dev);  		usb_lock_device(udev); -		ret = usb_remote_wakeup(udev); +		usb_reset_device(udev);  		usb_unlock_device(udev); -		if (ret < 0) -			connect_change = 1; -	} else { -		ret = -ENODEV; -		hub_port_disable(hub, port, 1); +		usb_lock_port(port_dev); +		connect_change = 0;  	} -	dev_dbg(hub->intfdev, "resume on port %d, status %d\n", -			port, ret); -	return connect_change; + +	if (connect_change) +		hub_port_connect_change(hub, port1, portstatus, portchange);  } +  static void hub_events(void)  {  	struct list_head *tmp; @@ -4617,10 +4936,7 @@ static void hub_events(void)  	struct device *hub_dev;  	u16 hubstatus;  	u16 hubchange; -	u16 portstatus; -	u16 portchange;  	int i, ret; -	int connect_change, wakeup_change;  	/*  	 *  We restart the list every time to avoid a deadlock with @@ -4694,127 +5010,28 @@ static void hub_events(void)  		/* deal with port status changes */  		for (i = 1; i <= hdev->maxchild; i++) { -			if (test_bit(i, hub->busy_bits)) -				continue; -			connect_change = test_bit(i, hub->change_bits); -			wakeup_change = test_and_clear_bit(i, hub->wakeup_bits); -			if (!test_and_clear_bit(i, hub->event_bits) && -					!connect_change && !wakeup_change) -				continue; - -			ret = hub_port_status(hub, i, -					&portstatus, &portchange); -			if (ret < 0) -				continue; - -			if (portchange & USB_PORT_STAT_C_CONNECTION) { -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_CONNECTION); -				connect_change = 1; -			} - -			if (portchange & USB_PORT_STAT_C_ENABLE) { -				if (!connect_change) -					dev_dbg (hub_dev, -						"port %d enable change, " -						"status %08x\n", -						i, portstatus); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_ENABLE); +			struct usb_port *port_dev = hub->ports[i - 1]; +			if (test_bit(i, hub->event_bits) +					|| test_bit(i, hub->change_bits) +					|| test_bit(i, hub->wakeup_bits)) {  				/* -				 * EM interference sometimes causes badly -				 * shielded USB devices to be shutdown by -				 * the hub, this hack enables them again. -				 * Works at least with mouse driver.  +				 * The get_noresume and barrier ensure that if +				 * the port was in the process of resuming, we +				 * flush that work and keep the port active for +				 * the duration of the port_event().  However, +				 * if the port is runtime pm suspended +				 * (powered-off), we leave it in that state, run +				 * an abbreviated port_event(), and move on.  				 */ -				if (!(portstatus & USB_PORT_STAT_ENABLE) -				    && !connect_change -				    && hub->ports[i - 1]->child) { -					dev_err (hub_dev, -					    "port %i " -					    "disabled by hub (EMI?), " -					    "re-enabling...\n", -						i); -					connect_change = 1; -				} +				pm_runtime_get_noresume(&port_dev->dev); +				pm_runtime_barrier(&port_dev->dev); +				usb_lock_port(port_dev); +				port_event(hub, i); +				usb_unlock_port(port_dev); +				pm_runtime_put_sync(&port_dev->dev);  			} - -			if (hub_handle_remote_wakeup(hub, i, -						portstatus, portchange)) -				connect_change = 1; - -			if (portchange & USB_PORT_STAT_C_OVERCURRENT) { -				u16 status = 0; -				u16 unused; - -				dev_dbg(hub_dev, "over-current change on port " -					"%d\n", i); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_OVER_CURRENT); -				msleep(100);	/* Cool down */ -				hub_power_on(hub, true); -				hub_port_status(hub, i, &status, &unused); -				if (status & USB_PORT_STAT_OVERCURRENT) -					dev_err(hub_dev, "over-current " -						"condition on port %d\n", i); -			} - -			if (portchange & USB_PORT_STAT_C_RESET) { -				dev_dbg (hub_dev, -					"reset change on port %d\n", -					i); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_RESET); -			} -			if ((portchange & USB_PORT_STAT_C_BH_RESET) && -					hub_is_superspeed(hub->hdev)) { -				dev_dbg(hub_dev, -					"warm reset change on port %d\n", -					i); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_BH_PORT_RESET); -			} -			if (portchange & USB_PORT_STAT_C_LINK_STATE) { -				usb_clear_port_feature(hub->hdev, i, -						USB_PORT_FEAT_C_PORT_LINK_STATE); -			} -			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { -				dev_warn(hub_dev, -					"config error on port %d\n", -					i); -				usb_clear_port_feature(hub->hdev, i, -						USB_PORT_FEAT_C_PORT_CONFIG_ERROR); -			} - -			/* Warm reset a USB3 protocol port if it's in -			 * SS.Inactive state. -			 */ -			if (hub_port_warm_reset_required(hub, portstatus)) { -				int status; -				struct usb_device *udev = -					hub->ports[i - 1]->child; - -				dev_dbg(hub_dev, "warm reset port %d\n", i); -				if (!udev || !(portstatus & -						USB_PORT_STAT_CONNECTION)) { -					status = hub_port_reset(hub, i, -							NULL, HUB_BH_RESET_TIME, -							true); -					if (status < 0) -						hub_port_disable(hub, i, 1); -				} else { -					usb_lock_device(udev); -					status = usb_reset_device(udev); -					usb_unlock_device(udev); -					connect_change = 0; -				} -			} - -			if (connect_change) -				hub_port_connect_change(hub, i, -						portstatus, portchange); -		} /* end for i */ +		}  		/* deal with hub status changes */  		if (test_and_clear_bit(0, hub->event_bits) == 0) @@ -4838,7 +5055,7 @@ static void hub_events(void)  				dev_dbg(hub_dev, "over-current change\n");  				clear_hub_feature(hdev, C_HUB_OVER_CURRENT);  				msleep(500);	/* Cool down */ -                        	hub_power_on(hub, true); +				hub_power_on(hub, true);  				hub_hub_status(hub, &status, &unused);  				if (status & HUB_STATUS_OVERCURRENT)  					dev_err(hub_dev, "over-current " @@ -4858,12 +5075,12 @@ static void hub_events(void)  		usb_unlock_device(hdev);  		kref_put(&hub->kref, hub_release); -        } /* end while (1) */ +	} /* end while (1) */  }  static int hub_thread(void *__unused)  { -	/* khubd needs to be freezable to avoid intefering with USB-PERSIST +	/* khubd needs to be freezable to avoid interfering with USB-PERSIST  	 * port handover.  Otherwise it might see that a full-speed device  	 * was gone before the EHCI controller had handed its port over to  	 * the companion full-speed controller. @@ -4883,7 +5100,7 @@ static int hub_thread(void *__unused)  static const struct usb_device_id hub_id_table[] = {      { .match_flags = USB_DEVICE_ID_MATCH_VENDOR -	           | USB_DEVICE_ID_MATCH_INT_CLASS, +			| USB_DEVICE_ID_MATCH_INT_CLASS,        .idVendor = USB_VENDOR_GENESYS_LOGIC,        .bInterfaceClass = USB_CLASS_HUB,        .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, @@ -5049,15 +5266,18 @@ static int descriptors_changed(struct usb_device *udev,   * if the reset wasn't even attempted.   *   * Note: - * The caller must own the device lock.  For example, it's safe to use - * this from a driver probe() routine after downloading new firmware. - * For calls that might not occur during probe(), drivers should lock - * the device using usb_lock_device_for_reset(). + * The caller must own the device lock and the port lock, the latter is + * taken by usb_reset_device().  For example, it's safe to use + * usb_reset_device() from a driver probe() routine after downloading + * new firmware.  For calls that might not occur during probe(), drivers + * should lock the device using usb_lock_device_for_reset().   *   * Locking exception: This routine may also be called from within an   * autoresume handler.  Such usage won't conflict with other tasks   * holding the device lock because these tasks should always call - * usb_autopm_resume_device(), thereby preventing any unwanted autoresume. + * usb_autopm_resume_device(), thereby preventing any unwanted + * autoresume.  The autoresume handler is expected to have already + * acquired the port lock before calling this routine.   */  static int usb_reset_and_verify_device(struct usb_device *udev)  { @@ -5066,7 +5286,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  	struct usb_hcd			*hcd = bus_to_hcd(udev->bus);  	struct usb_device_descriptor	descriptor = udev->descriptor;  	struct usb_host_bos		*bos; -	int 				i, ret = 0; +	int				i, j, ret = 0;  	int				port1 = udev->portnum;  	if (udev->state == USB_STATE_NOTATTACHED || @@ -5076,13 +5296,17 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  		return -EINVAL;  	} -	if (!parent_hdev) { -		/* this requires hcd-specific logic; see ohci_restart() */ -		dev_dbg(&udev->dev, "%s for root hub!\n", __func__); +	if (!parent_hdev)  		return -EISDIR; -	} +  	parent_hub = usb_hub_to_struct_hub(parent_hdev); +	/* Disable USB2 hardware LPM. +	 * It will be re-enabled by the enumeration process. +	 */ +	if (udev->usb2_hw_lpm_enabled == 1) +		usb_set_usb2_hardware_lpm(udev, 0); +  	bos = udev->bos;  	udev->bos = NULL; @@ -5103,7 +5327,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  		goto re_enumerate;  	} -	set_bit(port1, parent_hub->busy_bits);  	for (i = 0; i < SET_CONFIG_TRIES; ++i) {  		/* ep0 maxpacket size may change; let the HCD know about it. @@ -5113,17 +5336,16 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  		if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)  			break;  	} -	clear_bit(port1, parent_hub->busy_bits);  	if (ret < 0)  		goto re_enumerate; -  +  	/* Device might have changed firmware (DFU or similar) */  	if (descriptors_changed(udev, &descriptor, bos)) {  		dev_info(&udev->dev, "device firmware changed\n");  		udev->descriptor = descriptor;	/* for disconnect() calls */  		goto re_enumerate; -  	} +	}  	/* Restore the device's previous configuration */  	if (!udev->actconfig) @@ -5148,7 +5370,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  			udev->actconfig->desc.bConfigurationValue, ret);  		mutex_unlock(hcd->bandwidth_mutex);  		goto re_enumerate; -  	} +	}  	mutex_unlock(hcd->bandwidth_mutex);  	usb_set_device_state(udev, USB_STATE_CONFIGURED); @@ -5186,16 +5408,20 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  				ret);  			goto re_enumerate;  		} +		/* Resetting also frees any allocated streams */ +		for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++) +			intf->cur_altsetting->endpoint[j].streams = 0;  	}  done:  	/* Now that the alt settings are re-installed, enable LTM and LPM. */ +	usb_set_usb2_hardware_lpm(udev, 1);  	usb_unlocked_enable_lpm(udev);  	usb_enable_ltm(udev);  	usb_release_bos_descriptor(udev);  	udev->bos = bos;  	return 0; -  +  re_enumerate:  	/* LPM state doesn't matter when we're about to destroy the device. */  	hub_port_logical_disconnect(parent_hub, port1); @@ -5230,7 +5456,9 @@ int usb_reset_device(struct usb_device *udev)  	int ret;  	int i;  	unsigned int noio_flag; +	struct usb_port *port_dev;  	struct usb_host_config *config = udev->actconfig; +	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);  	if (udev->state == USB_STATE_NOTATTACHED ||  			udev->state == USB_STATE_SUSPENDED) { @@ -5239,6 +5467,14 @@ int usb_reset_device(struct usb_device *udev)  		return -EINVAL;  	} +	if (!udev->parent) { +		/* this requires hcd-specific logic; see ohci_restart() */ +		dev_dbg(&udev->dev, "%s for root hub!\n", __func__); +		return -EISDIR; +	} + +	port_dev = hub->ports[udev->portnum - 1]; +  	/*  	 * Don't allocate memory with GFP_KERNEL in current  	 * context to avoid possible deadlock if usb mass @@ -5272,7 +5508,9 @@ int usb_reset_device(struct usb_device *udev)  		}  	} +	usb_lock_port(port_dev);  	ret = usb_reset_and_verify_device(udev); +	usb_unlock_port(port_dev);  	if (config) {  		for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { @@ -5287,10 +5525,11 @@ int usb_reset_device(struct usb_device *udev)  				else if (cintf->condition ==  						USB_INTERFACE_BOUND)  					rebind = 1; +				if (rebind) +					cintf->needs_binding = 1;  			} -			if (ret == 0 && rebind) -				usb_rebind_intf(cintf);  		} +		usb_unbind_and_rebind_marked_interfaces(udev);  	}  	usb_autosuspend_device(udev); @@ -5366,56 +5605,26 @@ struct usb_device *usb_hub_find_child(struct usb_device *hdev,  }  EXPORT_SYMBOL_GPL(usb_hub_find_child); -/** - * usb_set_hub_port_connect_type - set hub port connect type. - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * @type: connect type of the port - */ -void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, -	enum usb_port_connect_type type) -{ -	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - -	if (hub) -		hub->ports[port1 - 1]->connect_type = type; -} - -/** - * usb_get_hub_port_connect_type - Get the port's connect type - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * - * Return: The connect type of the port if successful. Or - * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid. - */ -enum usb_port_connect_type -usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) -{ -	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - -	if (!hub) -		return USB_PORT_CONNECT_TYPE_UNKNOWN; - -	return hub->ports[port1 - 1]->connect_type; -} -  void usb_hub_adjust_deviceremovable(struct usb_device *hdev,  		struct usb_hub_descriptor *desc)  { +	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);  	enum usb_port_connect_type connect_type;  	int i; +	if (!hub) +		return; +  	if (!hub_is_superspeed(hdev)) {  		for (i = 1; i <= hdev->maxchild; i++) { -			connect_type = usb_get_hub_port_connect_type(hdev, i); +			struct usb_port *port_dev = hub->ports[i - 1]; +			connect_type = port_dev->connect_type;  			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {  				u8 mask = 1 << (i%8);  				if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) { -					dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", -						i); +					dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");  					desc->u.hs.DeviceRemovable[i/8]	|= mask;  				}  			} @@ -5424,14 +5633,14 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev,  		u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable);  		for (i = 1; i <= hdev->maxchild; i++) { -			connect_type = usb_get_hub_port_connect_type(hdev, i); +			struct usb_port *port_dev = hub->ports[i - 1]; +			connect_type = port_dev->connect_type;  			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {  				u16 mask = 1 << i;  				if (!(port_removable & mask)) { -					dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", -						i); +					dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");  					port_removable |= mask;  				}  			} @@ -5458,6 +5667,6 @@ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,  	if (!hub)  		return NULL; -	return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev); +	return ACPI_HANDLE(&hub->ports[port1 - 1]->dev);  }  #endif  | 
