18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * USB hub driver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * (C) Copyright 1999 Linus Torvalds
68c2ecf20Sopenharmony_ci * (C) Copyright 1999 Johannes Erdfelt
78c2ecf20Sopenharmony_ci * (C) Copyright 1999 Gregory P. Smith
88c2ecf20Sopenharmony_ci * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au)
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Released under the GPLv2 only.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
178c2ecf20Sopenharmony_ci#include <linux/completion.h>
188c2ecf20Sopenharmony_ci#include <linux/sched/mm.h>
198c2ecf20Sopenharmony_ci#include <linux/list.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/kcov.h>
228c2ecf20Sopenharmony_ci#include <linux/ioctl.h>
238c2ecf20Sopenharmony_ci#include <linux/usb.h>
248c2ecf20Sopenharmony_ci#include <linux/usbdevice_fs.h>
258c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h>
268c2ecf20Sopenharmony_ci#include <linux/usb/otg.h>
278c2ecf20Sopenharmony_ci#include <linux/usb/quirks.h>
288c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
298c2ecf20Sopenharmony_ci#include <linux/mutex.h>
308c2ecf20Sopenharmony_ci#include <linux/random.h>
318c2ecf20Sopenharmony_ci#include <linux/pm_qos.h>
328c2ecf20Sopenharmony_ci#include <linux/kobject.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
358c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
368c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include "hub.h"
398c2ecf20Sopenharmony_ci#include "otg_productlist.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define USB_VENDOR_GENESYS_LOGIC		0x05e3
428c2ecf20Sopenharmony_ci#define USB_VENDOR_SMSC				0x0424
438c2ecf20Sopenharmony_ci#define USB_PRODUCT_USB5534B			0x5534
448c2ecf20Sopenharmony_ci#define USB_VENDOR_CYPRESS			0x04b4
458c2ecf20Sopenharmony_ci#define USB_PRODUCT_CY7C65632			0x6570
468c2ecf20Sopenharmony_ci#define USB_VENDOR_TEXAS_INSTRUMENTS		0x0451
478c2ecf20Sopenharmony_ci#define USB_PRODUCT_TUSB8041_USB3		0x8140
488c2ecf20Sopenharmony_ci#define USB_PRODUCT_TUSB8041_USB2		0x8142
498c2ecf20Sopenharmony_ci#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND	BIT(0)
508c2ecf20Sopenharmony_ci#define HUB_QUIRK_DISABLE_AUTOSUSPEND		BIT(1)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define USB_TP_TRANSMISSION_DELAY	40	/* ns */
538c2ecf20Sopenharmony_ci#define USB_TP_TRANSMISSION_DELAY_MAX	65535	/* ns */
548c2ecf20Sopenharmony_ci#define USB_PING_RESPONSE_TIME		400	/* ns */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* Protect struct usb_device->state and ->children members
578c2ecf20Sopenharmony_ci * Note: Both are also protected by ->dev.sem, except that ->state can
588c2ecf20Sopenharmony_ci * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
598c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(device_state_lock);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* workqueue to process hub events */
628c2ecf20Sopenharmony_cistatic struct workqueue_struct *hub_wq;
638c2ecf20Sopenharmony_cistatic void hub_event(struct work_struct *work);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* synchronize hub-port add/remove and peering operations */
668c2ecf20Sopenharmony_ciDEFINE_MUTEX(usb_port_peer_mutex);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* cycle leds on hubs that aren't blinking for attention */
698c2ecf20Sopenharmony_cistatic bool blinkenlights;
708c2ecf20Sopenharmony_cimodule_param(blinkenlights, bool, S_IRUGO);
718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs");
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about
758c2ecf20Sopenharmony_ci * 10 seconds to send reply for the initial 64-byte descriptor request.
768c2ecf20Sopenharmony_ci */
778c2ecf20Sopenharmony_ci/* define initial 64-byte descriptor request timeout in milliseconds */
788c2ecf20Sopenharmony_cistatic int initial_descriptor_timeout = USB_CTRL_GET_TIMEOUT;
798c2ecf20Sopenharmony_cimodule_param(initial_descriptor_timeout, int, S_IRUGO|S_IWUSR);
808c2ecf20Sopenharmony_ciMODULE_PARM_DESC(initial_descriptor_timeout,
818c2ecf20Sopenharmony_ci		"initial 64-byte descriptor request timeout in milliseconds "
828c2ecf20Sopenharmony_ci		"(default 5000 - 5.0 seconds)");
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/*
858c2ecf20Sopenharmony_ci * As of 2.6.10 we introduce a new USB device initialization scheme which
868c2ecf20Sopenharmony_ci * closely resembles the way Windows works.  Hopefully it will be compatible
878c2ecf20Sopenharmony_ci * with a wider range of devices than the old scheme.  However some previously
888c2ecf20Sopenharmony_ci * working devices may start giving rise to "device not accepting address"
898c2ecf20Sopenharmony_ci * errors; if that happens the user can try the old scheme by adjusting the
908c2ecf20Sopenharmony_ci * following module parameters.
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * For maximum flexibility there are two boolean parameters to control the
938c2ecf20Sopenharmony_ci * hub driver's behavior.  On the first initialization attempt, if the
948c2ecf20Sopenharmony_ci * "old_scheme_first" parameter is set then the old scheme will be used,
958c2ecf20Sopenharmony_ci * otherwise the new scheme is used.  If that fails and "use_both_schemes"
968c2ecf20Sopenharmony_ci * is set, then the driver will make another attempt, using the other scheme.
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_cistatic bool old_scheme_first;
998c2ecf20Sopenharmony_cimodule_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
1008c2ecf20Sopenharmony_ciMODULE_PARM_DESC(old_scheme_first,
1018c2ecf20Sopenharmony_ci		 "start with the old device initialization scheme");
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic bool use_both_schemes = true;
1048c2ecf20Sopenharmony_cimodule_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
1058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_both_schemes,
1068c2ecf20Sopenharmony_ci		"try the other device initialization scheme if the "
1078c2ecf20Sopenharmony_ci		"first one fails");
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/* Mutual exclusion for EHCI CF initialization.  This interferes with
1108c2ecf20Sopenharmony_ci * port reset on some companion controllers.
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_ciDECLARE_RWSEM(ehci_cf_port_reset_rwsem);
1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define HUB_DEBOUNCE_TIMEOUT	2000
1168c2ecf20Sopenharmony_ci#define HUB_DEBOUNCE_STEP	  25
1178c2ecf20Sopenharmony_ci#define HUB_DEBOUNCE_STABLE	 100
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void hub_release(struct kref *kref);
1208c2ecf20Sopenharmony_cistatic int usb_reset_and_verify_device(struct usb_device *udev);
1218c2ecf20Sopenharmony_cistatic int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
1228c2ecf20Sopenharmony_cistatic bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
1238c2ecf20Sopenharmony_ci		u16 portstatus);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic inline char *portspeed(struct usb_hub *hub, int portstatus)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	if (hub_is_superspeedplus(hub->hdev))
1288c2ecf20Sopenharmony_ci		return "10.0 Gb/s";
1298c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hub->hdev))
1308c2ecf20Sopenharmony_ci		return "5.0 Gb/s";
1318c2ecf20Sopenharmony_ci	if (portstatus & USB_PORT_STAT_HIGH_SPEED)
1328c2ecf20Sopenharmony_ci		return "480 Mb/s";
1338c2ecf20Sopenharmony_ci	else if (portstatus & USB_PORT_STAT_LOW_SPEED)
1348c2ecf20Sopenharmony_ci		return "1.5 Mb/s";
1358c2ecf20Sopenharmony_ci	else
1368c2ecf20Sopenharmony_ci		return "12 Mb/s";
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/* Note that hdev or one of its children must be locked! */
1408c2ecf20Sopenharmony_cistruct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	if (!hdev || !hdev->actconfig || !hdev->maxchild)
1438c2ecf20Sopenharmony_ci		return NULL;
1448c2ecf20Sopenharmony_ci	return usb_get_intfdata(hdev->actconfig->interface[0]);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ciint usb_device_supports_lpm(struct usb_device *udev)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	/* Some devices have trouble with LPM */
1508c2ecf20Sopenharmony_ci	if (udev->quirks & USB_QUIRK_NO_LPM)
1518c2ecf20Sopenharmony_ci		return 0;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* Skip if the device BOS descriptor couldn't be read */
1548c2ecf20Sopenharmony_ci	if (!udev->bos)
1558c2ecf20Sopenharmony_ci		return 0;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* USB 2.1 (and greater) devices indicate LPM support through
1588c2ecf20Sopenharmony_ci	 * their USB 2.0 Extended Capabilities BOS descriptor.
1598c2ecf20Sopenharmony_ci	 */
1608c2ecf20Sopenharmony_ci	if (udev->speed == USB_SPEED_HIGH || udev->speed == USB_SPEED_FULL) {
1618c2ecf20Sopenharmony_ci		if (udev->bos->ext_cap &&
1628c2ecf20Sopenharmony_ci			(USB_LPM_SUPPORT &
1638c2ecf20Sopenharmony_ci			 le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
1648c2ecf20Sopenharmony_ci			return 1;
1658c2ecf20Sopenharmony_ci		return 0;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/*
1698c2ecf20Sopenharmony_ci	 * According to the USB 3.0 spec, all USB 3.0 devices must support LPM.
1708c2ecf20Sopenharmony_ci	 * However, there are some that don't, and they set the U1/U2 exit
1718c2ecf20Sopenharmony_ci	 * latencies to zero.
1728c2ecf20Sopenharmony_ci	 */
1738c2ecf20Sopenharmony_ci	if (!udev->bos->ss_cap) {
1748c2ecf20Sopenharmony_ci		dev_info(&udev->dev, "No LPM exit latency info found, disabling LPM.\n");
1758c2ecf20Sopenharmony_ci		return 0;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (udev->bos->ss_cap->bU1devExitLat == 0 &&
1798c2ecf20Sopenharmony_ci			udev->bos->ss_cap->bU2DevExitLat == 0) {
1808c2ecf20Sopenharmony_ci		if (udev->parent)
1818c2ecf20Sopenharmony_ci			dev_info(&udev->dev, "LPM exit latency is zeroed, disabling LPM.\n");
1828c2ecf20Sopenharmony_ci		else
1838c2ecf20Sopenharmony_ci			dev_info(&udev->dev, "We don't know the algorithms for LPM for this host, disabling LPM.\n");
1848c2ecf20Sopenharmony_ci		return 0;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (!udev->parent || udev->parent->lpm_capable)
1888c2ecf20Sopenharmony_ci		return 1;
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/*
1938c2ecf20Sopenharmony_ci * Set the Maximum Exit Latency (MEL) for the host to wakup up the path from
1948c2ecf20Sopenharmony_ci * U1/U2, send a PING to the device and receive a PING_RESPONSE.
1958c2ecf20Sopenharmony_ci * See USB 3.1 section C.1.5.2
1968c2ecf20Sopenharmony_ci */
1978c2ecf20Sopenharmony_cistatic void usb_set_lpm_mel(struct usb_device *udev,
1988c2ecf20Sopenharmony_ci		struct usb3_lpm_parameters *udev_lpm_params,
1998c2ecf20Sopenharmony_ci		unsigned int udev_exit_latency,
2008c2ecf20Sopenharmony_ci		struct usb_hub *hub,
2018c2ecf20Sopenharmony_ci		struct usb3_lpm_parameters *hub_lpm_params,
2028c2ecf20Sopenharmony_ci		unsigned int hub_exit_latency)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	unsigned int total_mel;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/*
2078c2ecf20Sopenharmony_ci	 * tMEL1. time to transition path from host to device into U0.
2088c2ecf20Sopenharmony_ci	 * MEL for parent already contains the delay up to parent, so only add
2098c2ecf20Sopenharmony_ci	 * the exit latency for the last link (pick the slower exit latency),
2108c2ecf20Sopenharmony_ci	 * and the hub header decode latency. See USB 3.1 section C 2.2.1
2118c2ecf20Sopenharmony_ci	 * Store MEL in nanoseconds
2128c2ecf20Sopenharmony_ci	 */
2138c2ecf20Sopenharmony_ci	total_mel = hub_lpm_params->mel +
2148c2ecf20Sopenharmony_ci		max(udev_exit_latency, hub_exit_latency) * 1000 +
2158c2ecf20Sopenharmony_ci		hub->descriptor->u.ss.bHubHdrDecLat * 100;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/*
2188c2ecf20Sopenharmony_ci	 * tMEL2. Time to submit PING packet. Sum of tTPTransmissionDelay for
2198c2ecf20Sopenharmony_ci	 * each link + wHubDelay for each hub. Add only for last link.
2208c2ecf20Sopenharmony_ci	 * tMEL4, the time for PING_RESPONSE to traverse upstream is similar.
2218c2ecf20Sopenharmony_ci	 * Multiply by 2 to include it as well.
2228c2ecf20Sopenharmony_ci	 */
2238c2ecf20Sopenharmony_ci	total_mel += (__le16_to_cpu(hub->descriptor->u.ss.wHubDelay) +
2248c2ecf20Sopenharmony_ci		      USB_TP_TRANSMISSION_DELAY) * 2;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/*
2278c2ecf20Sopenharmony_ci	 * tMEL3, tPingResponse. Time taken by device to generate PING_RESPONSE
2288c2ecf20Sopenharmony_ci	 * after receiving PING. Also add 2100ns as stated in USB 3.1 C 1.5.2.4
2298c2ecf20Sopenharmony_ci	 * to cover the delay if the PING_RESPONSE is queued behind a Max Packet
2308c2ecf20Sopenharmony_ci	 * Size DP.
2318c2ecf20Sopenharmony_ci	 * Note these delays should be added only once for the entire path, so
2328c2ecf20Sopenharmony_ci	 * add them to the MEL of the device connected to the roothub.
2338c2ecf20Sopenharmony_ci	 */
2348c2ecf20Sopenharmony_ci	if (!hub->hdev->parent)
2358c2ecf20Sopenharmony_ci		total_mel += USB_PING_RESPONSE_TIME + 2100;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	udev_lpm_params->mel = total_mel;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci/*
2418c2ecf20Sopenharmony_ci * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate
2428c2ecf20Sopenharmony_ci * a transition from either U1 or U2.
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_cistatic void usb_set_lpm_pel(struct usb_device *udev,
2458c2ecf20Sopenharmony_ci		struct usb3_lpm_parameters *udev_lpm_params,
2468c2ecf20Sopenharmony_ci		unsigned int udev_exit_latency,
2478c2ecf20Sopenharmony_ci		struct usb_hub *hub,
2488c2ecf20Sopenharmony_ci		struct usb3_lpm_parameters *hub_lpm_params,
2498c2ecf20Sopenharmony_ci		unsigned int hub_exit_latency,
2508c2ecf20Sopenharmony_ci		unsigned int port_to_port_exit_latency)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	unsigned int first_link_pel;
2538c2ecf20Sopenharmony_ci	unsigned int hub_pel;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/*
2568c2ecf20Sopenharmony_ci	 * First, the device sends an LFPS to transition the link between the
2578c2ecf20Sopenharmony_ci	 * device and the parent hub into U0.  The exit latency is the bigger of
2588c2ecf20Sopenharmony_ci	 * the device exit latency or the hub exit latency.
2598c2ecf20Sopenharmony_ci	 */
2608c2ecf20Sopenharmony_ci	if (udev_exit_latency > hub_exit_latency)
2618c2ecf20Sopenharmony_ci		first_link_pel = udev_exit_latency * 1000;
2628c2ecf20Sopenharmony_ci	else
2638c2ecf20Sopenharmony_ci		first_link_pel = hub_exit_latency * 1000;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	/*
2668c2ecf20Sopenharmony_ci	 * When the hub starts to receive the LFPS, there is a slight delay for
2678c2ecf20Sopenharmony_ci	 * it to figure out that one of the ports is sending an LFPS.  Then it
2688c2ecf20Sopenharmony_ci	 * will forward the LFPS to its upstream link.  The exit latency is the
2698c2ecf20Sopenharmony_ci	 * delay, plus the PEL that we calculated for this hub.
2708c2ecf20Sopenharmony_ci	 */
2718c2ecf20Sopenharmony_ci	hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/*
2748c2ecf20Sopenharmony_ci	 * According to figure C-7 in the USB 3.0 spec, the PEL for this device
2758c2ecf20Sopenharmony_ci	 * is the greater of the two exit latencies.
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	if (first_link_pel > hub_pel)
2788c2ecf20Sopenharmony_ci		udev_lpm_params->pel = first_link_pel;
2798c2ecf20Sopenharmony_ci	else
2808c2ecf20Sopenharmony_ci		udev_lpm_params->pel = hub_pel;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/*
2848c2ecf20Sopenharmony_ci * Set the System Exit Latency (SEL) to indicate the total worst-case time from
2858c2ecf20Sopenharmony_ci * when a device initiates a transition to U0, until when it will receive the
2868c2ecf20Sopenharmony_ci * first packet from the host controller.
2878c2ecf20Sopenharmony_ci *
2888c2ecf20Sopenharmony_ci * Section C.1.5.1 describes the four components to this:
2898c2ecf20Sopenharmony_ci *  - t1: device PEL
2908c2ecf20Sopenharmony_ci *  - t2: time for the ERDY to make it from the device to the host.
2918c2ecf20Sopenharmony_ci *  - t3: a host-specific delay to process the ERDY.
2928c2ecf20Sopenharmony_ci *  - t4: time for the packet to make it from the host to the device.
2938c2ecf20Sopenharmony_ci *
2948c2ecf20Sopenharmony_ci * t3 is specific to both the xHCI host and the platform the host is integrated
2958c2ecf20Sopenharmony_ci * into.  The Intel HW folks have said it's negligible, FIXME if a different
2968c2ecf20Sopenharmony_ci * vendor says otherwise.
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_cistatic void usb_set_lpm_sel(struct usb_device *udev,
2998c2ecf20Sopenharmony_ci		struct usb3_lpm_parameters *udev_lpm_params)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct usb_device *parent;
3028c2ecf20Sopenharmony_ci	unsigned int num_hubs;
3038c2ecf20Sopenharmony_ci	unsigned int total_sel;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* t1 = device PEL */
3068c2ecf20Sopenharmony_ci	total_sel = udev_lpm_params->pel;
3078c2ecf20Sopenharmony_ci	/* How many external hubs are in between the device & the root port. */
3088c2ecf20Sopenharmony_ci	for (parent = udev->parent, num_hubs = 0; parent->parent;
3098c2ecf20Sopenharmony_ci			parent = parent->parent)
3108c2ecf20Sopenharmony_ci		num_hubs++;
3118c2ecf20Sopenharmony_ci	/* t2 = 2.1us + 250ns * (num_hubs - 1) */
3128c2ecf20Sopenharmony_ci	if (num_hubs > 0)
3138c2ecf20Sopenharmony_ci		total_sel += 2100 + 250 * (num_hubs - 1);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/* t4 = 250ns * num_hubs */
3168c2ecf20Sopenharmony_ci	total_sel += 250 * num_hubs;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	udev_lpm_params->sel = total_sel;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void usb_set_lpm_parameters(struct usb_device *udev)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct usb_hub *hub;
3248c2ecf20Sopenharmony_ci	unsigned int port_to_port_delay;
3258c2ecf20Sopenharmony_ci	unsigned int udev_u1_del;
3268c2ecf20Sopenharmony_ci	unsigned int udev_u2_del;
3278c2ecf20Sopenharmony_ci	unsigned int hub_u1_del;
3288c2ecf20Sopenharmony_ci	unsigned int hub_u2_del;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
3318c2ecf20Sopenharmony_ci		return;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* Skip if the device BOS descriptor couldn't be read */
3348c2ecf20Sopenharmony_ci	if (!udev->bos)
3358c2ecf20Sopenharmony_ci		return;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	hub = usb_hub_to_struct_hub(udev->parent);
3388c2ecf20Sopenharmony_ci	/* It doesn't take time to transition the roothub into U0, since it
3398c2ecf20Sopenharmony_ci	 * doesn't have an upstream link.
3408c2ecf20Sopenharmony_ci	 */
3418c2ecf20Sopenharmony_ci	if (!hub)
3428c2ecf20Sopenharmony_ci		return;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	udev_u1_del = udev->bos->ss_cap->bU1devExitLat;
3458c2ecf20Sopenharmony_ci	udev_u2_del = le16_to_cpu(udev->bos->ss_cap->bU2DevExitLat);
3468c2ecf20Sopenharmony_ci	hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat;
3478c2ecf20Sopenharmony_ci	hub_u2_del = le16_to_cpu(udev->parent->bos->ss_cap->bU2DevExitLat);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,
3508c2ecf20Sopenharmony_ci			hub, &udev->parent->u1_params, hub_u1_del);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del,
3538c2ecf20Sopenharmony_ci			hub, &udev->parent->u2_params, hub_u2_del);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/*
3568c2ecf20Sopenharmony_ci	 * Appendix C, section C.2.2.2, says that there is a slight delay from
3578c2ecf20Sopenharmony_ci	 * when the parent hub notices the downstream port is trying to
3588c2ecf20Sopenharmony_ci	 * transition to U0 to when the hub initiates a U0 transition on its
3598c2ecf20Sopenharmony_ci	 * upstream port.  The section says the delays are tPort2PortU1EL and
3608c2ecf20Sopenharmony_ci	 * tPort2PortU2EL, but it doesn't define what they are.
3618c2ecf20Sopenharmony_ci	 *
3628c2ecf20Sopenharmony_ci	 * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking
3638c2ecf20Sopenharmony_ci	 * about the same delays.  Use the maximum delay calculations from those
3648c2ecf20Sopenharmony_ci	 * sections.  For U1, it's tHubPort2PortExitLat, which is 1us max.  For
3658c2ecf20Sopenharmony_ci	 * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat.  I
3668c2ecf20Sopenharmony_ci	 * assume the device exit latencies they are talking about are the hub
3678c2ecf20Sopenharmony_ci	 * exit latencies.
3688c2ecf20Sopenharmony_ci	 *
3698c2ecf20Sopenharmony_ci	 * What do we do if the U2 exit latency is less than the U1 exit
3708c2ecf20Sopenharmony_ci	 * latency?  It's possible, although not likely...
3718c2ecf20Sopenharmony_ci	 */
3728c2ecf20Sopenharmony_ci	port_to_port_delay = 1;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del,
3758c2ecf20Sopenharmony_ci			hub, &udev->parent->u1_params, hub_u1_del,
3768c2ecf20Sopenharmony_ci			port_to_port_delay);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (hub_u2_del > hub_u1_del)
3798c2ecf20Sopenharmony_ci		port_to_port_delay = 1 + hub_u2_del - hub_u1_del;
3808c2ecf20Sopenharmony_ci	else
3818c2ecf20Sopenharmony_ci		port_to_port_delay = 1 + hub_u1_del;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del,
3848c2ecf20Sopenharmony_ci			hub, &udev->parent->u2_params, hub_u2_del,
3858c2ecf20Sopenharmony_ci			port_to_port_delay);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* Now that we've got PEL, calculate SEL. */
3888c2ecf20Sopenharmony_ci	usb_set_lpm_sel(udev, &udev->u1_params);
3898c2ecf20Sopenharmony_ci	usb_set_lpm_sel(udev, &udev->u2_params);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/* USB 2.0 spec Section 11.24.4.5 */
3938c2ecf20Sopenharmony_cistatic int get_hub_descriptor(struct usb_device *hdev,
3948c2ecf20Sopenharmony_ci		struct usb_hub_descriptor *desc)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	int i, ret, size;
3978c2ecf20Sopenharmony_ci	unsigned dtype;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hdev)) {
4008c2ecf20Sopenharmony_ci		dtype = USB_DT_SS_HUB;
4018c2ecf20Sopenharmony_ci		size = USB_DT_SS_HUB_SIZE;
4028c2ecf20Sopenharmony_ci	} else {
4038c2ecf20Sopenharmony_ci		dtype = USB_DT_HUB;
4048c2ecf20Sopenharmony_ci		size = sizeof(struct usb_hub_descriptor);
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
4088c2ecf20Sopenharmony_ci		ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
4098c2ecf20Sopenharmony_ci			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
4108c2ecf20Sopenharmony_ci			dtype << 8, 0, desc, size,
4118c2ecf20Sopenharmony_ci			USB_CTRL_GET_TIMEOUT);
4128c2ecf20Sopenharmony_ci		if (hub_is_superspeed(hdev)) {
4138c2ecf20Sopenharmony_ci			if (ret == size)
4148c2ecf20Sopenharmony_ci				return ret;
4158c2ecf20Sopenharmony_ci		} else if (ret >= USB_DT_HUB_NONVAR_SIZE + 2) {
4168c2ecf20Sopenharmony_ci			/* Make sure we have the DeviceRemovable field. */
4178c2ecf20Sopenharmony_ci			size = USB_DT_HUB_NONVAR_SIZE + desc->bNbrPorts / 8 + 1;
4188c2ecf20Sopenharmony_ci			if (ret < size)
4198c2ecf20Sopenharmony_ci				return -EMSGSIZE;
4208c2ecf20Sopenharmony_ci			return ret;
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	return -EINVAL;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci/*
4278c2ecf20Sopenharmony_ci * USB 2.0 spec Section 11.24.2.1
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_cistatic int clear_hub_feature(struct usb_device *hdev, int feature)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
4328c2ecf20Sopenharmony_ci		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, 1000);
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci/*
4368c2ecf20Sopenharmony_ci * USB 2.0 spec Section 11.24.2.2
4378c2ecf20Sopenharmony_ci */
4388c2ecf20Sopenharmony_ciint usb_clear_port_feature(struct usb_device *hdev, int port1, int feature)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
4418c2ecf20Sopenharmony_ci		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
4428c2ecf20Sopenharmony_ci		NULL, 0, 1000);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci/*
4468c2ecf20Sopenharmony_ci * USB 2.0 spec Section 11.24.2.13
4478c2ecf20Sopenharmony_ci */
4488c2ecf20Sopenharmony_cistatic int set_port_feature(struct usb_device *hdev, int port1, int feature)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
4518c2ecf20Sopenharmony_ci		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
4528c2ecf20Sopenharmony_ci		NULL, 0, 1000);
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic char *to_led_name(int selector)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	switch (selector) {
4588c2ecf20Sopenharmony_ci	case HUB_LED_AMBER:
4598c2ecf20Sopenharmony_ci		return "amber";
4608c2ecf20Sopenharmony_ci	case HUB_LED_GREEN:
4618c2ecf20Sopenharmony_ci		return "green";
4628c2ecf20Sopenharmony_ci	case HUB_LED_OFF:
4638c2ecf20Sopenharmony_ci		return "off";
4648c2ecf20Sopenharmony_ci	case HUB_LED_AUTO:
4658c2ecf20Sopenharmony_ci		return "auto";
4668c2ecf20Sopenharmony_ci	default:
4678c2ecf20Sopenharmony_ci		return "??";
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci/*
4728c2ecf20Sopenharmony_ci * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7
4738c2ecf20Sopenharmony_ci * for info about using port indicators
4748c2ecf20Sopenharmony_ci */
4758c2ecf20Sopenharmony_cistatic void set_port_led(struct usb_hub *hub, int port1, int selector)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
4788c2ecf20Sopenharmony_ci	int status;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	status = set_port_feature(hub->hdev, (selector << 8) | port1,
4818c2ecf20Sopenharmony_ci			USB_PORT_FEAT_INDICATOR);
4828c2ecf20Sopenharmony_ci	dev_dbg(&port_dev->dev, "indicator %s status %d\n",
4838c2ecf20Sopenharmony_ci		to_led_name(selector), status);
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci#define	LED_CYCLE_PERIOD	((2*HZ)/3)
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic void led_work(struct work_struct *work)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	struct usb_hub		*hub =
4918c2ecf20Sopenharmony_ci		container_of(work, struct usb_hub, leds.work);
4928c2ecf20Sopenharmony_ci	struct usb_device	*hdev = hub->hdev;
4938c2ecf20Sopenharmony_ci	unsigned		i;
4948c2ecf20Sopenharmony_ci	unsigned		changed = 0;
4958c2ecf20Sopenharmony_ci	int			cursor = -1;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing)
4988c2ecf20Sopenharmony_ci		return;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	for (i = 0; i < hdev->maxchild; i++) {
5018c2ecf20Sopenharmony_ci		unsigned	selector, mode;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		/* 30%-50% duty cycle */
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		switch (hub->indicator[i]) {
5068c2ecf20Sopenharmony_ci		/* cycle marker */
5078c2ecf20Sopenharmony_ci		case INDICATOR_CYCLE:
5088c2ecf20Sopenharmony_ci			cursor = i;
5098c2ecf20Sopenharmony_ci			selector = HUB_LED_AUTO;
5108c2ecf20Sopenharmony_ci			mode = INDICATOR_AUTO;
5118c2ecf20Sopenharmony_ci			break;
5128c2ecf20Sopenharmony_ci		/* blinking green = sw attention */
5138c2ecf20Sopenharmony_ci		case INDICATOR_GREEN_BLINK:
5148c2ecf20Sopenharmony_ci			selector = HUB_LED_GREEN;
5158c2ecf20Sopenharmony_ci			mode = INDICATOR_GREEN_BLINK_OFF;
5168c2ecf20Sopenharmony_ci			break;
5178c2ecf20Sopenharmony_ci		case INDICATOR_GREEN_BLINK_OFF:
5188c2ecf20Sopenharmony_ci			selector = HUB_LED_OFF;
5198c2ecf20Sopenharmony_ci			mode = INDICATOR_GREEN_BLINK;
5208c2ecf20Sopenharmony_ci			break;
5218c2ecf20Sopenharmony_ci		/* blinking amber = hw attention */
5228c2ecf20Sopenharmony_ci		case INDICATOR_AMBER_BLINK:
5238c2ecf20Sopenharmony_ci			selector = HUB_LED_AMBER;
5248c2ecf20Sopenharmony_ci			mode = INDICATOR_AMBER_BLINK_OFF;
5258c2ecf20Sopenharmony_ci			break;
5268c2ecf20Sopenharmony_ci		case INDICATOR_AMBER_BLINK_OFF:
5278c2ecf20Sopenharmony_ci			selector = HUB_LED_OFF;
5288c2ecf20Sopenharmony_ci			mode = INDICATOR_AMBER_BLINK;
5298c2ecf20Sopenharmony_ci			break;
5308c2ecf20Sopenharmony_ci		/* blink green/amber = reserved */
5318c2ecf20Sopenharmony_ci		case INDICATOR_ALT_BLINK:
5328c2ecf20Sopenharmony_ci			selector = HUB_LED_GREEN;
5338c2ecf20Sopenharmony_ci			mode = INDICATOR_ALT_BLINK_OFF;
5348c2ecf20Sopenharmony_ci			break;
5358c2ecf20Sopenharmony_ci		case INDICATOR_ALT_BLINK_OFF:
5368c2ecf20Sopenharmony_ci			selector = HUB_LED_AMBER;
5378c2ecf20Sopenharmony_ci			mode = INDICATOR_ALT_BLINK;
5388c2ecf20Sopenharmony_ci			break;
5398c2ecf20Sopenharmony_ci		default:
5408c2ecf20Sopenharmony_ci			continue;
5418c2ecf20Sopenharmony_ci		}
5428c2ecf20Sopenharmony_ci		if (selector != HUB_LED_AUTO)
5438c2ecf20Sopenharmony_ci			changed = 1;
5448c2ecf20Sopenharmony_ci		set_port_led(hub, i + 1, selector);
5458c2ecf20Sopenharmony_ci		hub->indicator[i] = mode;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	if (!changed && blinkenlights) {
5488c2ecf20Sopenharmony_ci		cursor++;
5498c2ecf20Sopenharmony_ci		cursor %= hdev->maxchild;
5508c2ecf20Sopenharmony_ci		set_port_led(hub, cursor + 1, HUB_LED_GREEN);
5518c2ecf20Sopenharmony_ci		hub->indicator[cursor] = INDICATOR_CYCLE;
5528c2ecf20Sopenharmony_ci		changed++;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	if (changed)
5558c2ecf20Sopenharmony_ci		queue_delayed_work(system_power_efficient_wq,
5568c2ecf20Sopenharmony_ci				&hub->leds, LED_CYCLE_PERIOD);
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci/* use a short timeout for hub/port status fetches */
5608c2ecf20Sopenharmony_ci#define	USB_STS_TIMEOUT		1000
5618c2ecf20Sopenharmony_ci#define	USB_STS_RETRIES		5
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci/*
5648c2ecf20Sopenharmony_ci * USB 2.0 spec Section 11.24.2.6
5658c2ecf20Sopenharmony_ci */
5668c2ecf20Sopenharmony_cistatic int get_hub_status(struct usb_device *hdev,
5678c2ecf20Sopenharmony_ci		struct usb_hub_status *data)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	int i, status = -ETIMEDOUT;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	for (i = 0; i < USB_STS_RETRIES &&
5728c2ecf20Sopenharmony_ci			(status == -ETIMEDOUT || status == -EPIPE); i++) {
5738c2ecf20Sopenharmony_ci		status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
5748c2ecf20Sopenharmony_ci			USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
5758c2ecf20Sopenharmony_ci			data, sizeof(*data), USB_STS_TIMEOUT);
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci	return status;
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci/*
5818c2ecf20Sopenharmony_ci * USB 2.0 spec Section 11.24.2.7
5828c2ecf20Sopenharmony_ci * USB 3.1 takes into use the wValue and wLength fields, spec Section 10.16.2.6
5838c2ecf20Sopenharmony_ci */
5848c2ecf20Sopenharmony_cistatic int get_port_status(struct usb_device *hdev, int port1,
5858c2ecf20Sopenharmony_ci			   void *data, u16 value, u16 length)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	int i, status = -ETIMEDOUT;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	for (i = 0; i < USB_STS_RETRIES &&
5908c2ecf20Sopenharmony_ci			(status == -ETIMEDOUT || status == -EPIPE); i++) {
5918c2ecf20Sopenharmony_ci		status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
5928c2ecf20Sopenharmony_ci			USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value,
5938c2ecf20Sopenharmony_ci			port1, data, length, USB_STS_TIMEOUT);
5948c2ecf20Sopenharmony_ci	}
5958c2ecf20Sopenharmony_ci	return status;
5968c2ecf20Sopenharmony_ci}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_cistatic int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
5998c2ecf20Sopenharmony_ci			       u16 *status, u16 *change, u32 *ext_status)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	int ret;
6028c2ecf20Sopenharmony_ci	int len = 4;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	if (type != HUB_PORT_STATUS)
6058c2ecf20Sopenharmony_ci		len = 8;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	mutex_lock(&hub->status_mutex);
6088c2ecf20Sopenharmony_ci	ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len);
6098c2ecf20Sopenharmony_ci	if (ret < len) {
6108c2ecf20Sopenharmony_ci		if (ret != -ENODEV)
6118c2ecf20Sopenharmony_ci			dev_err(hub->intfdev,
6128c2ecf20Sopenharmony_ci				"%s failed (err = %d)\n", __func__, ret);
6138c2ecf20Sopenharmony_ci		if (ret >= 0)
6148c2ecf20Sopenharmony_ci			ret = -EIO;
6158c2ecf20Sopenharmony_ci	} else {
6168c2ecf20Sopenharmony_ci		*status = le16_to_cpu(hub->status->port.wPortStatus);
6178c2ecf20Sopenharmony_ci		*change = le16_to_cpu(hub->status->port.wPortChange);
6188c2ecf20Sopenharmony_ci		if (type != HUB_PORT_STATUS && ext_status)
6198c2ecf20Sopenharmony_ci			*ext_status = le32_to_cpu(
6208c2ecf20Sopenharmony_ci				hub->status->port.dwExtPortStatus);
6218c2ecf20Sopenharmony_ci		ret = 0;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci	mutex_unlock(&hub->status_mutex);
6248c2ecf20Sopenharmony_ci	return ret;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_cistatic int hub_port_status(struct usb_hub *hub, int port1,
6288c2ecf20Sopenharmony_ci		u16 *status, u16 *change)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	return hub_ext_port_status(hub, port1, HUB_PORT_STATUS,
6318c2ecf20Sopenharmony_ci				   status, change, NULL);
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cistatic void hub_resubmit_irq_urb(struct usb_hub *hub)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	unsigned long flags;
6378c2ecf20Sopenharmony_ci	int status;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hub->irq_urb_lock, flags);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (hub->quiescing) {
6428c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hub->irq_urb_lock, flags);
6438c2ecf20Sopenharmony_ci		return;
6448c2ecf20Sopenharmony_ci	}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	status = usb_submit_urb(hub->urb, GFP_ATOMIC);
6478c2ecf20Sopenharmony_ci	if (status && status != -ENODEV && status != -EPERM &&
6488c2ecf20Sopenharmony_ci	    status != -ESHUTDOWN) {
6498c2ecf20Sopenharmony_ci		dev_err(hub->intfdev, "resubmit --> %d\n", status);
6508c2ecf20Sopenharmony_ci		mod_timer(&hub->irq_urb_retry, jiffies + HZ);
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hub->irq_urb_lock, flags);
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic void hub_retry_irq_urb(struct timer_list *t)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	struct usb_hub *hub = from_timer(hub, t, irq_urb_retry);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	hub_resubmit_irq_urb(hub);
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_cistatic void kick_hub_wq(struct usb_hub *hub)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	struct usb_interface *intf;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	if (hub->disconnected || work_pending(&hub->events))
6698c2ecf20Sopenharmony_ci		return;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	/*
6728c2ecf20Sopenharmony_ci	 * Suppress autosuspend until the event is proceed.
6738c2ecf20Sopenharmony_ci	 *
6748c2ecf20Sopenharmony_ci	 * Be careful and make sure that the symmetric operation is
6758c2ecf20Sopenharmony_ci	 * always called. We are here only when there is no pending
6768c2ecf20Sopenharmony_ci	 * work for this hub. Therefore put the interface either when
6778c2ecf20Sopenharmony_ci	 * the new work is called or when it is canceled.
6788c2ecf20Sopenharmony_ci	 */
6798c2ecf20Sopenharmony_ci	intf = to_usb_interface(hub->intfdev);
6808c2ecf20Sopenharmony_ci	usb_autopm_get_interface_no_resume(intf);
6818c2ecf20Sopenharmony_ci	kref_get(&hub->kref);
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	if (queue_work(hub_wq, &hub->events))
6848c2ecf20Sopenharmony_ci		return;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	/* the work has already been scheduled */
6878c2ecf20Sopenharmony_ci	usb_autopm_put_interface_async(intf);
6888c2ecf20Sopenharmony_ci	kref_put(&hub->kref, hub_release);
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_civoid usb_kick_hub_wq(struct usb_device *hdev)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (hub)
6968c2ecf20Sopenharmony_ci		kick_hub_wq(hub);
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci/*
7008c2ecf20Sopenharmony_ci * Let the USB core know that a USB 3.0 device has sent a Function Wake Device
7018c2ecf20Sopenharmony_ci * Notification, which indicates it had initiated remote wakeup.
7028c2ecf20Sopenharmony_ci *
7038c2ecf20Sopenharmony_ci * USB 3.0 hubs do not report the port link state change from U3 to U0 when the
7048c2ecf20Sopenharmony_ci * device initiates resume, so the USB core will not receive notice of the
7058c2ecf20Sopenharmony_ci * resume through the normal hub interrupt URB.
7068c2ecf20Sopenharmony_ci */
7078c2ecf20Sopenharmony_civoid usb_wakeup_notification(struct usb_device *hdev,
7088c2ecf20Sopenharmony_ci		unsigned int portnum)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	struct usb_hub *hub;
7118c2ecf20Sopenharmony_ci	struct usb_port *port_dev;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	if (!hdev)
7148c2ecf20Sopenharmony_ci		return;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	hub = usb_hub_to_struct_hub(hdev);
7178c2ecf20Sopenharmony_ci	if (hub) {
7188c2ecf20Sopenharmony_ci		port_dev = hub->ports[portnum - 1];
7198c2ecf20Sopenharmony_ci		if (port_dev && port_dev->child)
7208c2ecf20Sopenharmony_ci			pm_wakeup_event(&port_dev->child->dev, 0);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci		set_bit(portnum, hub->wakeup_bits);
7238c2ecf20Sopenharmony_ci		kick_hub_wq(hub);
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_wakeup_notification);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci/* completion function, fires on port status changes and various faults */
7298c2ecf20Sopenharmony_cistatic void hub_irq(struct urb *urb)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	struct usb_hub *hub = urb->context;
7328c2ecf20Sopenharmony_ci	int status = urb->status;
7338c2ecf20Sopenharmony_ci	unsigned i;
7348c2ecf20Sopenharmony_ci	unsigned long bits;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	switch (status) {
7378c2ecf20Sopenharmony_ci	case -ENOENT:		/* synchronous unlink */
7388c2ecf20Sopenharmony_ci	case -ECONNRESET:	/* async unlink */
7398c2ecf20Sopenharmony_ci	case -ESHUTDOWN:	/* hardware going away */
7408c2ecf20Sopenharmony_ci		return;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	default:		/* presumably an error */
7438c2ecf20Sopenharmony_ci		/* Cause a hub reset after 10 consecutive errors */
7448c2ecf20Sopenharmony_ci		dev_dbg(hub->intfdev, "transfer --> %d\n", status);
7458c2ecf20Sopenharmony_ci		if ((++hub->nerrors < 10) || hub->error)
7468c2ecf20Sopenharmony_ci			goto resubmit;
7478c2ecf20Sopenharmony_ci		hub->error = status;
7488c2ecf20Sopenharmony_ci		fallthrough;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* let hub_wq handle things */
7518c2ecf20Sopenharmony_ci	case 0:			/* we got data:  port status changed */
7528c2ecf20Sopenharmony_ci		bits = 0;
7538c2ecf20Sopenharmony_ci		for (i = 0; i < urb->actual_length; ++i)
7548c2ecf20Sopenharmony_ci			bits |= ((unsigned long) ((*hub->buffer)[i]))
7558c2ecf20Sopenharmony_ci					<< (i*8);
7568c2ecf20Sopenharmony_ci		hub->event_bits[0] = bits;
7578c2ecf20Sopenharmony_ci		break;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	hub->nerrors = 0;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* Something happened, let hub_wq figure it out */
7638c2ecf20Sopenharmony_ci	kick_hub_wq(hub);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ciresubmit:
7668c2ecf20Sopenharmony_ci	hub_resubmit_irq_urb(hub);
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci/* USB 2.0 spec Section 11.24.2.3 */
7708c2ecf20Sopenharmony_cistatic inline int
7718c2ecf20Sopenharmony_cihub_clear_tt_buffer(struct usb_device *hdev, u16 devinfo, u16 tt)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	/* Need to clear both directions for control ep */
7748c2ecf20Sopenharmony_ci	if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) ==
7758c2ecf20Sopenharmony_ci			USB_ENDPOINT_XFER_CONTROL) {
7768c2ecf20Sopenharmony_ci		int status = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
7778c2ecf20Sopenharmony_ci				HUB_CLEAR_TT_BUFFER, USB_RT_PORT,
7788c2ecf20Sopenharmony_ci				devinfo ^ 0x8000, tt, NULL, 0, 1000);
7798c2ecf20Sopenharmony_ci		if (status)
7808c2ecf20Sopenharmony_ci			return status;
7818c2ecf20Sopenharmony_ci	}
7828c2ecf20Sopenharmony_ci	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
7838c2ecf20Sopenharmony_ci			       HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
7848c2ecf20Sopenharmony_ci			       tt, NULL, 0, 1000);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci/*
7888c2ecf20Sopenharmony_ci * enumeration blocks hub_wq for a long time. we use keventd instead, since
7898c2ecf20Sopenharmony_ci * long blocking there is the exception, not the rule.  accordingly, HCDs
7908c2ecf20Sopenharmony_ci * talking to TTs must queue control transfers (not just bulk and iso), so
7918c2ecf20Sopenharmony_ci * both can talk to the same hub concurrently.
7928c2ecf20Sopenharmony_ci */
7938c2ecf20Sopenharmony_cistatic void hub_tt_work(struct work_struct *work)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	struct usb_hub		*hub =
7968c2ecf20Sopenharmony_ci		container_of(work, struct usb_hub, tt.clear_work);
7978c2ecf20Sopenharmony_ci	unsigned long		flags;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hub->tt.lock, flags);
8008c2ecf20Sopenharmony_ci	while (!list_empty(&hub->tt.clear_list)) {
8018c2ecf20Sopenharmony_ci		struct list_head	*next;
8028c2ecf20Sopenharmony_ci		struct usb_tt_clear	*clear;
8038c2ecf20Sopenharmony_ci		struct usb_device	*hdev = hub->hdev;
8048c2ecf20Sopenharmony_ci		const struct hc_driver	*drv;
8058c2ecf20Sopenharmony_ci		int			status;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci		next = hub->tt.clear_list.next;
8088c2ecf20Sopenharmony_ci		clear = list_entry(next, struct usb_tt_clear, clear_list);
8098c2ecf20Sopenharmony_ci		list_del(&clear->clear_list);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		/* drop lock so HCD can concurrently report other TT errors */
8128c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hub->tt.lock, flags);
8138c2ecf20Sopenharmony_ci		status = hub_clear_tt_buffer(hdev, clear->devinfo, clear->tt);
8148c2ecf20Sopenharmony_ci		if (status && status != -ENODEV)
8158c2ecf20Sopenharmony_ci			dev_err(&hdev->dev,
8168c2ecf20Sopenharmony_ci				"clear tt %d (%04x) error %d\n",
8178c2ecf20Sopenharmony_ci				clear->tt, clear->devinfo, status);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		/* Tell the HCD, even if the operation failed */
8208c2ecf20Sopenharmony_ci		drv = clear->hcd->driver;
8218c2ecf20Sopenharmony_ci		if (drv->clear_tt_buffer_complete)
8228c2ecf20Sopenharmony_ci			(drv->clear_tt_buffer_complete)(clear->hcd, clear->ep);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci		kfree(clear);
8258c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hub->tt.lock, flags);
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hub->tt.lock, flags);
8288c2ecf20Sopenharmony_ci}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci/**
8318c2ecf20Sopenharmony_ci * usb_hub_set_port_power - control hub port's power state
8328c2ecf20Sopenharmony_ci * @hdev: USB device belonging to the usb hub
8338c2ecf20Sopenharmony_ci * @hub: target hub
8348c2ecf20Sopenharmony_ci * @port1: port index
8358c2ecf20Sopenharmony_ci * @set: expected status
8368c2ecf20Sopenharmony_ci *
8378c2ecf20Sopenharmony_ci * call this function to control port's power via setting or
8388c2ecf20Sopenharmony_ci * clearing the port's PORT_POWER feature.
8398c2ecf20Sopenharmony_ci *
8408c2ecf20Sopenharmony_ci * Return: 0 if successful. A negative error code otherwise.
8418c2ecf20Sopenharmony_ci */
8428c2ecf20Sopenharmony_ciint usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
8438c2ecf20Sopenharmony_ci			   int port1, bool set)
8448c2ecf20Sopenharmony_ci{
8458c2ecf20Sopenharmony_ci	int ret;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (set)
8488c2ecf20Sopenharmony_ci		ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
8498c2ecf20Sopenharmony_ci	else
8508c2ecf20Sopenharmony_ci		ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (ret)
8538c2ecf20Sopenharmony_ci		return ret;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (set)
8568c2ecf20Sopenharmony_ci		set_bit(port1, hub->power_bits);
8578c2ecf20Sopenharmony_ci	else
8588c2ecf20Sopenharmony_ci		clear_bit(port1, hub->power_bits);
8598c2ecf20Sopenharmony_ci	return 0;
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci/**
8638c2ecf20Sopenharmony_ci * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub
8648c2ecf20Sopenharmony_ci * @urb: an URB associated with the failed or incomplete split transaction
8658c2ecf20Sopenharmony_ci *
8668c2ecf20Sopenharmony_ci * High speed HCDs use this to tell the hub driver that some split control or
8678c2ecf20Sopenharmony_ci * bulk transaction failed in a way that requires clearing internal state of
8688c2ecf20Sopenharmony_ci * a transaction translator.  This is normally detected (and reported) from
8698c2ecf20Sopenharmony_ci * interrupt context.
8708c2ecf20Sopenharmony_ci *
8718c2ecf20Sopenharmony_ci * It may not be possible for that hub to handle additional full (or low)
8728c2ecf20Sopenharmony_ci * speed transactions until that state is fully cleared out.
8738c2ecf20Sopenharmony_ci *
8748c2ecf20Sopenharmony_ci * Return: 0 if successful. A negative error code otherwise.
8758c2ecf20Sopenharmony_ci */
8768c2ecf20Sopenharmony_ciint usb_hub_clear_tt_buffer(struct urb *urb)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct usb_device	*udev = urb->dev;
8798c2ecf20Sopenharmony_ci	int			pipe = urb->pipe;
8808c2ecf20Sopenharmony_ci	struct usb_tt		*tt = udev->tt;
8818c2ecf20Sopenharmony_ci	unsigned long		flags;
8828c2ecf20Sopenharmony_ci	struct usb_tt_clear	*clear;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	/* we've got to cope with an arbitrary number of pending TT clears,
8858c2ecf20Sopenharmony_ci	 * since each TT has "at least two" buffers that can need it (and
8868c2ecf20Sopenharmony_ci	 * there can be many TTs per hub).  even if they're uncommon.
8878c2ecf20Sopenharmony_ci	 */
8888c2ecf20Sopenharmony_ci	clear = kmalloc(sizeof *clear, GFP_ATOMIC);
8898c2ecf20Sopenharmony_ci	if (clear == NULL) {
8908c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
8918c2ecf20Sopenharmony_ci		/* FIXME recover somehow ... RESET_TT? */
8928c2ecf20Sopenharmony_ci		return -ENOMEM;
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* info that CLEAR_TT_BUFFER needs */
8968c2ecf20Sopenharmony_ci	clear->tt = tt->multi ? udev->ttport : 1;
8978c2ecf20Sopenharmony_ci	clear->devinfo = usb_pipeendpoint (pipe);
8988c2ecf20Sopenharmony_ci	clear->devinfo |= ((u16)udev->devaddr) << 4;
8998c2ecf20Sopenharmony_ci	clear->devinfo |= usb_pipecontrol(pipe)
9008c2ecf20Sopenharmony_ci			? (USB_ENDPOINT_XFER_CONTROL << 11)
9018c2ecf20Sopenharmony_ci			: (USB_ENDPOINT_XFER_BULK << 11);
9028c2ecf20Sopenharmony_ci	if (usb_pipein(pipe))
9038c2ecf20Sopenharmony_ci		clear->devinfo |= 1 << 15;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/* info for completion callback */
9068c2ecf20Sopenharmony_ci	clear->hcd = bus_to_hcd(udev->bus);
9078c2ecf20Sopenharmony_ci	clear->ep = urb->ep;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* tell keventd to clear state for this TT */
9108c2ecf20Sopenharmony_ci	spin_lock_irqsave(&tt->lock, flags);
9118c2ecf20Sopenharmony_ci	list_add_tail(&clear->clear_list, &tt->clear_list);
9128c2ecf20Sopenharmony_ci	schedule_work(&tt->clear_work);
9138c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&tt->lock, flags);
9148c2ecf20Sopenharmony_ci	return 0;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_cistatic void hub_power_on(struct usb_hub *hub, bool do_delay)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	int port1;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	/* Enable power on each port.  Some hubs have reserved values
9238c2ecf20Sopenharmony_ci	 * of LPSM (> 2) in their descriptors, even though they are
9248c2ecf20Sopenharmony_ci	 * USB 2.0 hubs.  Some hubs do not implement port-power switching
9258c2ecf20Sopenharmony_ci	 * but only emulate it.  In all cases, the ports won't work
9268c2ecf20Sopenharmony_ci	 * unless we send these messages to the hub.
9278c2ecf20Sopenharmony_ci	 */
9288c2ecf20Sopenharmony_ci	if (hub_is_port_power_switchable(hub))
9298c2ecf20Sopenharmony_ci		dev_dbg(hub->intfdev, "enabling power on all ports\n");
9308c2ecf20Sopenharmony_ci	else
9318c2ecf20Sopenharmony_ci		dev_dbg(hub->intfdev, "trying to enable port power on "
9328c2ecf20Sopenharmony_ci				"non-switchable hub\n");
9338c2ecf20Sopenharmony_ci	for (port1 = 1; port1 <= hub->hdev->maxchild; port1++)
9348c2ecf20Sopenharmony_ci		if (test_bit(port1, hub->power_bits))
9358c2ecf20Sopenharmony_ci			set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
9368c2ecf20Sopenharmony_ci		else
9378c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
9388c2ecf20Sopenharmony_ci						USB_PORT_FEAT_POWER);
9398c2ecf20Sopenharmony_ci	if (do_delay)
9408c2ecf20Sopenharmony_ci		msleep(hub_power_on_good_delay(hub));
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic int hub_hub_status(struct usb_hub *hub,
9448c2ecf20Sopenharmony_ci		u16 *status, u16 *change)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	int ret;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	mutex_lock(&hub->status_mutex);
9498c2ecf20Sopenharmony_ci	ret = get_hub_status(hub->hdev, &hub->status->hub);
9508c2ecf20Sopenharmony_ci	if (ret < 0) {
9518c2ecf20Sopenharmony_ci		if (ret != -ENODEV)
9528c2ecf20Sopenharmony_ci			dev_err(hub->intfdev,
9538c2ecf20Sopenharmony_ci				"%s failed (err = %d)\n", __func__, ret);
9548c2ecf20Sopenharmony_ci	} else {
9558c2ecf20Sopenharmony_ci		*status = le16_to_cpu(hub->status->hub.wHubStatus);
9568c2ecf20Sopenharmony_ci		*change = le16_to_cpu(hub->status->hub.wHubChange);
9578c2ecf20Sopenharmony_ci		ret = 0;
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci	mutex_unlock(&hub->status_mutex);
9608c2ecf20Sopenharmony_ci	return ret;
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistatic int hub_set_port_link_state(struct usb_hub *hub, int port1,
9648c2ecf20Sopenharmony_ci			unsigned int link_status)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	return set_port_feature(hub->hdev,
9678c2ecf20Sopenharmony_ci			port1 | (link_status << 3),
9688c2ecf20Sopenharmony_ci			USB_PORT_FEAT_LINK_STATE);
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci/*
9728c2ecf20Sopenharmony_ci * Disable a port and mark a logical connect-change event, so that some
9738c2ecf20Sopenharmony_ci * time later hub_wq will disconnect() any existing usb_device on the port
9748c2ecf20Sopenharmony_ci * and will re-enumerate if there actually is a device attached.
9758c2ecf20Sopenharmony_ci */
9768c2ecf20Sopenharmony_cistatic void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
9778c2ecf20Sopenharmony_ci{
9788c2ecf20Sopenharmony_ci	dev_dbg(&hub->ports[port1 - 1]->dev, "logical disconnect\n");
9798c2ecf20Sopenharmony_ci	hub_port_disable(hub, port1, 1);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	/* FIXME let caller ask to power down the port:
9828c2ecf20Sopenharmony_ci	 *  - some devices won't enumerate without a VBUS power cycle
9838c2ecf20Sopenharmony_ci	 *  - SRP saves power that way
9848c2ecf20Sopenharmony_ci	 *  - ... new call, TBD ...
9858c2ecf20Sopenharmony_ci	 * That's easy if this hub can switch power per-port, and
9868c2ecf20Sopenharmony_ci	 * hub_wq reactivates the port later (timer, SRP, etc).
9878c2ecf20Sopenharmony_ci	 * Powerdown must be optional, because of reset/DFU.
9888c2ecf20Sopenharmony_ci	 */
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	set_bit(port1, hub->change_bits);
9918c2ecf20Sopenharmony_ci	kick_hub_wq(hub);
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci/**
9958c2ecf20Sopenharmony_ci * usb_remove_device - disable a device's port on its parent hub
9968c2ecf20Sopenharmony_ci * @udev: device to be disabled and removed
9978c2ecf20Sopenharmony_ci * Context: @udev locked, must be able to sleep.
9988c2ecf20Sopenharmony_ci *
9998c2ecf20Sopenharmony_ci * After @udev's port has been disabled, hub_wq is notified and it will
10008c2ecf20Sopenharmony_ci * see that the device has been disconnected.  When the device is
10018c2ecf20Sopenharmony_ci * physically unplugged and something is plugged in, the events will
10028c2ecf20Sopenharmony_ci * be received and processed normally.
10038c2ecf20Sopenharmony_ci *
10048c2ecf20Sopenharmony_ci * Return: 0 if successful. A negative error code otherwise.
10058c2ecf20Sopenharmony_ci */
10068c2ecf20Sopenharmony_ciint usb_remove_device(struct usb_device *udev)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct usb_hub *hub;
10098c2ecf20Sopenharmony_ci	struct usb_interface *intf;
10108c2ecf20Sopenharmony_ci	int ret;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	if (!udev->parent)	/* Can't remove a root hub */
10138c2ecf20Sopenharmony_ci		return -EINVAL;
10148c2ecf20Sopenharmony_ci	hub = usb_hub_to_struct_hub(udev->parent);
10158c2ecf20Sopenharmony_ci	intf = to_usb_interface(hub->intfdev);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	ret = usb_autopm_get_interface(intf);
10188c2ecf20Sopenharmony_ci	if (ret < 0)
10198c2ecf20Sopenharmony_ci		return ret;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	set_bit(udev->portnum, hub->removed_bits);
10228c2ecf20Sopenharmony_ci	hub_port_logical_disconnect(hub, udev->portnum);
10238c2ecf20Sopenharmony_ci	usb_autopm_put_interface(intf);
10248c2ecf20Sopenharmony_ci	return 0;
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_cienum hub_activation_type {
10288c2ecf20Sopenharmony_ci	HUB_INIT, HUB_INIT2, HUB_INIT3,		/* INITs must come first */
10298c2ecf20Sopenharmony_ci	HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
10308c2ecf20Sopenharmony_ci};
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_cistatic void hub_init_func2(struct work_struct *ws);
10338c2ecf20Sopenharmony_cistatic void hub_init_func3(struct work_struct *ws);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_cistatic void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	struct usb_device *hdev = hub->hdev;
10388c2ecf20Sopenharmony_ci	struct usb_hcd *hcd;
10398c2ecf20Sopenharmony_ci	int ret;
10408c2ecf20Sopenharmony_ci	int port1;
10418c2ecf20Sopenharmony_ci	int status;
10428c2ecf20Sopenharmony_ci	bool need_debounce_delay = false;
10438c2ecf20Sopenharmony_ci	unsigned delay;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	/* Continue a partial initialization */
10468c2ecf20Sopenharmony_ci	if (type == HUB_INIT2 || type == HUB_INIT3) {
10478c2ecf20Sopenharmony_ci		device_lock(&hdev->dev);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci		/* Was the hub disconnected while we were waiting? */
10508c2ecf20Sopenharmony_ci		if (hub->disconnected)
10518c2ecf20Sopenharmony_ci			goto disconnected;
10528c2ecf20Sopenharmony_ci		if (type == HUB_INIT2)
10538c2ecf20Sopenharmony_ci			goto init2;
10548c2ecf20Sopenharmony_ci		goto init3;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci	kref_get(&hub->kref);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	/* The superspeed hub except for root hub has to use Hub Depth
10598c2ecf20Sopenharmony_ci	 * value as an offset into the route string to locate the bits
10608c2ecf20Sopenharmony_ci	 * it uses to determine the downstream port number. So hub driver
10618c2ecf20Sopenharmony_ci	 * should send a set hub depth request to superspeed hub after
10628c2ecf20Sopenharmony_ci	 * the superspeed hub is set configuration in initialization or
10638c2ecf20Sopenharmony_ci	 * reset procedure.
10648c2ecf20Sopenharmony_ci	 *
10658c2ecf20Sopenharmony_ci	 * After a resume, port power should still be on.
10668c2ecf20Sopenharmony_ci	 * For any other type of activation, turn it on.
10678c2ecf20Sopenharmony_ci	 */
10688c2ecf20Sopenharmony_ci	if (type != HUB_RESUME) {
10698c2ecf20Sopenharmony_ci		if (hdev->parent && hub_is_superspeed(hdev)) {
10708c2ecf20Sopenharmony_ci			ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
10718c2ecf20Sopenharmony_ci					HUB_SET_DEPTH, USB_RT_HUB,
10728c2ecf20Sopenharmony_ci					hdev->level - 1, 0, NULL, 0,
10738c2ecf20Sopenharmony_ci					USB_CTRL_SET_TIMEOUT);
10748c2ecf20Sopenharmony_ci			if (ret < 0)
10758c2ecf20Sopenharmony_ci				dev_err(hub->intfdev,
10768c2ecf20Sopenharmony_ci						"set hub depth failed\n");
10778c2ecf20Sopenharmony_ci		}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci		/* Speed up system boot by using a delayed_work for the
10808c2ecf20Sopenharmony_ci		 * hub's initial power-up delays.  This is pretty awkward
10818c2ecf20Sopenharmony_ci		 * and the implementation looks like a home-brewed sort of
10828c2ecf20Sopenharmony_ci		 * setjmp/longjmp, but it saves at least 100 ms for each
10838c2ecf20Sopenharmony_ci		 * root hub (assuming usbcore is compiled into the kernel
10848c2ecf20Sopenharmony_ci		 * rather than as a module).  It adds up.
10858c2ecf20Sopenharmony_ci		 *
10868c2ecf20Sopenharmony_ci		 * This can't be done for HUB_RESUME or HUB_RESET_RESUME
10878c2ecf20Sopenharmony_ci		 * because for those activation types the ports have to be
10888c2ecf20Sopenharmony_ci		 * operational when we return.  In theory this could be done
10898c2ecf20Sopenharmony_ci		 * for HUB_POST_RESET, but it's easier not to.
10908c2ecf20Sopenharmony_ci		 */
10918c2ecf20Sopenharmony_ci		if (type == HUB_INIT) {
10928c2ecf20Sopenharmony_ci			delay = hub_power_on_good_delay(hub);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci			hub_power_on(hub, false);
10958c2ecf20Sopenharmony_ci			INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
10968c2ecf20Sopenharmony_ci			queue_delayed_work(system_power_efficient_wq,
10978c2ecf20Sopenharmony_ci					&hub->init_work,
10988c2ecf20Sopenharmony_ci					msecs_to_jiffies(delay));
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci			/* Suppress autosuspend until init is done */
11018c2ecf20Sopenharmony_ci			usb_autopm_get_interface_no_resume(
11028c2ecf20Sopenharmony_ci					to_usb_interface(hub->intfdev));
11038c2ecf20Sopenharmony_ci			return;		/* Continues at init2: below */
11048c2ecf20Sopenharmony_ci		} else if (type == HUB_RESET_RESUME) {
11058c2ecf20Sopenharmony_ci			/* The internal host controller state for the hub device
11068c2ecf20Sopenharmony_ci			 * may be gone after a host power loss on system resume.
11078c2ecf20Sopenharmony_ci			 * Update the device's info so the HW knows it's a hub.
11088c2ecf20Sopenharmony_ci			 */
11098c2ecf20Sopenharmony_ci			hcd = bus_to_hcd(hdev->bus);
11108c2ecf20Sopenharmony_ci			if (hcd->driver->update_hub_device) {
11118c2ecf20Sopenharmony_ci				ret = hcd->driver->update_hub_device(hcd, hdev,
11128c2ecf20Sopenharmony_ci						&hub->tt, GFP_NOIO);
11138c2ecf20Sopenharmony_ci				if (ret < 0) {
11148c2ecf20Sopenharmony_ci					dev_err(hub->intfdev,
11158c2ecf20Sopenharmony_ci						"Host not accepting hub info update\n");
11168c2ecf20Sopenharmony_ci					dev_err(hub->intfdev,
11178c2ecf20Sopenharmony_ci						"LS/FS devices and hubs may not work under this hub\n");
11188c2ecf20Sopenharmony_ci				}
11198c2ecf20Sopenharmony_ci			}
11208c2ecf20Sopenharmony_ci			hub_power_on(hub, true);
11218c2ecf20Sopenharmony_ci		} else {
11228c2ecf20Sopenharmony_ci			hub_power_on(hub, true);
11238c2ecf20Sopenharmony_ci		}
11248c2ecf20Sopenharmony_ci	/* Give some time on remote wakeup to let links to transit to U0 */
11258c2ecf20Sopenharmony_ci	} else if (hub_is_superspeed(hub->hdev))
11268c2ecf20Sopenharmony_ci		msleep(20);
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci init2:
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	/*
11318c2ecf20Sopenharmony_ci	 * Check each port and set hub->change_bits to let hub_wq know
11328c2ecf20Sopenharmony_ci	 * which ports need attention.
11338c2ecf20Sopenharmony_ci	 */
11348c2ecf20Sopenharmony_ci	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
11358c2ecf20Sopenharmony_ci		struct usb_port *port_dev = hub->ports[port1 - 1];
11368c2ecf20Sopenharmony_ci		struct usb_device *udev = port_dev->child;
11378c2ecf20Sopenharmony_ci		u16 portstatus, portchange;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		portstatus = portchange = 0;
11408c2ecf20Sopenharmony_ci		status = hub_port_status(hub, port1, &portstatus, &portchange);
11418c2ecf20Sopenharmony_ci		if (status)
11428c2ecf20Sopenharmony_ci			goto abort;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci		if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
11458c2ecf20Sopenharmony_ci			dev_dbg(&port_dev->dev, "status %04x change %04x\n",
11468c2ecf20Sopenharmony_ci					portstatus, portchange);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci		/*
11498c2ecf20Sopenharmony_ci		 * After anything other than HUB_RESUME (i.e., initialization
11508c2ecf20Sopenharmony_ci		 * or any sort of reset), every port should be disabled.
11518c2ecf20Sopenharmony_ci		 * Unconnected ports should likewise be disabled (paranoia),
11528c2ecf20Sopenharmony_ci		 * and so should ports for which we have no usb_device.
11538c2ecf20Sopenharmony_ci		 */
11548c2ecf20Sopenharmony_ci		if ((portstatus & USB_PORT_STAT_ENABLE) && (
11558c2ecf20Sopenharmony_ci				type != HUB_RESUME ||
11568c2ecf20Sopenharmony_ci				!(portstatus & USB_PORT_STAT_CONNECTION) ||
11578c2ecf20Sopenharmony_ci				!udev ||
11588c2ecf20Sopenharmony_ci				udev->state == USB_STATE_NOTATTACHED)) {
11598c2ecf20Sopenharmony_ci			/*
11608c2ecf20Sopenharmony_ci			 * USB3 protocol ports will automatically transition
11618c2ecf20Sopenharmony_ci			 * to Enabled state when detect an USB3.0 device attach.
11628c2ecf20Sopenharmony_ci			 * Do not disable USB3 protocol ports, just pretend
11638c2ecf20Sopenharmony_ci			 * power was lost
11648c2ecf20Sopenharmony_ci			 */
11658c2ecf20Sopenharmony_ci			portstatus &= ~USB_PORT_STAT_ENABLE;
11668c2ecf20Sopenharmony_ci			if (!hub_is_superspeed(hdev))
11678c2ecf20Sopenharmony_ci				usb_clear_port_feature(hdev, port1,
11688c2ecf20Sopenharmony_ci						   USB_PORT_FEAT_ENABLE);
11698c2ecf20Sopenharmony_ci		}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci		/* Make sure a warm-reset request is handled by port_event */
11728c2ecf20Sopenharmony_ci		if (type == HUB_RESUME &&
11738c2ecf20Sopenharmony_ci		    hub_port_warm_reset_required(hub, port1, portstatus))
11748c2ecf20Sopenharmony_ci			set_bit(port1, hub->event_bits);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci		/*
11778c2ecf20Sopenharmony_ci		 * Add debounce if USB3 link is in polling/link training state.
11788c2ecf20Sopenharmony_ci		 * Link will automatically transition to Enabled state after
11798c2ecf20Sopenharmony_ci		 * link training completes.
11808c2ecf20Sopenharmony_ci		 */
11818c2ecf20Sopenharmony_ci		if (hub_is_superspeed(hdev) &&
11828c2ecf20Sopenharmony_ci		    ((portstatus & USB_PORT_STAT_LINK_STATE) ==
11838c2ecf20Sopenharmony_ci						USB_SS_PORT_LS_POLLING))
11848c2ecf20Sopenharmony_ci			need_debounce_delay = true;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci		/* Clear status-change flags; we'll debounce later */
11878c2ecf20Sopenharmony_ci		if (portchange & USB_PORT_STAT_C_CONNECTION) {
11888c2ecf20Sopenharmony_ci			need_debounce_delay = true;
11898c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
11908c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_CONNECTION);
11918c2ecf20Sopenharmony_ci		}
11928c2ecf20Sopenharmony_ci		if (portchange & USB_PORT_STAT_C_ENABLE) {
11938c2ecf20Sopenharmony_ci			need_debounce_delay = true;
11948c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
11958c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_ENABLE);
11968c2ecf20Sopenharmony_ci		}
11978c2ecf20Sopenharmony_ci		if (portchange & USB_PORT_STAT_C_RESET) {
11988c2ecf20Sopenharmony_ci			need_debounce_delay = true;
11998c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
12008c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_RESET);
12018c2ecf20Sopenharmony_ci		}
12028c2ecf20Sopenharmony_ci		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
12038c2ecf20Sopenharmony_ci				hub_is_superspeed(hub->hdev)) {
12048c2ecf20Sopenharmony_ci			need_debounce_delay = true;
12058c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
12068c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_BH_PORT_RESET);
12078c2ecf20Sopenharmony_ci		}
12088c2ecf20Sopenharmony_ci		/* We can forget about a "removed" device when there's a
12098c2ecf20Sopenharmony_ci		 * physical disconnect or the connect status changes.
12108c2ecf20Sopenharmony_ci		 */
12118c2ecf20Sopenharmony_ci		if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
12128c2ecf20Sopenharmony_ci				(portchange & USB_PORT_STAT_C_CONNECTION))
12138c2ecf20Sopenharmony_ci			clear_bit(port1, hub->removed_bits);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci		if (!udev || udev->state == USB_STATE_NOTATTACHED) {
12168c2ecf20Sopenharmony_ci			/* Tell hub_wq to disconnect the device or
12178c2ecf20Sopenharmony_ci			 * check for a new connection or over current condition.
12188c2ecf20Sopenharmony_ci			 * Based on USB2.0 Spec Section 11.12.5,
12198c2ecf20Sopenharmony_ci			 * C_PORT_OVER_CURRENT could be set while
12208c2ecf20Sopenharmony_ci			 * PORT_OVER_CURRENT is not. So check for any of them.
12218c2ecf20Sopenharmony_ci			 */
12228c2ecf20Sopenharmony_ci			if (udev || (portstatus & USB_PORT_STAT_CONNECTION) ||
12238c2ecf20Sopenharmony_ci			    (portchange & USB_PORT_STAT_C_CONNECTION) ||
12248c2ecf20Sopenharmony_ci			    (portstatus & USB_PORT_STAT_OVERCURRENT) ||
12258c2ecf20Sopenharmony_ci			    (portchange & USB_PORT_STAT_C_OVERCURRENT))
12268c2ecf20Sopenharmony_ci				set_bit(port1, hub->change_bits);
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci		} else if (portstatus & USB_PORT_STAT_ENABLE) {
12298c2ecf20Sopenharmony_ci			bool port_resumed = (portstatus &
12308c2ecf20Sopenharmony_ci					USB_PORT_STAT_LINK_STATE) ==
12318c2ecf20Sopenharmony_ci				USB_SS_PORT_LS_U0;
12328c2ecf20Sopenharmony_ci			/* The power session apparently survived the resume.
12338c2ecf20Sopenharmony_ci			 * If there was an overcurrent or suspend change
12348c2ecf20Sopenharmony_ci			 * (i.e., remote wakeup request), have hub_wq
12358c2ecf20Sopenharmony_ci			 * take care of it.  Look at the port link state
12368c2ecf20Sopenharmony_ci			 * for USB 3.0 hubs, since they don't have a suspend
12378c2ecf20Sopenharmony_ci			 * change bit, and they don't set the port link change
12388c2ecf20Sopenharmony_ci			 * bit on device-initiated resume.
12398c2ecf20Sopenharmony_ci			 */
12408c2ecf20Sopenharmony_ci			if (portchange || (hub_is_superspeed(hub->hdev) &&
12418c2ecf20Sopenharmony_ci						port_resumed))
12428c2ecf20Sopenharmony_ci				set_bit(port1, hub->event_bits);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci		} else if (udev->persist_enabled) {
12458c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
12468c2ecf20Sopenharmony_ci			udev->reset_resume = 1;
12478c2ecf20Sopenharmony_ci#endif
12488c2ecf20Sopenharmony_ci			/* Don't set the change_bits when the device
12498c2ecf20Sopenharmony_ci			 * was powered off.
12508c2ecf20Sopenharmony_ci			 */
12518c2ecf20Sopenharmony_ci			if (test_bit(port1, hub->power_bits))
12528c2ecf20Sopenharmony_ci				set_bit(port1, hub->change_bits);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci		} else {
12558c2ecf20Sopenharmony_ci			/* The power session is gone; tell hub_wq */
12568c2ecf20Sopenharmony_ci			usb_set_device_state(udev, USB_STATE_NOTATTACHED);
12578c2ecf20Sopenharmony_ci			set_bit(port1, hub->change_bits);
12588c2ecf20Sopenharmony_ci		}
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	/* If no port-status-change flags were set, we don't need any
12628c2ecf20Sopenharmony_ci	 * debouncing.  If flags were set we can try to debounce the
12638c2ecf20Sopenharmony_ci	 * ports all at once right now, instead of letting hub_wq do them
12648c2ecf20Sopenharmony_ci	 * one at a time later on.
12658c2ecf20Sopenharmony_ci	 *
12668c2ecf20Sopenharmony_ci	 * If any port-status changes do occur during this delay, hub_wq
12678c2ecf20Sopenharmony_ci	 * will see them later and handle them normally.
12688c2ecf20Sopenharmony_ci	 */
12698c2ecf20Sopenharmony_ci	if (need_debounce_delay) {
12708c2ecf20Sopenharmony_ci		delay = HUB_DEBOUNCE_STABLE;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci		/* Don't do a long sleep inside a workqueue routine */
12738c2ecf20Sopenharmony_ci		if (type == HUB_INIT2) {
12748c2ecf20Sopenharmony_ci			INIT_DELAYED_WORK(&hub->init_work, hub_init_func3);
12758c2ecf20Sopenharmony_ci			queue_delayed_work(system_power_efficient_wq,
12768c2ecf20Sopenharmony_ci					&hub->init_work,
12778c2ecf20Sopenharmony_ci					msecs_to_jiffies(delay));
12788c2ecf20Sopenharmony_ci			device_unlock(&hdev->dev);
12798c2ecf20Sopenharmony_ci			return;		/* Continues at init3: below */
12808c2ecf20Sopenharmony_ci		} else {
12818c2ecf20Sopenharmony_ci			msleep(delay);
12828c2ecf20Sopenharmony_ci		}
12838c2ecf20Sopenharmony_ci	}
12848c2ecf20Sopenharmony_ci init3:
12858c2ecf20Sopenharmony_ci	hub->quiescing = 0;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	status = usb_submit_urb(hub->urb, GFP_NOIO);
12888c2ecf20Sopenharmony_ci	if (status < 0)
12898c2ecf20Sopenharmony_ci		dev_err(hub->intfdev, "activate --> %d\n", status);
12908c2ecf20Sopenharmony_ci	if (hub->has_indicators && blinkenlights)
12918c2ecf20Sopenharmony_ci		queue_delayed_work(system_power_efficient_wq,
12928c2ecf20Sopenharmony_ci				&hub->leds, LED_CYCLE_PERIOD);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	/* Scan all ports that need attention */
12958c2ecf20Sopenharmony_ci	kick_hub_wq(hub);
12968c2ecf20Sopenharmony_ci abort:
12978c2ecf20Sopenharmony_ci	if (type == HUB_INIT2 || type == HUB_INIT3) {
12988c2ecf20Sopenharmony_ci		/* Allow autosuspend if it was suppressed */
12998c2ecf20Sopenharmony_ci disconnected:
13008c2ecf20Sopenharmony_ci		usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
13018c2ecf20Sopenharmony_ci		device_unlock(&hdev->dev);
13028c2ecf20Sopenharmony_ci	}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	kref_put(&hub->kref, hub_release);
13058c2ecf20Sopenharmony_ci}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci/* Implement the continuations for the delays above */
13088c2ecf20Sopenharmony_cistatic void hub_init_func2(struct work_struct *ws)
13098c2ecf20Sopenharmony_ci{
13108c2ecf20Sopenharmony_ci	struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	hub_activate(hub, HUB_INIT2);
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_cistatic void hub_init_func3(struct work_struct *ws)
13168c2ecf20Sopenharmony_ci{
13178c2ecf20Sopenharmony_ci	struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	hub_activate(hub, HUB_INIT3);
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_cienum hub_quiescing_type {
13238c2ecf20Sopenharmony_ci	HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND
13248c2ecf20Sopenharmony_ci};
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	struct usb_device *hdev = hub->hdev;
13298c2ecf20Sopenharmony_ci	unsigned long flags;
13308c2ecf20Sopenharmony_ci	int i;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	/* hub_wq and related activity won't re-trigger */
13338c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hub->irq_urb_lock, flags);
13348c2ecf20Sopenharmony_ci	hub->quiescing = 1;
13358c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hub->irq_urb_lock, flags);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	if (type != HUB_SUSPEND) {
13388c2ecf20Sopenharmony_ci		/* Disconnect all the children */
13398c2ecf20Sopenharmony_ci		for (i = 0; i < hdev->maxchild; ++i) {
13408c2ecf20Sopenharmony_ci			if (hub->ports[i]->child)
13418c2ecf20Sopenharmony_ci				usb_disconnect(&hub->ports[i]->child);
13428c2ecf20Sopenharmony_ci		}
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	/* Stop hub_wq and related activity */
13468c2ecf20Sopenharmony_ci	del_timer_sync(&hub->irq_urb_retry);
13478c2ecf20Sopenharmony_ci	usb_kill_urb(hub->urb);
13488c2ecf20Sopenharmony_ci	if (hub->has_indicators)
13498c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&hub->leds);
13508c2ecf20Sopenharmony_ci	if (hub->tt.hub)
13518c2ecf20Sopenharmony_ci		flush_work(&hub->tt.clear_work);
13528c2ecf20Sopenharmony_ci}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_cistatic void hub_pm_barrier_for_all_ports(struct usb_hub *hub)
13558c2ecf20Sopenharmony_ci{
13568c2ecf20Sopenharmony_ci	int i;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	for (i = 0; i < hub->hdev->maxchild; ++i)
13598c2ecf20Sopenharmony_ci		pm_runtime_barrier(&hub->ports[i]->dev);
13608c2ecf20Sopenharmony_ci}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci/* caller has locked the hub device */
13638c2ecf20Sopenharmony_cistatic int hub_pre_reset(struct usb_interface *intf)
13648c2ecf20Sopenharmony_ci{
13658c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_get_intfdata(intf);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	hub_quiesce(hub, HUB_PRE_RESET);
13688c2ecf20Sopenharmony_ci	hub->in_reset = 1;
13698c2ecf20Sopenharmony_ci	hub_pm_barrier_for_all_ports(hub);
13708c2ecf20Sopenharmony_ci	return 0;
13718c2ecf20Sopenharmony_ci}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci/* caller has locked the hub device */
13748c2ecf20Sopenharmony_cistatic int hub_post_reset(struct usb_interface *intf)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_get_intfdata(intf);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	hub->in_reset = 0;
13798c2ecf20Sopenharmony_ci	hub_pm_barrier_for_all_ports(hub);
13808c2ecf20Sopenharmony_ci	hub_activate(hub, HUB_POST_RESET);
13818c2ecf20Sopenharmony_ci	return 0;
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_cistatic int hub_configure(struct usb_hub *hub,
13858c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor *endpoint)
13868c2ecf20Sopenharmony_ci{
13878c2ecf20Sopenharmony_ci	struct usb_hcd *hcd;
13888c2ecf20Sopenharmony_ci	struct usb_device *hdev = hub->hdev;
13898c2ecf20Sopenharmony_ci	struct device *hub_dev = hub->intfdev;
13908c2ecf20Sopenharmony_ci	u16 hubstatus, hubchange;
13918c2ecf20Sopenharmony_ci	u16 wHubCharacteristics;
13928c2ecf20Sopenharmony_ci	unsigned int pipe;
13938c2ecf20Sopenharmony_ci	int maxp, ret, i;
13948c2ecf20Sopenharmony_ci	char *message = "out of memory";
13958c2ecf20Sopenharmony_ci	unsigned unit_load;
13968c2ecf20Sopenharmony_ci	unsigned full_load;
13978c2ecf20Sopenharmony_ci	unsigned maxchild;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
14008c2ecf20Sopenharmony_ci	if (!hub->buffer) {
14018c2ecf20Sopenharmony_ci		ret = -ENOMEM;
14028c2ecf20Sopenharmony_ci		goto fail;
14038c2ecf20Sopenharmony_ci	}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
14068c2ecf20Sopenharmony_ci	if (!hub->status) {
14078c2ecf20Sopenharmony_ci		ret = -ENOMEM;
14088c2ecf20Sopenharmony_ci		goto fail;
14098c2ecf20Sopenharmony_ci	}
14108c2ecf20Sopenharmony_ci	mutex_init(&hub->status_mutex);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL);
14138c2ecf20Sopenharmony_ci	if (!hub->descriptor) {
14148c2ecf20Sopenharmony_ci		ret = -ENOMEM;
14158c2ecf20Sopenharmony_ci		goto fail;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	/* Request the entire hub descriptor.
14198c2ecf20Sopenharmony_ci	 * hub->descriptor can handle USB_MAXCHILDREN ports,
14208c2ecf20Sopenharmony_ci	 * but a (non-SS) hub can/will return fewer bytes here.
14218c2ecf20Sopenharmony_ci	 */
14228c2ecf20Sopenharmony_ci	ret = get_hub_descriptor(hdev, hub->descriptor);
14238c2ecf20Sopenharmony_ci	if (ret < 0) {
14248c2ecf20Sopenharmony_ci		message = "can't read hub descriptor";
14258c2ecf20Sopenharmony_ci		goto fail;
14268c2ecf20Sopenharmony_ci	}
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	maxchild = USB_MAXCHILDREN;
14298c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hdev))
14308c2ecf20Sopenharmony_ci		maxchild = min_t(unsigned, maxchild, USB_SS_MAXPORTS);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	if (hub->descriptor->bNbrPorts > maxchild) {
14338c2ecf20Sopenharmony_ci		message = "hub has too many ports!";
14348c2ecf20Sopenharmony_ci		ret = -ENODEV;
14358c2ecf20Sopenharmony_ci		goto fail;
14368c2ecf20Sopenharmony_ci	} else if (hub->descriptor->bNbrPorts == 0) {
14378c2ecf20Sopenharmony_ci		message = "hub doesn't have any ports!";
14388c2ecf20Sopenharmony_ci		ret = -ENODEV;
14398c2ecf20Sopenharmony_ci		goto fail;
14408c2ecf20Sopenharmony_ci	}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	/*
14438c2ecf20Sopenharmony_ci	 * Accumulate wHubDelay + 40ns for every hub in the tree of devices.
14448c2ecf20Sopenharmony_ci	 * The resulting value will be used for SetIsochDelay() request.
14458c2ecf20Sopenharmony_ci	 */
14468c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hdev) || hub_is_superspeedplus(hdev)) {
14478c2ecf20Sopenharmony_ci		u32 delay = __le16_to_cpu(hub->descriptor->u.ss.wHubDelay);
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci		if (hdev->parent)
14508c2ecf20Sopenharmony_ci			delay += hdev->parent->hub_delay;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci		delay += USB_TP_TRANSMISSION_DELAY;
14538c2ecf20Sopenharmony_ci		hdev->hub_delay = min_t(u32, delay, USB_TP_TRANSMISSION_DELAY_MAX);
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	maxchild = hub->descriptor->bNbrPorts;
14578c2ecf20Sopenharmony_ci	dev_info(hub_dev, "%d port%s detected\n", maxchild,
14588c2ecf20Sopenharmony_ci			(maxchild == 1) ? "" : "s");
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	hub->ports = kcalloc(maxchild, sizeof(struct usb_port *), GFP_KERNEL);
14618c2ecf20Sopenharmony_ci	if (!hub->ports) {
14628c2ecf20Sopenharmony_ci		ret = -ENOMEM;
14638c2ecf20Sopenharmony_ci		goto fail;
14648c2ecf20Sopenharmony_ci	}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
14678c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hdev)) {
14688c2ecf20Sopenharmony_ci		unit_load = 150;
14698c2ecf20Sopenharmony_ci		full_load = 900;
14708c2ecf20Sopenharmony_ci	} else {
14718c2ecf20Sopenharmony_ci		unit_load = 100;
14728c2ecf20Sopenharmony_ci		full_load = 500;
14738c2ecf20Sopenharmony_ci	}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/* FIXME for USB 3.0, skip for now */
14768c2ecf20Sopenharmony_ci	if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
14778c2ecf20Sopenharmony_ci			!(hub_is_superspeed(hdev))) {
14788c2ecf20Sopenharmony_ci		char	portstr[USB_MAXCHILDREN + 1];
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci		for (i = 0; i < maxchild; i++)
14818c2ecf20Sopenharmony_ci			portstr[i] = hub->descriptor->u.hs.DeviceRemovable
14828c2ecf20Sopenharmony_ci				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
14838c2ecf20Sopenharmony_ci				? 'F' : 'R';
14848c2ecf20Sopenharmony_ci		portstr[maxchild] = 0;
14858c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
14868c2ecf20Sopenharmony_ci	} else
14878c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "standalone hub\n");
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	switch (wHubCharacteristics & HUB_CHAR_LPSM) {
14908c2ecf20Sopenharmony_ci	case HUB_CHAR_COMMON_LPSM:
14918c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "ganged power switching\n");
14928c2ecf20Sopenharmony_ci		break;
14938c2ecf20Sopenharmony_ci	case HUB_CHAR_INDV_PORT_LPSM:
14948c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "individual port power switching\n");
14958c2ecf20Sopenharmony_ci		break;
14968c2ecf20Sopenharmony_ci	case HUB_CHAR_NO_LPSM:
14978c2ecf20Sopenharmony_ci	case HUB_CHAR_LPSM:
14988c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
14998c2ecf20Sopenharmony_ci		break;
15008c2ecf20Sopenharmony_ci	}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	switch (wHubCharacteristics & HUB_CHAR_OCPM) {
15038c2ecf20Sopenharmony_ci	case HUB_CHAR_COMMON_OCPM:
15048c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "global over-current protection\n");
15058c2ecf20Sopenharmony_ci		break;
15068c2ecf20Sopenharmony_ci	case HUB_CHAR_INDV_PORT_OCPM:
15078c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "individual port over-current protection\n");
15088c2ecf20Sopenharmony_ci		break;
15098c2ecf20Sopenharmony_ci	case HUB_CHAR_NO_OCPM:
15108c2ecf20Sopenharmony_ci	case HUB_CHAR_OCPM:
15118c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "no over-current protection\n");
15128c2ecf20Sopenharmony_ci		break;
15138c2ecf20Sopenharmony_ci	}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	spin_lock_init(&hub->tt.lock);
15168c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hub->tt.clear_list);
15178c2ecf20Sopenharmony_ci	INIT_WORK(&hub->tt.clear_work, hub_tt_work);
15188c2ecf20Sopenharmony_ci	switch (hdev->descriptor.bDeviceProtocol) {
15198c2ecf20Sopenharmony_ci	case USB_HUB_PR_FS:
15208c2ecf20Sopenharmony_ci		break;
15218c2ecf20Sopenharmony_ci	case USB_HUB_PR_HS_SINGLE_TT:
15228c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "Single TT\n");
15238c2ecf20Sopenharmony_ci		hub->tt.hub = hdev;
15248c2ecf20Sopenharmony_ci		break;
15258c2ecf20Sopenharmony_ci	case USB_HUB_PR_HS_MULTI_TT:
15268c2ecf20Sopenharmony_ci		ret = usb_set_interface(hdev, 0, 1);
15278c2ecf20Sopenharmony_ci		if (ret == 0) {
15288c2ecf20Sopenharmony_ci			dev_dbg(hub_dev, "TT per port\n");
15298c2ecf20Sopenharmony_ci			hub->tt.multi = 1;
15308c2ecf20Sopenharmony_ci		} else
15318c2ecf20Sopenharmony_ci			dev_err(hub_dev, "Using single TT (err %d)\n",
15328c2ecf20Sopenharmony_ci				ret);
15338c2ecf20Sopenharmony_ci		hub->tt.hub = hdev;
15348c2ecf20Sopenharmony_ci		break;
15358c2ecf20Sopenharmony_ci	case USB_HUB_PR_SS:
15368c2ecf20Sopenharmony_ci		/* USB 3.0 hubs don't have a TT */
15378c2ecf20Sopenharmony_ci		break;
15388c2ecf20Sopenharmony_ci	default:
15398c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
15408c2ecf20Sopenharmony_ci			hdev->descriptor.bDeviceProtocol);
15418c2ecf20Sopenharmony_ci		break;
15428c2ecf20Sopenharmony_ci	}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
15458c2ecf20Sopenharmony_ci	switch (wHubCharacteristics & HUB_CHAR_TTTT) {
15468c2ecf20Sopenharmony_ci	case HUB_TTTT_8_BITS:
15478c2ecf20Sopenharmony_ci		if (hdev->descriptor.bDeviceProtocol != 0) {
15488c2ecf20Sopenharmony_ci			hub->tt.think_time = 666;
15498c2ecf20Sopenharmony_ci			dev_dbg(hub_dev, "TT requires at most %d "
15508c2ecf20Sopenharmony_ci					"FS bit times (%d ns)\n",
15518c2ecf20Sopenharmony_ci				8, hub->tt.think_time);
15528c2ecf20Sopenharmony_ci		}
15538c2ecf20Sopenharmony_ci		break;
15548c2ecf20Sopenharmony_ci	case HUB_TTTT_16_BITS:
15558c2ecf20Sopenharmony_ci		hub->tt.think_time = 666 * 2;
15568c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "TT requires at most %d "
15578c2ecf20Sopenharmony_ci				"FS bit times (%d ns)\n",
15588c2ecf20Sopenharmony_ci			16, hub->tt.think_time);
15598c2ecf20Sopenharmony_ci		break;
15608c2ecf20Sopenharmony_ci	case HUB_TTTT_24_BITS:
15618c2ecf20Sopenharmony_ci		hub->tt.think_time = 666 * 3;
15628c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "TT requires at most %d "
15638c2ecf20Sopenharmony_ci				"FS bit times (%d ns)\n",
15648c2ecf20Sopenharmony_ci			24, hub->tt.think_time);
15658c2ecf20Sopenharmony_ci		break;
15668c2ecf20Sopenharmony_ci	case HUB_TTTT_32_BITS:
15678c2ecf20Sopenharmony_ci		hub->tt.think_time = 666 * 4;
15688c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "TT requires at most %d "
15698c2ecf20Sopenharmony_ci				"FS bit times (%d ns)\n",
15708c2ecf20Sopenharmony_ci			32, hub->tt.think_time);
15718c2ecf20Sopenharmony_ci		break;
15728c2ecf20Sopenharmony_ci	}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	/* probe() zeroes hub->indicator[] */
15758c2ecf20Sopenharmony_ci	if (wHubCharacteristics & HUB_CHAR_PORTIND) {
15768c2ecf20Sopenharmony_ci		hub->has_indicators = 1;
15778c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "Port indicators are supported\n");
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	dev_dbg(hub_dev, "power on to power good time: %dms\n",
15818c2ecf20Sopenharmony_ci		hub->descriptor->bPwrOn2PwrGood * 2);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	/* power budgeting mostly matters with bus-powered hubs,
15848c2ecf20Sopenharmony_ci	 * and battery-powered root hubs (may provide just 8 mA).
15858c2ecf20Sopenharmony_ci	 */
15868c2ecf20Sopenharmony_ci	ret = usb_get_std_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
15878c2ecf20Sopenharmony_ci	if (ret) {
15888c2ecf20Sopenharmony_ci		message = "can't get hub status";
15898c2ecf20Sopenharmony_ci		goto fail;
15908c2ecf20Sopenharmony_ci	}
15918c2ecf20Sopenharmony_ci	hcd = bus_to_hcd(hdev->bus);
15928c2ecf20Sopenharmony_ci	if (hdev == hdev->bus->root_hub) {
15938c2ecf20Sopenharmony_ci		if (hcd->power_budget > 0)
15948c2ecf20Sopenharmony_ci			hdev->bus_mA = hcd->power_budget;
15958c2ecf20Sopenharmony_ci		else
15968c2ecf20Sopenharmony_ci			hdev->bus_mA = full_load * maxchild;
15978c2ecf20Sopenharmony_ci		if (hdev->bus_mA >= full_load)
15988c2ecf20Sopenharmony_ci			hub->mA_per_port = full_load;
15998c2ecf20Sopenharmony_ci		else {
16008c2ecf20Sopenharmony_ci			hub->mA_per_port = hdev->bus_mA;
16018c2ecf20Sopenharmony_ci			hub->limited_power = 1;
16028c2ecf20Sopenharmony_ci		}
16038c2ecf20Sopenharmony_ci	} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
16048c2ecf20Sopenharmony_ci		int remaining = hdev->bus_mA -
16058c2ecf20Sopenharmony_ci			hub->descriptor->bHubContrCurrent;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
16088c2ecf20Sopenharmony_ci			hub->descriptor->bHubContrCurrent);
16098c2ecf20Sopenharmony_ci		hub->limited_power = 1;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci		if (remaining < maxchild * unit_load)
16128c2ecf20Sopenharmony_ci			dev_warn(hub_dev,
16138c2ecf20Sopenharmony_ci					"insufficient power available "
16148c2ecf20Sopenharmony_ci					"to use all downstream ports\n");
16158c2ecf20Sopenharmony_ci		hub->mA_per_port = unit_load;	/* 7.2.1 */
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	} else {	/* Self-powered external hub */
16188c2ecf20Sopenharmony_ci		/* FIXME: What about battery-powered external hubs that
16198c2ecf20Sopenharmony_ci		 * provide less current per port? */
16208c2ecf20Sopenharmony_ci		hub->mA_per_port = full_load;
16218c2ecf20Sopenharmony_ci	}
16228c2ecf20Sopenharmony_ci	if (hub->mA_per_port < full_load)
16238c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "%umA bus power budget for each child\n",
16248c2ecf20Sopenharmony_ci				hub->mA_per_port);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	ret = hub_hub_status(hub, &hubstatus, &hubchange);
16278c2ecf20Sopenharmony_ci	if (ret < 0) {
16288c2ecf20Sopenharmony_ci		message = "can't get hub status";
16298c2ecf20Sopenharmony_ci		goto fail;
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	/* local power status reports aren't always correct */
16338c2ecf20Sopenharmony_ci	if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
16348c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "local power source is %s\n",
16358c2ecf20Sopenharmony_ci			(hubstatus & HUB_STATUS_LOCAL_POWER)
16368c2ecf20Sopenharmony_ci			? "lost (inactive)" : "good");
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)
16398c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "%sover-current condition exists\n",
16408c2ecf20Sopenharmony_ci			(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	/* set up the interrupt endpoint
16438c2ecf20Sopenharmony_ci	 * We use the EP's maxpacket size instead of (PORTS+1+7)/8
16448c2ecf20Sopenharmony_ci	 * bytes as USB2.0[11.12.3] says because some hubs are known
16458c2ecf20Sopenharmony_ci	 * to send more data (and thus cause overflow). For root hubs,
16468c2ecf20Sopenharmony_ci	 * maxpktsize is defined in hcd.c's fake endpoint descriptors
16478c2ecf20Sopenharmony_ci	 * to be big enough for at least USB_MAXCHILDREN ports. */
16488c2ecf20Sopenharmony_ci	pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
16498c2ecf20Sopenharmony_ci	maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	if (maxp > sizeof(*hub->buffer))
16528c2ecf20Sopenharmony_ci		maxp = sizeof(*hub->buffer);
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	hub->urb = usb_alloc_urb(0, GFP_KERNEL);
16558c2ecf20Sopenharmony_ci	if (!hub->urb) {
16568c2ecf20Sopenharmony_ci		ret = -ENOMEM;
16578c2ecf20Sopenharmony_ci		goto fail;
16588c2ecf20Sopenharmony_ci	}
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
16618c2ecf20Sopenharmony_ci		hub, endpoint->bInterval);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	/* maybe cycle the hub leds */
16648c2ecf20Sopenharmony_ci	if (hub->has_indicators && blinkenlights)
16658c2ecf20Sopenharmony_ci		hub->indicator[0] = INDICATOR_CYCLE;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	mutex_lock(&usb_port_peer_mutex);
16688c2ecf20Sopenharmony_ci	for (i = 0; i < maxchild; i++) {
16698c2ecf20Sopenharmony_ci		ret = usb_hub_create_port_device(hub, i + 1);
16708c2ecf20Sopenharmony_ci		if (ret < 0) {
16718c2ecf20Sopenharmony_ci			dev_err(hub->intfdev,
16728c2ecf20Sopenharmony_ci				"couldn't create port%d device.\n", i + 1);
16738c2ecf20Sopenharmony_ci			break;
16748c2ecf20Sopenharmony_ci		}
16758c2ecf20Sopenharmony_ci	}
16768c2ecf20Sopenharmony_ci	hdev->maxchild = i;
16778c2ecf20Sopenharmony_ci	for (i = 0; i < hdev->maxchild; i++) {
16788c2ecf20Sopenharmony_ci		struct usb_port *port_dev = hub->ports[i];
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci		pm_runtime_put(&port_dev->dev);
16818c2ecf20Sopenharmony_ci	}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	mutex_unlock(&usb_port_peer_mutex);
16848c2ecf20Sopenharmony_ci	if (ret < 0)
16858c2ecf20Sopenharmony_ci		goto fail;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	/* Update the HCD's internal representation of this hub before hub_wq
16888c2ecf20Sopenharmony_ci	 * starts getting port status changes for devices under the hub.
16898c2ecf20Sopenharmony_ci	 */
16908c2ecf20Sopenharmony_ci	if (hcd->driver->update_hub_device) {
16918c2ecf20Sopenharmony_ci		ret = hcd->driver->update_hub_device(hcd, hdev,
16928c2ecf20Sopenharmony_ci				&hub->tt, GFP_KERNEL);
16938c2ecf20Sopenharmony_ci		if (ret < 0) {
16948c2ecf20Sopenharmony_ci			message = "can't update HCD hub info";
16958c2ecf20Sopenharmony_ci			goto fail;
16968c2ecf20Sopenharmony_ci		}
16978c2ecf20Sopenharmony_ci	}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	usb_hub_adjust_deviceremovable(hdev, hub->descriptor);
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	hub_activate(hub, HUB_INIT);
17028c2ecf20Sopenharmony_ci	return 0;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_cifail:
17058c2ecf20Sopenharmony_ci	dev_err(hub_dev, "config failed, %s (err %d)\n",
17068c2ecf20Sopenharmony_ci			message, ret);
17078c2ecf20Sopenharmony_ci	/* hub_disconnect() frees urb and descriptor */
17088c2ecf20Sopenharmony_ci	return ret;
17098c2ecf20Sopenharmony_ci}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_cistatic void hub_release(struct kref *kref)
17128c2ecf20Sopenharmony_ci{
17138c2ecf20Sopenharmony_ci	struct usb_hub *hub = container_of(kref, struct usb_hub, kref);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	usb_put_dev(hub->hdev);
17168c2ecf20Sopenharmony_ci	usb_put_intf(to_usb_interface(hub->intfdev));
17178c2ecf20Sopenharmony_ci	kfree(hub);
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_cistatic unsigned highspeed_hubs;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_cistatic void hub_disconnect(struct usb_interface *intf)
17238c2ecf20Sopenharmony_ci{
17248c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_get_intfdata(intf);
17258c2ecf20Sopenharmony_ci	struct usb_device *hdev = interface_to_usbdev(intf);
17268c2ecf20Sopenharmony_ci	int port1;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	/*
17298c2ecf20Sopenharmony_ci	 * Stop adding new hub events. We do not want to block here and thus
17308c2ecf20Sopenharmony_ci	 * will not try to remove any pending work item.
17318c2ecf20Sopenharmony_ci	 */
17328c2ecf20Sopenharmony_ci	hub->disconnected = 1;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	/* Disconnect all children and quiesce the hub */
17358c2ecf20Sopenharmony_ci	hub->error = 0;
17368c2ecf20Sopenharmony_ci	hub_quiesce(hub, HUB_DISCONNECT);
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	mutex_lock(&usb_port_peer_mutex);
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	/* Avoid races with recursively_mark_NOTATTACHED() */
17418c2ecf20Sopenharmony_ci	spin_lock_irq(&device_state_lock);
17428c2ecf20Sopenharmony_ci	port1 = hdev->maxchild;
17438c2ecf20Sopenharmony_ci	hdev->maxchild = 0;
17448c2ecf20Sopenharmony_ci	usb_set_intfdata(intf, NULL);
17458c2ecf20Sopenharmony_ci	spin_unlock_irq(&device_state_lock);
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	for (; port1 > 0; --port1)
17488c2ecf20Sopenharmony_ci		usb_hub_remove_port_device(hub, port1);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	mutex_unlock(&usb_port_peer_mutex);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	if (hub->hdev->speed == USB_SPEED_HIGH)
17538c2ecf20Sopenharmony_ci		highspeed_hubs--;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	usb_free_urb(hub->urb);
17568c2ecf20Sopenharmony_ci	kfree(hub->ports);
17578c2ecf20Sopenharmony_ci	kfree(hub->descriptor);
17588c2ecf20Sopenharmony_ci	kfree(hub->status);
17598c2ecf20Sopenharmony_ci	kfree(hub->buffer);
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	pm_suspend_ignore_children(&intf->dev, false);
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	if (hub->quirk_disable_autosuspend)
17648c2ecf20Sopenharmony_ci		usb_autopm_put_interface(intf);
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	kref_put(&hub->kref, hub_release);
17678c2ecf20Sopenharmony_ci}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_cistatic bool hub_descriptor_is_sane(struct usb_host_interface *desc)
17708c2ecf20Sopenharmony_ci{
17718c2ecf20Sopenharmony_ci	/* Some hubs have a subclass of 1, which AFAICT according to the */
17728c2ecf20Sopenharmony_ci	/*  specs is not defined, but it works */
17738c2ecf20Sopenharmony_ci	if (desc->desc.bInterfaceSubClass != 0 &&
17748c2ecf20Sopenharmony_ci	    desc->desc.bInterfaceSubClass != 1)
17758c2ecf20Sopenharmony_ci		return false;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
17788c2ecf20Sopenharmony_ci	if (desc->desc.bNumEndpoints != 1)
17798c2ecf20Sopenharmony_ci		return false;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	/* If the first endpoint is not interrupt IN, we'd better punt! */
17828c2ecf20Sopenharmony_ci	if (!usb_endpoint_is_int_in(&desc->endpoint[0].desc))
17838c2ecf20Sopenharmony_ci		return false;
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci        return true;
17868c2ecf20Sopenharmony_ci}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_cistatic int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
17898c2ecf20Sopenharmony_ci{
17908c2ecf20Sopenharmony_ci	struct usb_host_interface *desc;
17918c2ecf20Sopenharmony_ci	struct usb_device *hdev;
17928c2ecf20Sopenharmony_ci	struct usb_hub *hub;
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	desc = intf->cur_altsetting;
17958c2ecf20Sopenharmony_ci	hdev = interface_to_usbdev(intf);
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	/*
17988c2ecf20Sopenharmony_ci	 * Set default autosuspend delay as 0 to speedup bus suspend,
17998c2ecf20Sopenharmony_ci	 * based on the below considerations:
18008c2ecf20Sopenharmony_ci	 *
18018c2ecf20Sopenharmony_ci	 * - Unlike other drivers, the hub driver does not rely on the
18028c2ecf20Sopenharmony_ci	 *   autosuspend delay to provide enough time to handle a wakeup
18038c2ecf20Sopenharmony_ci	 *   event, and the submitted status URB is just to check future
18048c2ecf20Sopenharmony_ci	 *   change on hub downstream ports, so it is safe to do it.
18058c2ecf20Sopenharmony_ci	 *
18068c2ecf20Sopenharmony_ci	 * - The patch might cause one or more auto supend/resume for
18078c2ecf20Sopenharmony_ci	 *   below very rare devices when they are plugged into hub
18088c2ecf20Sopenharmony_ci	 *   first time:
18098c2ecf20Sopenharmony_ci	 *
18108c2ecf20Sopenharmony_ci	 *   	devices having trouble initializing, and disconnect
18118c2ecf20Sopenharmony_ci	 *   	themselves from the bus and then reconnect a second
18128c2ecf20Sopenharmony_ci	 *   	or so later
18138c2ecf20Sopenharmony_ci	 *
18148c2ecf20Sopenharmony_ci	 *   	devices just for downloading firmware, and disconnects
18158c2ecf20Sopenharmony_ci	 *   	themselves after completing it
18168c2ecf20Sopenharmony_ci	 *
18178c2ecf20Sopenharmony_ci	 *   For these quite rare devices, their drivers may change the
18188c2ecf20Sopenharmony_ci	 *   autosuspend delay of their parent hub in the probe() to one
18198c2ecf20Sopenharmony_ci	 *   appropriate value to avoid the subtle problem if someone
18208c2ecf20Sopenharmony_ci	 *   does care it.
18218c2ecf20Sopenharmony_ci	 *
18228c2ecf20Sopenharmony_ci	 * - The patch may cause one or more auto suspend/resume on
18238c2ecf20Sopenharmony_ci	 *   hub during running 'lsusb', but it is probably too
18248c2ecf20Sopenharmony_ci	 *   infrequent to worry about.
18258c2ecf20Sopenharmony_ci	 *
18268c2ecf20Sopenharmony_ci	 * - Change autosuspend delay of hub can avoid unnecessary auto
18278c2ecf20Sopenharmony_ci	 *   suspend timer for hub, also may decrease power consumption
18288c2ecf20Sopenharmony_ci	 *   of USB bus.
18298c2ecf20Sopenharmony_ci	 *
18308c2ecf20Sopenharmony_ci	 * - If user has indicated to prevent autosuspend by passing
18318c2ecf20Sopenharmony_ci	 *   usbcore.autosuspend = -1 then keep autosuspend disabled.
18328c2ecf20Sopenharmony_ci	 */
18338c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
18348c2ecf20Sopenharmony_ci	if (hdev->dev.power.autosuspend_delay >= 0)
18358c2ecf20Sopenharmony_ci		pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
18368c2ecf20Sopenharmony_ci#endif
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	/*
18398c2ecf20Sopenharmony_ci	 * Hubs have proper suspend/resume support, except for root hubs
18408c2ecf20Sopenharmony_ci	 * where the controller driver doesn't have bus_suspend and
18418c2ecf20Sopenharmony_ci	 * bus_resume methods.
18428c2ecf20Sopenharmony_ci	 */
18438c2ecf20Sopenharmony_ci	if (hdev->parent) {		/* normal device */
18448c2ecf20Sopenharmony_ci		usb_enable_autosuspend(hdev);
18458c2ecf20Sopenharmony_ci	} else {			/* root hub */
18468c2ecf20Sopenharmony_ci		const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver;
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci		if (drv->bus_suspend && drv->bus_resume)
18498c2ecf20Sopenharmony_ci			usb_enable_autosuspend(hdev);
18508c2ecf20Sopenharmony_ci	}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	if (hdev->level == MAX_TOPO_LEVEL) {
18538c2ecf20Sopenharmony_ci		dev_err(&intf->dev,
18548c2ecf20Sopenharmony_ci			"Unsupported bus topology: hub nested too deep\n");
18558c2ecf20Sopenharmony_ci		return -E2BIG;
18568c2ecf20Sopenharmony_ci	}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci#ifdef	CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB
18598c2ecf20Sopenharmony_ci	if (hdev->parent) {
18608c2ecf20Sopenharmony_ci		dev_warn(&intf->dev, "ignoring external hub\n");
18618c2ecf20Sopenharmony_ci		return -ENODEV;
18628c2ecf20Sopenharmony_ci	}
18638c2ecf20Sopenharmony_ci#endif
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	if (!hub_descriptor_is_sane(desc)) {
18668c2ecf20Sopenharmony_ci		dev_err(&intf->dev, "bad descriptor, ignoring hub\n");
18678c2ecf20Sopenharmony_ci		return -EIO;
18688c2ecf20Sopenharmony_ci	}
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	/* We found a hub */
18718c2ecf20Sopenharmony_ci	dev_info(&intf->dev, "USB hub found\n");
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	hub = kzalloc(sizeof(*hub), GFP_KERNEL);
18748c2ecf20Sopenharmony_ci	if (!hub)
18758c2ecf20Sopenharmony_ci		return -ENOMEM;
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	kref_init(&hub->kref);
18788c2ecf20Sopenharmony_ci	hub->intfdev = &intf->dev;
18798c2ecf20Sopenharmony_ci	hub->hdev = hdev;
18808c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hub->leds, led_work);
18818c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hub->init_work, NULL);
18828c2ecf20Sopenharmony_ci	INIT_WORK(&hub->events, hub_event);
18838c2ecf20Sopenharmony_ci	spin_lock_init(&hub->irq_urb_lock);
18848c2ecf20Sopenharmony_ci	timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
18858c2ecf20Sopenharmony_ci	usb_get_intf(intf);
18868c2ecf20Sopenharmony_ci	usb_get_dev(hdev);
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	usb_set_intfdata(intf, hub);
18898c2ecf20Sopenharmony_ci	intf->needs_remote_wakeup = 1;
18908c2ecf20Sopenharmony_ci	pm_suspend_ignore_children(&intf->dev, true);
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	if (hdev->speed == USB_SPEED_HIGH)
18938c2ecf20Sopenharmony_ci		highspeed_hubs++;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
18968c2ecf20Sopenharmony_ci		hub->quirk_check_port_auto_suspend = 1;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	if (id->driver_info & HUB_QUIRK_DISABLE_AUTOSUSPEND) {
18998c2ecf20Sopenharmony_ci		hub->quirk_disable_autosuspend = 1;
19008c2ecf20Sopenharmony_ci		usb_autopm_get_interface_no_resume(intf);
19018c2ecf20Sopenharmony_ci	}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
19048c2ecf20Sopenharmony_ci		return 0;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	hub_disconnect(intf);
19078c2ecf20Sopenharmony_ci	return -ENODEV;
19088c2ecf20Sopenharmony_ci}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_cistatic int
19118c2ecf20Sopenharmony_cihub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
19128c2ecf20Sopenharmony_ci{
19138c2ecf20Sopenharmony_ci	struct usb_device *hdev = interface_to_usbdev(intf);
19148c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	/* assert ifno == 0 (part of hub spec) */
19178c2ecf20Sopenharmony_ci	switch (code) {
19188c2ecf20Sopenharmony_ci	case USBDEVFS_HUB_PORTINFO: {
19198c2ecf20Sopenharmony_ci		struct usbdevfs_hub_portinfo *info = user_data;
19208c2ecf20Sopenharmony_ci		int i;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci		spin_lock_irq(&device_state_lock);
19238c2ecf20Sopenharmony_ci		if (hdev->devnum <= 0)
19248c2ecf20Sopenharmony_ci			info->nports = 0;
19258c2ecf20Sopenharmony_ci		else {
19268c2ecf20Sopenharmony_ci			info->nports = hdev->maxchild;
19278c2ecf20Sopenharmony_ci			for (i = 0; i < info->nports; i++) {
19288c2ecf20Sopenharmony_ci				if (hub->ports[i]->child == NULL)
19298c2ecf20Sopenharmony_ci					info->port[i] = 0;
19308c2ecf20Sopenharmony_ci				else
19318c2ecf20Sopenharmony_ci					info->port[i] =
19328c2ecf20Sopenharmony_ci						hub->ports[i]->child->devnum;
19338c2ecf20Sopenharmony_ci			}
19348c2ecf20Sopenharmony_ci		}
19358c2ecf20Sopenharmony_ci		spin_unlock_irq(&device_state_lock);
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci		return info->nports + 1;
19388c2ecf20Sopenharmony_ci		}
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	default:
19418c2ecf20Sopenharmony_ci		return -ENOSYS;
19428c2ecf20Sopenharmony_ci	}
19438c2ecf20Sopenharmony_ci}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci/*
19468c2ecf20Sopenharmony_ci * Allow user programs to claim ports on a hub.  When a device is attached
19478c2ecf20Sopenharmony_ci * to one of these "claimed" ports, the program will "own" the device.
19488c2ecf20Sopenharmony_ci */
19498c2ecf20Sopenharmony_cistatic int find_port_owner(struct usb_device *hdev, unsigned port1,
19508c2ecf20Sopenharmony_ci		struct usb_dev_state ***ppowner)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	if (hdev->state == USB_STATE_NOTATTACHED)
19558c2ecf20Sopenharmony_ci		return -ENODEV;
19568c2ecf20Sopenharmony_ci	if (port1 == 0 || port1 > hdev->maxchild)
19578c2ecf20Sopenharmony_ci		return -EINVAL;
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	/* Devices not managed by the hub driver
19608c2ecf20Sopenharmony_ci	 * will always have maxchild equal to 0.
19618c2ecf20Sopenharmony_ci	 */
19628c2ecf20Sopenharmony_ci	*ppowner = &(hub->ports[port1 - 1]->port_owner);
19638c2ecf20Sopenharmony_ci	return 0;
19648c2ecf20Sopenharmony_ci}
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci/* In the following three functions, the caller must hold hdev's lock */
19678c2ecf20Sopenharmony_ciint usb_hub_claim_port(struct usb_device *hdev, unsigned port1,
19688c2ecf20Sopenharmony_ci		       struct usb_dev_state *owner)
19698c2ecf20Sopenharmony_ci{
19708c2ecf20Sopenharmony_ci	int rc;
19718c2ecf20Sopenharmony_ci	struct usb_dev_state **powner;
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	rc = find_port_owner(hdev, port1, &powner);
19748c2ecf20Sopenharmony_ci	if (rc)
19758c2ecf20Sopenharmony_ci		return rc;
19768c2ecf20Sopenharmony_ci	if (*powner)
19778c2ecf20Sopenharmony_ci		return -EBUSY;
19788c2ecf20Sopenharmony_ci	*powner = owner;
19798c2ecf20Sopenharmony_ci	return rc;
19808c2ecf20Sopenharmony_ci}
19818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_hub_claim_port);
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ciint usb_hub_release_port(struct usb_device *hdev, unsigned port1,
19848c2ecf20Sopenharmony_ci			 struct usb_dev_state *owner)
19858c2ecf20Sopenharmony_ci{
19868c2ecf20Sopenharmony_ci	int rc;
19878c2ecf20Sopenharmony_ci	struct usb_dev_state **powner;
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	rc = find_port_owner(hdev, port1, &powner);
19908c2ecf20Sopenharmony_ci	if (rc)
19918c2ecf20Sopenharmony_ci		return rc;
19928c2ecf20Sopenharmony_ci	if (*powner != owner)
19938c2ecf20Sopenharmony_ci		return -ENOENT;
19948c2ecf20Sopenharmony_ci	*powner = NULL;
19958c2ecf20Sopenharmony_ci	return rc;
19968c2ecf20Sopenharmony_ci}
19978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_hub_release_port);
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_civoid usb_hub_release_all_ports(struct usb_device *hdev, struct usb_dev_state *owner)
20008c2ecf20Sopenharmony_ci{
20018c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
20028c2ecf20Sopenharmony_ci	int n;
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	for (n = 0; n < hdev->maxchild; n++) {
20058c2ecf20Sopenharmony_ci		if (hub->ports[n]->port_owner == owner)
20068c2ecf20Sopenharmony_ci			hub->ports[n]->port_owner = NULL;
20078c2ecf20Sopenharmony_ci	}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci/* The caller must hold udev's lock */
20128c2ecf20Sopenharmony_cibool usb_device_is_owned(struct usb_device *udev)
20138c2ecf20Sopenharmony_ci{
20148c2ecf20Sopenharmony_ci	struct usb_hub *hub;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
20178c2ecf20Sopenharmony_ci		return false;
20188c2ecf20Sopenharmony_ci	hub = usb_hub_to_struct_hub(udev->parent);
20198c2ecf20Sopenharmony_ci	return !!hub->ports[udev->portnum - 1]->port_owner;
20208c2ecf20Sopenharmony_ci}
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cistatic void recursively_mark_NOTATTACHED(struct usb_device *udev)
20238c2ecf20Sopenharmony_ci{
20248c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(udev);
20258c2ecf20Sopenharmony_ci	int i;
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	for (i = 0; i < udev->maxchild; ++i) {
20288c2ecf20Sopenharmony_ci		if (hub->ports[i]->child)
20298c2ecf20Sopenharmony_ci			recursively_mark_NOTATTACHED(hub->ports[i]->child);
20308c2ecf20Sopenharmony_ci	}
20318c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_SUSPENDED)
20328c2ecf20Sopenharmony_ci		udev->active_duration -= jiffies;
20338c2ecf20Sopenharmony_ci	udev->state = USB_STATE_NOTATTACHED;
20348c2ecf20Sopenharmony_ci}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci/**
20378c2ecf20Sopenharmony_ci * usb_set_device_state - change a device's current state (usbcore, hcds)
20388c2ecf20Sopenharmony_ci * @udev: pointer to device whose state should be changed
20398c2ecf20Sopenharmony_ci * @new_state: new state value to be stored
20408c2ecf20Sopenharmony_ci *
20418c2ecf20Sopenharmony_ci * udev->state is _not_ fully protected by the device lock.  Although
20428c2ecf20Sopenharmony_ci * most transitions are made only while holding the lock, the state can
20438c2ecf20Sopenharmony_ci * can change to USB_STATE_NOTATTACHED at almost any time.  This
20448c2ecf20Sopenharmony_ci * is so that devices can be marked as disconnected as soon as possible,
20458c2ecf20Sopenharmony_ci * without having to wait for any semaphores to be released.  As a result,
20468c2ecf20Sopenharmony_ci * all changes to any device's state must be protected by the
20478c2ecf20Sopenharmony_ci * device_state_lock spinlock.
20488c2ecf20Sopenharmony_ci *
20498c2ecf20Sopenharmony_ci * Once a device has been added to the device tree, all changes to its state
20508c2ecf20Sopenharmony_ci * should be made using this routine.  The state should _not_ be set directly.
20518c2ecf20Sopenharmony_ci *
20528c2ecf20Sopenharmony_ci * If udev->state is already USB_STATE_NOTATTACHED then no change is made.
20538c2ecf20Sopenharmony_ci * Otherwise udev->state is set to new_state, and if new_state is
20548c2ecf20Sopenharmony_ci * USB_STATE_NOTATTACHED then all of udev's descendants' states are also set
20558c2ecf20Sopenharmony_ci * to USB_STATE_NOTATTACHED.
20568c2ecf20Sopenharmony_ci */
20578c2ecf20Sopenharmony_civoid usb_set_device_state(struct usb_device *udev,
20588c2ecf20Sopenharmony_ci		enum usb_device_state new_state)
20598c2ecf20Sopenharmony_ci{
20608c2ecf20Sopenharmony_ci	unsigned long flags;
20618c2ecf20Sopenharmony_ci	int wakeup = -1;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&device_state_lock, flags);
20648c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_NOTATTACHED)
20658c2ecf20Sopenharmony_ci		;	/* do nothing */
20668c2ecf20Sopenharmony_ci	else if (new_state != USB_STATE_NOTATTACHED) {
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci		/* root hub wakeup capabilities are managed out-of-band
20698c2ecf20Sopenharmony_ci		 * and may involve silicon errata ... ignore them here.
20708c2ecf20Sopenharmony_ci		 */
20718c2ecf20Sopenharmony_ci		if (udev->parent) {
20728c2ecf20Sopenharmony_ci			if (udev->state == USB_STATE_SUSPENDED
20738c2ecf20Sopenharmony_ci					|| new_state == USB_STATE_SUSPENDED)
20748c2ecf20Sopenharmony_ci				;	/* No change to wakeup settings */
20758c2ecf20Sopenharmony_ci			else if (new_state == USB_STATE_CONFIGURED)
20768c2ecf20Sopenharmony_ci				wakeup = (udev->quirks &
20778c2ecf20Sopenharmony_ci					USB_QUIRK_IGNORE_REMOTE_WAKEUP) ? 0 :
20788c2ecf20Sopenharmony_ci					udev->actconfig->desc.bmAttributes &
20798c2ecf20Sopenharmony_ci					USB_CONFIG_ATT_WAKEUP;
20808c2ecf20Sopenharmony_ci			else
20818c2ecf20Sopenharmony_ci				wakeup = 0;
20828c2ecf20Sopenharmony_ci		}
20838c2ecf20Sopenharmony_ci		if (udev->state == USB_STATE_SUSPENDED &&
20848c2ecf20Sopenharmony_ci			new_state != USB_STATE_SUSPENDED)
20858c2ecf20Sopenharmony_ci			udev->active_duration -= jiffies;
20868c2ecf20Sopenharmony_ci		else if (new_state == USB_STATE_SUSPENDED &&
20878c2ecf20Sopenharmony_ci				udev->state != USB_STATE_SUSPENDED)
20888c2ecf20Sopenharmony_ci			udev->active_duration += jiffies;
20898c2ecf20Sopenharmony_ci		udev->state = new_state;
20908c2ecf20Sopenharmony_ci	} else
20918c2ecf20Sopenharmony_ci		recursively_mark_NOTATTACHED(udev);
20928c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&device_state_lock, flags);
20938c2ecf20Sopenharmony_ci	if (wakeup >= 0)
20948c2ecf20Sopenharmony_ci		device_set_wakeup_capable(&udev->dev, wakeup);
20958c2ecf20Sopenharmony_ci}
20968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_set_device_state);
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci/*
20998c2ecf20Sopenharmony_ci * Choose a device number.
21008c2ecf20Sopenharmony_ci *
21018c2ecf20Sopenharmony_ci * Device numbers are used as filenames in usbfs.  On USB-1.1 and
21028c2ecf20Sopenharmony_ci * USB-2.0 buses they are also used as device addresses, however on
21038c2ecf20Sopenharmony_ci * USB-3.0 buses the address is assigned by the controller hardware
21048c2ecf20Sopenharmony_ci * and it usually is not the same as the device number.
21058c2ecf20Sopenharmony_ci *
21068c2ecf20Sopenharmony_ci * WUSB devices are simple: they have no hubs behind, so the mapping
21078c2ecf20Sopenharmony_ci * device <-> virtual port number becomes 1:1. Why? to simplify the
21088c2ecf20Sopenharmony_ci * life of the device connection logic in
21098c2ecf20Sopenharmony_ci * drivers/usb/wusbcore/devconnect.c. When we do the initial secret
21108c2ecf20Sopenharmony_ci * handshake we need to assign a temporary address in the unauthorized
21118c2ecf20Sopenharmony_ci * space. For simplicity we use the first virtual port number found to
21128c2ecf20Sopenharmony_ci * be free [drivers/usb/wusbcore/devconnect.c:wusbhc_devconnect_ack()]
21138c2ecf20Sopenharmony_ci * and that becomes it's address [X < 128] or its unauthorized address
21148c2ecf20Sopenharmony_ci * [X | 0x80].
21158c2ecf20Sopenharmony_ci *
21168c2ecf20Sopenharmony_ci * We add 1 as an offset to the one-based USB-stack port number
21178c2ecf20Sopenharmony_ci * (zero-based wusb virtual port index) for two reasons: (a) dev addr
21188c2ecf20Sopenharmony_ci * 0 is reserved by USB for default address; (b) Linux's USB stack
21198c2ecf20Sopenharmony_ci * uses always #1 for the root hub of the controller. So USB stack's
21208c2ecf20Sopenharmony_ci * port #1, which is wusb virtual-port #0 has address #2.
21218c2ecf20Sopenharmony_ci *
21228c2ecf20Sopenharmony_ci * Devices connected under xHCI are not as simple.  The host controller
21238c2ecf20Sopenharmony_ci * supports virtualization, so the hardware assigns device addresses and
21248c2ecf20Sopenharmony_ci * the HCD must setup data structures before issuing a set address
21258c2ecf20Sopenharmony_ci * command to the hardware.
21268c2ecf20Sopenharmony_ci */
21278c2ecf20Sopenharmony_cistatic void choose_devnum(struct usb_device *udev)
21288c2ecf20Sopenharmony_ci{
21298c2ecf20Sopenharmony_ci	int		devnum;
21308c2ecf20Sopenharmony_ci	struct usb_bus	*bus = udev->bus;
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci	/* be safe when more hub events are proceed in parallel */
21338c2ecf20Sopenharmony_ci	mutex_lock(&bus->devnum_next_mutex);
21348c2ecf20Sopenharmony_ci	if (udev->wusb) {
21358c2ecf20Sopenharmony_ci		devnum = udev->portnum + 1;
21368c2ecf20Sopenharmony_ci		BUG_ON(test_bit(devnum, bus->devmap.devicemap));
21378c2ecf20Sopenharmony_ci	} else {
21388c2ecf20Sopenharmony_ci		/* Try to allocate the next devnum beginning at
21398c2ecf20Sopenharmony_ci		 * bus->devnum_next. */
21408c2ecf20Sopenharmony_ci		devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
21418c2ecf20Sopenharmony_ci					    bus->devnum_next);
21428c2ecf20Sopenharmony_ci		if (devnum >= 128)
21438c2ecf20Sopenharmony_ci			devnum = find_next_zero_bit(bus->devmap.devicemap,
21448c2ecf20Sopenharmony_ci						    128, 1);
21458c2ecf20Sopenharmony_ci		bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);
21468c2ecf20Sopenharmony_ci	}
21478c2ecf20Sopenharmony_ci	if (devnum < 128) {
21488c2ecf20Sopenharmony_ci		set_bit(devnum, bus->devmap.devicemap);
21498c2ecf20Sopenharmony_ci		udev->devnum = devnum;
21508c2ecf20Sopenharmony_ci	}
21518c2ecf20Sopenharmony_ci	mutex_unlock(&bus->devnum_next_mutex);
21528c2ecf20Sopenharmony_ci}
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_cistatic void release_devnum(struct usb_device *udev)
21558c2ecf20Sopenharmony_ci{
21568c2ecf20Sopenharmony_ci	if (udev->devnum > 0) {
21578c2ecf20Sopenharmony_ci		clear_bit(udev->devnum, udev->bus->devmap.devicemap);
21588c2ecf20Sopenharmony_ci		udev->devnum = -1;
21598c2ecf20Sopenharmony_ci	}
21608c2ecf20Sopenharmony_ci}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_cistatic void update_devnum(struct usb_device *udev, int devnum)
21638c2ecf20Sopenharmony_ci{
21648c2ecf20Sopenharmony_ci	/* The address for a WUSB device is managed by wusbcore. */
21658c2ecf20Sopenharmony_ci	if (!udev->wusb)
21668c2ecf20Sopenharmony_ci		udev->devnum = devnum;
21678c2ecf20Sopenharmony_ci	if (!udev->devaddr)
21688c2ecf20Sopenharmony_ci		udev->devaddr = (u8)devnum;
21698c2ecf20Sopenharmony_ci}
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_cistatic void hub_free_dev(struct usb_device *udev)
21728c2ecf20Sopenharmony_ci{
21738c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	/* Root hubs aren't real devices, so don't free HCD resources */
21768c2ecf20Sopenharmony_ci	if (hcd->driver->free_dev && udev->parent)
21778c2ecf20Sopenharmony_ci		hcd->driver->free_dev(hcd, udev);
21788c2ecf20Sopenharmony_ci}
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_cistatic void hub_disconnect_children(struct usb_device *udev)
21818c2ecf20Sopenharmony_ci{
21828c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(udev);
21838c2ecf20Sopenharmony_ci	int i;
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	/* Free up all the children before we remove this device */
21868c2ecf20Sopenharmony_ci	for (i = 0; i < udev->maxchild; i++) {
21878c2ecf20Sopenharmony_ci		if (hub->ports[i]->child)
21888c2ecf20Sopenharmony_ci			usb_disconnect(&hub->ports[i]->child);
21898c2ecf20Sopenharmony_ci	}
21908c2ecf20Sopenharmony_ci}
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci/**
21938c2ecf20Sopenharmony_ci * usb_disconnect - disconnect a device (usbcore-internal)
21948c2ecf20Sopenharmony_ci * @pdev: pointer to device being disconnected
21958c2ecf20Sopenharmony_ci * Context: !in_interrupt ()
21968c2ecf20Sopenharmony_ci *
21978c2ecf20Sopenharmony_ci * Something got disconnected. Get rid of it and all of its children.
21988c2ecf20Sopenharmony_ci *
21998c2ecf20Sopenharmony_ci * If *pdev is a normal device then the parent hub must already be locked.
22008c2ecf20Sopenharmony_ci * If *pdev is a root hub then the caller must hold the usb_bus_idr_lock,
22018c2ecf20Sopenharmony_ci * which protects the set of root hubs as well as the list of buses.
22028c2ecf20Sopenharmony_ci *
22038c2ecf20Sopenharmony_ci * Only hub drivers (including virtual root hub drivers for host
22048c2ecf20Sopenharmony_ci * controllers) should ever call this.
22058c2ecf20Sopenharmony_ci *
22068c2ecf20Sopenharmony_ci * This call is synchronous, and may not be used in an interrupt context.
22078c2ecf20Sopenharmony_ci */
22088c2ecf20Sopenharmony_civoid usb_disconnect(struct usb_device **pdev)
22098c2ecf20Sopenharmony_ci{
22108c2ecf20Sopenharmony_ci	struct usb_port *port_dev = NULL;
22118c2ecf20Sopenharmony_ci	struct usb_device *udev = *pdev;
22128c2ecf20Sopenharmony_ci	struct usb_hub *hub = NULL;
22138c2ecf20Sopenharmony_ci	int port1 = 1;
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	/* mark the device as inactive, so any further urb submissions for
22168c2ecf20Sopenharmony_ci	 * this device (and any of its children) will fail immediately.
22178c2ecf20Sopenharmony_ci	 * this quiesces everything except pending urbs.
22188c2ecf20Sopenharmony_ci	 */
22198c2ecf20Sopenharmony_ci	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
22208c2ecf20Sopenharmony_ci	dev_info(&udev->dev, "USB disconnect, device number %d\n",
22218c2ecf20Sopenharmony_ci			udev->devnum);
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	/*
22248c2ecf20Sopenharmony_ci	 * Ensure that the pm runtime code knows that the USB device
22258c2ecf20Sopenharmony_ci	 * is in the process of being disconnected.
22268c2ecf20Sopenharmony_ci	 */
22278c2ecf20Sopenharmony_ci	pm_runtime_barrier(&udev->dev);
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	usb_lock_device(udev);
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	hub_disconnect_children(udev);
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	/* deallocate hcd/hardware state ... nuking all pending urbs and
22348c2ecf20Sopenharmony_ci	 * cleaning up all state associated with the current configuration
22358c2ecf20Sopenharmony_ci	 * so that the hardware is now fully quiesced.
22368c2ecf20Sopenharmony_ci	 */
22378c2ecf20Sopenharmony_ci	dev_dbg(&udev->dev, "unregistering device\n");
22388c2ecf20Sopenharmony_ci	usb_disable_device(udev, 0);
22398c2ecf20Sopenharmony_ci	usb_hcd_synchronize_unlinks(udev);
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	if (udev->parent) {
22428c2ecf20Sopenharmony_ci		port1 = udev->portnum;
22438c2ecf20Sopenharmony_ci		hub = usb_hub_to_struct_hub(udev->parent);
22448c2ecf20Sopenharmony_ci		port_dev = hub->ports[port1 - 1];
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci		sysfs_remove_link(&udev->dev.kobj, "port");
22478c2ecf20Sopenharmony_ci		sysfs_remove_link(&port_dev->dev.kobj, "device");
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci		/*
22508c2ecf20Sopenharmony_ci		 * As usb_port_runtime_resume() de-references udev, make
22518c2ecf20Sopenharmony_ci		 * sure no resumes occur during removal
22528c2ecf20Sopenharmony_ci		 */
22538c2ecf20Sopenharmony_ci		if (!test_and_set_bit(port1, hub->child_usage_bits))
22548c2ecf20Sopenharmony_ci			pm_runtime_get_sync(&port_dev->dev);
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	usb_remove_ep_devs(&udev->ep0);
22588c2ecf20Sopenharmony_ci	usb_unlock_device(udev);
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci	/* Unregister the device.  The device driver is responsible
22618c2ecf20Sopenharmony_ci	 * for de-configuring the device and invoking the remove-device
22628c2ecf20Sopenharmony_ci	 * notifier chain (used by usbfs and possibly others).
22638c2ecf20Sopenharmony_ci	 */
22648c2ecf20Sopenharmony_ci	device_del(&udev->dev);
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	/* Free the device number and delete the parent's children[]
22678c2ecf20Sopenharmony_ci	 * (or root_hub) pointer.
22688c2ecf20Sopenharmony_ci	 */
22698c2ecf20Sopenharmony_ci	release_devnum(udev);
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	/* Avoid races with recursively_mark_NOTATTACHED() */
22728c2ecf20Sopenharmony_ci	spin_lock_irq(&device_state_lock);
22738c2ecf20Sopenharmony_ci	*pdev = NULL;
22748c2ecf20Sopenharmony_ci	spin_unlock_irq(&device_state_lock);
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits))
22778c2ecf20Sopenharmony_ci		pm_runtime_put(&port_dev->dev);
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	hub_free_dev(udev);
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	put_device(&udev->dev);
22828c2ecf20Sopenharmony_ci}
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
22858c2ecf20Sopenharmony_cistatic void show_string(struct usb_device *udev, char *id, char *string)
22868c2ecf20Sopenharmony_ci{
22878c2ecf20Sopenharmony_ci	if (!string)
22888c2ecf20Sopenharmony_ci		return;
22898c2ecf20Sopenharmony_ci	dev_info(&udev->dev, "%s: %s\n", id, string);
22908c2ecf20Sopenharmony_ci}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_cistatic void announce_device(struct usb_device *udev)
22938c2ecf20Sopenharmony_ci{
22948c2ecf20Sopenharmony_ci	u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	dev_info(&udev->dev,
22978c2ecf20Sopenharmony_ci		"New USB device found, idVendor=%04x, idProduct=%04x, bcdDevice=%2x.%02x\n",
22988c2ecf20Sopenharmony_ci		le16_to_cpu(udev->descriptor.idVendor),
22998c2ecf20Sopenharmony_ci		le16_to_cpu(udev->descriptor.idProduct),
23008c2ecf20Sopenharmony_ci		bcdDevice >> 8, bcdDevice & 0xff);
23018c2ecf20Sopenharmony_ci	dev_info(&udev->dev,
23028c2ecf20Sopenharmony_ci		"New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
23038c2ecf20Sopenharmony_ci		udev->descriptor.iManufacturer,
23048c2ecf20Sopenharmony_ci		udev->descriptor.iProduct,
23058c2ecf20Sopenharmony_ci		udev->descriptor.iSerialNumber);
23068c2ecf20Sopenharmony_ci	show_string(udev, "Product", udev->product);
23078c2ecf20Sopenharmony_ci	show_string(udev, "Manufacturer", udev->manufacturer);
23088c2ecf20Sopenharmony_ci	show_string(udev, "SerialNumber", udev->serial);
23098c2ecf20Sopenharmony_ci}
23108c2ecf20Sopenharmony_ci#else
23118c2ecf20Sopenharmony_cistatic inline void announce_device(struct usb_device *udev) { }
23128c2ecf20Sopenharmony_ci#endif
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci/**
23168c2ecf20Sopenharmony_ci * usb_enumerate_device_otg - FIXME (usbcore-internal)
23178c2ecf20Sopenharmony_ci * @udev: newly addressed device (in ADDRESS state)
23188c2ecf20Sopenharmony_ci *
23198c2ecf20Sopenharmony_ci * Finish enumeration for On-The-Go devices
23208c2ecf20Sopenharmony_ci *
23218c2ecf20Sopenharmony_ci * Return: 0 if successful. A negative error code otherwise.
23228c2ecf20Sopenharmony_ci */
23238c2ecf20Sopenharmony_cistatic int usb_enumerate_device_otg(struct usb_device *udev)
23248c2ecf20Sopenharmony_ci{
23258c2ecf20Sopenharmony_ci	int err = 0;
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci#ifdef	CONFIG_USB_OTG
23288c2ecf20Sopenharmony_ci	/*
23298c2ecf20Sopenharmony_ci	 * OTG-aware devices on OTG-capable root hubs may be able to use SRP,
23308c2ecf20Sopenharmony_ci	 * to wake us after we've powered off VBUS; and HNP, switching roles
23318c2ecf20Sopenharmony_ci	 * "host" to "peripheral".  The OTG descriptor helps figure this out.
23328c2ecf20Sopenharmony_ci	 */
23338c2ecf20Sopenharmony_ci	if (!udev->bus->is_b_host
23348c2ecf20Sopenharmony_ci			&& udev->config
23358c2ecf20Sopenharmony_ci			&& udev->parent == udev->bus->root_hub) {
23368c2ecf20Sopenharmony_ci		struct usb_otg_descriptor	*desc = NULL;
23378c2ecf20Sopenharmony_ci		struct usb_bus			*bus = udev->bus;
23388c2ecf20Sopenharmony_ci		unsigned			port1 = udev->portnum;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci		/* descriptor may appear anywhere in config */
23418c2ecf20Sopenharmony_ci		err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
23428c2ecf20Sopenharmony_ci				le16_to_cpu(udev->config[0].desc.wTotalLength),
23438c2ecf20Sopenharmony_ci				USB_DT_OTG, (void **) &desc, sizeof(*desc));
23448c2ecf20Sopenharmony_ci		if (err || !(desc->bmAttributes & USB_OTG_HNP))
23458c2ecf20Sopenharmony_ci			return 0;
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci		dev_info(&udev->dev, "Dual-Role OTG device on %sHNP port\n",
23488c2ecf20Sopenharmony_ci					(port1 == bus->otg_port) ? "" : "non-");
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci		/* enable HNP before suspend, it's simpler */
23518c2ecf20Sopenharmony_ci		if (port1 == bus->otg_port) {
23528c2ecf20Sopenharmony_ci			bus->b_hnp_enable = 1;
23538c2ecf20Sopenharmony_ci			err = usb_control_msg(udev,
23548c2ecf20Sopenharmony_ci				usb_sndctrlpipe(udev, 0),
23558c2ecf20Sopenharmony_ci				USB_REQ_SET_FEATURE, 0,
23568c2ecf20Sopenharmony_ci				USB_DEVICE_B_HNP_ENABLE,
23578c2ecf20Sopenharmony_ci				0, NULL, 0,
23588c2ecf20Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
23598c2ecf20Sopenharmony_ci			if (err < 0) {
23608c2ecf20Sopenharmony_ci				/*
23618c2ecf20Sopenharmony_ci				 * OTG MESSAGE: report errors here,
23628c2ecf20Sopenharmony_ci				 * customize to match your product.
23638c2ecf20Sopenharmony_ci				 */
23648c2ecf20Sopenharmony_ci				dev_err(&udev->dev, "can't set HNP mode: %d\n",
23658c2ecf20Sopenharmony_ci									err);
23668c2ecf20Sopenharmony_ci				bus->b_hnp_enable = 0;
23678c2ecf20Sopenharmony_ci			}
23688c2ecf20Sopenharmony_ci		} else if (desc->bLength == sizeof
23698c2ecf20Sopenharmony_ci				(struct usb_otg_descriptor)) {
23708c2ecf20Sopenharmony_ci			/*
23718c2ecf20Sopenharmony_ci			 * We are operating on a legacy OTP device
23728c2ecf20Sopenharmony_ci			 * These should be told that they are operating
23738c2ecf20Sopenharmony_ci			 * on the wrong port if we have another port that does
23748c2ecf20Sopenharmony_ci			 * support HNP
23758c2ecf20Sopenharmony_ci			 */
23768c2ecf20Sopenharmony_ci			if (bus->otg_port != 0) {
23778c2ecf20Sopenharmony_ci				/* Set a_alt_hnp_support for legacy otg device */
23788c2ecf20Sopenharmony_ci				err = usb_control_msg(udev,
23798c2ecf20Sopenharmony_ci					usb_sndctrlpipe(udev, 0),
23808c2ecf20Sopenharmony_ci					USB_REQ_SET_FEATURE, 0,
23818c2ecf20Sopenharmony_ci					USB_DEVICE_A_ALT_HNP_SUPPORT,
23828c2ecf20Sopenharmony_ci					0, NULL, 0,
23838c2ecf20Sopenharmony_ci					USB_CTRL_SET_TIMEOUT);
23848c2ecf20Sopenharmony_ci				if (err < 0)
23858c2ecf20Sopenharmony_ci					dev_err(&udev->dev,
23868c2ecf20Sopenharmony_ci						"set a_alt_hnp_support failed: %d\n",
23878c2ecf20Sopenharmony_ci						err);
23888c2ecf20Sopenharmony_ci			}
23898c2ecf20Sopenharmony_ci		}
23908c2ecf20Sopenharmony_ci	}
23918c2ecf20Sopenharmony_ci#endif
23928c2ecf20Sopenharmony_ci	return err;
23938c2ecf20Sopenharmony_ci}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci/**
23978c2ecf20Sopenharmony_ci * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal)
23988c2ecf20Sopenharmony_ci * @udev: newly addressed device (in ADDRESS state)
23998c2ecf20Sopenharmony_ci *
24008c2ecf20Sopenharmony_ci * This is only called by usb_new_device() -- all comments that apply there
24018c2ecf20Sopenharmony_ci * apply here wrt to environment.
24028c2ecf20Sopenharmony_ci *
24038c2ecf20Sopenharmony_ci * If the device is WUSB and not authorized, we don't attempt to read
24048c2ecf20Sopenharmony_ci * the string descriptors, as they will be errored out by the device
24058c2ecf20Sopenharmony_ci * until it has been authorized.
24068c2ecf20Sopenharmony_ci *
24078c2ecf20Sopenharmony_ci * Return: 0 if successful. A negative error code otherwise.
24088c2ecf20Sopenharmony_ci */
24098c2ecf20Sopenharmony_cistatic int usb_enumerate_device(struct usb_device *udev)
24108c2ecf20Sopenharmony_ci{
24118c2ecf20Sopenharmony_ci	int err;
24128c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	if (udev->config == NULL) {
24158c2ecf20Sopenharmony_ci		err = usb_get_configuration(udev);
24168c2ecf20Sopenharmony_ci		if (err < 0) {
24178c2ecf20Sopenharmony_ci			if (err != -ENODEV)
24188c2ecf20Sopenharmony_ci				dev_err(&udev->dev, "can't read configurations, error %d\n",
24198c2ecf20Sopenharmony_ci						err);
24208c2ecf20Sopenharmony_ci			return err;
24218c2ecf20Sopenharmony_ci		}
24228c2ecf20Sopenharmony_ci	}
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	/* read the standard strings and cache them if present */
24258c2ecf20Sopenharmony_ci	udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
24268c2ecf20Sopenharmony_ci	udev->manufacturer = usb_cache_string(udev,
24278c2ecf20Sopenharmony_ci					      udev->descriptor.iManufacturer);
24288c2ecf20Sopenharmony_ci	udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci	err = usb_enumerate_device_otg(udev);
24318c2ecf20Sopenharmony_ci	if (err < 0)
24328c2ecf20Sopenharmony_ci		return err;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_USB_OTG_PRODUCTLIST) && hcd->tpl_support &&
24358c2ecf20Sopenharmony_ci		!is_targeted(udev)) {
24368c2ecf20Sopenharmony_ci		/* Maybe it can talk to us, though we can't talk to it.
24378c2ecf20Sopenharmony_ci		 * (Includes HNP test device.)
24388c2ecf20Sopenharmony_ci		 */
24398c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_USB_OTG) && (udev->bus->b_hnp_enable
24408c2ecf20Sopenharmony_ci			|| udev->bus->is_b_host)) {
24418c2ecf20Sopenharmony_ci			err = usb_port_suspend(udev, PMSG_AUTO_SUSPEND);
24428c2ecf20Sopenharmony_ci			if (err < 0)
24438c2ecf20Sopenharmony_ci				dev_dbg(&udev->dev, "HNP fail, %d\n", err);
24448c2ecf20Sopenharmony_ci		}
24458c2ecf20Sopenharmony_ci		return -ENOTSUPP;
24468c2ecf20Sopenharmony_ci	}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	usb_detect_interface_quirks(udev);
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci	return 0;
24518c2ecf20Sopenharmony_ci}
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_cistatic void set_usb_port_removable(struct usb_device *udev)
24548c2ecf20Sopenharmony_ci{
24558c2ecf20Sopenharmony_ci	struct usb_device *hdev = udev->parent;
24568c2ecf20Sopenharmony_ci	struct usb_hub *hub;
24578c2ecf20Sopenharmony_ci	u8 port = udev->portnum;
24588c2ecf20Sopenharmony_ci	u16 wHubCharacteristics;
24598c2ecf20Sopenharmony_ci	bool removable = true;
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	dev_set_removable(&udev->dev, DEVICE_REMOVABLE_UNKNOWN);
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	if (!hdev)
24648c2ecf20Sopenharmony_ci		return;
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	hub = usb_hub_to_struct_hub(udev->parent);
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci	/*
24698c2ecf20Sopenharmony_ci	 * If the platform firmware has provided information about a port,
24708c2ecf20Sopenharmony_ci	 * use that to determine whether it's removable.
24718c2ecf20Sopenharmony_ci	 */
24728c2ecf20Sopenharmony_ci	switch (hub->ports[udev->portnum - 1]->connect_type) {
24738c2ecf20Sopenharmony_ci	case USB_PORT_CONNECT_TYPE_HOT_PLUG:
24748c2ecf20Sopenharmony_ci		dev_set_removable(&udev->dev, DEVICE_REMOVABLE);
24758c2ecf20Sopenharmony_ci		return;
24768c2ecf20Sopenharmony_ci	case USB_PORT_CONNECT_TYPE_HARD_WIRED:
24778c2ecf20Sopenharmony_ci	case USB_PORT_NOT_USED:
24788c2ecf20Sopenharmony_ci		dev_set_removable(&udev->dev, DEVICE_FIXED);
24798c2ecf20Sopenharmony_ci		return;
24808c2ecf20Sopenharmony_ci	default:
24818c2ecf20Sopenharmony_ci		break;
24828c2ecf20Sopenharmony_ci	}
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	/*
24858c2ecf20Sopenharmony_ci	 * Otherwise, check whether the hub knows whether a port is removable
24868c2ecf20Sopenharmony_ci	 * or not
24878c2ecf20Sopenharmony_ci	 */
24888c2ecf20Sopenharmony_ci	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
24918c2ecf20Sopenharmony_ci		return;
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hdev)) {
24948c2ecf20Sopenharmony_ci		if (le16_to_cpu(hub->descriptor->u.ss.DeviceRemovable)
24958c2ecf20Sopenharmony_ci				& (1 << port))
24968c2ecf20Sopenharmony_ci			removable = false;
24978c2ecf20Sopenharmony_ci	} else {
24988c2ecf20Sopenharmony_ci		if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
24998c2ecf20Sopenharmony_ci			removable = false;
25008c2ecf20Sopenharmony_ci	}
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	if (removable)
25038c2ecf20Sopenharmony_ci		dev_set_removable(&udev->dev, DEVICE_REMOVABLE);
25048c2ecf20Sopenharmony_ci	else
25058c2ecf20Sopenharmony_ci		dev_set_removable(&udev->dev, DEVICE_FIXED);
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci}
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci/**
25108c2ecf20Sopenharmony_ci * usb_new_device - perform initial device setup (usbcore-internal)
25118c2ecf20Sopenharmony_ci * @udev: newly addressed device (in ADDRESS state)
25128c2ecf20Sopenharmony_ci *
25138c2ecf20Sopenharmony_ci * This is called with devices which have been detected but not fully
25148c2ecf20Sopenharmony_ci * enumerated.  The device descriptor is available, but not descriptors
25158c2ecf20Sopenharmony_ci * for any device configuration.  The caller must have locked either
25168c2ecf20Sopenharmony_ci * the parent hub (if udev is a normal device) or else the
25178c2ecf20Sopenharmony_ci * usb_bus_idr_lock (if udev is a root hub).  The parent's pointer to
25188c2ecf20Sopenharmony_ci * udev has already been installed, but udev is not yet visible through
25198c2ecf20Sopenharmony_ci * sysfs or other filesystem code.
25208c2ecf20Sopenharmony_ci *
25218c2ecf20Sopenharmony_ci * This call is synchronous, and may not be used in an interrupt context.
25228c2ecf20Sopenharmony_ci *
25238c2ecf20Sopenharmony_ci * Only the hub driver or root-hub registrar should ever call this.
25248c2ecf20Sopenharmony_ci *
25258c2ecf20Sopenharmony_ci * Return: Whether the device is configured properly or not. Zero if the
25268c2ecf20Sopenharmony_ci * interface was registered with the driver core; else a negative errno
25278c2ecf20Sopenharmony_ci * value.
25288c2ecf20Sopenharmony_ci *
25298c2ecf20Sopenharmony_ci */
25308c2ecf20Sopenharmony_ciint usb_new_device(struct usb_device *udev)
25318c2ecf20Sopenharmony_ci{
25328c2ecf20Sopenharmony_ci	int err;
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	if (udev->parent) {
25358c2ecf20Sopenharmony_ci		/* Initialize non-root-hub device wakeup to disabled;
25368c2ecf20Sopenharmony_ci		 * device (un)configuration controls wakeup capable
25378c2ecf20Sopenharmony_ci		 * sysfs power/wakeup controls wakeup enabled/disabled
25388c2ecf20Sopenharmony_ci		 */
25398c2ecf20Sopenharmony_ci		device_init_wakeup(&udev->dev, 0);
25408c2ecf20Sopenharmony_ci	}
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	/* Tell the runtime-PM framework the device is active */
25438c2ecf20Sopenharmony_ci	pm_runtime_set_active(&udev->dev);
25448c2ecf20Sopenharmony_ci	pm_runtime_get_noresume(&udev->dev);
25458c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(&udev->dev);
25468c2ecf20Sopenharmony_ci	pm_runtime_enable(&udev->dev);
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	/* By default, forbid autosuspend for all devices.  It will be
25498c2ecf20Sopenharmony_ci	 * allowed for hubs during binding.
25508c2ecf20Sopenharmony_ci	 */
25518c2ecf20Sopenharmony_ci	usb_disable_autosuspend(udev);
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	err = usb_enumerate_device(udev);	/* Read descriptors */
25548c2ecf20Sopenharmony_ci	if (err < 0)
25558c2ecf20Sopenharmony_ci		goto fail;
25568c2ecf20Sopenharmony_ci	dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
25578c2ecf20Sopenharmony_ci			udev->devnum, udev->bus->busnum,
25588c2ecf20Sopenharmony_ci			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
25598c2ecf20Sopenharmony_ci	/* export the usbdev device-node for libusb */
25608c2ecf20Sopenharmony_ci	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
25618c2ecf20Sopenharmony_ci			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	/* Tell the world! */
25648c2ecf20Sopenharmony_ci	announce_device(udev);
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci	if (udev->serial)
25678c2ecf20Sopenharmony_ci		add_device_randomness(udev->serial, strlen(udev->serial));
25688c2ecf20Sopenharmony_ci	if (udev->product)
25698c2ecf20Sopenharmony_ci		add_device_randomness(udev->product, strlen(udev->product));
25708c2ecf20Sopenharmony_ci	if (udev->manufacturer)
25718c2ecf20Sopenharmony_ci		add_device_randomness(udev->manufacturer,
25728c2ecf20Sopenharmony_ci				      strlen(udev->manufacturer));
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	device_enable_async_suspend(&udev->dev);
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	/* check whether the hub or firmware marks this port as non-removable */
25778c2ecf20Sopenharmony_ci	set_usb_port_removable(udev);
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci	/* Register the device.  The device driver is responsible
25808c2ecf20Sopenharmony_ci	 * for configuring the device and invoking the add-device
25818c2ecf20Sopenharmony_ci	 * notifier chain (used by usbfs and possibly others).
25828c2ecf20Sopenharmony_ci	 */
25838c2ecf20Sopenharmony_ci	err = device_add(&udev->dev);
25848c2ecf20Sopenharmony_ci	if (err) {
25858c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "can't device_add, error %d\n", err);
25868c2ecf20Sopenharmony_ci		goto fail;
25878c2ecf20Sopenharmony_ci	}
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	/* Create link files between child device and usb port device. */
25908c2ecf20Sopenharmony_ci	if (udev->parent) {
25918c2ecf20Sopenharmony_ci		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
25928c2ecf20Sopenharmony_ci		int port1 = udev->portnum;
25938c2ecf20Sopenharmony_ci		struct usb_port	*port_dev = hub->ports[port1 - 1];
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci		err = sysfs_create_link(&udev->dev.kobj,
25968c2ecf20Sopenharmony_ci				&port_dev->dev.kobj, "port");
25978c2ecf20Sopenharmony_ci		if (err)
25988c2ecf20Sopenharmony_ci			goto fail;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci		err = sysfs_create_link(&port_dev->dev.kobj,
26018c2ecf20Sopenharmony_ci				&udev->dev.kobj, "device");
26028c2ecf20Sopenharmony_ci		if (err) {
26038c2ecf20Sopenharmony_ci			sysfs_remove_link(&udev->dev.kobj, "port");
26048c2ecf20Sopenharmony_ci			goto fail;
26058c2ecf20Sopenharmony_ci		}
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci		if (!test_and_set_bit(port1, hub->child_usage_bits))
26088c2ecf20Sopenharmony_ci			pm_runtime_get_sync(&port_dev->dev);
26098c2ecf20Sopenharmony_ci	}
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci	(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
26128c2ecf20Sopenharmony_ci	usb_mark_last_busy(udev);
26138c2ecf20Sopenharmony_ci	pm_runtime_put_sync_autosuspend(&udev->dev);
26148c2ecf20Sopenharmony_ci	return err;
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_cifail:
26178c2ecf20Sopenharmony_ci	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
26188c2ecf20Sopenharmony_ci	pm_runtime_disable(&udev->dev);
26198c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(&udev->dev);
26208c2ecf20Sopenharmony_ci	return err;
26218c2ecf20Sopenharmony_ci}
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci/**
26258c2ecf20Sopenharmony_ci * usb_deauthorize_device - deauthorize a device (usbcore-internal)
26268c2ecf20Sopenharmony_ci * @usb_dev: USB device
26278c2ecf20Sopenharmony_ci *
26288c2ecf20Sopenharmony_ci * Move the USB device to a very basic state where interfaces are disabled
26298c2ecf20Sopenharmony_ci * and the device is in fact unconfigured and unusable.
26308c2ecf20Sopenharmony_ci *
26318c2ecf20Sopenharmony_ci * We share a lock (that we have) with device_del(), so we need to
26328c2ecf20Sopenharmony_ci * defer its call.
26338c2ecf20Sopenharmony_ci *
26348c2ecf20Sopenharmony_ci * Return: 0.
26358c2ecf20Sopenharmony_ci */
26368c2ecf20Sopenharmony_ciint usb_deauthorize_device(struct usb_device *usb_dev)
26378c2ecf20Sopenharmony_ci{
26388c2ecf20Sopenharmony_ci	usb_lock_device(usb_dev);
26398c2ecf20Sopenharmony_ci	if (usb_dev->authorized == 0)
26408c2ecf20Sopenharmony_ci		goto out_unauthorized;
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci	usb_dev->authorized = 0;
26438c2ecf20Sopenharmony_ci	usb_set_configuration(usb_dev, -1);
26448c2ecf20Sopenharmony_ci
26458c2ecf20Sopenharmony_ciout_unauthorized:
26468c2ecf20Sopenharmony_ci	usb_unlock_device(usb_dev);
26478c2ecf20Sopenharmony_ci	return 0;
26488c2ecf20Sopenharmony_ci}
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ciint usb_authorize_device(struct usb_device *usb_dev)
26528c2ecf20Sopenharmony_ci{
26538c2ecf20Sopenharmony_ci	int result = 0, c;
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	usb_lock_device(usb_dev);
26568c2ecf20Sopenharmony_ci	if (usb_dev->authorized == 1)
26578c2ecf20Sopenharmony_ci		goto out_authorized;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	result = usb_autoresume_device(usb_dev);
26608c2ecf20Sopenharmony_ci	if (result < 0) {
26618c2ecf20Sopenharmony_ci		dev_err(&usb_dev->dev,
26628c2ecf20Sopenharmony_ci			"can't autoresume for authorization: %d\n", result);
26638c2ecf20Sopenharmony_ci		goto error_autoresume;
26648c2ecf20Sopenharmony_ci	}
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	if (usb_dev->wusb) {
26678c2ecf20Sopenharmony_ci		struct usb_device_descriptor *descr;
26688c2ecf20Sopenharmony_ci
26698c2ecf20Sopenharmony_ci		descr = usb_get_device_descriptor(usb_dev);
26708c2ecf20Sopenharmony_ci		if (IS_ERR(descr)) {
26718c2ecf20Sopenharmony_ci			result = PTR_ERR(descr);
26728c2ecf20Sopenharmony_ci			dev_err(&usb_dev->dev, "can't re-read device descriptor for "
26738c2ecf20Sopenharmony_ci				"authorization: %d\n", result);
26748c2ecf20Sopenharmony_ci			goto error_device_descriptor;
26758c2ecf20Sopenharmony_ci		}
26768c2ecf20Sopenharmony_ci		usb_dev->descriptor = *descr;
26778c2ecf20Sopenharmony_ci		kfree(descr);
26788c2ecf20Sopenharmony_ci	}
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	usb_dev->authorized = 1;
26818c2ecf20Sopenharmony_ci	/* Choose and set the configuration.  This registers the interfaces
26828c2ecf20Sopenharmony_ci	 * with the driver core and lets interface drivers bind to them.
26838c2ecf20Sopenharmony_ci	 */
26848c2ecf20Sopenharmony_ci	c = usb_choose_configuration(usb_dev);
26858c2ecf20Sopenharmony_ci	if (c >= 0) {
26868c2ecf20Sopenharmony_ci		result = usb_set_configuration(usb_dev, c);
26878c2ecf20Sopenharmony_ci		if (result) {
26888c2ecf20Sopenharmony_ci			dev_err(&usb_dev->dev,
26898c2ecf20Sopenharmony_ci				"can't set config #%d, error %d\n", c, result);
26908c2ecf20Sopenharmony_ci			/* This need not be fatal.  The user can try to
26918c2ecf20Sopenharmony_ci			 * set other configurations. */
26928c2ecf20Sopenharmony_ci		}
26938c2ecf20Sopenharmony_ci	}
26948c2ecf20Sopenharmony_ci	dev_info(&usb_dev->dev, "authorized to connect\n");
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_cierror_device_descriptor:
26978c2ecf20Sopenharmony_ci	usb_autosuspend_device(usb_dev);
26988c2ecf20Sopenharmony_cierror_autoresume:
26998c2ecf20Sopenharmony_ciout_authorized:
27008c2ecf20Sopenharmony_ci	usb_unlock_device(usb_dev);	/* complements locktree */
27018c2ecf20Sopenharmony_ci	return result;
27028c2ecf20Sopenharmony_ci}
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci/**
27058c2ecf20Sopenharmony_ci * get_port_ssp_rate - Match the extended port status to SSP rate
27068c2ecf20Sopenharmony_ci * @hdev: The hub device
27078c2ecf20Sopenharmony_ci * @ext_portstatus: extended port status
27088c2ecf20Sopenharmony_ci *
27098c2ecf20Sopenharmony_ci * Match the extended port status speed id to the SuperSpeed Plus sublink speed
27108c2ecf20Sopenharmony_ci * capability attributes. Base on the number of connected lanes and speed,
27118c2ecf20Sopenharmony_ci * return the corresponding enum usb_ssp_rate.
27128c2ecf20Sopenharmony_ci */
27138c2ecf20Sopenharmony_cistatic enum usb_ssp_rate get_port_ssp_rate(struct usb_device *hdev,
27148c2ecf20Sopenharmony_ci					   u32 ext_portstatus)
27158c2ecf20Sopenharmony_ci{
27168c2ecf20Sopenharmony_ci	struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap;
27178c2ecf20Sopenharmony_ci	u32 attr;
27188c2ecf20Sopenharmony_ci	u8 speed_id;
27198c2ecf20Sopenharmony_ci	u8 ssac;
27208c2ecf20Sopenharmony_ci	u8 lanes;
27218c2ecf20Sopenharmony_ci	int i;
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	if (!ssp_cap)
27248c2ecf20Sopenharmony_ci		goto out;
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	speed_id = ext_portstatus & USB_EXT_PORT_STAT_RX_SPEED_ID;
27278c2ecf20Sopenharmony_ci	lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	ssac = le32_to_cpu(ssp_cap->bmAttributes) &
27308c2ecf20Sopenharmony_ci		USB_SSP_SUBLINK_SPEED_ATTRIBS;
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci	for (i = 0; i <= ssac; i++) {
27338c2ecf20Sopenharmony_ci		u8 ssid;
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_ci		attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]);
27368c2ecf20Sopenharmony_ci		ssid = FIELD_GET(USB_SSP_SUBLINK_SPEED_SSID, attr);
27378c2ecf20Sopenharmony_ci		if (speed_id == ssid) {
27388c2ecf20Sopenharmony_ci			u16 mantissa;
27398c2ecf20Sopenharmony_ci			u8 lse;
27408c2ecf20Sopenharmony_ci			u8 type;
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci			/*
27438c2ecf20Sopenharmony_ci			 * Note: currently asymmetric lane types are only
27448c2ecf20Sopenharmony_ci			 * applicable for SSIC operate in SuperSpeed protocol
27458c2ecf20Sopenharmony_ci			 */
27468c2ecf20Sopenharmony_ci			type = FIELD_GET(USB_SSP_SUBLINK_SPEED_ST, attr);
27478c2ecf20Sopenharmony_ci			if (type == USB_SSP_SUBLINK_SPEED_ST_ASYM_RX ||
27488c2ecf20Sopenharmony_ci			    type == USB_SSP_SUBLINK_SPEED_ST_ASYM_TX)
27498c2ecf20Sopenharmony_ci				goto out;
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci			if (FIELD_GET(USB_SSP_SUBLINK_SPEED_LP, attr) !=
27528c2ecf20Sopenharmony_ci			    USB_SSP_SUBLINK_SPEED_LP_SSP)
27538c2ecf20Sopenharmony_ci				goto out;
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci			lse = FIELD_GET(USB_SSP_SUBLINK_SPEED_LSE, attr);
27568c2ecf20Sopenharmony_ci			mantissa = FIELD_GET(USB_SSP_SUBLINK_SPEED_LSM, attr);
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci			/* Convert to Gbps */
27598c2ecf20Sopenharmony_ci			for (; lse < USB_SSP_SUBLINK_SPEED_LSE_GBPS; lse++)
27608c2ecf20Sopenharmony_ci				mantissa /= 1000;
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci			if (mantissa >= 10 && lanes == 1)
27638c2ecf20Sopenharmony_ci				return USB_SSP_GEN_2x1;
27648c2ecf20Sopenharmony_ci
27658c2ecf20Sopenharmony_ci			if (mantissa >= 10 && lanes == 2)
27668c2ecf20Sopenharmony_ci				return USB_SSP_GEN_2x2;
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci			if (mantissa >= 5 && lanes == 2)
27698c2ecf20Sopenharmony_ci				return USB_SSP_GEN_1x2;
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci			goto out;
27728c2ecf20Sopenharmony_ci		}
27738c2ecf20Sopenharmony_ci	}
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ciout:
27768c2ecf20Sopenharmony_ci	return USB_SSP_GEN_UNKNOWN;
27778c2ecf20Sopenharmony_ci}
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci/*
27808c2ecf20Sopenharmony_ci * Return 1 if port speed is SuperSpeedPlus, 0 otherwise or if the
27818c2ecf20Sopenharmony_ci * capability couldn't be checked.
27828c2ecf20Sopenharmony_ci * check it from the link protocol field of the current speed ID attribute.
27838c2ecf20Sopenharmony_ci * current speed ID is got from ext port status request. Sublink speed attribute
27848c2ecf20Sopenharmony_ci * table is returned with the hub BOS SSP device capability descriptor
27858c2ecf20Sopenharmony_ci */
27868c2ecf20Sopenharmony_cistatic int port_speed_is_ssp(struct usb_device *hdev, int speed_id)
27878c2ecf20Sopenharmony_ci{
27888c2ecf20Sopenharmony_ci	int ssa_count;
27898c2ecf20Sopenharmony_ci	u32 ss_attr;
27908c2ecf20Sopenharmony_ci	int i;
27918c2ecf20Sopenharmony_ci	struct usb_ssp_cap_descriptor *ssp_cap;
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ci	if (!hdev->bos)
27948c2ecf20Sopenharmony_ci		return 0;
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	ssp_cap = hdev->bos->ssp_cap;
27978c2ecf20Sopenharmony_ci	if (!ssp_cap)
27988c2ecf20Sopenharmony_ci		return 0;
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci	ssa_count = le32_to_cpu(ssp_cap->bmAttributes) &
28018c2ecf20Sopenharmony_ci		USB_SSP_SUBLINK_SPEED_ATTRIBS;
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	for (i = 0; i <= ssa_count; i++) {
28048c2ecf20Sopenharmony_ci		ss_attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]);
28058c2ecf20Sopenharmony_ci		if (speed_id == (ss_attr & USB_SSP_SUBLINK_SPEED_SSID))
28068c2ecf20Sopenharmony_ci			return !!(ss_attr & USB_SSP_SUBLINK_SPEED_LP);
28078c2ecf20Sopenharmony_ci	}
28088c2ecf20Sopenharmony_ci	return 0;
28098c2ecf20Sopenharmony_ci}
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_ci/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
28128c2ecf20Sopenharmony_cistatic unsigned hub_is_wusb(struct usb_hub *hub)
28138c2ecf20Sopenharmony_ci{
28148c2ecf20Sopenharmony_ci	struct usb_hcd *hcd;
28158c2ecf20Sopenharmony_ci	if (hub->hdev->parent != NULL)  /* not a root hub? */
28168c2ecf20Sopenharmony_ci		return 0;
28178c2ecf20Sopenharmony_ci	hcd = bus_to_hcd(hub->hdev->bus);
28188c2ecf20Sopenharmony_ci	return hcd->wireless;
28198c2ecf20Sopenharmony_ci}
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_FEW_INIT_RETRIES
28238c2ecf20Sopenharmony_ci#define PORT_RESET_TRIES	2
28248c2ecf20Sopenharmony_ci#define SET_ADDRESS_TRIES	1
28258c2ecf20Sopenharmony_ci#define GET_DESCRIPTOR_TRIES	1
28268c2ecf20Sopenharmony_ci#define GET_MAXPACKET0_TRIES	1
28278c2ecf20Sopenharmony_ci#define PORT_INIT_TRIES		4
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci#else
28308c2ecf20Sopenharmony_ci#define PORT_RESET_TRIES	5
28318c2ecf20Sopenharmony_ci#define SET_ADDRESS_TRIES	2
28328c2ecf20Sopenharmony_ci#define GET_DESCRIPTOR_TRIES	2
28338c2ecf20Sopenharmony_ci#define GET_MAXPACKET0_TRIES	3
28348c2ecf20Sopenharmony_ci#define PORT_INIT_TRIES		4
28358c2ecf20Sopenharmony_ci#endif	/* CONFIG_USB_FEW_INIT_RETRIES */
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci#define HUB_ROOT_RESET_TIME	60	/* times are in msec */
28388c2ecf20Sopenharmony_ci#define HUB_SHORT_RESET_TIME	10
28398c2ecf20Sopenharmony_ci#define HUB_BH_RESET_TIME	50
28408c2ecf20Sopenharmony_ci#define HUB_LONG_RESET_TIME	200
28418c2ecf20Sopenharmony_ci#define HUB_RESET_TIMEOUT	800
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_cistatic bool use_new_scheme(struct usb_device *udev, int retry,
28448c2ecf20Sopenharmony_ci			   struct usb_port *port_dev)
28458c2ecf20Sopenharmony_ci{
28468c2ecf20Sopenharmony_ci	int old_scheme_first_port =
28478c2ecf20Sopenharmony_ci		(port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME) ||
28488c2ecf20Sopenharmony_ci		old_scheme_first;
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	/*
28518c2ecf20Sopenharmony_ci	 * "New scheme" enumeration causes an extra state transition to be
28528c2ecf20Sopenharmony_ci	 * exposed to an xhci host and causes USB3 devices to receive control
28538c2ecf20Sopenharmony_ci	 * commands in the default state.  This has been seen to cause
28548c2ecf20Sopenharmony_ci	 * enumeration failures, so disable this enumeration scheme for USB3
28558c2ecf20Sopenharmony_ci	 * devices.
28568c2ecf20Sopenharmony_ci	 */
28578c2ecf20Sopenharmony_ci	if (udev->speed >= USB_SPEED_SUPER)
28588c2ecf20Sopenharmony_ci		return false;
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	/*
28618c2ecf20Sopenharmony_ci	 * If use_both_schemes is set, use the first scheme (whichever
28628c2ecf20Sopenharmony_ci	 * it is) for the larger half of the retries, then use the other
28638c2ecf20Sopenharmony_ci	 * scheme.  Otherwise, use the first scheme for all the retries.
28648c2ecf20Sopenharmony_ci	 */
28658c2ecf20Sopenharmony_ci	if (use_both_schemes && retry >= (PORT_INIT_TRIES + 1) / 2)
28668c2ecf20Sopenharmony_ci		return old_scheme_first_port;	/* Second half */
28678c2ecf20Sopenharmony_ci	return !old_scheme_first_port;		/* First half or all */
28688c2ecf20Sopenharmony_ci}
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
28718c2ecf20Sopenharmony_ci * Port warm reset is required to recover
28728c2ecf20Sopenharmony_ci */
28738c2ecf20Sopenharmony_cistatic bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
28748c2ecf20Sopenharmony_ci		u16 portstatus)
28758c2ecf20Sopenharmony_ci{
28768c2ecf20Sopenharmony_ci	u16 link_state;
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci	if (!hub_is_superspeed(hub->hdev))
28798c2ecf20Sopenharmony_ci		return false;
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci	if (test_bit(port1, hub->warm_reset_bits))
28828c2ecf20Sopenharmony_ci		return true;
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	link_state = portstatus & USB_PORT_STAT_LINK_STATE;
28858c2ecf20Sopenharmony_ci	return link_state == USB_SS_PORT_LS_SS_INACTIVE
28868c2ecf20Sopenharmony_ci		|| link_state == USB_SS_PORT_LS_COMP_MOD;
28878c2ecf20Sopenharmony_ci}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_cistatic int hub_port_wait_reset(struct usb_hub *hub, int port1,
28908c2ecf20Sopenharmony_ci			struct usb_device *udev, unsigned int delay, bool warm)
28918c2ecf20Sopenharmony_ci{
28928c2ecf20Sopenharmony_ci	int delay_time, ret;
28938c2ecf20Sopenharmony_ci	u16 portstatus;
28948c2ecf20Sopenharmony_ci	u16 portchange;
28958c2ecf20Sopenharmony_ci	u32 ext_portstatus = 0;
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci	for (delay_time = 0;
28988c2ecf20Sopenharmony_ci			delay_time < HUB_RESET_TIMEOUT;
28998c2ecf20Sopenharmony_ci			delay_time += delay) {
29008c2ecf20Sopenharmony_ci		/* wait to give the device a chance to reset */
29018c2ecf20Sopenharmony_ci		msleep(delay);
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci		/* read and decode port status */
29048c2ecf20Sopenharmony_ci		if (hub_is_superspeedplus(hub->hdev))
29058c2ecf20Sopenharmony_ci			ret = hub_ext_port_status(hub, port1,
29068c2ecf20Sopenharmony_ci						  HUB_EXT_PORT_STATUS,
29078c2ecf20Sopenharmony_ci						  &portstatus, &portchange,
29088c2ecf20Sopenharmony_ci						  &ext_portstatus);
29098c2ecf20Sopenharmony_ci		else
29108c2ecf20Sopenharmony_ci			ret = hub_port_status(hub, port1, &portstatus,
29118c2ecf20Sopenharmony_ci					      &portchange);
29128c2ecf20Sopenharmony_ci		if (ret < 0)
29138c2ecf20Sopenharmony_ci			return ret;
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci		/*
29168c2ecf20Sopenharmony_ci		 * The port state is unknown until the reset completes.
29178c2ecf20Sopenharmony_ci		 *
29188c2ecf20Sopenharmony_ci		 * On top of that, some chips may require additional time
29198c2ecf20Sopenharmony_ci		 * to re-establish a connection after the reset is complete,
29208c2ecf20Sopenharmony_ci		 * so also wait for the connection to be re-established.
29218c2ecf20Sopenharmony_ci		 */
29228c2ecf20Sopenharmony_ci		if (!(portstatus & USB_PORT_STAT_RESET) &&
29238c2ecf20Sopenharmony_ci		    (portstatus & USB_PORT_STAT_CONNECTION))
29248c2ecf20Sopenharmony_ci			break;
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci		/* switch to the long delay after two short delay failures */
29278c2ecf20Sopenharmony_ci		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
29288c2ecf20Sopenharmony_ci			delay = HUB_LONG_RESET_TIME;
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci		dev_dbg(&hub->ports[port1 - 1]->dev,
29318c2ecf20Sopenharmony_ci				"not %sreset yet, waiting %dms\n",
29328c2ecf20Sopenharmony_ci				warm ? "warm " : "", delay);
29338c2ecf20Sopenharmony_ci	}
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	if ((portstatus & USB_PORT_STAT_RESET))
29368c2ecf20Sopenharmony_ci		return -EBUSY;
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	if (hub_port_warm_reset_required(hub, port1, portstatus))
29398c2ecf20Sopenharmony_ci		return -ENOTCONN;
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci	/* Device went away? */
29428c2ecf20Sopenharmony_ci	if (!(portstatus & USB_PORT_STAT_CONNECTION))
29438c2ecf20Sopenharmony_ci		return -ENOTCONN;
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_ci	/* Retry if connect change is set but status is still connected.
29468c2ecf20Sopenharmony_ci	 * A USB 3.0 connection may bounce if multiple warm resets were issued,
29478c2ecf20Sopenharmony_ci	 * but the device may have successfully re-connected. Ignore it.
29488c2ecf20Sopenharmony_ci	 */
29498c2ecf20Sopenharmony_ci	if (!hub_is_superspeed(hub->hdev) &&
29508c2ecf20Sopenharmony_ci	    (portchange & USB_PORT_STAT_C_CONNECTION)) {
29518c2ecf20Sopenharmony_ci		usb_clear_port_feature(hub->hdev, port1,
29528c2ecf20Sopenharmony_ci				       USB_PORT_FEAT_C_CONNECTION);
29538c2ecf20Sopenharmony_ci		return -EAGAIN;
29548c2ecf20Sopenharmony_ci	}
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci	if (!(portstatus & USB_PORT_STAT_ENABLE))
29578c2ecf20Sopenharmony_ci		return -EBUSY;
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci	if (!udev)
29608c2ecf20Sopenharmony_ci		return 0;
29618c2ecf20Sopenharmony_ci
29628c2ecf20Sopenharmony_ci	if (hub_is_superspeedplus(hub->hdev)) {
29638c2ecf20Sopenharmony_ci		/* extended portstatus Rx and Tx lane count are zero based */
29648c2ecf20Sopenharmony_ci		udev->rx_lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1;
29658c2ecf20Sopenharmony_ci		udev->tx_lanes = USB_EXT_PORT_TX_LANES(ext_portstatus) + 1;
29668c2ecf20Sopenharmony_ci		udev->ssp_rate = get_port_ssp_rate(hub->hdev, ext_portstatus);
29678c2ecf20Sopenharmony_ci	} else {
29688c2ecf20Sopenharmony_ci		udev->rx_lanes = 1;
29698c2ecf20Sopenharmony_ci		udev->tx_lanes = 1;
29708c2ecf20Sopenharmony_ci		udev->ssp_rate = USB_SSP_GEN_UNKNOWN;
29718c2ecf20Sopenharmony_ci	}
29728c2ecf20Sopenharmony_ci	if (hub_is_wusb(hub))
29738c2ecf20Sopenharmony_ci		udev->speed = USB_SPEED_WIRELESS;
29748c2ecf20Sopenharmony_ci	else if (hub_is_superspeedplus(hub->hdev) &&
29758c2ecf20Sopenharmony_ci		 port_speed_is_ssp(hub->hdev, ext_portstatus &
29768c2ecf20Sopenharmony_ci				   USB_EXT_PORT_STAT_RX_SPEED_ID))
29778c2ecf20Sopenharmony_ci		udev->speed = USB_SPEED_SUPER_PLUS;
29788c2ecf20Sopenharmony_ci	else if (hub_is_superspeed(hub->hdev))
29798c2ecf20Sopenharmony_ci		udev->speed = USB_SPEED_SUPER;
29808c2ecf20Sopenharmony_ci	else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
29818c2ecf20Sopenharmony_ci		udev->speed = USB_SPEED_HIGH;
29828c2ecf20Sopenharmony_ci	else if (portstatus & USB_PORT_STAT_LOW_SPEED)
29838c2ecf20Sopenharmony_ci		udev->speed = USB_SPEED_LOW;
29848c2ecf20Sopenharmony_ci	else
29858c2ecf20Sopenharmony_ci		udev->speed = USB_SPEED_FULL;
29868c2ecf20Sopenharmony_ci	return 0;
29878c2ecf20Sopenharmony_ci}
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
29908c2ecf20Sopenharmony_cistatic int hub_port_reset(struct usb_hub *hub, int port1,
29918c2ecf20Sopenharmony_ci			struct usb_device *udev, unsigned int delay, bool warm)
29928c2ecf20Sopenharmony_ci{
29938c2ecf20Sopenharmony_ci	int i, status;
29948c2ecf20Sopenharmony_ci	u16 portchange, portstatus;
29958c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
29968c2ecf20Sopenharmony_ci	int reset_recovery_time;
29978c2ecf20Sopenharmony_ci
29988c2ecf20Sopenharmony_ci	if (!hub_is_superspeed(hub->hdev)) {
29998c2ecf20Sopenharmony_ci		if (warm) {
30008c2ecf20Sopenharmony_ci			dev_err(hub->intfdev, "only USB3 hub support "
30018c2ecf20Sopenharmony_ci						"warm reset\n");
30028c2ecf20Sopenharmony_ci			return -EINVAL;
30038c2ecf20Sopenharmony_ci		}
30048c2ecf20Sopenharmony_ci		/* Block EHCI CF initialization during the port reset.
30058c2ecf20Sopenharmony_ci		 * Some companion controllers don't like it when they mix.
30068c2ecf20Sopenharmony_ci		 */
30078c2ecf20Sopenharmony_ci		down_read(&ehci_cf_port_reset_rwsem);
30088c2ecf20Sopenharmony_ci	} else if (!warm) {
30098c2ecf20Sopenharmony_ci		/*
30108c2ecf20Sopenharmony_ci		 * If the caller hasn't explicitly requested a warm reset,
30118c2ecf20Sopenharmony_ci		 * double check and see if one is needed.
30128c2ecf20Sopenharmony_ci		 */
30138c2ecf20Sopenharmony_ci		if (hub_port_status(hub, port1, &portstatus, &portchange) == 0)
30148c2ecf20Sopenharmony_ci			if (hub_port_warm_reset_required(hub, port1,
30158c2ecf20Sopenharmony_ci							portstatus))
30168c2ecf20Sopenharmony_ci				warm = true;
30178c2ecf20Sopenharmony_ci	}
30188c2ecf20Sopenharmony_ci	clear_bit(port1, hub->warm_reset_bits);
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci	/* Reset the port */
30218c2ecf20Sopenharmony_ci	for (i = 0; i < PORT_RESET_TRIES; i++) {
30228c2ecf20Sopenharmony_ci		status = set_port_feature(hub->hdev, port1, (warm ?
30238c2ecf20Sopenharmony_ci					USB_PORT_FEAT_BH_PORT_RESET :
30248c2ecf20Sopenharmony_ci					USB_PORT_FEAT_RESET));
30258c2ecf20Sopenharmony_ci		if (status == -ENODEV) {
30268c2ecf20Sopenharmony_ci			;	/* The hub is gone */
30278c2ecf20Sopenharmony_ci		} else if (status) {
30288c2ecf20Sopenharmony_ci			dev_err(&port_dev->dev,
30298c2ecf20Sopenharmony_ci					"cannot %sreset (err = %d)\n",
30308c2ecf20Sopenharmony_ci					warm ? "warm " : "", status);
30318c2ecf20Sopenharmony_ci		} else {
30328c2ecf20Sopenharmony_ci			status = hub_port_wait_reset(hub, port1, udev, delay,
30338c2ecf20Sopenharmony_ci								warm);
30348c2ecf20Sopenharmony_ci			if (status && status != -ENOTCONN && status != -ENODEV)
30358c2ecf20Sopenharmony_ci				dev_dbg(hub->intfdev,
30368c2ecf20Sopenharmony_ci						"port_wait_reset: err = %d\n",
30378c2ecf20Sopenharmony_ci						status);
30388c2ecf20Sopenharmony_ci		}
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_ci		/* Check for disconnect or reset */
30418c2ecf20Sopenharmony_ci		if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
30428c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
30438c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_RESET);
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci			if (!hub_is_superspeed(hub->hdev))
30468c2ecf20Sopenharmony_ci				goto done;
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
30498c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_BH_PORT_RESET);
30508c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
30518c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_PORT_LINK_STATE);
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci			if (udev)
30548c2ecf20Sopenharmony_ci				usb_clear_port_feature(hub->hdev, port1,
30558c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_CONNECTION);
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci			/*
30588c2ecf20Sopenharmony_ci			 * If a USB 3.0 device migrates from reset to an error
30598c2ecf20Sopenharmony_ci			 * state, re-issue the warm reset.
30608c2ecf20Sopenharmony_ci			 */
30618c2ecf20Sopenharmony_ci			if (hub_port_status(hub, port1,
30628c2ecf20Sopenharmony_ci					&portstatus, &portchange) < 0)
30638c2ecf20Sopenharmony_ci				goto done;
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci			if (!hub_port_warm_reset_required(hub, port1,
30668c2ecf20Sopenharmony_ci					portstatus))
30678c2ecf20Sopenharmony_ci				goto done;
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci			/*
30708c2ecf20Sopenharmony_ci			 * If the port is in SS.Inactive or Compliance Mode, the
30718c2ecf20Sopenharmony_ci			 * hot or warm reset failed.  Try another warm reset.
30728c2ecf20Sopenharmony_ci			 */
30738c2ecf20Sopenharmony_ci			if (!warm) {
30748c2ecf20Sopenharmony_ci				dev_dbg(&port_dev->dev,
30758c2ecf20Sopenharmony_ci						"hot reset failed, warm reset\n");
30768c2ecf20Sopenharmony_ci				warm = true;
30778c2ecf20Sopenharmony_ci			}
30788c2ecf20Sopenharmony_ci		}
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev,
30818c2ecf20Sopenharmony_ci				"not enabled, trying %sreset again...\n",
30828c2ecf20Sopenharmony_ci				warm ? "warm " : "");
30838c2ecf20Sopenharmony_ci		delay = HUB_LONG_RESET_TIME;
30848c2ecf20Sopenharmony_ci	}
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci	dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_cidone:
30898c2ecf20Sopenharmony_ci	if (status == 0) {
30908c2ecf20Sopenharmony_ci		if (port_dev->quirks & USB_PORT_QUIRK_FAST_ENUM)
30918c2ecf20Sopenharmony_ci			usleep_range(10000, 12000);
30928c2ecf20Sopenharmony_ci		else {
30938c2ecf20Sopenharmony_ci			/* TRSTRCY = 10 ms; plus some extra */
30948c2ecf20Sopenharmony_ci			reset_recovery_time = 10 + 40;
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ci			/* Hub needs extra delay after resetting its port. */
30978c2ecf20Sopenharmony_ci			if (hub->hdev->quirks & USB_QUIRK_HUB_SLOW_RESET)
30988c2ecf20Sopenharmony_ci				reset_recovery_time += 100;
30998c2ecf20Sopenharmony_ci
31008c2ecf20Sopenharmony_ci			msleep(reset_recovery_time);
31018c2ecf20Sopenharmony_ci		}
31028c2ecf20Sopenharmony_ci
31038c2ecf20Sopenharmony_ci		if (udev) {
31048c2ecf20Sopenharmony_ci			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci			update_devnum(udev, 0);
31078c2ecf20Sopenharmony_ci			/* The xHC may think the device is already reset,
31088c2ecf20Sopenharmony_ci			 * so ignore the status.
31098c2ecf20Sopenharmony_ci			 */
31108c2ecf20Sopenharmony_ci			if (hcd->driver->reset_device)
31118c2ecf20Sopenharmony_ci				hcd->driver->reset_device(hcd, udev);
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci			usb_set_device_state(udev, USB_STATE_DEFAULT);
31148c2ecf20Sopenharmony_ci		}
31158c2ecf20Sopenharmony_ci	} else {
31168c2ecf20Sopenharmony_ci		if (udev)
31178c2ecf20Sopenharmony_ci			usb_set_device_state(udev, USB_STATE_NOTATTACHED);
31188c2ecf20Sopenharmony_ci	}
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci	if (!hub_is_superspeed(hub->hdev))
31218c2ecf20Sopenharmony_ci		up_read(&ehci_cf_port_reset_rwsem);
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci	return status;
31248c2ecf20Sopenharmony_ci}
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci/* Check if a port is power on */
31278c2ecf20Sopenharmony_cistatic int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
31288c2ecf20Sopenharmony_ci{
31298c2ecf20Sopenharmony_ci	int ret = 0;
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hub->hdev)) {
31328c2ecf20Sopenharmony_ci		if (portstatus & USB_SS_PORT_STAT_POWER)
31338c2ecf20Sopenharmony_ci			ret = 1;
31348c2ecf20Sopenharmony_ci	} else {
31358c2ecf20Sopenharmony_ci		if (portstatus & USB_PORT_STAT_POWER)
31368c2ecf20Sopenharmony_ci			ret = 1;
31378c2ecf20Sopenharmony_ci	}
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci	return ret;
31408c2ecf20Sopenharmony_ci}
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_cistatic void usb_lock_port(struct usb_port *port_dev)
31438c2ecf20Sopenharmony_ci		__acquires(&port_dev->status_lock)
31448c2ecf20Sopenharmony_ci{
31458c2ecf20Sopenharmony_ci	mutex_lock(&port_dev->status_lock);
31468c2ecf20Sopenharmony_ci	__acquire(&port_dev->status_lock);
31478c2ecf20Sopenharmony_ci}
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_cistatic void usb_unlock_port(struct usb_port *port_dev)
31508c2ecf20Sopenharmony_ci		__releases(&port_dev->status_lock)
31518c2ecf20Sopenharmony_ci{
31528c2ecf20Sopenharmony_ci	mutex_unlock(&port_dev->status_lock);
31538c2ecf20Sopenharmony_ci	__release(&port_dev->status_lock);
31548c2ecf20Sopenharmony_ci}
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci#ifdef	CONFIG_PM
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
31598c2ecf20Sopenharmony_cistatic int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
31608c2ecf20Sopenharmony_ci{
31618c2ecf20Sopenharmony_ci	int ret = 0;
31628c2ecf20Sopenharmony_ci
31638c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hub->hdev)) {
31648c2ecf20Sopenharmony_ci		if ((portstatus & USB_PORT_STAT_LINK_STATE)
31658c2ecf20Sopenharmony_ci				== USB_SS_PORT_LS_U3)
31668c2ecf20Sopenharmony_ci			ret = 1;
31678c2ecf20Sopenharmony_ci	} else {
31688c2ecf20Sopenharmony_ci		if (portstatus & USB_PORT_STAT_SUSPEND)
31698c2ecf20Sopenharmony_ci			ret = 1;
31708c2ecf20Sopenharmony_ci	}
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	return ret;
31738c2ecf20Sopenharmony_ci}
31748c2ecf20Sopenharmony_ci
31758c2ecf20Sopenharmony_ci/* Determine whether the device on a port is ready for a normal resume,
31768c2ecf20Sopenharmony_ci * is ready for a reset-resume, or should be disconnected.
31778c2ecf20Sopenharmony_ci */
31788c2ecf20Sopenharmony_cistatic int check_port_resume_type(struct usb_device *udev,
31798c2ecf20Sopenharmony_ci		struct usb_hub *hub, int port1,
31808c2ecf20Sopenharmony_ci		int status, u16 portchange, u16 portstatus)
31818c2ecf20Sopenharmony_ci{
31828c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
31838c2ecf20Sopenharmony_ci	int retries = 3;
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci retry:
31868c2ecf20Sopenharmony_ci	/* Is a warm reset needed to recover the connection? */
31878c2ecf20Sopenharmony_ci	if (status == 0 && udev->reset_resume
31888c2ecf20Sopenharmony_ci		&& hub_port_warm_reset_required(hub, port1, portstatus)) {
31898c2ecf20Sopenharmony_ci		/* pass */;
31908c2ecf20Sopenharmony_ci	}
31918c2ecf20Sopenharmony_ci	/* Is the device still present? */
31928c2ecf20Sopenharmony_ci	else if (status || port_is_suspended(hub, portstatus) ||
31938c2ecf20Sopenharmony_ci			!port_is_power_on(hub, portstatus)) {
31948c2ecf20Sopenharmony_ci		if (status >= 0)
31958c2ecf20Sopenharmony_ci			status = -ENODEV;
31968c2ecf20Sopenharmony_ci	} else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
31978c2ecf20Sopenharmony_ci		if (retries--) {
31988c2ecf20Sopenharmony_ci			usleep_range(200, 300);
31998c2ecf20Sopenharmony_ci			status = hub_port_status(hub, port1, &portstatus,
32008c2ecf20Sopenharmony_ci							     &portchange);
32018c2ecf20Sopenharmony_ci			goto retry;
32028c2ecf20Sopenharmony_ci		}
32038c2ecf20Sopenharmony_ci		status = -ENODEV;
32048c2ecf20Sopenharmony_ci	}
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	/* Can't do a normal resume if the port isn't enabled,
32078c2ecf20Sopenharmony_ci	 * so try a reset-resume instead.
32088c2ecf20Sopenharmony_ci	 */
32098c2ecf20Sopenharmony_ci	else if (!(portstatus & USB_PORT_STAT_ENABLE) && !udev->reset_resume) {
32108c2ecf20Sopenharmony_ci		if (udev->persist_enabled)
32118c2ecf20Sopenharmony_ci			udev->reset_resume = 1;
32128c2ecf20Sopenharmony_ci		else
32138c2ecf20Sopenharmony_ci			status = -ENODEV;
32148c2ecf20Sopenharmony_ci	}
32158c2ecf20Sopenharmony_ci
32168c2ecf20Sopenharmony_ci	if (status) {
32178c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "status %04x.%04x after resume, %d\n",
32188c2ecf20Sopenharmony_ci				portchange, portstatus, status);
32198c2ecf20Sopenharmony_ci	} else if (udev->reset_resume) {
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci		/* Late port handoff can set status-change bits */
32228c2ecf20Sopenharmony_ci		if (portchange & USB_PORT_STAT_C_CONNECTION)
32238c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
32248c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_CONNECTION);
32258c2ecf20Sopenharmony_ci		if (portchange & USB_PORT_STAT_C_ENABLE)
32268c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
32278c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_ENABLE);
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_ci		/*
32308c2ecf20Sopenharmony_ci		 * Whatever made this reset-resume necessary may have
32318c2ecf20Sopenharmony_ci		 * turned on the port1 bit in hub->change_bits.  But after
32328c2ecf20Sopenharmony_ci		 * a successful reset-resume we want the bit to be clear;
32338c2ecf20Sopenharmony_ci		 * if it was on it would indicate that something happened
32348c2ecf20Sopenharmony_ci		 * following the reset-resume.
32358c2ecf20Sopenharmony_ci		 */
32368c2ecf20Sopenharmony_ci		clear_bit(port1, hub->change_bits);
32378c2ecf20Sopenharmony_ci	}
32388c2ecf20Sopenharmony_ci
32398c2ecf20Sopenharmony_ci	return status;
32408c2ecf20Sopenharmony_ci}
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ciint usb_disable_ltm(struct usb_device *udev)
32438c2ecf20Sopenharmony_ci{
32448c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ci	/* Check if the roothub and device supports LTM. */
32478c2ecf20Sopenharmony_ci	if (!usb_device_supports_ltm(hcd->self.root_hub) ||
32488c2ecf20Sopenharmony_ci			!usb_device_supports_ltm(udev))
32498c2ecf20Sopenharmony_ci		return 0;
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci	/* Clear Feature LTM Enable can only be sent if the device is
32528c2ecf20Sopenharmony_ci	 * configured.
32538c2ecf20Sopenharmony_ci	 */
32548c2ecf20Sopenharmony_ci	if (!udev->actconfig)
32558c2ecf20Sopenharmony_ci		return 0;
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
32588c2ecf20Sopenharmony_ci			USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
32598c2ecf20Sopenharmony_ci			USB_DEVICE_LTM_ENABLE, 0, NULL, 0,
32608c2ecf20Sopenharmony_ci			USB_CTRL_SET_TIMEOUT);
32618c2ecf20Sopenharmony_ci}
32628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_disable_ltm);
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_civoid usb_enable_ltm(struct usb_device *udev)
32658c2ecf20Sopenharmony_ci{
32668c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	/* Check if the roothub and device supports LTM. */
32698c2ecf20Sopenharmony_ci	if (!usb_device_supports_ltm(hcd->self.root_hub) ||
32708c2ecf20Sopenharmony_ci			!usb_device_supports_ltm(udev))
32718c2ecf20Sopenharmony_ci		return;
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	/* Set Feature LTM Enable can only be sent if the device is
32748c2ecf20Sopenharmony_ci	 * configured.
32758c2ecf20Sopenharmony_ci	 */
32768c2ecf20Sopenharmony_ci	if (!udev->actconfig)
32778c2ecf20Sopenharmony_ci		return;
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_ci	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
32808c2ecf20Sopenharmony_ci			USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
32818c2ecf20Sopenharmony_ci			USB_DEVICE_LTM_ENABLE, 0, NULL, 0,
32828c2ecf20Sopenharmony_ci			USB_CTRL_SET_TIMEOUT);
32838c2ecf20Sopenharmony_ci}
32848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_enable_ltm);
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_ci/*
32878c2ecf20Sopenharmony_ci * usb_enable_remote_wakeup - enable remote wakeup for a device
32888c2ecf20Sopenharmony_ci * @udev: target device
32898c2ecf20Sopenharmony_ci *
32908c2ecf20Sopenharmony_ci * For USB-2 devices: Set the device's remote wakeup feature.
32918c2ecf20Sopenharmony_ci *
32928c2ecf20Sopenharmony_ci * For USB-3 devices: Assume there's only one function on the device and
32938c2ecf20Sopenharmony_ci * enable remote wake for the first interface.  FIXME if the interface
32948c2ecf20Sopenharmony_ci * association descriptor shows there's more than one function.
32958c2ecf20Sopenharmony_ci */
32968c2ecf20Sopenharmony_cistatic int usb_enable_remote_wakeup(struct usb_device *udev)
32978c2ecf20Sopenharmony_ci{
32988c2ecf20Sopenharmony_ci	if (udev->speed < USB_SPEED_SUPER)
32998c2ecf20Sopenharmony_ci		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
33008c2ecf20Sopenharmony_ci				USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
33018c2ecf20Sopenharmony_ci				USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
33028c2ecf20Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
33038c2ecf20Sopenharmony_ci	else
33048c2ecf20Sopenharmony_ci		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
33058c2ecf20Sopenharmony_ci				USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE,
33068c2ecf20Sopenharmony_ci				USB_INTRF_FUNC_SUSPEND,
33078c2ecf20Sopenharmony_ci				USB_INTRF_FUNC_SUSPEND_RW |
33088c2ecf20Sopenharmony_ci					USB_INTRF_FUNC_SUSPEND_LP,
33098c2ecf20Sopenharmony_ci				NULL, 0, USB_CTRL_SET_TIMEOUT);
33108c2ecf20Sopenharmony_ci}
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci/*
33138c2ecf20Sopenharmony_ci * usb_disable_remote_wakeup - disable remote wakeup for a device
33148c2ecf20Sopenharmony_ci * @udev: target device
33158c2ecf20Sopenharmony_ci *
33168c2ecf20Sopenharmony_ci * For USB-2 devices: Clear the device's remote wakeup feature.
33178c2ecf20Sopenharmony_ci *
33188c2ecf20Sopenharmony_ci * For USB-3 devices: Assume there's only one function on the device and
33198c2ecf20Sopenharmony_ci * disable remote wake for the first interface.  FIXME if the interface
33208c2ecf20Sopenharmony_ci * association descriptor shows there's more than one function.
33218c2ecf20Sopenharmony_ci */
33228c2ecf20Sopenharmony_cistatic int usb_disable_remote_wakeup(struct usb_device *udev)
33238c2ecf20Sopenharmony_ci{
33248c2ecf20Sopenharmony_ci	if (udev->speed < USB_SPEED_SUPER)
33258c2ecf20Sopenharmony_ci		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
33268c2ecf20Sopenharmony_ci				USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
33278c2ecf20Sopenharmony_ci				USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
33288c2ecf20Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
33298c2ecf20Sopenharmony_ci	else
33308c2ecf20Sopenharmony_ci		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
33318c2ecf20Sopenharmony_ci				USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE,
33328c2ecf20Sopenharmony_ci				USB_INTRF_FUNC_SUSPEND,	0, NULL, 0,
33338c2ecf20Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
33348c2ecf20Sopenharmony_ci}
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_ci/* Count of wakeup-enabled devices at or below udev */
33378c2ecf20Sopenharmony_ciunsigned usb_wakeup_enabled_descendants(struct usb_device *udev)
33388c2ecf20Sopenharmony_ci{
33398c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(udev);
33408c2ecf20Sopenharmony_ci
33418c2ecf20Sopenharmony_ci	return udev->do_remote_wakeup +
33428c2ecf20Sopenharmony_ci			(hub ? hub->wakeup_enabled_descendants : 0);
33438c2ecf20Sopenharmony_ci}
33448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_wakeup_enabled_descendants);
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci/*
33478c2ecf20Sopenharmony_ci * usb_port_suspend - suspend a usb device's upstream port
33488c2ecf20Sopenharmony_ci * @udev: device that's no longer in active use, not a root hub
33498c2ecf20Sopenharmony_ci * Context: must be able to sleep; device not locked; pm locks held
33508c2ecf20Sopenharmony_ci *
33518c2ecf20Sopenharmony_ci * Suspends a USB device that isn't in active use, conserving power.
33528c2ecf20Sopenharmony_ci * Devices may wake out of a suspend, if anything important happens,
33538c2ecf20Sopenharmony_ci * using the remote wakeup mechanism.  They may also be taken out of
33548c2ecf20Sopenharmony_ci * suspend by the host, using usb_port_resume().  It's also routine
33558c2ecf20Sopenharmony_ci * to disconnect devices while they are suspended.
33568c2ecf20Sopenharmony_ci *
33578c2ecf20Sopenharmony_ci * This only affects the USB hardware for a device; its interfaces
33588c2ecf20Sopenharmony_ci * (and, for hubs, child devices) must already have been suspended.
33598c2ecf20Sopenharmony_ci *
33608c2ecf20Sopenharmony_ci * Selective port suspend reduces power; most suspended devices draw
33618c2ecf20Sopenharmony_ci * less than 500 uA.  It's also used in OTG, along with remote wakeup.
33628c2ecf20Sopenharmony_ci * All devices below the suspended port are also suspended.
33638c2ecf20Sopenharmony_ci *
33648c2ecf20Sopenharmony_ci * Devices leave suspend state when the host wakes them up.  Some devices
33658c2ecf20Sopenharmony_ci * also support "remote wakeup", where the device can activate the USB
33668c2ecf20Sopenharmony_ci * tree above them to deliver data, such as a keypress or packet.  In
33678c2ecf20Sopenharmony_ci * some cases, this wakes the USB host.
33688c2ecf20Sopenharmony_ci *
33698c2ecf20Sopenharmony_ci * Suspending OTG devices may trigger HNP, if that's been enabled
33708c2ecf20Sopenharmony_ci * between a pair of dual-role devices.  That will change roles, such
33718c2ecf20Sopenharmony_ci * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
33728c2ecf20Sopenharmony_ci *
33738c2ecf20Sopenharmony_ci * Devices on USB hub ports have only one "suspend" state, corresponding
33748c2ecf20Sopenharmony_ci * to ACPI D2, "may cause the device to lose some context".
33758c2ecf20Sopenharmony_ci * State transitions include:
33768c2ecf20Sopenharmony_ci *
33778c2ecf20Sopenharmony_ci *   - suspend, resume ... when the VBUS power link stays live
33788c2ecf20Sopenharmony_ci *   - suspend, disconnect ... VBUS lost
33798c2ecf20Sopenharmony_ci *
33808c2ecf20Sopenharmony_ci * Once VBUS drop breaks the circuit, the port it's using has to go through
33818c2ecf20Sopenharmony_ci * normal re-enumeration procedures, starting with enabling VBUS power.
33828c2ecf20Sopenharmony_ci * Other than re-initializing the hub (plug/unplug, except for root hubs),
33838c2ecf20Sopenharmony_ci * Linux (2.6) currently has NO mechanisms to initiate that:  no hub_wq
33848c2ecf20Sopenharmony_ci * timer, no SRP, no requests through sysfs.
33858c2ecf20Sopenharmony_ci *
33868c2ecf20Sopenharmony_ci * If Runtime PM isn't enabled or used, non-SuperSpeed devices may not get
33878c2ecf20Sopenharmony_ci * suspended until their bus goes into global suspend (i.e., the root
33888c2ecf20Sopenharmony_ci * hub is suspended).  Nevertheless, we change @udev->state to
33898c2ecf20Sopenharmony_ci * USB_STATE_SUSPENDED as this is the device's "logical" state.  The actual
33908c2ecf20Sopenharmony_ci * upstream port setting is stored in @udev->port_is_suspended.
33918c2ecf20Sopenharmony_ci *
33928c2ecf20Sopenharmony_ci * Returns 0 on success, else negative errno.
33938c2ecf20Sopenharmony_ci */
33948c2ecf20Sopenharmony_ciint usb_port_suspend(struct usb_device *udev, pm_message_t msg)
33958c2ecf20Sopenharmony_ci{
33968c2ecf20Sopenharmony_ci	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent);
33978c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[udev->portnum - 1];
33988c2ecf20Sopenharmony_ci	int		port1 = udev->portnum;
33998c2ecf20Sopenharmony_ci	int		status;
34008c2ecf20Sopenharmony_ci	bool		really_suspend = true;
34018c2ecf20Sopenharmony_ci
34028c2ecf20Sopenharmony_ci	usb_lock_port(port_dev);
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	/* enable remote wakeup when appropriate; this lets the device
34058c2ecf20Sopenharmony_ci	 * wake up the upstream hub (including maybe the root hub).
34068c2ecf20Sopenharmony_ci	 *
34078c2ecf20Sopenharmony_ci	 * NOTE:  OTG devices may issue remote wakeup (or SRP) even when
34088c2ecf20Sopenharmony_ci	 * we don't explicitly enable it here.
34098c2ecf20Sopenharmony_ci	 */
34108c2ecf20Sopenharmony_ci	if (udev->do_remote_wakeup) {
34118c2ecf20Sopenharmony_ci		status = usb_enable_remote_wakeup(udev);
34128c2ecf20Sopenharmony_ci		if (status) {
34138c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
34148c2ecf20Sopenharmony_ci					status);
34158c2ecf20Sopenharmony_ci			/* bail if autosuspend is requested */
34168c2ecf20Sopenharmony_ci			if (PMSG_IS_AUTO(msg))
34178c2ecf20Sopenharmony_ci				goto err_wakeup;
34188c2ecf20Sopenharmony_ci		}
34198c2ecf20Sopenharmony_ci	}
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci	/* disable USB2 hardware LPM */
34228c2ecf20Sopenharmony_ci	usb_disable_usb2_hardware_lpm(udev);
34238c2ecf20Sopenharmony_ci
34248c2ecf20Sopenharmony_ci	if (usb_disable_ltm(udev)) {
34258c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "Failed to disable LTM before suspend\n");
34268c2ecf20Sopenharmony_ci		status = -ENOMEM;
34278c2ecf20Sopenharmony_ci		if (PMSG_IS_AUTO(msg))
34288c2ecf20Sopenharmony_ci			goto err_ltm;
34298c2ecf20Sopenharmony_ci	}
34308c2ecf20Sopenharmony_ci
34318c2ecf20Sopenharmony_ci	/* see 7.1.7.6 */
34328c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hub->hdev))
34338c2ecf20Sopenharmony_ci		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_ci	/*
34368c2ecf20Sopenharmony_ci	 * For system suspend, we do not need to enable the suspend feature
34378c2ecf20Sopenharmony_ci	 * on individual USB-2 ports.  The devices will automatically go
34388c2ecf20Sopenharmony_ci	 * into suspend a few ms after the root hub stops sending packets.
34398c2ecf20Sopenharmony_ci	 * The USB 2.0 spec calls this "global suspend".
34408c2ecf20Sopenharmony_ci	 *
34418c2ecf20Sopenharmony_ci	 * However, many USB hubs have a bug: They don't relay wakeup requests
34428c2ecf20Sopenharmony_ci	 * from a downstream port if the port's suspend feature isn't on.
34438c2ecf20Sopenharmony_ci	 * Therefore we will turn on the suspend feature if udev or any of its
34448c2ecf20Sopenharmony_ci	 * descendants is enabled for remote wakeup.
34458c2ecf20Sopenharmony_ci	 */
34468c2ecf20Sopenharmony_ci	else if (PMSG_IS_AUTO(msg) || usb_wakeup_enabled_descendants(udev) > 0)
34478c2ecf20Sopenharmony_ci		status = set_port_feature(hub->hdev, port1,
34488c2ecf20Sopenharmony_ci				USB_PORT_FEAT_SUSPEND);
34498c2ecf20Sopenharmony_ci	else {
34508c2ecf20Sopenharmony_ci		really_suspend = false;
34518c2ecf20Sopenharmony_ci		status = 0;
34528c2ecf20Sopenharmony_ci	}
34538c2ecf20Sopenharmony_ci	if (status) {
34548c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_ci		/* Try to enable USB3 LTM again */
34578c2ecf20Sopenharmony_ci		usb_enable_ltm(udev);
34588c2ecf20Sopenharmony_ci err_ltm:
34598c2ecf20Sopenharmony_ci		/* Try to enable USB2 hardware LPM again */
34608c2ecf20Sopenharmony_ci		usb_enable_usb2_hardware_lpm(udev);
34618c2ecf20Sopenharmony_ci
34628c2ecf20Sopenharmony_ci		if (udev->do_remote_wakeup)
34638c2ecf20Sopenharmony_ci			(void) usb_disable_remote_wakeup(udev);
34648c2ecf20Sopenharmony_ci err_wakeup:
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci		/* System sleep transitions should never fail */
34678c2ecf20Sopenharmony_ci		if (!PMSG_IS_AUTO(msg))
34688c2ecf20Sopenharmony_ci			status = 0;
34698c2ecf20Sopenharmony_ci	} else {
34708c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
34718c2ecf20Sopenharmony_ci				(PMSG_IS_AUTO(msg) ? "auto-" : ""),
34728c2ecf20Sopenharmony_ci				udev->do_remote_wakeup);
34738c2ecf20Sopenharmony_ci		if (really_suspend) {
34748c2ecf20Sopenharmony_ci			udev->port_is_suspended = 1;
34758c2ecf20Sopenharmony_ci
34768c2ecf20Sopenharmony_ci			/* device has up to 10 msec to fully suspend */
34778c2ecf20Sopenharmony_ci			msleep(10);
34788c2ecf20Sopenharmony_ci		}
34798c2ecf20Sopenharmony_ci		usb_set_device_state(udev, USB_STATE_SUSPENDED);
34808c2ecf20Sopenharmony_ci	}
34818c2ecf20Sopenharmony_ci
34828c2ecf20Sopenharmony_ci	if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled
34838c2ecf20Sopenharmony_ci			&& test_and_clear_bit(port1, hub->child_usage_bits))
34848c2ecf20Sopenharmony_ci		pm_runtime_put_sync(&port_dev->dev);
34858c2ecf20Sopenharmony_ci
34868c2ecf20Sopenharmony_ci	usb_mark_last_busy(hub->hdev);
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_ci	usb_unlock_port(port_dev);
34898c2ecf20Sopenharmony_ci	return status;
34908c2ecf20Sopenharmony_ci}
34918c2ecf20Sopenharmony_ci
34928c2ecf20Sopenharmony_ci/*
34938c2ecf20Sopenharmony_ci * If the USB "suspend" state is in use (rather than "global suspend"),
34948c2ecf20Sopenharmony_ci * many devices will be individually taken out of suspend state using
34958c2ecf20Sopenharmony_ci * special "resume" signaling.  This routine kicks in shortly after
34968c2ecf20Sopenharmony_ci * hardware resume signaling is finished, either because of selective
34978c2ecf20Sopenharmony_ci * resume (by host) or remote wakeup (by device) ... now see what changed
34988c2ecf20Sopenharmony_ci * in the tree that's rooted at this device.
34998c2ecf20Sopenharmony_ci *
35008c2ecf20Sopenharmony_ci * If @udev->reset_resume is set then the device is reset before the
35018c2ecf20Sopenharmony_ci * status check is done.
35028c2ecf20Sopenharmony_ci */
35038c2ecf20Sopenharmony_cistatic int finish_port_resume(struct usb_device *udev)
35048c2ecf20Sopenharmony_ci{
35058c2ecf20Sopenharmony_ci	int	status = 0;
35068c2ecf20Sopenharmony_ci	u16	devstatus = 0;
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci	/* caller owns the udev device lock */
35098c2ecf20Sopenharmony_ci	dev_dbg(&udev->dev, "%s\n",
35108c2ecf20Sopenharmony_ci		udev->reset_resume ? "finish reset-resume" : "finish resume");
35118c2ecf20Sopenharmony_ci
35128c2ecf20Sopenharmony_ci	/* usb ch9 identifies four variants of SUSPENDED, based on what
35138c2ecf20Sopenharmony_ci	 * state the device resumes to.  Linux currently won't see the
35148c2ecf20Sopenharmony_ci	 * first two on the host side; they'd be inside hub_port_init()
35158c2ecf20Sopenharmony_ci	 * during many timeouts, but hub_wq can't suspend until later.
35168c2ecf20Sopenharmony_ci	 */
35178c2ecf20Sopenharmony_ci	usb_set_device_state(udev, udev->actconfig
35188c2ecf20Sopenharmony_ci			? USB_STATE_CONFIGURED
35198c2ecf20Sopenharmony_ci			: USB_STATE_ADDRESS);
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_ci	/* 10.5.4.5 says not to reset a suspended port if the attached
35228c2ecf20Sopenharmony_ci	 * device is enabled for remote wakeup.  Hence the reset
35238c2ecf20Sopenharmony_ci	 * operation is carried out here, after the port has been
35248c2ecf20Sopenharmony_ci	 * resumed.
35258c2ecf20Sopenharmony_ci	 */
35268c2ecf20Sopenharmony_ci	if (udev->reset_resume) {
35278c2ecf20Sopenharmony_ci		/*
35288c2ecf20Sopenharmony_ci		 * If the device morphs or switches modes when it is reset,
35298c2ecf20Sopenharmony_ci		 * we don't want to perform a reset-resume.  We'll fail the
35308c2ecf20Sopenharmony_ci		 * resume, which will cause a logical disconnect, and then
35318c2ecf20Sopenharmony_ci		 * the device will be rediscovered.
35328c2ecf20Sopenharmony_ci		 */
35338c2ecf20Sopenharmony_ci retry_reset_resume:
35348c2ecf20Sopenharmony_ci		if (udev->quirks & USB_QUIRK_RESET)
35358c2ecf20Sopenharmony_ci			status = -ENODEV;
35368c2ecf20Sopenharmony_ci		else
35378c2ecf20Sopenharmony_ci			status = usb_reset_and_verify_device(udev);
35388c2ecf20Sopenharmony_ci	}
35398c2ecf20Sopenharmony_ci
35408c2ecf20Sopenharmony_ci	/* 10.5.4.5 says be sure devices in the tree are still there.
35418c2ecf20Sopenharmony_ci	 * For now let's assume the device didn't go crazy on resume,
35428c2ecf20Sopenharmony_ci	 * and device drivers will know about any resume quirks.
35438c2ecf20Sopenharmony_ci	 */
35448c2ecf20Sopenharmony_ci	if (status == 0) {
35458c2ecf20Sopenharmony_ci		devstatus = 0;
35468c2ecf20Sopenharmony_ci		status = usb_get_std_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
35478c2ecf20Sopenharmony_ci
35488c2ecf20Sopenharmony_ci		/* If a normal resume failed, try doing a reset-resume */
35498c2ecf20Sopenharmony_ci		if (status && !udev->reset_resume && udev->persist_enabled) {
35508c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "retry with reset-resume\n");
35518c2ecf20Sopenharmony_ci			udev->reset_resume = 1;
35528c2ecf20Sopenharmony_ci			goto retry_reset_resume;
35538c2ecf20Sopenharmony_ci		}
35548c2ecf20Sopenharmony_ci	}
35558c2ecf20Sopenharmony_ci
35568c2ecf20Sopenharmony_ci	if (status) {
35578c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
35588c2ecf20Sopenharmony_ci				status);
35598c2ecf20Sopenharmony_ci	/*
35608c2ecf20Sopenharmony_ci	 * There are a few quirky devices which violate the standard
35618c2ecf20Sopenharmony_ci	 * by claiming to have remote wakeup enabled after a reset,
35628c2ecf20Sopenharmony_ci	 * which crash if the feature is cleared, hence check for
35638c2ecf20Sopenharmony_ci	 * udev->reset_resume
35648c2ecf20Sopenharmony_ci	 */
35658c2ecf20Sopenharmony_ci	} else if (udev->actconfig && !udev->reset_resume) {
35668c2ecf20Sopenharmony_ci		if (udev->speed < USB_SPEED_SUPER) {
35678c2ecf20Sopenharmony_ci			if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
35688c2ecf20Sopenharmony_ci				status = usb_disable_remote_wakeup(udev);
35698c2ecf20Sopenharmony_ci		} else {
35708c2ecf20Sopenharmony_ci			status = usb_get_std_status(udev, USB_RECIP_INTERFACE, 0,
35718c2ecf20Sopenharmony_ci					&devstatus);
35728c2ecf20Sopenharmony_ci			if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP
35738c2ecf20Sopenharmony_ci					| USB_INTRF_STAT_FUNC_RW))
35748c2ecf20Sopenharmony_ci				status = usb_disable_remote_wakeup(udev);
35758c2ecf20Sopenharmony_ci		}
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_ci		if (status)
35788c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev,
35798c2ecf20Sopenharmony_ci				"disable remote wakeup, status %d\n",
35808c2ecf20Sopenharmony_ci				status);
35818c2ecf20Sopenharmony_ci		status = 0;
35828c2ecf20Sopenharmony_ci	}
35838c2ecf20Sopenharmony_ci	return status;
35848c2ecf20Sopenharmony_ci}
35858c2ecf20Sopenharmony_ci
35868c2ecf20Sopenharmony_ci/*
35878c2ecf20Sopenharmony_ci * There are some SS USB devices which take longer time for link training.
35888c2ecf20Sopenharmony_ci * XHCI specs 4.19.4 says that when Link training is successful, port
35898c2ecf20Sopenharmony_ci * sets CCS bit to 1. So if SW reads port status before successful link
35908c2ecf20Sopenharmony_ci * training, then it will not find device to be present.
35918c2ecf20Sopenharmony_ci * USB Analyzer log with such buggy devices show that in some cases
35928c2ecf20Sopenharmony_ci * device switch on the RX termination after long delay of host enabling
35938c2ecf20Sopenharmony_ci * the VBUS. In few other cases it has been seen that device fails to
35948c2ecf20Sopenharmony_ci * negotiate link training in first attempt. It has been
35958c2ecf20Sopenharmony_ci * reported till now that few devices take as long as 2000 ms to train
35968c2ecf20Sopenharmony_ci * the link after host enabling its VBUS and termination. Following
35978c2ecf20Sopenharmony_ci * routine implements a 2000 ms timeout for link training. If in a case
35988c2ecf20Sopenharmony_ci * link trains before timeout, loop will exit earlier.
35998c2ecf20Sopenharmony_ci *
36008c2ecf20Sopenharmony_ci * There are also some 2.0 hard drive based devices and 3.0 thumb
36018c2ecf20Sopenharmony_ci * drives that, when plugged into a 2.0 only port, take a long
36028c2ecf20Sopenharmony_ci * time to set CCS after VBUS enable.
36038c2ecf20Sopenharmony_ci *
36048c2ecf20Sopenharmony_ci * FIXME: If a device was connected before suspend, but was removed
36058c2ecf20Sopenharmony_ci * while system was asleep, then the loop in the following routine will
36068c2ecf20Sopenharmony_ci * only exit at timeout.
36078c2ecf20Sopenharmony_ci *
36088c2ecf20Sopenharmony_ci * This routine should only be called when persist is enabled.
36098c2ecf20Sopenharmony_ci */
36108c2ecf20Sopenharmony_cistatic int wait_for_connected(struct usb_device *udev,
36118c2ecf20Sopenharmony_ci		struct usb_hub *hub, int *port1,
36128c2ecf20Sopenharmony_ci		u16 *portchange, u16 *portstatus)
36138c2ecf20Sopenharmony_ci{
36148c2ecf20Sopenharmony_ci	int status = 0, delay_ms = 0;
36158c2ecf20Sopenharmony_ci
36168c2ecf20Sopenharmony_ci	while (delay_ms < 2000) {
36178c2ecf20Sopenharmony_ci		if (status || *portstatus & USB_PORT_STAT_CONNECTION)
36188c2ecf20Sopenharmony_ci			break;
36198c2ecf20Sopenharmony_ci		if (!port_is_power_on(hub, *portstatus)) {
36208c2ecf20Sopenharmony_ci			status = -ENODEV;
36218c2ecf20Sopenharmony_ci			break;
36228c2ecf20Sopenharmony_ci		}
36238c2ecf20Sopenharmony_ci		msleep(20);
36248c2ecf20Sopenharmony_ci		delay_ms += 20;
36258c2ecf20Sopenharmony_ci		status = hub_port_status(hub, *port1, portstatus, portchange);
36268c2ecf20Sopenharmony_ci	}
36278c2ecf20Sopenharmony_ci	dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms);
36288c2ecf20Sopenharmony_ci	return status;
36298c2ecf20Sopenharmony_ci}
36308c2ecf20Sopenharmony_ci
36318c2ecf20Sopenharmony_ci/*
36328c2ecf20Sopenharmony_ci * usb_port_resume - re-activate a suspended usb device's upstream port
36338c2ecf20Sopenharmony_ci * @udev: device to re-activate, not a root hub
36348c2ecf20Sopenharmony_ci * Context: must be able to sleep; device not locked; pm locks held
36358c2ecf20Sopenharmony_ci *
36368c2ecf20Sopenharmony_ci * This will re-activate the suspended device, increasing power usage
36378c2ecf20Sopenharmony_ci * while letting drivers communicate again with its endpoints.
36388c2ecf20Sopenharmony_ci * USB resume explicitly guarantees that the power session between
36398c2ecf20Sopenharmony_ci * the host and the device is the same as it was when the device
36408c2ecf20Sopenharmony_ci * suspended.
36418c2ecf20Sopenharmony_ci *
36428c2ecf20Sopenharmony_ci * If @udev->reset_resume is set then this routine won't check that the
36438c2ecf20Sopenharmony_ci * port is still enabled.  Furthermore, finish_port_resume() above will
36448c2ecf20Sopenharmony_ci * reset @udev.  The end result is that a broken power session can be
36458c2ecf20Sopenharmony_ci * recovered and @udev will appear to persist across a loss of VBUS power.
36468c2ecf20Sopenharmony_ci *
36478c2ecf20Sopenharmony_ci * For example, if a host controller doesn't maintain VBUS suspend current
36488c2ecf20Sopenharmony_ci * during a system sleep or is reset when the system wakes up, all the USB
36498c2ecf20Sopenharmony_ci * power sessions below it will be broken.  This is especially troublesome
36508c2ecf20Sopenharmony_ci * for mass-storage devices containing mounted filesystems, since the
36518c2ecf20Sopenharmony_ci * device will appear to have disconnected and all the memory mappings
36528c2ecf20Sopenharmony_ci * to it will be lost.  Using the USB_PERSIST facility, the device can be
36538c2ecf20Sopenharmony_ci * made to appear as if it had not disconnected.
36548c2ecf20Sopenharmony_ci *
36558c2ecf20Sopenharmony_ci * This facility can be dangerous.  Although usb_reset_and_verify_device() makes
36568c2ecf20Sopenharmony_ci * every effort to insure that the same device is present after the
36578c2ecf20Sopenharmony_ci * reset as before, it cannot provide a 100% guarantee.  Furthermore it's
36588c2ecf20Sopenharmony_ci * quite possible for a device to remain unaltered but its media to be
36598c2ecf20Sopenharmony_ci * changed.  If the user replaces a flash memory card while the system is
36608c2ecf20Sopenharmony_ci * asleep, he will have only himself to blame when the filesystem on the
36618c2ecf20Sopenharmony_ci * new card is corrupted and the system crashes.
36628c2ecf20Sopenharmony_ci *
36638c2ecf20Sopenharmony_ci * Returns 0 on success, else negative errno.
36648c2ecf20Sopenharmony_ci */
36658c2ecf20Sopenharmony_ciint usb_port_resume(struct usb_device *udev, pm_message_t msg)
36668c2ecf20Sopenharmony_ci{
36678c2ecf20Sopenharmony_ci	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent);
36688c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[udev->portnum  - 1];
36698c2ecf20Sopenharmony_ci	int		port1 = udev->portnum;
36708c2ecf20Sopenharmony_ci	int		status;
36718c2ecf20Sopenharmony_ci	u16		portchange, portstatus;
36728c2ecf20Sopenharmony_ci
36738c2ecf20Sopenharmony_ci	if (!test_and_set_bit(port1, hub->child_usage_bits)) {
36748c2ecf20Sopenharmony_ci		status = pm_runtime_resume_and_get(&port_dev->dev);
36758c2ecf20Sopenharmony_ci		if (status < 0) {
36768c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "can't resume usb port, status %d\n",
36778c2ecf20Sopenharmony_ci					status);
36788c2ecf20Sopenharmony_ci			return status;
36798c2ecf20Sopenharmony_ci		}
36808c2ecf20Sopenharmony_ci	}
36818c2ecf20Sopenharmony_ci
36828c2ecf20Sopenharmony_ci	usb_lock_port(port_dev);
36838c2ecf20Sopenharmony_ci
36848c2ecf20Sopenharmony_ci	/* Skip the initial Clear-Suspend step for a remote wakeup */
36858c2ecf20Sopenharmony_ci	status = hub_port_status(hub, port1, &portstatus, &portchange);
36868c2ecf20Sopenharmony_ci	if (status == 0 && !port_is_suspended(hub, portstatus)) {
36878c2ecf20Sopenharmony_ci		if (portchange & USB_PORT_STAT_C_SUSPEND)
36888c2ecf20Sopenharmony_ci			pm_wakeup_event(&udev->dev, 0);
36898c2ecf20Sopenharmony_ci		goto SuspendCleared;
36908c2ecf20Sopenharmony_ci	}
36918c2ecf20Sopenharmony_ci
36928c2ecf20Sopenharmony_ci	/* see 7.1.7.7; affects power usage, but not budgeting */
36938c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hub->hdev))
36948c2ecf20Sopenharmony_ci		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0);
36958c2ecf20Sopenharmony_ci	else
36968c2ecf20Sopenharmony_ci		status = usb_clear_port_feature(hub->hdev,
36978c2ecf20Sopenharmony_ci				port1, USB_PORT_FEAT_SUSPEND);
36988c2ecf20Sopenharmony_ci	if (status) {
36998c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "can't resume, status %d\n", status);
37008c2ecf20Sopenharmony_ci	} else {
37018c2ecf20Sopenharmony_ci		/* drive resume for USB_RESUME_TIMEOUT msec */
37028c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "usb %sresume\n",
37038c2ecf20Sopenharmony_ci				(PMSG_IS_AUTO(msg) ? "auto-" : ""));
37048c2ecf20Sopenharmony_ci		msleep(USB_RESUME_TIMEOUT);
37058c2ecf20Sopenharmony_ci
37068c2ecf20Sopenharmony_ci		/* Virtual root hubs can trigger on GET_PORT_STATUS to
37078c2ecf20Sopenharmony_ci		 * stop resume signaling.  Then finish the resume
37088c2ecf20Sopenharmony_ci		 * sequence.
37098c2ecf20Sopenharmony_ci		 */
37108c2ecf20Sopenharmony_ci		status = hub_port_status(hub, port1, &portstatus, &portchange);
37118c2ecf20Sopenharmony_ci	}
37128c2ecf20Sopenharmony_ci
37138c2ecf20Sopenharmony_ci SuspendCleared:
37148c2ecf20Sopenharmony_ci	if (status == 0) {
37158c2ecf20Sopenharmony_ci		udev->port_is_suspended = 0;
37168c2ecf20Sopenharmony_ci		if (hub_is_superspeed(hub->hdev)) {
37178c2ecf20Sopenharmony_ci			if (portchange & USB_PORT_STAT_C_LINK_STATE)
37188c2ecf20Sopenharmony_ci				usb_clear_port_feature(hub->hdev, port1,
37198c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_PORT_LINK_STATE);
37208c2ecf20Sopenharmony_ci		} else {
37218c2ecf20Sopenharmony_ci			if (portchange & USB_PORT_STAT_C_SUSPEND)
37228c2ecf20Sopenharmony_ci				usb_clear_port_feature(hub->hdev, port1,
37238c2ecf20Sopenharmony_ci						USB_PORT_FEAT_C_SUSPEND);
37248c2ecf20Sopenharmony_ci		}
37258c2ecf20Sopenharmony_ci
37268c2ecf20Sopenharmony_ci		/* TRSMRCY = 10 msec */
37278c2ecf20Sopenharmony_ci		msleep(10);
37288c2ecf20Sopenharmony_ci	}
37298c2ecf20Sopenharmony_ci
37308c2ecf20Sopenharmony_ci	if (udev->persist_enabled)
37318c2ecf20Sopenharmony_ci		status = wait_for_connected(udev, hub, &port1, &portchange,
37328c2ecf20Sopenharmony_ci				&portstatus);
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_ci	status = check_port_resume_type(udev,
37358c2ecf20Sopenharmony_ci			hub, port1, status, portchange, portstatus);
37368c2ecf20Sopenharmony_ci	if (status == 0)
37378c2ecf20Sopenharmony_ci		status = finish_port_resume(udev);
37388c2ecf20Sopenharmony_ci	if (status < 0) {
37398c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "can't resume, status %d\n", status);
37408c2ecf20Sopenharmony_ci		hub_port_logical_disconnect(hub, port1);
37418c2ecf20Sopenharmony_ci	} else  {
37428c2ecf20Sopenharmony_ci		/* Try to enable USB2 hardware LPM */
37438c2ecf20Sopenharmony_ci		usb_enable_usb2_hardware_lpm(udev);
37448c2ecf20Sopenharmony_ci
37458c2ecf20Sopenharmony_ci		/* Try to enable USB3 LTM */
37468c2ecf20Sopenharmony_ci		usb_enable_ltm(udev);
37478c2ecf20Sopenharmony_ci	}
37488c2ecf20Sopenharmony_ci
37498c2ecf20Sopenharmony_ci	usb_unlock_port(port_dev);
37508c2ecf20Sopenharmony_ci
37518c2ecf20Sopenharmony_ci	return status;
37528c2ecf20Sopenharmony_ci}
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ciint usb_remote_wakeup(struct usb_device *udev)
37558c2ecf20Sopenharmony_ci{
37568c2ecf20Sopenharmony_ci	int	status = 0;
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci	usb_lock_device(udev);
37598c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_SUSPENDED) {
37608c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
37618c2ecf20Sopenharmony_ci		status = usb_autoresume_device(udev);
37628c2ecf20Sopenharmony_ci		if (status == 0) {
37638c2ecf20Sopenharmony_ci			/* Let the drivers do their thing, then... */
37648c2ecf20Sopenharmony_ci			usb_autosuspend_device(udev);
37658c2ecf20Sopenharmony_ci		}
37668c2ecf20Sopenharmony_ci	}
37678c2ecf20Sopenharmony_ci	usb_unlock_device(udev);
37688c2ecf20Sopenharmony_ci	return status;
37698c2ecf20Sopenharmony_ci}
37708c2ecf20Sopenharmony_ci
37718c2ecf20Sopenharmony_ci/* Returns 1 if there was a remote wakeup and a connect status change. */
37728c2ecf20Sopenharmony_cistatic int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
37738c2ecf20Sopenharmony_ci		u16 portstatus, u16 portchange)
37748c2ecf20Sopenharmony_ci		__must_hold(&port_dev->status_lock)
37758c2ecf20Sopenharmony_ci{
37768c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port - 1];
37778c2ecf20Sopenharmony_ci	struct usb_device *hdev;
37788c2ecf20Sopenharmony_ci	struct usb_device *udev;
37798c2ecf20Sopenharmony_ci	int connect_change = 0;
37808c2ecf20Sopenharmony_ci	u16 link_state;
37818c2ecf20Sopenharmony_ci	int ret;
37828c2ecf20Sopenharmony_ci
37838c2ecf20Sopenharmony_ci	hdev = hub->hdev;
37848c2ecf20Sopenharmony_ci	udev = port_dev->child;
37858c2ecf20Sopenharmony_ci	if (!hub_is_superspeed(hdev)) {
37868c2ecf20Sopenharmony_ci		if (!(portchange & USB_PORT_STAT_C_SUSPEND))
37878c2ecf20Sopenharmony_ci			return 0;
37888c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
37898c2ecf20Sopenharmony_ci	} else {
37908c2ecf20Sopenharmony_ci		link_state = portstatus & USB_PORT_STAT_LINK_STATE;
37918c2ecf20Sopenharmony_ci		if (!udev || udev->state != USB_STATE_SUSPENDED ||
37928c2ecf20Sopenharmony_ci				(link_state != USB_SS_PORT_LS_U0 &&
37938c2ecf20Sopenharmony_ci				 link_state != USB_SS_PORT_LS_U1 &&
37948c2ecf20Sopenharmony_ci				 link_state != USB_SS_PORT_LS_U2))
37958c2ecf20Sopenharmony_ci			return 0;
37968c2ecf20Sopenharmony_ci	}
37978c2ecf20Sopenharmony_ci
37988c2ecf20Sopenharmony_ci	if (udev) {
37998c2ecf20Sopenharmony_ci		/* TRSMRCY = 10 msec */
38008c2ecf20Sopenharmony_ci		msleep(10);
38018c2ecf20Sopenharmony_ci
38028c2ecf20Sopenharmony_ci		usb_unlock_port(port_dev);
38038c2ecf20Sopenharmony_ci		ret = usb_remote_wakeup(udev);
38048c2ecf20Sopenharmony_ci		usb_lock_port(port_dev);
38058c2ecf20Sopenharmony_ci		if (ret < 0)
38068c2ecf20Sopenharmony_ci			connect_change = 1;
38078c2ecf20Sopenharmony_ci	} else {
38088c2ecf20Sopenharmony_ci		ret = -ENODEV;
38098c2ecf20Sopenharmony_ci		hub_port_disable(hub, port, 1);
38108c2ecf20Sopenharmony_ci	}
38118c2ecf20Sopenharmony_ci	dev_dbg(&port_dev->dev, "resume, status %d\n", ret);
38128c2ecf20Sopenharmony_ci	return connect_change;
38138c2ecf20Sopenharmony_ci}
38148c2ecf20Sopenharmony_ci
38158c2ecf20Sopenharmony_cistatic int check_ports_changed(struct usb_hub *hub)
38168c2ecf20Sopenharmony_ci{
38178c2ecf20Sopenharmony_ci	int port1;
38188c2ecf20Sopenharmony_ci
38198c2ecf20Sopenharmony_ci	for (port1 = 1; port1 <= hub->hdev->maxchild; ++port1) {
38208c2ecf20Sopenharmony_ci		u16 portstatus, portchange;
38218c2ecf20Sopenharmony_ci		int status;
38228c2ecf20Sopenharmony_ci
38238c2ecf20Sopenharmony_ci		status = hub_port_status(hub, port1, &portstatus, &portchange);
38248c2ecf20Sopenharmony_ci		if (!status && portchange)
38258c2ecf20Sopenharmony_ci			return 1;
38268c2ecf20Sopenharmony_ci	}
38278c2ecf20Sopenharmony_ci	return 0;
38288c2ecf20Sopenharmony_ci}
38298c2ecf20Sopenharmony_ci
38308c2ecf20Sopenharmony_cistatic int hub_suspend(struct usb_interface *intf, pm_message_t msg)
38318c2ecf20Sopenharmony_ci{
38328c2ecf20Sopenharmony_ci	struct usb_hub		*hub = usb_get_intfdata(intf);
38338c2ecf20Sopenharmony_ci	struct usb_device	*hdev = hub->hdev;
38348c2ecf20Sopenharmony_ci	unsigned		port1;
38358c2ecf20Sopenharmony_ci
38368c2ecf20Sopenharmony_ci	/*
38378c2ecf20Sopenharmony_ci	 * Warn if children aren't already suspended.
38388c2ecf20Sopenharmony_ci	 * Also, add up the number of wakeup-enabled descendants.
38398c2ecf20Sopenharmony_ci	 */
38408c2ecf20Sopenharmony_ci	hub->wakeup_enabled_descendants = 0;
38418c2ecf20Sopenharmony_ci	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
38428c2ecf20Sopenharmony_ci		struct usb_port *port_dev = hub->ports[port1 - 1];
38438c2ecf20Sopenharmony_ci		struct usb_device *udev = port_dev->child;
38448c2ecf20Sopenharmony_ci
38458c2ecf20Sopenharmony_ci		if (udev && udev->can_submit) {
38468c2ecf20Sopenharmony_ci			dev_warn(&port_dev->dev, "device %s not suspended yet\n",
38478c2ecf20Sopenharmony_ci					dev_name(&udev->dev));
38488c2ecf20Sopenharmony_ci			if (PMSG_IS_AUTO(msg))
38498c2ecf20Sopenharmony_ci				return -EBUSY;
38508c2ecf20Sopenharmony_ci		}
38518c2ecf20Sopenharmony_ci		if (udev)
38528c2ecf20Sopenharmony_ci			hub->wakeup_enabled_descendants +=
38538c2ecf20Sopenharmony_ci					usb_wakeup_enabled_descendants(udev);
38548c2ecf20Sopenharmony_ci	}
38558c2ecf20Sopenharmony_ci
38568c2ecf20Sopenharmony_ci	if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) {
38578c2ecf20Sopenharmony_ci		/* check if there are changes pending on hub ports */
38588c2ecf20Sopenharmony_ci		if (check_ports_changed(hub)) {
38598c2ecf20Sopenharmony_ci			if (PMSG_IS_AUTO(msg))
38608c2ecf20Sopenharmony_ci				return -EBUSY;
38618c2ecf20Sopenharmony_ci			pm_wakeup_event(&hdev->dev, 2000);
38628c2ecf20Sopenharmony_ci		}
38638c2ecf20Sopenharmony_ci	}
38648c2ecf20Sopenharmony_ci
38658c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
38668c2ecf20Sopenharmony_ci		/* Enable hub to send remote wakeup for all ports. */
38678c2ecf20Sopenharmony_ci		for (port1 = 1; port1 <= hdev->maxchild; port1++) {
38688c2ecf20Sopenharmony_ci			set_port_feature(hdev,
38698c2ecf20Sopenharmony_ci					 port1 |
38708c2ecf20Sopenharmony_ci					 USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
38718c2ecf20Sopenharmony_ci					 USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
38728c2ecf20Sopenharmony_ci					 USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
38738c2ecf20Sopenharmony_ci					 USB_PORT_FEAT_REMOTE_WAKE_MASK);
38748c2ecf20Sopenharmony_ci		}
38758c2ecf20Sopenharmony_ci	}
38768c2ecf20Sopenharmony_ci
38778c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "%s\n", __func__);
38788c2ecf20Sopenharmony_ci
38798c2ecf20Sopenharmony_ci	/* stop hub_wq and related activity */
38808c2ecf20Sopenharmony_ci	hub_quiesce(hub, HUB_SUSPEND);
38818c2ecf20Sopenharmony_ci	return 0;
38828c2ecf20Sopenharmony_ci}
38838c2ecf20Sopenharmony_ci
38848c2ecf20Sopenharmony_ci/* Report wakeup requests from the ports of a resuming root hub */
38858c2ecf20Sopenharmony_cistatic void report_wakeup_requests(struct usb_hub *hub)
38868c2ecf20Sopenharmony_ci{
38878c2ecf20Sopenharmony_ci	struct usb_device	*hdev = hub->hdev;
38888c2ecf20Sopenharmony_ci	struct usb_device	*udev;
38898c2ecf20Sopenharmony_ci	struct usb_hcd		*hcd;
38908c2ecf20Sopenharmony_ci	unsigned long		resuming_ports;
38918c2ecf20Sopenharmony_ci	int			i;
38928c2ecf20Sopenharmony_ci
38938c2ecf20Sopenharmony_ci	if (hdev->parent)
38948c2ecf20Sopenharmony_ci		return;		/* Not a root hub */
38958c2ecf20Sopenharmony_ci
38968c2ecf20Sopenharmony_ci	hcd = bus_to_hcd(hdev->bus);
38978c2ecf20Sopenharmony_ci	if (hcd->driver->get_resuming_ports) {
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_ci		/*
39008c2ecf20Sopenharmony_ci		 * The get_resuming_ports() method returns a bitmap (origin 0)
39018c2ecf20Sopenharmony_ci		 * of ports which have started wakeup signaling but have not
39028c2ecf20Sopenharmony_ci		 * yet finished resuming.  During system resume we will
39038c2ecf20Sopenharmony_ci		 * resume all the enabled ports, regardless of any wakeup
39048c2ecf20Sopenharmony_ci		 * signals, which means the wakeup requests would be lost.
39058c2ecf20Sopenharmony_ci		 * To prevent this, report them to the PM core here.
39068c2ecf20Sopenharmony_ci		 */
39078c2ecf20Sopenharmony_ci		resuming_ports = hcd->driver->get_resuming_ports(hcd);
39088c2ecf20Sopenharmony_ci		for (i = 0; i < hdev->maxchild; ++i) {
39098c2ecf20Sopenharmony_ci			if (test_bit(i, &resuming_ports)) {
39108c2ecf20Sopenharmony_ci				udev = hub->ports[i]->child;
39118c2ecf20Sopenharmony_ci				if (udev)
39128c2ecf20Sopenharmony_ci					pm_wakeup_event(&udev->dev, 0);
39138c2ecf20Sopenharmony_ci			}
39148c2ecf20Sopenharmony_ci		}
39158c2ecf20Sopenharmony_ci	}
39168c2ecf20Sopenharmony_ci}
39178c2ecf20Sopenharmony_ci
39188c2ecf20Sopenharmony_cistatic int hub_resume(struct usb_interface *intf)
39198c2ecf20Sopenharmony_ci{
39208c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_get_intfdata(intf);
39218c2ecf20Sopenharmony_ci
39228c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "%s\n", __func__);
39238c2ecf20Sopenharmony_ci	hub_activate(hub, HUB_RESUME);
39248c2ecf20Sopenharmony_ci
39258c2ecf20Sopenharmony_ci	/*
39268c2ecf20Sopenharmony_ci	 * This should be called only for system resume, not runtime resume.
39278c2ecf20Sopenharmony_ci	 * We can't tell the difference here, so some wakeup requests will be
39288c2ecf20Sopenharmony_ci	 * reported at the wrong time or more than once.  This shouldn't
39298c2ecf20Sopenharmony_ci	 * matter much, so long as they do get reported.
39308c2ecf20Sopenharmony_ci	 */
39318c2ecf20Sopenharmony_ci	report_wakeup_requests(hub);
39328c2ecf20Sopenharmony_ci	return 0;
39338c2ecf20Sopenharmony_ci}
39348c2ecf20Sopenharmony_ci
39358c2ecf20Sopenharmony_cistatic int hub_reset_resume(struct usb_interface *intf)
39368c2ecf20Sopenharmony_ci{
39378c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_get_intfdata(intf);
39388c2ecf20Sopenharmony_ci
39398c2ecf20Sopenharmony_ci	dev_dbg(&intf->dev, "%s\n", __func__);
39408c2ecf20Sopenharmony_ci	hub_activate(hub, HUB_RESET_RESUME);
39418c2ecf20Sopenharmony_ci	return 0;
39428c2ecf20Sopenharmony_ci}
39438c2ecf20Sopenharmony_ci
39448c2ecf20Sopenharmony_ci/**
39458c2ecf20Sopenharmony_ci * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
39468c2ecf20Sopenharmony_ci * @rhdev: struct usb_device for the root hub
39478c2ecf20Sopenharmony_ci *
39488c2ecf20Sopenharmony_ci * The USB host controller driver calls this function when its root hub
39498c2ecf20Sopenharmony_ci * is resumed and Vbus power has been interrupted or the controller
39508c2ecf20Sopenharmony_ci * has been reset.  The routine marks @rhdev as having lost power.
39518c2ecf20Sopenharmony_ci * When the hub driver is resumed it will take notice and carry out
39528c2ecf20Sopenharmony_ci * power-session recovery for all the "USB-PERSIST"-enabled child devices;
39538c2ecf20Sopenharmony_ci * the others will be disconnected.
39548c2ecf20Sopenharmony_ci */
39558c2ecf20Sopenharmony_civoid usb_root_hub_lost_power(struct usb_device *rhdev)
39568c2ecf20Sopenharmony_ci{
39578c2ecf20Sopenharmony_ci	dev_notice(&rhdev->dev, "root hub lost power or was reset\n");
39588c2ecf20Sopenharmony_ci	rhdev->reset_resume = 1;
39598c2ecf20Sopenharmony_ci}
39608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
39618c2ecf20Sopenharmony_ci
39628c2ecf20Sopenharmony_cistatic const char * const usb3_lpm_names[]  = {
39638c2ecf20Sopenharmony_ci	"U0",
39648c2ecf20Sopenharmony_ci	"U1",
39658c2ecf20Sopenharmony_ci	"U2",
39668c2ecf20Sopenharmony_ci	"U3",
39678c2ecf20Sopenharmony_ci};
39688c2ecf20Sopenharmony_ci
39698c2ecf20Sopenharmony_ci/*
39708c2ecf20Sopenharmony_ci * Send a Set SEL control transfer to the device, prior to enabling
39718c2ecf20Sopenharmony_ci * device-initiated U1 or U2.  This lets the device know the exit latencies from
39728c2ecf20Sopenharmony_ci * the time the device initiates a U1 or U2 exit, to the time it will receive a
39738c2ecf20Sopenharmony_ci * packet from the host.
39748c2ecf20Sopenharmony_ci *
39758c2ecf20Sopenharmony_ci * This function will fail if the SEL or PEL values for udev are greater than
39768c2ecf20Sopenharmony_ci * the maximum allowed values for the link state to be enabled.
39778c2ecf20Sopenharmony_ci */
39788c2ecf20Sopenharmony_cistatic int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
39798c2ecf20Sopenharmony_ci{
39808c2ecf20Sopenharmony_ci	struct usb_set_sel_req *sel_values;
39818c2ecf20Sopenharmony_ci	unsigned long long u1_sel;
39828c2ecf20Sopenharmony_ci	unsigned long long u1_pel;
39838c2ecf20Sopenharmony_ci	unsigned long long u2_sel;
39848c2ecf20Sopenharmony_ci	unsigned long long u2_pel;
39858c2ecf20Sopenharmony_ci	int ret;
39868c2ecf20Sopenharmony_ci
39878c2ecf20Sopenharmony_ci	if (udev->state != USB_STATE_CONFIGURED)
39888c2ecf20Sopenharmony_ci		return 0;
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_ci	/* Convert SEL and PEL stored in ns to us */
39918c2ecf20Sopenharmony_ci	u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
39928c2ecf20Sopenharmony_ci	u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
39938c2ecf20Sopenharmony_ci	u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
39948c2ecf20Sopenharmony_ci	u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
39958c2ecf20Sopenharmony_ci
39968c2ecf20Sopenharmony_ci	/*
39978c2ecf20Sopenharmony_ci	 * Make sure that the calculated SEL and PEL values for the link
39988c2ecf20Sopenharmony_ci	 * state we're enabling aren't bigger than the max SEL/PEL
39998c2ecf20Sopenharmony_ci	 * value that will fit in the SET SEL control transfer.
40008c2ecf20Sopenharmony_ci	 * Otherwise the device would get an incorrect idea of the exit
40018c2ecf20Sopenharmony_ci	 * latency for the link state, and could start a device-initiated
40028c2ecf20Sopenharmony_ci	 * U1/U2 when the exit latencies are too high.
40038c2ecf20Sopenharmony_ci	 */
40048c2ecf20Sopenharmony_ci	if ((state == USB3_LPM_U1 &&
40058c2ecf20Sopenharmony_ci				(u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
40068c2ecf20Sopenharmony_ci				 u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) ||
40078c2ecf20Sopenharmony_ci			(state == USB3_LPM_U2 &&
40088c2ecf20Sopenharmony_ci			 (u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
40098c2ecf20Sopenharmony_ci			  u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
40108c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "Device-initiated %s disabled due to long SEL %llu us or PEL %llu us\n",
40118c2ecf20Sopenharmony_ci				usb3_lpm_names[state], u1_sel, u1_pel);
40128c2ecf20Sopenharmony_ci		return -EINVAL;
40138c2ecf20Sopenharmony_ci	}
40148c2ecf20Sopenharmony_ci
40158c2ecf20Sopenharmony_ci	/*
40168c2ecf20Sopenharmony_ci	 * If we're enabling device-initiated LPM for one link state,
40178c2ecf20Sopenharmony_ci	 * but the other link state has a too high SEL or PEL value,
40188c2ecf20Sopenharmony_ci	 * just set those values to the max in the Set SEL request.
40198c2ecf20Sopenharmony_ci	 */
40208c2ecf20Sopenharmony_ci	if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL)
40218c2ecf20Sopenharmony_ci		u1_sel = USB3_LPM_MAX_U1_SEL_PEL;
40228c2ecf20Sopenharmony_ci
40238c2ecf20Sopenharmony_ci	if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL)
40248c2ecf20Sopenharmony_ci		u1_pel = USB3_LPM_MAX_U1_SEL_PEL;
40258c2ecf20Sopenharmony_ci
40268c2ecf20Sopenharmony_ci	if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL)
40278c2ecf20Sopenharmony_ci		u2_sel = USB3_LPM_MAX_U2_SEL_PEL;
40288c2ecf20Sopenharmony_ci
40298c2ecf20Sopenharmony_ci	if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL)
40308c2ecf20Sopenharmony_ci		u2_pel = USB3_LPM_MAX_U2_SEL_PEL;
40318c2ecf20Sopenharmony_ci
40328c2ecf20Sopenharmony_ci	/*
40338c2ecf20Sopenharmony_ci	 * usb_enable_lpm() can be called as part of a failed device reset,
40348c2ecf20Sopenharmony_ci	 * which may be initiated by an error path of a mass storage driver.
40358c2ecf20Sopenharmony_ci	 * Therefore, use GFP_NOIO.
40368c2ecf20Sopenharmony_ci	 */
40378c2ecf20Sopenharmony_ci	sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO);
40388c2ecf20Sopenharmony_ci	if (!sel_values)
40398c2ecf20Sopenharmony_ci		return -ENOMEM;
40408c2ecf20Sopenharmony_ci
40418c2ecf20Sopenharmony_ci	sel_values->u1_sel = u1_sel;
40428c2ecf20Sopenharmony_ci	sel_values->u1_pel = u1_pel;
40438c2ecf20Sopenharmony_ci	sel_values->u2_sel = cpu_to_le16(u2_sel);
40448c2ecf20Sopenharmony_ci	sel_values->u2_pel = cpu_to_le16(u2_pel);
40458c2ecf20Sopenharmony_ci
40468c2ecf20Sopenharmony_ci	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
40478c2ecf20Sopenharmony_ci			USB_REQ_SET_SEL,
40488c2ecf20Sopenharmony_ci			USB_RECIP_DEVICE,
40498c2ecf20Sopenharmony_ci			0, 0,
40508c2ecf20Sopenharmony_ci			sel_values, sizeof *(sel_values),
40518c2ecf20Sopenharmony_ci			USB_CTRL_SET_TIMEOUT);
40528c2ecf20Sopenharmony_ci	kfree(sel_values);
40538c2ecf20Sopenharmony_ci	return ret;
40548c2ecf20Sopenharmony_ci}
40558c2ecf20Sopenharmony_ci
40568c2ecf20Sopenharmony_ci/*
40578c2ecf20Sopenharmony_ci * Enable or disable device-initiated U1 or U2 transitions.
40588c2ecf20Sopenharmony_ci */
40598c2ecf20Sopenharmony_cistatic int usb_set_device_initiated_lpm(struct usb_device *udev,
40608c2ecf20Sopenharmony_ci		enum usb3_link_state state, bool enable)
40618c2ecf20Sopenharmony_ci{
40628c2ecf20Sopenharmony_ci	int ret;
40638c2ecf20Sopenharmony_ci	int feature;
40648c2ecf20Sopenharmony_ci
40658c2ecf20Sopenharmony_ci	switch (state) {
40668c2ecf20Sopenharmony_ci	case USB3_LPM_U1:
40678c2ecf20Sopenharmony_ci		feature = USB_DEVICE_U1_ENABLE;
40688c2ecf20Sopenharmony_ci		break;
40698c2ecf20Sopenharmony_ci	case USB3_LPM_U2:
40708c2ecf20Sopenharmony_ci		feature = USB_DEVICE_U2_ENABLE;
40718c2ecf20Sopenharmony_ci		break;
40728c2ecf20Sopenharmony_ci	default:
40738c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n",
40748c2ecf20Sopenharmony_ci				__func__, enable ? "enable" : "disable");
40758c2ecf20Sopenharmony_ci		return -EINVAL;
40768c2ecf20Sopenharmony_ci	}
40778c2ecf20Sopenharmony_ci
40788c2ecf20Sopenharmony_ci	if (udev->state != USB_STATE_CONFIGURED) {
40798c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "%s: Can't %s %s state "
40808c2ecf20Sopenharmony_ci				"for unconfigured device.\n",
40818c2ecf20Sopenharmony_ci				__func__, enable ? "enable" : "disable",
40828c2ecf20Sopenharmony_ci				usb3_lpm_names[state]);
40838c2ecf20Sopenharmony_ci		return 0;
40848c2ecf20Sopenharmony_ci	}
40858c2ecf20Sopenharmony_ci
40868c2ecf20Sopenharmony_ci	if (enable) {
40878c2ecf20Sopenharmony_ci		/*
40888c2ecf20Sopenharmony_ci		 * Now send the control transfer to enable device-initiated LPM
40898c2ecf20Sopenharmony_ci		 * for either U1 or U2.
40908c2ecf20Sopenharmony_ci		 */
40918c2ecf20Sopenharmony_ci		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
40928c2ecf20Sopenharmony_ci				USB_REQ_SET_FEATURE,
40938c2ecf20Sopenharmony_ci				USB_RECIP_DEVICE,
40948c2ecf20Sopenharmony_ci				feature,
40958c2ecf20Sopenharmony_ci				0, NULL, 0,
40968c2ecf20Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
40978c2ecf20Sopenharmony_ci	} else {
40988c2ecf20Sopenharmony_ci		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
40998c2ecf20Sopenharmony_ci				USB_REQ_CLEAR_FEATURE,
41008c2ecf20Sopenharmony_ci				USB_RECIP_DEVICE,
41018c2ecf20Sopenharmony_ci				feature,
41028c2ecf20Sopenharmony_ci				0, NULL, 0,
41038c2ecf20Sopenharmony_ci				USB_CTRL_SET_TIMEOUT);
41048c2ecf20Sopenharmony_ci	}
41058c2ecf20Sopenharmony_ci	if (ret < 0) {
41068c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "%s of device-initiated %s failed.\n",
41078c2ecf20Sopenharmony_ci				enable ? "Enable" : "Disable",
41088c2ecf20Sopenharmony_ci				usb3_lpm_names[state]);
41098c2ecf20Sopenharmony_ci		return -EBUSY;
41108c2ecf20Sopenharmony_ci	}
41118c2ecf20Sopenharmony_ci	return 0;
41128c2ecf20Sopenharmony_ci}
41138c2ecf20Sopenharmony_ci
41148c2ecf20Sopenharmony_cistatic int usb_set_lpm_timeout(struct usb_device *udev,
41158c2ecf20Sopenharmony_ci		enum usb3_link_state state, int timeout)
41168c2ecf20Sopenharmony_ci{
41178c2ecf20Sopenharmony_ci	int ret;
41188c2ecf20Sopenharmony_ci	int feature;
41198c2ecf20Sopenharmony_ci
41208c2ecf20Sopenharmony_ci	switch (state) {
41218c2ecf20Sopenharmony_ci	case USB3_LPM_U1:
41228c2ecf20Sopenharmony_ci		feature = USB_PORT_FEAT_U1_TIMEOUT;
41238c2ecf20Sopenharmony_ci		break;
41248c2ecf20Sopenharmony_ci	case USB3_LPM_U2:
41258c2ecf20Sopenharmony_ci		feature = USB_PORT_FEAT_U2_TIMEOUT;
41268c2ecf20Sopenharmony_ci		break;
41278c2ecf20Sopenharmony_ci	default:
41288c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n",
41298c2ecf20Sopenharmony_ci				__func__);
41308c2ecf20Sopenharmony_ci		return -EINVAL;
41318c2ecf20Sopenharmony_ci	}
41328c2ecf20Sopenharmony_ci
41338c2ecf20Sopenharmony_ci	if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT &&
41348c2ecf20Sopenharmony_ci			timeout != USB3_LPM_DEVICE_INITIATED) {
41358c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, "
41368c2ecf20Sopenharmony_ci				"which is a reserved value.\n",
41378c2ecf20Sopenharmony_ci				usb3_lpm_names[state], timeout);
41388c2ecf20Sopenharmony_ci		return -EINVAL;
41398c2ecf20Sopenharmony_ci	}
41408c2ecf20Sopenharmony_ci
41418c2ecf20Sopenharmony_ci	ret = set_port_feature(udev->parent,
41428c2ecf20Sopenharmony_ci			USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum,
41438c2ecf20Sopenharmony_ci			feature);
41448c2ecf20Sopenharmony_ci	if (ret < 0) {
41458c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x,"
41468c2ecf20Sopenharmony_ci				"error code %i\n", usb3_lpm_names[state],
41478c2ecf20Sopenharmony_ci				timeout, ret);
41488c2ecf20Sopenharmony_ci		return -EBUSY;
41498c2ecf20Sopenharmony_ci	}
41508c2ecf20Sopenharmony_ci	if (state == USB3_LPM_U1)
41518c2ecf20Sopenharmony_ci		udev->u1_params.timeout = timeout;
41528c2ecf20Sopenharmony_ci	else
41538c2ecf20Sopenharmony_ci		udev->u2_params.timeout = timeout;
41548c2ecf20Sopenharmony_ci	return 0;
41558c2ecf20Sopenharmony_ci}
41568c2ecf20Sopenharmony_ci
41578c2ecf20Sopenharmony_ci/*
41588c2ecf20Sopenharmony_ci * Don't allow device intiated U1/U2 if the system exit latency + one bus
41598c2ecf20Sopenharmony_ci * interval is greater than the minimum service interval of any active
41608c2ecf20Sopenharmony_ci * periodic endpoint. See USB 3.2 section 9.4.9
41618c2ecf20Sopenharmony_ci */
41628c2ecf20Sopenharmony_cistatic bool usb_device_may_initiate_lpm(struct usb_device *udev,
41638c2ecf20Sopenharmony_ci					enum usb3_link_state state)
41648c2ecf20Sopenharmony_ci{
41658c2ecf20Sopenharmony_ci	unsigned int sel;		/* us */
41668c2ecf20Sopenharmony_ci	int i, j;
41678c2ecf20Sopenharmony_ci
41688c2ecf20Sopenharmony_ci	if (state == USB3_LPM_U1)
41698c2ecf20Sopenharmony_ci		sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
41708c2ecf20Sopenharmony_ci	else if (state == USB3_LPM_U2)
41718c2ecf20Sopenharmony_ci		sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
41728c2ecf20Sopenharmony_ci	else
41738c2ecf20Sopenharmony_ci		return false;
41748c2ecf20Sopenharmony_ci
41758c2ecf20Sopenharmony_ci	for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
41768c2ecf20Sopenharmony_ci		struct usb_interface *intf;
41778c2ecf20Sopenharmony_ci		struct usb_endpoint_descriptor *desc;
41788c2ecf20Sopenharmony_ci		unsigned int interval;
41798c2ecf20Sopenharmony_ci
41808c2ecf20Sopenharmony_ci		intf = udev->actconfig->interface[i];
41818c2ecf20Sopenharmony_ci		if (!intf)
41828c2ecf20Sopenharmony_ci			continue;
41838c2ecf20Sopenharmony_ci
41848c2ecf20Sopenharmony_ci		for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++) {
41858c2ecf20Sopenharmony_ci			desc = &intf->cur_altsetting->endpoint[j].desc;
41868c2ecf20Sopenharmony_ci
41878c2ecf20Sopenharmony_ci			if (usb_endpoint_xfer_int(desc) ||
41888c2ecf20Sopenharmony_ci			    usb_endpoint_xfer_isoc(desc)) {
41898c2ecf20Sopenharmony_ci				interval = (1 << (desc->bInterval - 1)) * 125;
41908c2ecf20Sopenharmony_ci				if (sel + 125 > interval)
41918c2ecf20Sopenharmony_ci					return false;
41928c2ecf20Sopenharmony_ci			}
41938c2ecf20Sopenharmony_ci		}
41948c2ecf20Sopenharmony_ci	}
41958c2ecf20Sopenharmony_ci	return true;
41968c2ecf20Sopenharmony_ci}
41978c2ecf20Sopenharmony_ci
41988c2ecf20Sopenharmony_ci/*
41998c2ecf20Sopenharmony_ci * Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated
42008c2ecf20Sopenharmony_ci * U1/U2 entry.
42018c2ecf20Sopenharmony_ci *
42028c2ecf20Sopenharmony_ci * We will attempt to enable U1 or U2, but there are no guarantees that the
42038c2ecf20Sopenharmony_ci * control transfers to set the hub timeout or enable device-initiated U1/U2
42048c2ecf20Sopenharmony_ci * will be successful.
42058c2ecf20Sopenharmony_ci *
42068c2ecf20Sopenharmony_ci * If the control transfer to enable device-initiated U1/U2 entry fails, then
42078c2ecf20Sopenharmony_ci * hub-initiated U1/U2 will be disabled.
42088c2ecf20Sopenharmony_ci *
42098c2ecf20Sopenharmony_ci * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
42108c2ecf20Sopenharmony_ci * driver know about it.  If that call fails, it should be harmless, and just
42118c2ecf20Sopenharmony_ci * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
42128c2ecf20Sopenharmony_ci */
42138c2ecf20Sopenharmony_cistatic void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
42148c2ecf20Sopenharmony_ci		enum usb3_link_state state)
42158c2ecf20Sopenharmony_ci{
42168c2ecf20Sopenharmony_ci	int timeout, ret;
42178c2ecf20Sopenharmony_ci	__u8 u1_mel;
42188c2ecf20Sopenharmony_ci	__le16 u2_mel;
42198c2ecf20Sopenharmony_ci
42208c2ecf20Sopenharmony_ci	/* Skip if the device BOS descriptor couldn't be read */
42218c2ecf20Sopenharmony_ci	if (!udev->bos)
42228c2ecf20Sopenharmony_ci		return;
42238c2ecf20Sopenharmony_ci
42248c2ecf20Sopenharmony_ci	u1_mel = udev->bos->ss_cap->bU1devExitLat;
42258c2ecf20Sopenharmony_ci	u2_mel = udev->bos->ss_cap->bU2DevExitLat;
42268c2ecf20Sopenharmony_ci
42278c2ecf20Sopenharmony_ci	/* If the device says it doesn't have *any* exit latency to come out of
42288c2ecf20Sopenharmony_ci	 * U1 or U2, it's probably lying.  Assume it doesn't implement that link
42298c2ecf20Sopenharmony_ci	 * state.
42308c2ecf20Sopenharmony_ci	 */
42318c2ecf20Sopenharmony_ci	if ((state == USB3_LPM_U1 && u1_mel == 0) ||
42328c2ecf20Sopenharmony_ci			(state == USB3_LPM_U2 && u2_mel == 0))
42338c2ecf20Sopenharmony_ci		return;
42348c2ecf20Sopenharmony_ci
42358c2ecf20Sopenharmony_ci	/*
42368c2ecf20Sopenharmony_ci	 * First, let the device know about the exit latencies
42378c2ecf20Sopenharmony_ci	 * associated with the link state we're about to enable.
42388c2ecf20Sopenharmony_ci	 */
42398c2ecf20Sopenharmony_ci	ret = usb_req_set_sel(udev, state);
42408c2ecf20Sopenharmony_ci	if (ret < 0) {
42418c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "Set SEL for device-initiated %s failed.\n",
42428c2ecf20Sopenharmony_ci				usb3_lpm_names[state]);
42438c2ecf20Sopenharmony_ci		return;
42448c2ecf20Sopenharmony_ci	}
42458c2ecf20Sopenharmony_ci
42468c2ecf20Sopenharmony_ci	/* We allow the host controller to set the U1/U2 timeout internally
42478c2ecf20Sopenharmony_ci	 * first, so that it can change its schedule to account for the
42488c2ecf20Sopenharmony_ci	 * additional latency to send data to a device in a lower power
42498c2ecf20Sopenharmony_ci	 * link state.
42508c2ecf20Sopenharmony_ci	 */
42518c2ecf20Sopenharmony_ci	timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state);
42528c2ecf20Sopenharmony_ci
42538c2ecf20Sopenharmony_ci	/* xHCI host controller doesn't want to enable this LPM state. */
42548c2ecf20Sopenharmony_ci	if (timeout == 0)
42558c2ecf20Sopenharmony_ci		return;
42568c2ecf20Sopenharmony_ci
42578c2ecf20Sopenharmony_ci	if (timeout < 0) {
42588c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "Could not enable %s link state, "
42598c2ecf20Sopenharmony_ci				"xHCI error %i.\n", usb3_lpm_names[state],
42608c2ecf20Sopenharmony_ci				timeout);
42618c2ecf20Sopenharmony_ci		return;
42628c2ecf20Sopenharmony_ci	}
42638c2ecf20Sopenharmony_ci
42648c2ecf20Sopenharmony_ci	if (usb_set_lpm_timeout(udev, state, timeout)) {
42658c2ecf20Sopenharmony_ci		/* If we can't set the parent hub U1/U2 timeout,
42668c2ecf20Sopenharmony_ci		 * device-initiated LPM won't be allowed either, so let the xHCI
42678c2ecf20Sopenharmony_ci		 * host know that this link state won't be enabled.
42688c2ecf20Sopenharmony_ci		 */
42698c2ecf20Sopenharmony_ci		hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
42708c2ecf20Sopenharmony_ci		return;
42718c2ecf20Sopenharmony_ci	}
42728c2ecf20Sopenharmony_ci
42738c2ecf20Sopenharmony_ci	/* Only a configured device will accept the Set Feature
42748c2ecf20Sopenharmony_ci	 * U1/U2_ENABLE
42758c2ecf20Sopenharmony_ci	 */
42768c2ecf20Sopenharmony_ci	if (udev->actconfig &&
42778c2ecf20Sopenharmony_ci	    usb_device_may_initiate_lpm(udev, state)) {
42788c2ecf20Sopenharmony_ci		if (usb_set_device_initiated_lpm(udev, state, true)) {
42798c2ecf20Sopenharmony_ci			/*
42808c2ecf20Sopenharmony_ci			 * Request to enable device initiated U1/U2 failed,
42818c2ecf20Sopenharmony_ci			 * better to turn off lpm in this case.
42828c2ecf20Sopenharmony_ci			 */
42838c2ecf20Sopenharmony_ci			usb_set_lpm_timeout(udev, state, 0);
42848c2ecf20Sopenharmony_ci			hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
42858c2ecf20Sopenharmony_ci			return;
42868c2ecf20Sopenharmony_ci		}
42878c2ecf20Sopenharmony_ci	}
42888c2ecf20Sopenharmony_ci
42898c2ecf20Sopenharmony_ci	if (state == USB3_LPM_U1)
42908c2ecf20Sopenharmony_ci		udev->usb3_lpm_u1_enabled = 1;
42918c2ecf20Sopenharmony_ci	else if (state == USB3_LPM_U2)
42928c2ecf20Sopenharmony_ci		udev->usb3_lpm_u2_enabled = 1;
42938c2ecf20Sopenharmony_ci}
42948c2ecf20Sopenharmony_ci/*
42958c2ecf20Sopenharmony_ci * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated
42968c2ecf20Sopenharmony_ci * U1/U2 entry.
42978c2ecf20Sopenharmony_ci *
42988c2ecf20Sopenharmony_ci * If this function returns -EBUSY, the parent hub will still allow U1/U2 entry.
42998c2ecf20Sopenharmony_ci * If zero is returned, the parent will not allow the link to go into U1/U2.
43008c2ecf20Sopenharmony_ci *
43018c2ecf20Sopenharmony_ci * If zero is returned, device-initiated U1/U2 entry may still be enabled, but
43028c2ecf20Sopenharmony_ci * it won't have an effect on the bus link state because the parent hub will
43038c2ecf20Sopenharmony_ci * still disallow device-initiated U1/U2 entry.
43048c2ecf20Sopenharmony_ci *
43058c2ecf20Sopenharmony_ci * If zero is returned, the xHCI host controller may still think U1/U2 entry is
43068c2ecf20Sopenharmony_ci * possible.  The result will be slightly more bus bandwidth will be taken up
43078c2ecf20Sopenharmony_ci * (to account for U1/U2 exit latency), but it should be harmless.
43088c2ecf20Sopenharmony_ci */
43098c2ecf20Sopenharmony_cistatic int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
43108c2ecf20Sopenharmony_ci		enum usb3_link_state state)
43118c2ecf20Sopenharmony_ci{
43128c2ecf20Sopenharmony_ci	switch (state) {
43138c2ecf20Sopenharmony_ci	case USB3_LPM_U1:
43148c2ecf20Sopenharmony_ci	case USB3_LPM_U2:
43158c2ecf20Sopenharmony_ci		break;
43168c2ecf20Sopenharmony_ci	default:
43178c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
43188c2ecf20Sopenharmony_ci				__func__);
43198c2ecf20Sopenharmony_ci		return -EINVAL;
43208c2ecf20Sopenharmony_ci	}
43218c2ecf20Sopenharmony_ci
43228c2ecf20Sopenharmony_ci	if (usb_set_lpm_timeout(udev, state, 0))
43238c2ecf20Sopenharmony_ci		return -EBUSY;
43248c2ecf20Sopenharmony_ci
43258c2ecf20Sopenharmony_ci	usb_set_device_initiated_lpm(udev, state, false);
43268c2ecf20Sopenharmony_ci
43278c2ecf20Sopenharmony_ci	if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state))
43288c2ecf20Sopenharmony_ci		dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
43298c2ecf20Sopenharmony_ci				"bus schedule bandwidth may be impacted.\n",
43308c2ecf20Sopenharmony_ci				usb3_lpm_names[state]);
43318c2ecf20Sopenharmony_ci
43328c2ecf20Sopenharmony_ci	/* As soon as usb_set_lpm_timeout(0) return 0, hub initiated LPM
43338c2ecf20Sopenharmony_ci	 * is disabled. Hub will disallows link to enter U1/U2 as well,
43348c2ecf20Sopenharmony_ci	 * even device is initiating LPM. Hence LPM is disabled if hub LPM
43358c2ecf20Sopenharmony_ci	 * timeout set to 0, no matter device-initiated LPM is disabled or
43368c2ecf20Sopenharmony_ci	 * not.
43378c2ecf20Sopenharmony_ci	 */
43388c2ecf20Sopenharmony_ci	if (state == USB3_LPM_U1)
43398c2ecf20Sopenharmony_ci		udev->usb3_lpm_u1_enabled = 0;
43408c2ecf20Sopenharmony_ci	else if (state == USB3_LPM_U2)
43418c2ecf20Sopenharmony_ci		udev->usb3_lpm_u2_enabled = 0;
43428c2ecf20Sopenharmony_ci
43438c2ecf20Sopenharmony_ci	return 0;
43448c2ecf20Sopenharmony_ci}
43458c2ecf20Sopenharmony_ci
43468c2ecf20Sopenharmony_ci/*
43478c2ecf20Sopenharmony_ci * Disable hub-initiated and device-initiated U1 and U2 entry.
43488c2ecf20Sopenharmony_ci * Caller must own the bandwidth_mutex.
43498c2ecf20Sopenharmony_ci *
43508c2ecf20Sopenharmony_ci * This will call usb_enable_lpm() on failure, which will decrement
43518c2ecf20Sopenharmony_ci * lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero.
43528c2ecf20Sopenharmony_ci */
43538c2ecf20Sopenharmony_ciint usb_disable_lpm(struct usb_device *udev)
43548c2ecf20Sopenharmony_ci{
43558c2ecf20Sopenharmony_ci	struct usb_hcd *hcd;
43568c2ecf20Sopenharmony_ci
43578c2ecf20Sopenharmony_ci	if (!udev || !udev->parent ||
43588c2ecf20Sopenharmony_ci			udev->speed < USB_SPEED_SUPER ||
43598c2ecf20Sopenharmony_ci			!udev->lpm_capable ||
43608c2ecf20Sopenharmony_ci			udev->state < USB_STATE_CONFIGURED)
43618c2ecf20Sopenharmony_ci		return 0;
43628c2ecf20Sopenharmony_ci
43638c2ecf20Sopenharmony_ci	hcd = bus_to_hcd(udev->bus);
43648c2ecf20Sopenharmony_ci	if (!hcd || !hcd->driver->disable_usb3_lpm_timeout)
43658c2ecf20Sopenharmony_ci		return 0;
43668c2ecf20Sopenharmony_ci
43678c2ecf20Sopenharmony_ci	udev->lpm_disable_count++;
43688c2ecf20Sopenharmony_ci	if ((udev->u1_params.timeout == 0 && udev->u2_params.timeout == 0))
43698c2ecf20Sopenharmony_ci		return 0;
43708c2ecf20Sopenharmony_ci
43718c2ecf20Sopenharmony_ci	/* If LPM is enabled, attempt to disable it. */
43728c2ecf20Sopenharmony_ci	if (usb_disable_link_state(hcd, udev, USB3_LPM_U1))
43738c2ecf20Sopenharmony_ci		goto enable_lpm;
43748c2ecf20Sopenharmony_ci	if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
43758c2ecf20Sopenharmony_ci		goto enable_lpm;
43768c2ecf20Sopenharmony_ci
43778c2ecf20Sopenharmony_ci	return 0;
43788c2ecf20Sopenharmony_ci
43798c2ecf20Sopenharmony_cienable_lpm:
43808c2ecf20Sopenharmony_ci	usb_enable_lpm(udev);
43818c2ecf20Sopenharmony_ci	return -EBUSY;
43828c2ecf20Sopenharmony_ci}
43838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_disable_lpm);
43848c2ecf20Sopenharmony_ci
43858c2ecf20Sopenharmony_ci/* Grab the bandwidth_mutex before calling usb_disable_lpm() */
43868c2ecf20Sopenharmony_ciint usb_unlocked_disable_lpm(struct usb_device *udev)
43878c2ecf20Sopenharmony_ci{
43888c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
43898c2ecf20Sopenharmony_ci	int ret;
43908c2ecf20Sopenharmony_ci
43918c2ecf20Sopenharmony_ci	if (!hcd)
43928c2ecf20Sopenharmony_ci		return -EINVAL;
43938c2ecf20Sopenharmony_ci
43948c2ecf20Sopenharmony_ci	mutex_lock(hcd->bandwidth_mutex);
43958c2ecf20Sopenharmony_ci	ret = usb_disable_lpm(udev);
43968c2ecf20Sopenharmony_ci	mutex_unlock(hcd->bandwidth_mutex);
43978c2ecf20Sopenharmony_ci
43988c2ecf20Sopenharmony_ci	return ret;
43998c2ecf20Sopenharmony_ci}
44008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
44018c2ecf20Sopenharmony_ci
44028c2ecf20Sopenharmony_ci/*
44038c2ecf20Sopenharmony_ci * Attempt to enable device-initiated and hub-initiated U1 and U2 entry.  The
44048c2ecf20Sopenharmony_ci * xHCI host policy may prevent U1 or U2 from being enabled.
44058c2ecf20Sopenharmony_ci *
44068c2ecf20Sopenharmony_ci * Other callers may have disabled link PM, so U1 and U2 entry will be disabled
44078c2ecf20Sopenharmony_ci * until the lpm_disable_count drops to zero.  Caller must own the
44088c2ecf20Sopenharmony_ci * bandwidth_mutex.
44098c2ecf20Sopenharmony_ci */
44108c2ecf20Sopenharmony_civoid usb_enable_lpm(struct usb_device *udev)
44118c2ecf20Sopenharmony_ci{
44128c2ecf20Sopenharmony_ci	struct usb_hcd *hcd;
44138c2ecf20Sopenharmony_ci	struct usb_hub *hub;
44148c2ecf20Sopenharmony_ci	struct usb_port *port_dev;
44158c2ecf20Sopenharmony_ci
44168c2ecf20Sopenharmony_ci	if (!udev || !udev->parent ||
44178c2ecf20Sopenharmony_ci			udev->speed < USB_SPEED_SUPER ||
44188c2ecf20Sopenharmony_ci			!udev->lpm_capable ||
44198c2ecf20Sopenharmony_ci			udev->state < USB_STATE_CONFIGURED)
44208c2ecf20Sopenharmony_ci		return;
44218c2ecf20Sopenharmony_ci
44228c2ecf20Sopenharmony_ci	udev->lpm_disable_count--;
44238c2ecf20Sopenharmony_ci	hcd = bus_to_hcd(udev->bus);
44248c2ecf20Sopenharmony_ci	/* Double check that we can both enable and disable LPM.
44258c2ecf20Sopenharmony_ci	 * Device must be configured to accept set feature U1/U2 timeout.
44268c2ecf20Sopenharmony_ci	 */
44278c2ecf20Sopenharmony_ci	if (!hcd || !hcd->driver->enable_usb3_lpm_timeout ||
44288c2ecf20Sopenharmony_ci			!hcd->driver->disable_usb3_lpm_timeout)
44298c2ecf20Sopenharmony_ci		return;
44308c2ecf20Sopenharmony_ci
44318c2ecf20Sopenharmony_ci	if (udev->lpm_disable_count > 0)
44328c2ecf20Sopenharmony_ci		return;
44338c2ecf20Sopenharmony_ci
44348c2ecf20Sopenharmony_ci	hub = usb_hub_to_struct_hub(udev->parent);
44358c2ecf20Sopenharmony_ci	if (!hub)
44368c2ecf20Sopenharmony_ci		return;
44378c2ecf20Sopenharmony_ci
44388c2ecf20Sopenharmony_ci	port_dev = hub->ports[udev->portnum - 1];
44398c2ecf20Sopenharmony_ci
44408c2ecf20Sopenharmony_ci	if (port_dev->usb3_lpm_u1_permit)
44418c2ecf20Sopenharmony_ci		usb_enable_link_state(hcd, udev, USB3_LPM_U1);
44428c2ecf20Sopenharmony_ci
44438c2ecf20Sopenharmony_ci	if (port_dev->usb3_lpm_u2_permit)
44448c2ecf20Sopenharmony_ci		usb_enable_link_state(hcd, udev, USB3_LPM_U2);
44458c2ecf20Sopenharmony_ci}
44468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_enable_lpm);
44478c2ecf20Sopenharmony_ci
44488c2ecf20Sopenharmony_ci/* Grab the bandwidth_mutex before calling usb_enable_lpm() */
44498c2ecf20Sopenharmony_civoid usb_unlocked_enable_lpm(struct usb_device *udev)
44508c2ecf20Sopenharmony_ci{
44518c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
44528c2ecf20Sopenharmony_ci
44538c2ecf20Sopenharmony_ci	if (!hcd)
44548c2ecf20Sopenharmony_ci		return;
44558c2ecf20Sopenharmony_ci
44568c2ecf20Sopenharmony_ci	mutex_lock(hcd->bandwidth_mutex);
44578c2ecf20Sopenharmony_ci	usb_enable_lpm(udev);
44588c2ecf20Sopenharmony_ci	mutex_unlock(hcd->bandwidth_mutex);
44598c2ecf20Sopenharmony_ci}
44608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
44618c2ecf20Sopenharmony_ci
44628c2ecf20Sopenharmony_ci/* usb3 devices use U3 for disabled, make sure remote wakeup is disabled */
44638c2ecf20Sopenharmony_cistatic void hub_usb3_port_prepare_disable(struct usb_hub *hub,
44648c2ecf20Sopenharmony_ci					  struct usb_port *port_dev)
44658c2ecf20Sopenharmony_ci{
44668c2ecf20Sopenharmony_ci	struct usb_device *udev = port_dev->child;
44678c2ecf20Sopenharmony_ci	int ret;
44688c2ecf20Sopenharmony_ci
44698c2ecf20Sopenharmony_ci	if (udev && udev->port_is_suspended && udev->do_remote_wakeup) {
44708c2ecf20Sopenharmony_ci		ret = hub_set_port_link_state(hub, port_dev->portnum,
44718c2ecf20Sopenharmony_ci					      USB_SS_PORT_LS_U0);
44728c2ecf20Sopenharmony_ci		if (!ret) {
44738c2ecf20Sopenharmony_ci			msleep(USB_RESUME_TIMEOUT);
44748c2ecf20Sopenharmony_ci			ret = usb_disable_remote_wakeup(udev);
44758c2ecf20Sopenharmony_ci		}
44768c2ecf20Sopenharmony_ci		if (ret)
44778c2ecf20Sopenharmony_ci			dev_warn(&udev->dev,
44788c2ecf20Sopenharmony_ci				 "Port disable: can't disable remote wake\n");
44798c2ecf20Sopenharmony_ci		udev->do_remote_wakeup = 0;
44808c2ecf20Sopenharmony_ci	}
44818c2ecf20Sopenharmony_ci}
44828c2ecf20Sopenharmony_ci
44838c2ecf20Sopenharmony_ci#else	/* CONFIG_PM */
44848c2ecf20Sopenharmony_ci
44858c2ecf20Sopenharmony_ci#define hub_suspend		NULL
44868c2ecf20Sopenharmony_ci#define hub_resume		NULL
44878c2ecf20Sopenharmony_ci#define hub_reset_resume	NULL
44888c2ecf20Sopenharmony_ci
44898c2ecf20Sopenharmony_cistatic inline void hub_usb3_port_prepare_disable(struct usb_hub *hub,
44908c2ecf20Sopenharmony_ci						 struct usb_port *port_dev) { }
44918c2ecf20Sopenharmony_ci
44928c2ecf20Sopenharmony_ciint usb_disable_lpm(struct usb_device *udev)
44938c2ecf20Sopenharmony_ci{
44948c2ecf20Sopenharmony_ci	return 0;
44958c2ecf20Sopenharmony_ci}
44968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_disable_lpm);
44978c2ecf20Sopenharmony_ci
44988c2ecf20Sopenharmony_civoid usb_enable_lpm(struct usb_device *udev) { }
44998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_enable_lpm);
45008c2ecf20Sopenharmony_ci
45018c2ecf20Sopenharmony_ciint usb_unlocked_disable_lpm(struct usb_device *udev)
45028c2ecf20Sopenharmony_ci{
45038c2ecf20Sopenharmony_ci	return 0;
45048c2ecf20Sopenharmony_ci}
45058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
45068c2ecf20Sopenharmony_ci
45078c2ecf20Sopenharmony_civoid usb_unlocked_enable_lpm(struct usb_device *udev) { }
45088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
45098c2ecf20Sopenharmony_ci
45108c2ecf20Sopenharmony_ciint usb_disable_ltm(struct usb_device *udev)
45118c2ecf20Sopenharmony_ci{
45128c2ecf20Sopenharmony_ci	return 0;
45138c2ecf20Sopenharmony_ci}
45148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_disable_ltm);
45158c2ecf20Sopenharmony_ci
45168c2ecf20Sopenharmony_civoid usb_enable_ltm(struct usb_device *udev) { }
45178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_enable_ltm);
45188c2ecf20Sopenharmony_ci
45198c2ecf20Sopenharmony_cistatic int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
45208c2ecf20Sopenharmony_ci		u16 portstatus, u16 portchange)
45218c2ecf20Sopenharmony_ci{
45228c2ecf20Sopenharmony_ci	return 0;
45238c2ecf20Sopenharmony_ci}
45248c2ecf20Sopenharmony_ci
45258c2ecf20Sopenharmony_ci#endif	/* CONFIG_PM */
45268c2ecf20Sopenharmony_ci
45278c2ecf20Sopenharmony_ci/*
45288c2ecf20Sopenharmony_ci * USB-3 does not have a similar link state as USB-2 that will avoid negotiating
45298c2ecf20Sopenharmony_ci * a connection with a plugged-in cable but will signal the host when the cable
45308c2ecf20Sopenharmony_ci * is unplugged. Disable remote wake and set link state to U3 for USB-3 devices
45318c2ecf20Sopenharmony_ci */
45328c2ecf20Sopenharmony_cistatic int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
45338c2ecf20Sopenharmony_ci{
45348c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
45358c2ecf20Sopenharmony_ci	struct usb_device *hdev = hub->hdev;
45368c2ecf20Sopenharmony_ci	int ret = 0;
45378c2ecf20Sopenharmony_ci
45388c2ecf20Sopenharmony_ci	if (!hub->error) {
45398c2ecf20Sopenharmony_ci		if (hub_is_superspeed(hub->hdev)) {
45408c2ecf20Sopenharmony_ci			hub_usb3_port_prepare_disable(hub, port_dev);
45418c2ecf20Sopenharmony_ci			ret = hub_set_port_link_state(hub, port_dev->portnum,
45428c2ecf20Sopenharmony_ci						      USB_SS_PORT_LS_U3);
45438c2ecf20Sopenharmony_ci		} else {
45448c2ecf20Sopenharmony_ci			ret = usb_clear_port_feature(hdev, port1,
45458c2ecf20Sopenharmony_ci					USB_PORT_FEAT_ENABLE);
45468c2ecf20Sopenharmony_ci		}
45478c2ecf20Sopenharmony_ci	}
45488c2ecf20Sopenharmony_ci	if (port_dev->child && set_state)
45498c2ecf20Sopenharmony_ci		usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
45508c2ecf20Sopenharmony_ci	if (ret && ret != -ENODEV)
45518c2ecf20Sopenharmony_ci		dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);
45528c2ecf20Sopenharmony_ci	return ret;
45538c2ecf20Sopenharmony_ci}
45548c2ecf20Sopenharmony_ci
45558c2ecf20Sopenharmony_ci/*
45568c2ecf20Sopenharmony_ci * usb_port_disable - disable a usb device's upstream port
45578c2ecf20Sopenharmony_ci * @udev: device to disable
45588c2ecf20Sopenharmony_ci * Context: @udev locked, must be able to sleep.
45598c2ecf20Sopenharmony_ci *
45608c2ecf20Sopenharmony_ci * Disables a USB device that isn't in active use.
45618c2ecf20Sopenharmony_ci */
45628c2ecf20Sopenharmony_ciint usb_port_disable(struct usb_device *udev)
45638c2ecf20Sopenharmony_ci{
45648c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
45658c2ecf20Sopenharmony_ci
45668c2ecf20Sopenharmony_ci	return hub_port_disable(hub, udev->portnum, 0);
45678c2ecf20Sopenharmony_ci}
45688c2ecf20Sopenharmony_ci
45698c2ecf20Sopenharmony_ci/* USB 2.0 spec, 7.1.7.3 / fig 7-29:
45708c2ecf20Sopenharmony_ci *
45718c2ecf20Sopenharmony_ci * Between connect detection and reset signaling there must be a delay
45728c2ecf20Sopenharmony_ci * of 100ms at least for debounce and power-settling.  The corresponding
45738c2ecf20Sopenharmony_ci * timer shall restart whenever the downstream port detects a disconnect.
45748c2ecf20Sopenharmony_ci *
45758c2ecf20Sopenharmony_ci * Apparently there are some bluetooth and irda-dongles and a number of
45768c2ecf20Sopenharmony_ci * low-speed devices for which this debounce period may last over a second.
45778c2ecf20Sopenharmony_ci * Not covered by the spec - but easy to deal with.
45788c2ecf20Sopenharmony_ci *
45798c2ecf20Sopenharmony_ci * This implementation uses a 1500ms total debounce timeout; if the
45808c2ecf20Sopenharmony_ci * connection isn't stable by then it returns -ETIMEDOUT.  It checks
45818c2ecf20Sopenharmony_ci * every 25ms for transient disconnects.  When the port status has been
45828c2ecf20Sopenharmony_ci * unchanged for 100ms it returns the port status.
45838c2ecf20Sopenharmony_ci */
45848c2ecf20Sopenharmony_ciint hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)
45858c2ecf20Sopenharmony_ci{
45868c2ecf20Sopenharmony_ci	int ret;
45878c2ecf20Sopenharmony_ci	u16 portchange, portstatus;
45888c2ecf20Sopenharmony_ci	unsigned connection = 0xffff;
45898c2ecf20Sopenharmony_ci	int total_time, stable_time = 0;
45908c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
45918c2ecf20Sopenharmony_ci
45928c2ecf20Sopenharmony_ci	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
45938c2ecf20Sopenharmony_ci		ret = hub_port_status(hub, port1, &portstatus, &portchange);
45948c2ecf20Sopenharmony_ci		if (ret < 0)
45958c2ecf20Sopenharmony_ci			return ret;
45968c2ecf20Sopenharmony_ci
45978c2ecf20Sopenharmony_ci		if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&
45988c2ecf20Sopenharmony_ci		     (portstatus & USB_PORT_STAT_CONNECTION) == connection) {
45998c2ecf20Sopenharmony_ci			if (!must_be_connected ||
46008c2ecf20Sopenharmony_ci			     (connection == USB_PORT_STAT_CONNECTION))
46018c2ecf20Sopenharmony_ci				stable_time += HUB_DEBOUNCE_STEP;
46028c2ecf20Sopenharmony_ci			if (stable_time >= HUB_DEBOUNCE_STABLE)
46038c2ecf20Sopenharmony_ci				break;
46048c2ecf20Sopenharmony_ci		} else {
46058c2ecf20Sopenharmony_ci			stable_time = 0;
46068c2ecf20Sopenharmony_ci			connection = portstatus & USB_PORT_STAT_CONNECTION;
46078c2ecf20Sopenharmony_ci		}
46088c2ecf20Sopenharmony_ci
46098c2ecf20Sopenharmony_ci		if (portchange & USB_PORT_STAT_C_CONNECTION) {
46108c2ecf20Sopenharmony_ci			usb_clear_port_feature(hub->hdev, port1,
46118c2ecf20Sopenharmony_ci					USB_PORT_FEAT_C_CONNECTION);
46128c2ecf20Sopenharmony_ci		}
46138c2ecf20Sopenharmony_ci
46148c2ecf20Sopenharmony_ci		if (total_time >= HUB_DEBOUNCE_TIMEOUT)
46158c2ecf20Sopenharmony_ci			break;
46168c2ecf20Sopenharmony_ci		msleep(HUB_DEBOUNCE_STEP);
46178c2ecf20Sopenharmony_ci	}
46188c2ecf20Sopenharmony_ci
46198c2ecf20Sopenharmony_ci	dev_dbg(&port_dev->dev, "debounce total %dms stable %dms status 0x%x\n",
46208c2ecf20Sopenharmony_ci			total_time, stable_time, portstatus);
46218c2ecf20Sopenharmony_ci
46228c2ecf20Sopenharmony_ci	if (stable_time < HUB_DEBOUNCE_STABLE)
46238c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
46248c2ecf20Sopenharmony_ci	return portstatus;
46258c2ecf20Sopenharmony_ci}
46268c2ecf20Sopenharmony_ci
46278c2ecf20Sopenharmony_civoid usb_ep0_reinit(struct usb_device *udev)
46288c2ecf20Sopenharmony_ci{
46298c2ecf20Sopenharmony_ci	usb_disable_endpoint(udev, 0 + USB_DIR_IN, true);
46308c2ecf20Sopenharmony_ci	usb_disable_endpoint(udev, 0 + USB_DIR_OUT, true);
46318c2ecf20Sopenharmony_ci	usb_enable_endpoint(udev, &udev->ep0, true);
46328c2ecf20Sopenharmony_ci}
46338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_ep0_reinit);
46348c2ecf20Sopenharmony_ci
46358c2ecf20Sopenharmony_ci#define usb_sndaddr0pipe()	(PIPE_CONTROL << 30)
46368c2ecf20Sopenharmony_ci#define usb_rcvaddr0pipe()	((PIPE_CONTROL << 30) | USB_DIR_IN)
46378c2ecf20Sopenharmony_ci
46388c2ecf20Sopenharmony_cistatic int hub_set_address(struct usb_device *udev, int devnum)
46398c2ecf20Sopenharmony_ci{
46408c2ecf20Sopenharmony_ci	int retval;
46418c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
46428c2ecf20Sopenharmony_ci
46438c2ecf20Sopenharmony_ci	/*
46448c2ecf20Sopenharmony_ci	 * The host controller will choose the device address,
46458c2ecf20Sopenharmony_ci	 * instead of the core having chosen it earlier
46468c2ecf20Sopenharmony_ci	 */
46478c2ecf20Sopenharmony_ci	if (!hcd->driver->address_device && devnum <= 1)
46488c2ecf20Sopenharmony_ci		return -EINVAL;
46498c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_ADDRESS)
46508c2ecf20Sopenharmony_ci		return 0;
46518c2ecf20Sopenharmony_ci	if (udev->state != USB_STATE_DEFAULT)
46528c2ecf20Sopenharmony_ci		return -EINVAL;
46538c2ecf20Sopenharmony_ci	if (hcd->driver->address_device)
46548c2ecf20Sopenharmony_ci		retval = hcd->driver->address_device(hcd, udev);
46558c2ecf20Sopenharmony_ci	else
46568c2ecf20Sopenharmony_ci		retval = usb_control_msg(udev, usb_sndaddr0pipe(),
46578c2ecf20Sopenharmony_ci				USB_REQ_SET_ADDRESS, 0, devnum, 0,
46588c2ecf20Sopenharmony_ci				NULL, 0, USB_CTRL_SET_TIMEOUT);
46598c2ecf20Sopenharmony_ci	if (retval == 0) {
46608c2ecf20Sopenharmony_ci		update_devnum(udev, devnum);
46618c2ecf20Sopenharmony_ci		/* Device now using proper address. */
46628c2ecf20Sopenharmony_ci		usb_set_device_state(udev, USB_STATE_ADDRESS);
46638c2ecf20Sopenharmony_ci		usb_ep0_reinit(udev);
46648c2ecf20Sopenharmony_ci	}
46658c2ecf20Sopenharmony_ci	return retval;
46668c2ecf20Sopenharmony_ci}
46678c2ecf20Sopenharmony_ci
46688c2ecf20Sopenharmony_ci/*
46698c2ecf20Sopenharmony_ci * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM
46708c2ecf20Sopenharmony_ci * when they're plugged into a USB 2.0 port, but they don't work when LPM is
46718c2ecf20Sopenharmony_ci * enabled.
46728c2ecf20Sopenharmony_ci *
46738c2ecf20Sopenharmony_ci * Only enable USB 2.0 Link PM if the port is internal (hardwired), or the
46748c2ecf20Sopenharmony_ci * device says it supports the new USB 2.0 Link PM errata by setting the BESL
46758c2ecf20Sopenharmony_ci * support bit in the BOS descriptor.
46768c2ecf20Sopenharmony_ci */
46778c2ecf20Sopenharmony_cistatic void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
46788c2ecf20Sopenharmony_ci{
46798c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
46808c2ecf20Sopenharmony_ci	int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
46818c2ecf20Sopenharmony_ci
46828c2ecf20Sopenharmony_ci	if (!udev->usb2_hw_lpm_capable || !udev->bos)
46838c2ecf20Sopenharmony_ci		return;
46848c2ecf20Sopenharmony_ci
46858c2ecf20Sopenharmony_ci	if (hub)
46868c2ecf20Sopenharmony_ci		connect_type = hub->ports[udev->portnum - 1]->connect_type;
46878c2ecf20Sopenharmony_ci
46888c2ecf20Sopenharmony_ci	if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) ||
46898c2ecf20Sopenharmony_ci			connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
46908c2ecf20Sopenharmony_ci		udev->usb2_hw_lpm_allowed = 1;
46918c2ecf20Sopenharmony_ci		usb_enable_usb2_hardware_lpm(udev);
46928c2ecf20Sopenharmony_ci	}
46938c2ecf20Sopenharmony_ci}
46948c2ecf20Sopenharmony_ci
46958c2ecf20Sopenharmony_cistatic int hub_enable_device(struct usb_device *udev)
46968c2ecf20Sopenharmony_ci{
46978c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
46988c2ecf20Sopenharmony_ci
46998c2ecf20Sopenharmony_ci	if (!hcd->driver->enable_device)
47008c2ecf20Sopenharmony_ci		return 0;
47018c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_ADDRESS)
47028c2ecf20Sopenharmony_ci		return 0;
47038c2ecf20Sopenharmony_ci	if (udev->state != USB_STATE_DEFAULT)
47048c2ecf20Sopenharmony_ci		return -EINVAL;
47058c2ecf20Sopenharmony_ci
47068c2ecf20Sopenharmony_ci	return hcd->driver->enable_device(hcd, udev);
47078c2ecf20Sopenharmony_ci}
47088c2ecf20Sopenharmony_ci
47098c2ecf20Sopenharmony_ci/*
47108c2ecf20Sopenharmony_ci * Get the bMaxPacketSize0 value during initialization by reading the
47118c2ecf20Sopenharmony_ci * device's device descriptor.  Since we don't already know this value,
47128c2ecf20Sopenharmony_ci * the transfer is unsafe and it ignores I/O errors, only testing for
47138c2ecf20Sopenharmony_ci * reasonable received values.
47148c2ecf20Sopenharmony_ci *
47158c2ecf20Sopenharmony_ci * For "old scheme" initialization, size will be 8 so we read just the
47168c2ecf20Sopenharmony_ci * start of the device descriptor, which should work okay regardless of
47178c2ecf20Sopenharmony_ci * the actual bMaxPacketSize0 value.  For "new scheme" initialization,
47188c2ecf20Sopenharmony_ci * size will be 64 (and buf will point to a sufficiently large buffer),
47198c2ecf20Sopenharmony_ci * which might not be kosher according to the USB spec but it's what
47208c2ecf20Sopenharmony_ci * Windows does and what many devices expect.
47218c2ecf20Sopenharmony_ci *
47228c2ecf20Sopenharmony_ci * Returns: bMaxPacketSize0 or a negative error code.
47238c2ecf20Sopenharmony_ci */
47248c2ecf20Sopenharmony_cistatic int get_bMaxPacketSize0(struct usb_device *udev,
47258c2ecf20Sopenharmony_ci		struct usb_device_descriptor *buf, int size, bool first_time)
47268c2ecf20Sopenharmony_ci{
47278c2ecf20Sopenharmony_ci	int i, rc;
47288c2ecf20Sopenharmony_ci
47298c2ecf20Sopenharmony_ci	/*
47308c2ecf20Sopenharmony_ci	 * Retry on all errors; some devices are flakey.
47318c2ecf20Sopenharmony_ci	 * 255 is for WUSB devices, we actually need to use
47328c2ecf20Sopenharmony_ci	 * 512 (WUSB1.0[4.8.1]).
47338c2ecf20Sopenharmony_ci	 */
47348c2ecf20Sopenharmony_ci	for (i = 0; i < GET_MAXPACKET0_TRIES; ++i) {
47358c2ecf20Sopenharmony_ci		/* Start with invalid values in case the transfer fails */
47368c2ecf20Sopenharmony_ci		buf->bDescriptorType = buf->bMaxPacketSize0 = 0;
47378c2ecf20Sopenharmony_ci		rc = usb_control_msg(udev, usb_rcvaddr0pipe(),
47388c2ecf20Sopenharmony_ci				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
47398c2ecf20Sopenharmony_ci				USB_DT_DEVICE << 8, 0,
47408c2ecf20Sopenharmony_ci				buf, size,
47418c2ecf20Sopenharmony_ci				initial_descriptor_timeout);
47428c2ecf20Sopenharmony_ci		switch (buf->bMaxPacketSize0) {
47438c2ecf20Sopenharmony_ci		case 8: case 16: case 32: case 64: case 9:
47448c2ecf20Sopenharmony_ci			if (buf->bDescriptorType == USB_DT_DEVICE) {
47458c2ecf20Sopenharmony_ci				rc = buf->bMaxPacketSize0;
47468c2ecf20Sopenharmony_ci				break;
47478c2ecf20Sopenharmony_ci			}
47488c2ecf20Sopenharmony_ci			fallthrough;
47498c2ecf20Sopenharmony_ci		default:
47508c2ecf20Sopenharmony_ci			if (rc >= 0)
47518c2ecf20Sopenharmony_ci				rc = -EPROTO;
47528c2ecf20Sopenharmony_ci			break;
47538c2ecf20Sopenharmony_ci		}
47548c2ecf20Sopenharmony_ci
47558c2ecf20Sopenharmony_ci		/*
47568c2ecf20Sopenharmony_ci		 * Some devices time out if they are powered on
47578c2ecf20Sopenharmony_ci		 * when already connected. They need a second
47588c2ecf20Sopenharmony_ci		 * reset, so return early. But only on the first
47598c2ecf20Sopenharmony_ci		 * attempt, lest we get into a time-out/reset loop.
47608c2ecf20Sopenharmony_ci		 */
47618c2ecf20Sopenharmony_ci		if (rc > 0 || (rc == -ETIMEDOUT && first_time &&
47628c2ecf20Sopenharmony_ci				udev->speed > USB_SPEED_FULL))
47638c2ecf20Sopenharmony_ci			break;
47648c2ecf20Sopenharmony_ci	}
47658c2ecf20Sopenharmony_ci	return rc;
47668c2ecf20Sopenharmony_ci}
47678c2ecf20Sopenharmony_ci
47688c2ecf20Sopenharmony_ci#define GET_DESCRIPTOR_BUFSIZE	64
47698c2ecf20Sopenharmony_ci
47708c2ecf20Sopenharmony_ci/* Reset device, (re)assign address, get device descriptor.
47718c2ecf20Sopenharmony_ci * Device connection must be stable, no more debouncing needed.
47728c2ecf20Sopenharmony_ci * Returns device in USB_STATE_ADDRESS, except on error.
47738c2ecf20Sopenharmony_ci *
47748c2ecf20Sopenharmony_ci * If this is called for an already-existing device (as part of
47758c2ecf20Sopenharmony_ci * usb_reset_and_verify_device), the caller must own the device lock and
47768c2ecf20Sopenharmony_ci * the port lock.  For a newly detected device that is not accessible
47778c2ecf20Sopenharmony_ci * through any global pointers, it's not necessary to lock the device,
47788c2ecf20Sopenharmony_ci * but it is still necessary to lock the port.
47798c2ecf20Sopenharmony_ci *
47808c2ecf20Sopenharmony_ci * For a newly detected device, @dev_descr must be NULL.  The device
47818c2ecf20Sopenharmony_ci * descriptor retrieved from the device will then be stored in
47828c2ecf20Sopenharmony_ci * @udev->descriptor.  For an already existing device, @dev_descr
47838c2ecf20Sopenharmony_ci * must be non-NULL.  The device descriptor will be stored there,
47848c2ecf20Sopenharmony_ci * not in @udev->descriptor, because descriptors for registered
47858c2ecf20Sopenharmony_ci * devices are meant to be immutable.
47868c2ecf20Sopenharmony_ci */
47878c2ecf20Sopenharmony_cistatic int
47888c2ecf20Sopenharmony_cihub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
47898c2ecf20Sopenharmony_ci		int retry_counter, struct usb_device_descriptor *dev_descr)
47908c2ecf20Sopenharmony_ci{
47918c2ecf20Sopenharmony_ci	struct usb_device	*hdev = hub->hdev;
47928c2ecf20Sopenharmony_ci	struct usb_hcd		*hcd = bus_to_hcd(hdev->bus);
47938c2ecf20Sopenharmony_ci	struct usb_port		*port_dev = hub->ports[port1 - 1];
47948c2ecf20Sopenharmony_ci	int			retries, operations, retval, i;
47958c2ecf20Sopenharmony_ci	unsigned		delay = HUB_SHORT_RESET_TIME;
47968c2ecf20Sopenharmony_ci	enum usb_device_speed	oldspeed = udev->speed;
47978c2ecf20Sopenharmony_ci	const char		*speed;
47988c2ecf20Sopenharmony_ci	int			devnum = udev->devnum;
47998c2ecf20Sopenharmony_ci	const char		*driver_name;
48008c2ecf20Sopenharmony_ci	bool			do_new_scheme;
48018c2ecf20Sopenharmony_ci	const bool		initial = !dev_descr;
48028c2ecf20Sopenharmony_ci	int			maxp0;
48038c2ecf20Sopenharmony_ci	struct usb_device_descriptor	*buf, *descr;
48048c2ecf20Sopenharmony_ci
48058c2ecf20Sopenharmony_ci	buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
48068c2ecf20Sopenharmony_ci	if (!buf)
48078c2ecf20Sopenharmony_ci		return -ENOMEM;
48088c2ecf20Sopenharmony_ci
48098c2ecf20Sopenharmony_ci	/* root hub ports have a slightly longer reset period
48108c2ecf20Sopenharmony_ci	 * (from USB 2.0 spec, section 7.1.7.5)
48118c2ecf20Sopenharmony_ci	 */
48128c2ecf20Sopenharmony_ci	if (!hdev->parent) {
48138c2ecf20Sopenharmony_ci		delay = HUB_ROOT_RESET_TIME;
48148c2ecf20Sopenharmony_ci		if (port1 == hdev->bus->otg_port)
48158c2ecf20Sopenharmony_ci			hdev->bus->b_hnp_enable = 0;
48168c2ecf20Sopenharmony_ci	}
48178c2ecf20Sopenharmony_ci
48188c2ecf20Sopenharmony_ci	/* Some low speed devices have problems with the quick delay, so */
48198c2ecf20Sopenharmony_ci	/*  be a bit pessimistic with those devices. RHbug #23670 */
48208c2ecf20Sopenharmony_ci	if (oldspeed == USB_SPEED_LOW)
48218c2ecf20Sopenharmony_ci		delay = HUB_LONG_RESET_TIME;
48228c2ecf20Sopenharmony_ci
48238c2ecf20Sopenharmony_ci	/* Reset the device; full speed may morph to high speed */
48248c2ecf20Sopenharmony_ci	/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
48258c2ecf20Sopenharmony_ci	retval = hub_port_reset(hub, port1, udev, delay, false);
48268c2ecf20Sopenharmony_ci	if (retval < 0)		/* error or disconnect */
48278c2ecf20Sopenharmony_ci		goto fail;
48288c2ecf20Sopenharmony_ci	/* success, speed is known */
48298c2ecf20Sopenharmony_ci
48308c2ecf20Sopenharmony_ci	retval = -ENODEV;
48318c2ecf20Sopenharmony_ci
48328c2ecf20Sopenharmony_ci	/* Don't allow speed changes at reset, except usb 3.0 to faster */
48338c2ecf20Sopenharmony_ci	if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
48348c2ecf20Sopenharmony_ci	    !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
48358c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "device reset changed speed!\n");
48368c2ecf20Sopenharmony_ci		goto fail;
48378c2ecf20Sopenharmony_ci	}
48388c2ecf20Sopenharmony_ci	oldspeed = udev->speed;
48398c2ecf20Sopenharmony_ci
48408c2ecf20Sopenharmony_ci	if (initial) {
48418c2ecf20Sopenharmony_ci		/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
48428c2ecf20Sopenharmony_ci		 * it's fixed size except for full speed devices.
48438c2ecf20Sopenharmony_ci		 * For Wireless USB devices, ep0 max packet is always 512 (tho
48448c2ecf20Sopenharmony_ci		 * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
48458c2ecf20Sopenharmony_ci		 */
48468c2ecf20Sopenharmony_ci		switch (udev->speed) {
48478c2ecf20Sopenharmony_ci		case USB_SPEED_SUPER_PLUS:
48488c2ecf20Sopenharmony_ci		case USB_SPEED_SUPER:
48498c2ecf20Sopenharmony_ci		case USB_SPEED_WIRELESS:	/* fixed at 512 */
48508c2ecf20Sopenharmony_ci			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
48518c2ecf20Sopenharmony_ci			break;
48528c2ecf20Sopenharmony_ci		case USB_SPEED_HIGH:		/* fixed at 64 */
48538c2ecf20Sopenharmony_ci			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
48548c2ecf20Sopenharmony_ci			break;
48558c2ecf20Sopenharmony_ci		case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
48568c2ecf20Sopenharmony_ci			/* to determine the ep0 maxpacket size, try to read
48578c2ecf20Sopenharmony_ci			 * the device descriptor to get bMaxPacketSize0 and
48588c2ecf20Sopenharmony_ci			 * then correct our initial guess.
48598c2ecf20Sopenharmony_ci			 */
48608c2ecf20Sopenharmony_ci			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
48618c2ecf20Sopenharmony_ci			break;
48628c2ecf20Sopenharmony_ci		case USB_SPEED_LOW:		/* fixed at 8 */
48638c2ecf20Sopenharmony_ci			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
48648c2ecf20Sopenharmony_ci			break;
48658c2ecf20Sopenharmony_ci		default:
48668c2ecf20Sopenharmony_ci			goto fail;
48678c2ecf20Sopenharmony_ci		}
48688c2ecf20Sopenharmony_ci	}
48698c2ecf20Sopenharmony_ci
48708c2ecf20Sopenharmony_ci	if (udev->speed == USB_SPEED_WIRELESS)
48718c2ecf20Sopenharmony_ci		speed = "variable speed Wireless";
48728c2ecf20Sopenharmony_ci	else
48738c2ecf20Sopenharmony_ci		speed = usb_speed_string(udev->speed);
48748c2ecf20Sopenharmony_ci
48758c2ecf20Sopenharmony_ci	/*
48768c2ecf20Sopenharmony_ci	 * The controller driver may be NULL if the controller device
48778c2ecf20Sopenharmony_ci	 * is the middle device between platform device and roothub.
48788c2ecf20Sopenharmony_ci	 * This middle device may not need a device driver due to
48798c2ecf20Sopenharmony_ci	 * all hardware control can be at platform device driver, this
48808c2ecf20Sopenharmony_ci	 * platform device is usually a dual-role USB controller device.
48818c2ecf20Sopenharmony_ci	 */
48828c2ecf20Sopenharmony_ci	if (udev->bus->controller->driver)
48838c2ecf20Sopenharmony_ci		driver_name = udev->bus->controller->driver->name;
48848c2ecf20Sopenharmony_ci	else
48858c2ecf20Sopenharmony_ci		driver_name = udev->bus->sysdev->driver->name;
48868c2ecf20Sopenharmony_ci
48878c2ecf20Sopenharmony_ci	if (udev->speed < USB_SPEED_SUPER)
48888c2ecf20Sopenharmony_ci		dev_info(&udev->dev,
48898c2ecf20Sopenharmony_ci				"%s %s USB device number %d using %s\n",
48908c2ecf20Sopenharmony_ci				(initial ? "new" : "reset"), speed,
48918c2ecf20Sopenharmony_ci				devnum, driver_name);
48928c2ecf20Sopenharmony_ci
48938c2ecf20Sopenharmony_ci	if (initial) {
48948c2ecf20Sopenharmony_ci		/* Set up TT records, if needed  */
48958c2ecf20Sopenharmony_ci		if (hdev->tt) {
48968c2ecf20Sopenharmony_ci			udev->tt = hdev->tt;
48978c2ecf20Sopenharmony_ci			udev->ttport = hdev->ttport;
48988c2ecf20Sopenharmony_ci		} else if (udev->speed != USB_SPEED_HIGH
48998c2ecf20Sopenharmony_ci				&& hdev->speed == USB_SPEED_HIGH) {
49008c2ecf20Sopenharmony_ci			if (!hub->tt.hub) {
49018c2ecf20Sopenharmony_ci				dev_err(&udev->dev, "parent hub has no TT\n");
49028c2ecf20Sopenharmony_ci				retval = -EINVAL;
49038c2ecf20Sopenharmony_ci				goto fail;
49048c2ecf20Sopenharmony_ci			}
49058c2ecf20Sopenharmony_ci			udev->tt = &hub->tt;
49068c2ecf20Sopenharmony_ci			udev->ttport = port1;
49078c2ecf20Sopenharmony_ci		}
49088c2ecf20Sopenharmony_ci	}
49098c2ecf20Sopenharmony_ci
49108c2ecf20Sopenharmony_ci	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
49118c2ecf20Sopenharmony_ci	 * Because device hardware and firmware is sometimes buggy in
49128c2ecf20Sopenharmony_ci	 * this area, and this is how Linux has done it for ages.
49138c2ecf20Sopenharmony_ci	 * Change it cautiously.
49148c2ecf20Sopenharmony_ci	 *
49158c2ecf20Sopenharmony_ci	 * NOTE:  If use_new_scheme() is true we will start by issuing
49168c2ecf20Sopenharmony_ci	 * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,
49178c2ecf20Sopenharmony_ci	 * so it may help with some non-standards-compliant devices.
49188c2ecf20Sopenharmony_ci	 * Otherwise we start with SET_ADDRESS and then try to read the
49198c2ecf20Sopenharmony_ci	 * first 8 bytes of the device descriptor to get the ep0 maxpacket
49208c2ecf20Sopenharmony_ci	 * value.
49218c2ecf20Sopenharmony_ci	 */
49228c2ecf20Sopenharmony_ci	do_new_scheme = use_new_scheme(udev, retry_counter, port_dev);
49238c2ecf20Sopenharmony_ci
49248c2ecf20Sopenharmony_ci	for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
49258c2ecf20Sopenharmony_ci		if (do_new_scheme) {
49268c2ecf20Sopenharmony_ci			retval = hub_enable_device(udev);
49278c2ecf20Sopenharmony_ci			if (retval < 0) {
49288c2ecf20Sopenharmony_ci				dev_err(&udev->dev,
49298c2ecf20Sopenharmony_ci					"hub failed to enable device, error %d\n",
49308c2ecf20Sopenharmony_ci					retval);
49318c2ecf20Sopenharmony_ci				goto fail;
49328c2ecf20Sopenharmony_ci			}
49338c2ecf20Sopenharmony_ci
49348c2ecf20Sopenharmony_ci			maxp0 = get_bMaxPacketSize0(udev, buf,
49358c2ecf20Sopenharmony_ci					GET_DESCRIPTOR_BUFSIZE, retries == 0);
49368c2ecf20Sopenharmony_ci			if (maxp0 > 0 && !initial &&
49378c2ecf20Sopenharmony_ci					maxp0 != udev->descriptor.bMaxPacketSize0) {
49388c2ecf20Sopenharmony_ci				dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n");
49398c2ecf20Sopenharmony_ci				retval = -ENODEV;
49408c2ecf20Sopenharmony_ci				goto fail;
49418c2ecf20Sopenharmony_ci			}
49428c2ecf20Sopenharmony_ci
49438c2ecf20Sopenharmony_ci			retval = hub_port_reset(hub, port1, udev, delay, false);
49448c2ecf20Sopenharmony_ci			if (retval < 0)		/* error or disconnect */
49458c2ecf20Sopenharmony_ci				goto fail;
49468c2ecf20Sopenharmony_ci			if (oldspeed != udev->speed) {
49478c2ecf20Sopenharmony_ci				dev_dbg(&udev->dev,
49488c2ecf20Sopenharmony_ci					"device reset changed speed!\n");
49498c2ecf20Sopenharmony_ci				retval = -ENODEV;
49508c2ecf20Sopenharmony_ci				goto fail;
49518c2ecf20Sopenharmony_ci			}
49528c2ecf20Sopenharmony_ci			if (maxp0 < 0) {
49538c2ecf20Sopenharmony_ci				if (maxp0 != -ENODEV)
49548c2ecf20Sopenharmony_ci					dev_err(&udev->dev, "device descriptor read/64, error %d\n",
49558c2ecf20Sopenharmony_ci							maxp0);
49568c2ecf20Sopenharmony_ci				retval = maxp0;
49578c2ecf20Sopenharmony_ci				continue;
49588c2ecf20Sopenharmony_ci			}
49598c2ecf20Sopenharmony_ci		}
49608c2ecf20Sopenharmony_ci
49618c2ecf20Sopenharmony_ci		/*
49628c2ecf20Sopenharmony_ci		 * If device is WUSB, we already assigned an
49638c2ecf20Sopenharmony_ci		 * unauthorized address in the Connect Ack sequence;
49648c2ecf20Sopenharmony_ci		 * authorization will assign the final address.
49658c2ecf20Sopenharmony_ci		 */
49668c2ecf20Sopenharmony_ci		if (udev->wusb == 0) {
49678c2ecf20Sopenharmony_ci			for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
49688c2ecf20Sopenharmony_ci				retval = hub_set_address(udev, devnum);
49698c2ecf20Sopenharmony_ci				if (retval >= 0)
49708c2ecf20Sopenharmony_ci					break;
49718c2ecf20Sopenharmony_ci				msleep(200);
49728c2ecf20Sopenharmony_ci			}
49738c2ecf20Sopenharmony_ci			if (retval < 0) {
49748c2ecf20Sopenharmony_ci				if (retval != -ENODEV)
49758c2ecf20Sopenharmony_ci					dev_err(&udev->dev, "device not accepting address %d, error %d\n",
49768c2ecf20Sopenharmony_ci							devnum, retval);
49778c2ecf20Sopenharmony_ci				goto fail;
49788c2ecf20Sopenharmony_ci			}
49798c2ecf20Sopenharmony_ci			if (udev->speed >= USB_SPEED_SUPER) {
49808c2ecf20Sopenharmony_ci				devnum = udev->devnum;
49818c2ecf20Sopenharmony_ci				dev_info(&udev->dev,
49828c2ecf20Sopenharmony_ci						"%s SuperSpeed%s%s USB device number %d using %s\n",
49838c2ecf20Sopenharmony_ci						(udev->config) ? "reset" : "new",
49848c2ecf20Sopenharmony_ci					 (udev->speed == USB_SPEED_SUPER_PLUS) ?
49858c2ecf20Sopenharmony_ci							"Plus Gen 2" : " Gen 1",
49868c2ecf20Sopenharmony_ci					 (udev->rx_lanes == 2 && udev->tx_lanes == 2) ?
49878c2ecf20Sopenharmony_ci							"x2" : "",
49888c2ecf20Sopenharmony_ci					 devnum, driver_name);
49898c2ecf20Sopenharmony_ci			}
49908c2ecf20Sopenharmony_ci
49918c2ecf20Sopenharmony_ci			/* cope with hardware quirkiness:
49928c2ecf20Sopenharmony_ci			 *  - let SET_ADDRESS settle, some device hardware wants it
49938c2ecf20Sopenharmony_ci			 *  - read ep0 maxpacket even for high and low speed,
49948c2ecf20Sopenharmony_ci			 */
49958c2ecf20Sopenharmony_ci			msleep(10);
49968c2ecf20Sopenharmony_ci			if (do_new_scheme)
49978c2ecf20Sopenharmony_ci				break;
49988c2ecf20Sopenharmony_ci		}
49998c2ecf20Sopenharmony_ci
50008c2ecf20Sopenharmony_ci		/* !do_new_scheme || wusb */
50018c2ecf20Sopenharmony_ci		maxp0 = get_bMaxPacketSize0(udev, buf, 8, retries == 0);
50028c2ecf20Sopenharmony_ci		if (maxp0 < 0) {
50038c2ecf20Sopenharmony_ci			retval = maxp0;
50048c2ecf20Sopenharmony_ci			if (retval != -ENODEV)
50058c2ecf20Sopenharmony_ci				dev_err(&udev->dev,
50068c2ecf20Sopenharmony_ci					"device descriptor read/8, error %d\n",
50078c2ecf20Sopenharmony_ci					retval);
50088c2ecf20Sopenharmony_ci		} else {
50098c2ecf20Sopenharmony_ci			u32 delay;
50108c2ecf20Sopenharmony_ci
50118c2ecf20Sopenharmony_ci			if (!initial && maxp0 != udev->descriptor.bMaxPacketSize0) {
50128c2ecf20Sopenharmony_ci				dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n");
50138c2ecf20Sopenharmony_ci				retval = -ENODEV;
50148c2ecf20Sopenharmony_ci				goto fail;
50158c2ecf20Sopenharmony_ci			}
50168c2ecf20Sopenharmony_ci
50178c2ecf20Sopenharmony_ci			delay = udev->parent->hub_delay;
50188c2ecf20Sopenharmony_ci			udev->hub_delay = min_t(u32, delay,
50198c2ecf20Sopenharmony_ci						USB_TP_TRANSMISSION_DELAY_MAX);
50208c2ecf20Sopenharmony_ci			retval = usb_set_isoch_delay(udev);
50218c2ecf20Sopenharmony_ci			if (retval) {
50228c2ecf20Sopenharmony_ci				dev_dbg(&udev->dev,
50238c2ecf20Sopenharmony_ci					"Failed set isoch delay, error %d\n",
50248c2ecf20Sopenharmony_ci					retval);
50258c2ecf20Sopenharmony_ci				retval = 0;
50268c2ecf20Sopenharmony_ci			}
50278c2ecf20Sopenharmony_ci			break;
50288c2ecf20Sopenharmony_ci		}
50298c2ecf20Sopenharmony_ci	}
50308c2ecf20Sopenharmony_ci	if (retval)
50318c2ecf20Sopenharmony_ci		goto fail;
50328c2ecf20Sopenharmony_ci
50338c2ecf20Sopenharmony_ci	/*
50348c2ecf20Sopenharmony_ci	 * Check the ep0 maxpacket guess and correct it if necessary.
50358c2ecf20Sopenharmony_ci	 * maxp0 is the value stored in the device descriptor;
50368c2ecf20Sopenharmony_ci	 * i is the value it encodes (logarithmic for SuperSpeed or greater).
50378c2ecf20Sopenharmony_ci	 */
50388c2ecf20Sopenharmony_ci	i = maxp0;
50398c2ecf20Sopenharmony_ci	if (udev->speed >= USB_SPEED_SUPER) {
50408c2ecf20Sopenharmony_ci		if (maxp0 <= 16)
50418c2ecf20Sopenharmony_ci			i = 1 << maxp0;
50428c2ecf20Sopenharmony_ci		else
50438c2ecf20Sopenharmony_ci			i = 0;		/* Invalid */
50448c2ecf20Sopenharmony_ci	}
50458c2ecf20Sopenharmony_ci	if (usb_endpoint_maxp(&udev->ep0.desc) == i) {
50468c2ecf20Sopenharmony_ci		;	/* Initial ep0 maxpacket guess is right */
50478c2ecf20Sopenharmony_ci	} else if ((udev->speed == USB_SPEED_FULL ||
50488c2ecf20Sopenharmony_ci				udev->speed == USB_SPEED_HIGH) &&
50498c2ecf20Sopenharmony_ci			(i == 8 || i == 16 || i == 32 || i == 64)) {
50508c2ecf20Sopenharmony_ci		/* Initial guess is wrong; use the descriptor's value */
50518c2ecf20Sopenharmony_ci		if (udev->speed == USB_SPEED_FULL)
50528c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
50538c2ecf20Sopenharmony_ci		else
50548c2ecf20Sopenharmony_ci			dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
50558c2ecf20Sopenharmony_ci		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
50568c2ecf20Sopenharmony_ci		usb_ep0_reinit(udev);
50578c2ecf20Sopenharmony_ci	} else {
50588c2ecf20Sopenharmony_ci		/* Initial guess is wrong and descriptor's value is invalid */
50598c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", maxp0);
50608c2ecf20Sopenharmony_ci		retval = -EMSGSIZE;
50618c2ecf20Sopenharmony_ci		goto fail;
50628c2ecf20Sopenharmony_ci	}
50638c2ecf20Sopenharmony_ci
50648c2ecf20Sopenharmony_ci	descr = usb_get_device_descriptor(udev);
50658c2ecf20Sopenharmony_ci	if (IS_ERR(descr)) {
50668c2ecf20Sopenharmony_ci		retval = PTR_ERR(descr);
50678c2ecf20Sopenharmony_ci		if (retval != -ENODEV)
50688c2ecf20Sopenharmony_ci			dev_err(&udev->dev, "device descriptor read/all, error %d\n",
50698c2ecf20Sopenharmony_ci					retval);
50708c2ecf20Sopenharmony_ci		goto fail;
50718c2ecf20Sopenharmony_ci	}
50728c2ecf20Sopenharmony_ci	if (initial)
50738c2ecf20Sopenharmony_ci		udev->descriptor = *descr;
50748c2ecf20Sopenharmony_ci	else
50758c2ecf20Sopenharmony_ci		*dev_descr = *descr;
50768c2ecf20Sopenharmony_ci	kfree(descr);
50778c2ecf20Sopenharmony_ci
50788c2ecf20Sopenharmony_ci	/*
50798c2ecf20Sopenharmony_ci	 * Some superspeed devices have finished the link training process
50808c2ecf20Sopenharmony_ci	 * and attached to a superspeed hub port, but the device descriptor
50818c2ecf20Sopenharmony_ci	 * got from those devices show they aren't superspeed devices. Warm
50828c2ecf20Sopenharmony_ci	 * reset the port attached by the devices can fix them.
50838c2ecf20Sopenharmony_ci	 */
50848c2ecf20Sopenharmony_ci	if ((udev->speed >= USB_SPEED_SUPER) &&
50858c2ecf20Sopenharmony_ci			(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
50868c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "got a wrong device descriptor, warm reset device\n");
50878c2ecf20Sopenharmony_ci		hub_port_reset(hub, port1, udev, HUB_BH_RESET_TIME, true);
50888c2ecf20Sopenharmony_ci		retval = -EINVAL;
50898c2ecf20Sopenharmony_ci		goto fail;
50908c2ecf20Sopenharmony_ci	}
50918c2ecf20Sopenharmony_ci
50928c2ecf20Sopenharmony_ci	usb_detect_quirks(udev);
50938c2ecf20Sopenharmony_ci
50948c2ecf20Sopenharmony_ci	if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
50958c2ecf20Sopenharmony_ci		retval = usb_get_bos_descriptor(udev);
50968c2ecf20Sopenharmony_ci		if (!retval) {
50978c2ecf20Sopenharmony_ci			udev->lpm_capable = usb_device_supports_lpm(udev);
50988c2ecf20Sopenharmony_ci			usb_set_lpm_parameters(udev);
50998c2ecf20Sopenharmony_ci		}
51008c2ecf20Sopenharmony_ci	}
51018c2ecf20Sopenharmony_ci
51028c2ecf20Sopenharmony_ci	retval = 0;
51038c2ecf20Sopenharmony_ci	/* notify HCD that we have a device connected and addressed */
51048c2ecf20Sopenharmony_ci	if (hcd->driver->update_device)
51058c2ecf20Sopenharmony_ci		hcd->driver->update_device(hcd, udev);
51068c2ecf20Sopenharmony_ci	hub_set_initial_usb2_lpm_policy(udev);
51078c2ecf20Sopenharmony_cifail:
51088c2ecf20Sopenharmony_ci	if (retval) {
51098c2ecf20Sopenharmony_ci		hub_port_disable(hub, port1, 0);
51108c2ecf20Sopenharmony_ci		update_devnum(udev, devnum);	/* for disconnect processing */
51118c2ecf20Sopenharmony_ci	}
51128c2ecf20Sopenharmony_ci	kfree(buf);
51138c2ecf20Sopenharmony_ci	return retval;
51148c2ecf20Sopenharmony_ci}
51158c2ecf20Sopenharmony_ci
51168c2ecf20Sopenharmony_cistatic void
51178c2ecf20Sopenharmony_cicheck_highspeed(struct usb_hub *hub, struct usb_device *udev, int port1)
51188c2ecf20Sopenharmony_ci{
51198c2ecf20Sopenharmony_ci	struct usb_qualifier_descriptor	*qual;
51208c2ecf20Sopenharmony_ci	int				status;
51218c2ecf20Sopenharmony_ci
51228c2ecf20Sopenharmony_ci	if (udev->quirks & USB_QUIRK_DEVICE_QUALIFIER)
51238c2ecf20Sopenharmony_ci		return;
51248c2ecf20Sopenharmony_ci
51258c2ecf20Sopenharmony_ci	qual = kmalloc(sizeof *qual, GFP_KERNEL);
51268c2ecf20Sopenharmony_ci	if (qual == NULL)
51278c2ecf20Sopenharmony_ci		return;
51288c2ecf20Sopenharmony_ci
51298c2ecf20Sopenharmony_ci	status = usb_get_descriptor(udev, USB_DT_DEVICE_QUALIFIER, 0,
51308c2ecf20Sopenharmony_ci			qual, sizeof *qual);
51318c2ecf20Sopenharmony_ci	if (status == sizeof *qual) {
51328c2ecf20Sopenharmony_ci		dev_info(&udev->dev, "not running at top speed; "
51338c2ecf20Sopenharmony_ci			"connect to a high speed hub\n");
51348c2ecf20Sopenharmony_ci		/* hub LEDs are probably harder to miss than syslog */
51358c2ecf20Sopenharmony_ci		if (hub->has_indicators) {
51368c2ecf20Sopenharmony_ci			hub->indicator[port1-1] = INDICATOR_GREEN_BLINK;
51378c2ecf20Sopenharmony_ci			queue_delayed_work(system_power_efficient_wq,
51388c2ecf20Sopenharmony_ci					&hub->leds, 0);
51398c2ecf20Sopenharmony_ci		}
51408c2ecf20Sopenharmony_ci	}
51418c2ecf20Sopenharmony_ci	kfree(qual);
51428c2ecf20Sopenharmony_ci}
51438c2ecf20Sopenharmony_ci
51448c2ecf20Sopenharmony_cistatic unsigned
51458c2ecf20Sopenharmony_cihub_power_remaining(struct usb_hub *hub)
51468c2ecf20Sopenharmony_ci{
51478c2ecf20Sopenharmony_ci	struct usb_device *hdev = hub->hdev;
51488c2ecf20Sopenharmony_ci	int remaining;
51498c2ecf20Sopenharmony_ci	int port1;
51508c2ecf20Sopenharmony_ci
51518c2ecf20Sopenharmony_ci	if (!hub->limited_power)
51528c2ecf20Sopenharmony_ci		return 0;
51538c2ecf20Sopenharmony_ci
51548c2ecf20Sopenharmony_ci	remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
51558c2ecf20Sopenharmony_ci	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
51568c2ecf20Sopenharmony_ci		struct usb_port *port_dev = hub->ports[port1 - 1];
51578c2ecf20Sopenharmony_ci		struct usb_device *udev = port_dev->child;
51588c2ecf20Sopenharmony_ci		unsigned unit_load;
51598c2ecf20Sopenharmony_ci		int delta;
51608c2ecf20Sopenharmony_ci
51618c2ecf20Sopenharmony_ci		if (!udev)
51628c2ecf20Sopenharmony_ci			continue;
51638c2ecf20Sopenharmony_ci		if (hub_is_superspeed(udev))
51648c2ecf20Sopenharmony_ci			unit_load = 150;
51658c2ecf20Sopenharmony_ci		else
51668c2ecf20Sopenharmony_ci			unit_load = 100;
51678c2ecf20Sopenharmony_ci
51688c2ecf20Sopenharmony_ci		/*
51698c2ecf20Sopenharmony_ci		 * Unconfigured devices may not use more than one unit load,
51708c2ecf20Sopenharmony_ci		 * or 8mA for OTG ports
51718c2ecf20Sopenharmony_ci		 */
51728c2ecf20Sopenharmony_ci		if (udev->actconfig)
51738c2ecf20Sopenharmony_ci			delta = usb_get_max_power(udev, udev->actconfig);
51748c2ecf20Sopenharmony_ci		else if (port1 != udev->bus->otg_port || hdev->parent)
51758c2ecf20Sopenharmony_ci			delta = unit_load;
51768c2ecf20Sopenharmony_ci		else
51778c2ecf20Sopenharmony_ci			delta = 8;
51788c2ecf20Sopenharmony_ci		if (delta > hub->mA_per_port)
51798c2ecf20Sopenharmony_ci			dev_warn(&port_dev->dev, "%dmA is over %umA budget!\n",
51808c2ecf20Sopenharmony_ci					delta, hub->mA_per_port);
51818c2ecf20Sopenharmony_ci		remaining -= delta;
51828c2ecf20Sopenharmony_ci	}
51838c2ecf20Sopenharmony_ci	if (remaining < 0) {
51848c2ecf20Sopenharmony_ci		dev_warn(hub->intfdev, "%dmA over power budget!\n",
51858c2ecf20Sopenharmony_ci			-remaining);
51868c2ecf20Sopenharmony_ci		remaining = 0;
51878c2ecf20Sopenharmony_ci	}
51888c2ecf20Sopenharmony_ci	return remaining;
51898c2ecf20Sopenharmony_ci}
51908c2ecf20Sopenharmony_ci
51918c2ecf20Sopenharmony_ci
51928c2ecf20Sopenharmony_cistatic int descriptors_changed(struct usb_device *udev,
51938c2ecf20Sopenharmony_ci		struct usb_device_descriptor *new_device_descriptor,
51948c2ecf20Sopenharmony_ci		struct usb_host_bos *old_bos)
51958c2ecf20Sopenharmony_ci{
51968c2ecf20Sopenharmony_ci	int		changed = 0;
51978c2ecf20Sopenharmony_ci	unsigned	index;
51988c2ecf20Sopenharmony_ci	unsigned	serial_len = 0;
51998c2ecf20Sopenharmony_ci	unsigned	len;
52008c2ecf20Sopenharmony_ci	unsigned	old_length;
52018c2ecf20Sopenharmony_ci	int		length;
52028c2ecf20Sopenharmony_ci	char		*buf;
52038c2ecf20Sopenharmony_ci
52048c2ecf20Sopenharmony_ci	if (memcmp(&udev->descriptor, new_device_descriptor,
52058c2ecf20Sopenharmony_ci			sizeof(*new_device_descriptor)) != 0)
52068c2ecf20Sopenharmony_ci		return 1;
52078c2ecf20Sopenharmony_ci
52088c2ecf20Sopenharmony_ci	if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
52098c2ecf20Sopenharmony_ci		return 1;
52108c2ecf20Sopenharmony_ci	if (udev->bos) {
52118c2ecf20Sopenharmony_ci		len = le16_to_cpu(udev->bos->desc->wTotalLength);
52128c2ecf20Sopenharmony_ci		if (len != le16_to_cpu(old_bos->desc->wTotalLength))
52138c2ecf20Sopenharmony_ci			return 1;
52148c2ecf20Sopenharmony_ci		if (memcmp(udev->bos->desc, old_bos->desc, len))
52158c2ecf20Sopenharmony_ci			return 1;
52168c2ecf20Sopenharmony_ci	}
52178c2ecf20Sopenharmony_ci
52188c2ecf20Sopenharmony_ci	/* Since the idVendor, idProduct, and bcdDevice values in the
52198c2ecf20Sopenharmony_ci	 * device descriptor haven't changed, we will assume the
52208c2ecf20Sopenharmony_ci	 * Manufacturer and Product strings haven't changed either.
52218c2ecf20Sopenharmony_ci	 * But the SerialNumber string could be different (e.g., a
52228c2ecf20Sopenharmony_ci	 * different flash card of the same brand).
52238c2ecf20Sopenharmony_ci	 */
52248c2ecf20Sopenharmony_ci	if (udev->serial)
52258c2ecf20Sopenharmony_ci		serial_len = strlen(udev->serial) + 1;
52268c2ecf20Sopenharmony_ci
52278c2ecf20Sopenharmony_ci	len = serial_len;
52288c2ecf20Sopenharmony_ci	for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
52298c2ecf20Sopenharmony_ci		old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
52308c2ecf20Sopenharmony_ci		len = max(len, old_length);
52318c2ecf20Sopenharmony_ci	}
52328c2ecf20Sopenharmony_ci
52338c2ecf20Sopenharmony_ci	buf = kmalloc(len, GFP_NOIO);
52348c2ecf20Sopenharmony_ci	if (!buf)
52358c2ecf20Sopenharmony_ci		/* assume the worst */
52368c2ecf20Sopenharmony_ci		return 1;
52378c2ecf20Sopenharmony_ci
52388c2ecf20Sopenharmony_ci	for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
52398c2ecf20Sopenharmony_ci		old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
52408c2ecf20Sopenharmony_ci		length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
52418c2ecf20Sopenharmony_ci				old_length);
52428c2ecf20Sopenharmony_ci		if (length != old_length) {
52438c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "config index %d, error %d\n",
52448c2ecf20Sopenharmony_ci					index, length);
52458c2ecf20Sopenharmony_ci			changed = 1;
52468c2ecf20Sopenharmony_ci			break;
52478c2ecf20Sopenharmony_ci		}
52488c2ecf20Sopenharmony_ci		if (memcmp(buf, udev->rawdescriptors[index], old_length)
52498c2ecf20Sopenharmony_ci				!= 0) {
52508c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
52518c2ecf20Sopenharmony_ci				index,
52528c2ecf20Sopenharmony_ci				((struct usb_config_descriptor *) buf)->
52538c2ecf20Sopenharmony_ci					bConfigurationValue);
52548c2ecf20Sopenharmony_ci			changed = 1;
52558c2ecf20Sopenharmony_ci			break;
52568c2ecf20Sopenharmony_ci		}
52578c2ecf20Sopenharmony_ci	}
52588c2ecf20Sopenharmony_ci
52598c2ecf20Sopenharmony_ci	if (!changed && serial_len) {
52608c2ecf20Sopenharmony_ci		length = usb_string(udev, udev->descriptor.iSerialNumber,
52618c2ecf20Sopenharmony_ci				buf, serial_len);
52628c2ecf20Sopenharmony_ci		if (length + 1 != serial_len) {
52638c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "serial string error %d\n",
52648c2ecf20Sopenharmony_ci					length);
52658c2ecf20Sopenharmony_ci			changed = 1;
52668c2ecf20Sopenharmony_ci		} else if (memcmp(buf, udev->serial, length) != 0) {
52678c2ecf20Sopenharmony_ci			dev_dbg(&udev->dev, "serial string changed\n");
52688c2ecf20Sopenharmony_ci			changed = 1;
52698c2ecf20Sopenharmony_ci		}
52708c2ecf20Sopenharmony_ci	}
52718c2ecf20Sopenharmony_ci
52728c2ecf20Sopenharmony_ci	kfree(buf);
52738c2ecf20Sopenharmony_ci	return changed;
52748c2ecf20Sopenharmony_ci}
52758c2ecf20Sopenharmony_ci
52768c2ecf20Sopenharmony_cistatic void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
52778c2ecf20Sopenharmony_ci		u16 portchange)
52788c2ecf20Sopenharmony_ci{
52798c2ecf20Sopenharmony_ci	int status = -ENODEV;
52808c2ecf20Sopenharmony_ci	int i;
52818c2ecf20Sopenharmony_ci	unsigned unit_load;
52828c2ecf20Sopenharmony_ci	struct usb_device *hdev = hub->hdev;
52838c2ecf20Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
52848c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
52858c2ecf20Sopenharmony_ci	struct usb_device *udev = port_dev->child;
52868c2ecf20Sopenharmony_ci	static int unreliable_port = -1;
52878c2ecf20Sopenharmony_ci	bool retry_locked;
52888c2ecf20Sopenharmony_ci
52898c2ecf20Sopenharmony_ci	/* Disconnect any existing devices under this port */
52908c2ecf20Sopenharmony_ci	if (udev) {
52918c2ecf20Sopenharmony_ci		if (hcd->usb_phy && !hdev->parent)
52928c2ecf20Sopenharmony_ci			usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);
52938c2ecf20Sopenharmony_ci		usb_disconnect(&port_dev->child);
52948c2ecf20Sopenharmony_ci	}
52958c2ecf20Sopenharmony_ci
52968c2ecf20Sopenharmony_ci	/* We can forget about a "removed" device when there's a physical
52978c2ecf20Sopenharmony_ci	 * disconnect or the connect status changes.
52988c2ecf20Sopenharmony_ci	 */
52998c2ecf20Sopenharmony_ci	if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
53008c2ecf20Sopenharmony_ci			(portchange & USB_PORT_STAT_C_CONNECTION))
53018c2ecf20Sopenharmony_ci		clear_bit(port1, hub->removed_bits);
53028c2ecf20Sopenharmony_ci
53038c2ecf20Sopenharmony_ci	if (portchange & (USB_PORT_STAT_C_CONNECTION |
53048c2ecf20Sopenharmony_ci				USB_PORT_STAT_C_ENABLE)) {
53058c2ecf20Sopenharmony_ci		status = hub_port_debounce_be_stable(hub, port1);
53068c2ecf20Sopenharmony_ci		if (status < 0) {
53078c2ecf20Sopenharmony_ci			if (status != -ENODEV &&
53088c2ecf20Sopenharmony_ci				port1 != unreliable_port &&
53098c2ecf20Sopenharmony_ci				printk_ratelimit())
53108c2ecf20Sopenharmony_ci				dev_err(&port_dev->dev, "connect-debounce failed\n");
53118c2ecf20Sopenharmony_ci			portstatus &= ~USB_PORT_STAT_CONNECTION;
53128c2ecf20Sopenharmony_ci			unreliable_port = port1;
53138c2ecf20Sopenharmony_ci		} else {
53148c2ecf20Sopenharmony_ci			portstatus = status;
53158c2ecf20Sopenharmony_ci		}
53168c2ecf20Sopenharmony_ci	}
53178c2ecf20Sopenharmony_ci
53188c2ecf20Sopenharmony_ci	/* Return now if debouncing failed or nothing is connected or
53198c2ecf20Sopenharmony_ci	 * the device was "removed".
53208c2ecf20Sopenharmony_ci	 */
53218c2ecf20Sopenharmony_ci	if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
53228c2ecf20Sopenharmony_ci			test_bit(port1, hub->removed_bits)) {
53238c2ecf20Sopenharmony_ci
53248c2ecf20Sopenharmony_ci		/*
53258c2ecf20Sopenharmony_ci		 * maybe switch power back on (e.g. root hub was reset)
53268c2ecf20Sopenharmony_ci		 * but only if the port isn't owned by someone else.
53278c2ecf20Sopenharmony_ci		 */
53288c2ecf20Sopenharmony_ci		if (hub_is_port_power_switchable(hub)
53298c2ecf20Sopenharmony_ci				&& !port_is_power_on(hub, portstatus)
53308c2ecf20Sopenharmony_ci				&& !port_dev->port_owner)
53318c2ecf20Sopenharmony_ci			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
53328c2ecf20Sopenharmony_ci
53338c2ecf20Sopenharmony_ci		if (portstatus & USB_PORT_STAT_ENABLE)
53348c2ecf20Sopenharmony_ci			goto done;
53358c2ecf20Sopenharmony_ci		return;
53368c2ecf20Sopenharmony_ci	}
53378c2ecf20Sopenharmony_ci	if (hub_is_superspeed(hub->hdev))
53388c2ecf20Sopenharmony_ci		unit_load = 150;
53398c2ecf20Sopenharmony_ci	else
53408c2ecf20Sopenharmony_ci		unit_load = 100;
53418c2ecf20Sopenharmony_ci
53428c2ecf20Sopenharmony_ci	status = 0;
53438c2ecf20Sopenharmony_ci
53448c2ecf20Sopenharmony_ci	for (i = 0; i < PORT_INIT_TRIES; i++) {
53458c2ecf20Sopenharmony_ci		usb_lock_port(port_dev);
53468c2ecf20Sopenharmony_ci		mutex_lock(hcd->address0_mutex);
53478c2ecf20Sopenharmony_ci		retry_locked = true;
53488c2ecf20Sopenharmony_ci		/* reallocate for each attempt, since references
53498c2ecf20Sopenharmony_ci		 * to the previous one can escape in various ways
53508c2ecf20Sopenharmony_ci		 */
53518c2ecf20Sopenharmony_ci		udev = usb_alloc_dev(hdev, hdev->bus, port1);
53528c2ecf20Sopenharmony_ci		if (!udev) {
53538c2ecf20Sopenharmony_ci			dev_err(&port_dev->dev,
53548c2ecf20Sopenharmony_ci					"couldn't allocate usb_device\n");
53558c2ecf20Sopenharmony_ci			mutex_unlock(hcd->address0_mutex);
53568c2ecf20Sopenharmony_ci			usb_unlock_port(port_dev);
53578c2ecf20Sopenharmony_ci			goto done;
53588c2ecf20Sopenharmony_ci		}
53598c2ecf20Sopenharmony_ci
53608c2ecf20Sopenharmony_ci		usb_set_device_state(udev, USB_STATE_POWERED);
53618c2ecf20Sopenharmony_ci		udev->bus_mA = hub->mA_per_port;
53628c2ecf20Sopenharmony_ci		udev->level = hdev->level + 1;
53638c2ecf20Sopenharmony_ci		udev->wusb = hub_is_wusb(hub);
53648c2ecf20Sopenharmony_ci
53658c2ecf20Sopenharmony_ci		/* Devices connected to SuperSpeed hubs are USB 3.0 or later */
53668c2ecf20Sopenharmony_ci		if (hub_is_superspeed(hub->hdev))
53678c2ecf20Sopenharmony_ci			udev->speed = USB_SPEED_SUPER;
53688c2ecf20Sopenharmony_ci		else
53698c2ecf20Sopenharmony_ci			udev->speed = USB_SPEED_UNKNOWN;
53708c2ecf20Sopenharmony_ci
53718c2ecf20Sopenharmony_ci		choose_devnum(udev);
53728c2ecf20Sopenharmony_ci		if (udev->devnum <= 0) {
53738c2ecf20Sopenharmony_ci			status = -ENOTCONN;	/* Don't retry */
53748c2ecf20Sopenharmony_ci			goto loop;
53758c2ecf20Sopenharmony_ci		}
53768c2ecf20Sopenharmony_ci
53778c2ecf20Sopenharmony_ci		/* reset (non-USB 3.0 devices) and get descriptor */
53788c2ecf20Sopenharmony_ci		status = hub_port_init(hub, udev, port1, i, NULL);
53798c2ecf20Sopenharmony_ci		if (status < 0)
53808c2ecf20Sopenharmony_ci			goto loop;
53818c2ecf20Sopenharmony_ci
53828c2ecf20Sopenharmony_ci		mutex_unlock(hcd->address0_mutex);
53838c2ecf20Sopenharmony_ci		usb_unlock_port(port_dev);
53848c2ecf20Sopenharmony_ci		retry_locked = false;
53858c2ecf20Sopenharmony_ci
53868c2ecf20Sopenharmony_ci		if (udev->quirks & USB_QUIRK_DELAY_INIT)
53878c2ecf20Sopenharmony_ci			msleep(2000);
53888c2ecf20Sopenharmony_ci
53898c2ecf20Sopenharmony_ci		/* consecutive bus-powered hubs aren't reliable; they can
53908c2ecf20Sopenharmony_ci		 * violate the voltage drop budget.  if the new child has
53918c2ecf20Sopenharmony_ci		 * a "powered" LED, users should notice we didn't enable it
53928c2ecf20Sopenharmony_ci		 * (without reading syslog), even without per-port LEDs
53938c2ecf20Sopenharmony_ci		 * on the parent.
53948c2ecf20Sopenharmony_ci		 */
53958c2ecf20Sopenharmony_ci		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
53968c2ecf20Sopenharmony_ci				&& udev->bus_mA <= unit_load) {
53978c2ecf20Sopenharmony_ci			u16	devstat;
53988c2ecf20Sopenharmony_ci
53998c2ecf20Sopenharmony_ci			status = usb_get_std_status(udev, USB_RECIP_DEVICE, 0,
54008c2ecf20Sopenharmony_ci					&devstat);
54018c2ecf20Sopenharmony_ci			if (status) {
54028c2ecf20Sopenharmony_ci				dev_dbg(&udev->dev, "get status %d ?\n", status);
54038c2ecf20Sopenharmony_ci				goto loop_disable;
54048c2ecf20Sopenharmony_ci			}
54058c2ecf20Sopenharmony_ci			if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
54068c2ecf20Sopenharmony_ci				dev_err(&udev->dev,
54078c2ecf20Sopenharmony_ci					"can't connect bus-powered hub "
54088c2ecf20Sopenharmony_ci					"to this port\n");
54098c2ecf20Sopenharmony_ci				if (hub->has_indicators) {
54108c2ecf20Sopenharmony_ci					hub->indicator[port1-1] =
54118c2ecf20Sopenharmony_ci						INDICATOR_AMBER_BLINK;
54128c2ecf20Sopenharmony_ci					queue_delayed_work(
54138c2ecf20Sopenharmony_ci						system_power_efficient_wq,
54148c2ecf20Sopenharmony_ci						&hub->leds, 0);
54158c2ecf20Sopenharmony_ci				}
54168c2ecf20Sopenharmony_ci				status = -ENOTCONN;	/* Don't retry */
54178c2ecf20Sopenharmony_ci				goto loop_disable;
54188c2ecf20Sopenharmony_ci			}
54198c2ecf20Sopenharmony_ci		}
54208c2ecf20Sopenharmony_ci
54218c2ecf20Sopenharmony_ci		/* check for devices running slower than they could */
54228c2ecf20Sopenharmony_ci		if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
54238c2ecf20Sopenharmony_ci				&& udev->speed == USB_SPEED_FULL
54248c2ecf20Sopenharmony_ci				&& highspeed_hubs != 0)
54258c2ecf20Sopenharmony_ci			check_highspeed(hub, udev, port1);
54268c2ecf20Sopenharmony_ci
54278c2ecf20Sopenharmony_ci		/* Store the parent's children[] pointer.  At this point
54288c2ecf20Sopenharmony_ci		 * udev becomes globally accessible, although presumably
54298c2ecf20Sopenharmony_ci		 * no one will look at it until hdev is unlocked.
54308c2ecf20Sopenharmony_ci		 */
54318c2ecf20Sopenharmony_ci		status = 0;
54328c2ecf20Sopenharmony_ci
54338c2ecf20Sopenharmony_ci		mutex_lock(&usb_port_peer_mutex);
54348c2ecf20Sopenharmony_ci
54358c2ecf20Sopenharmony_ci		/* We mustn't add new devices if the parent hub has
54368c2ecf20Sopenharmony_ci		 * been disconnected; we would race with the
54378c2ecf20Sopenharmony_ci		 * recursively_mark_NOTATTACHED() routine.
54388c2ecf20Sopenharmony_ci		 */
54398c2ecf20Sopenharmony_ci		spin_lock_irq(&device_state_lock);
54408c2ecf20Sopenharmony_ci		if (hdev->state == USB_STATE_NOTATTACHED)
54418c2ecf20Sopenharmony_ci			status = -ENOTCONN;
54428c2ecf20Sopenharmony_ci		else
54438c2ecf20Sopenharmony_ci			port_dev->child = udev;
54448c2ecf20Sopenharmony_ci		spin_unlock_irq(&device_state_lock);
54458c2ecf20Sopenharmony_ci		mutex_unlock(&usb_port_peer_mutex);
54468c2ecf20Sopenharmony_ci
54478c2ecf20Sopenharmony_ci		/* Run it through the hoops (find a driver, etc) */
54488c2ecf20Sopenharmony_ci		if (!status) {
54498c2ecf20Sopenharmony_ci			status = usb_new_device(udev);
54508c2ecf20Sopenharmony_ci			if (status) {
54518c2ecf20Sopenharmony_ci				mutex_lock(&usb_port_peer_mutex);
54528c2ecf20Sopenharmony_ci				spin_lock_irq(&device_state_lock);
54538c2ecf20Sopenharmony_ci				port_dev->child = NULL;
54548c2ecf20Sopenharmony_ci				spin_unlock_irq(&device_state_lock);
54558c2ecf20Sopenharmony_ci				mutex_unlock(&usb_port_peer_mutex);
54568c2ecf20Sopenharmony_ci			} else {
54578c2ecf20Sopenharmony_ci				if (hcd->usb_phy && !hdev->parent)
54588c2ecf20Sopenharmony_ci					usb_phy_notify_connect(hcd->usb_phy,
54598c2ecf20Sopenharmony_ci							udev->speed);
54608c2ecf20Sopenharmony_ci			}
54618c2ecf20Sopenharmony_ci		}
54628c2ecf20Sopenharmony_ci
54638c2ecf20Sopenharmony_ci		if (status)
54648c2ecf20Sopenharmony_ci			goto loop_disable;
54658c2ecf20Sopenharmony_ci
54668c2ecf20Sopenharmony_ci		status = hub_power_remaining(hub);
54678c2ecf20Sopenharmony_ci		if (status)
54688c2ecf20Sopenharmony_ci			dev_dbg(hub->intfdev, "%dmA power budget left\n", status);
54698c2ecf20Sopenharmony_ci
54708c2ecf20Sopenharmony_ci		return;
54718c2ecf20Sopenharmony_ci
54728c2ecf20Sopenharmony_ciloop_disable:
54738c2ecf20Sopenharmony_ci		hub_port_disable(hub, port1, 1);
54748c2ecf20Sopenharmony_ciloop:
54758c2ecf20Sopenharmony_ci		usb_ep0_reinit(udev);
54768c2ecf20Sopenharmony_ci		release_devnum(udev);
54778c2ecf20Sopenharmony_ci		hub_free_dev(udev);
54788c2ecf20Sopenharmony_ci		if (retry_locked) {
54798c2ecf20Sopenharmony_ci			mutex_unlock(hcd->address0_mutex);
54808c2ecf20Sopenharmony_ci			usb_unlock_port(port_dev);
54818c2ecf20Sopenharmony_ci		}
54828c2ecf20Sopenharmony_ci		usb_put_dev(udev);
54838c2ecf20Sopenharmony_ci		if ((status == -ENOTCONN) || (status == -ENOTSUPP))
54848c2ecf20Sopenharmony_ci			break;
54858c2ecf20Sopenharmony_ci
54868c2ecf20Sopenharmony_ci		/* When halfway through our retry count, power-cycle the port */
54878c2ecf20Sopenharmony_ci		if (i == (PORT_INIT_TRIES - 1) / 2) {
54888c2ecf20Sopenharmony_ci			dev_info(&port_dev->dev, "attempt power cycle\n");
54898c2ecf20Sopenharmony_ci			usb_hub_set_port_power(hdev, hub, port1, false);
54908c2ecf20Sopenharmony_ci			msleep(2 * hub_power_on_good_delay(hub));
54918c2ecf20Sopenharmony_ci			usb_hub_set_port_power(hdev, hub, port1, true);
54928c2ecf20Sopenharmony_ci			msleep(hub_power_on_good_delay(hub));
54938c2ecf20Sopenharmony_ci		}
54948c2ecf20Sopenharmony_ci	}
54958c2ecf20Sopenharmony_ci	if (hub->hdev->parent ||
54968c2ecf20Sopenharmony_ci			!hcd->driver->port_handed_over ||
54978c2ecf20Sopenharmony_ci			!(hcd->driver->port_handed_over)(hcd, port1)) {
54988c2ecf20Sopenharmony_ci		if (status != -ENOTCONN && status != -ENODEV)
54998c2ecf20Sopenharmony_ci			dev_err(&port_dev->dev,
55008c2ecf20Sopenharmony_ci					"unable to enumerate USB device\n");
55018c2ecf20Sopenharmony_ci	}
55028c2ecf20Sopenharmony_ci
55038c2ecf20Sopenharmony_cidone:
55048c2ecf20Sopenharmony_ci	hub_port_disable(hub, port1, 1);
55058c2ecf20Sopenharmony_ci	if (hcd->driver->relinquish_port && !hub->hdev->parent) {
55068c2ecf20Sopenharmony_ci		if (status != -ENOTCONN && status != -ENODEV)
55078c2ecf20Sopenharmony_ci			hcd->driver->relinquish_port(hcd, port1);
55088c2ecf20Sopenharmony_ci	}
55098c2ecf20Sopenharmony_ci}
55108c2ecf20Sopenharmony_ci
55118c2ecf20Sopenharmony_ci/* Handle physical or logical connection change events.
55128c2ecf20Sopenharmony_ci * This routine is called when:
55138c2ecf20Sopenharmony_ci *	a port connection-change occurs;
55148c2ecf20Sopenharmony_ci *	a port enable-change occurs (often caused by EMI);
55158c2ecf20Sopenharmony_ci *	usb_reset_and_verify_device() encounters changed descriptors (as from
55168c2ecf20Sopenharmony_ci *		a firmware download)
55178c2ecf20Sopenharmony_ci * caller already locked the hub
55188c2ecf20Sopenharmony_ci */
55198c2ecf20Sopenharmony_cistatic void hub_port_connect_change(struct usb_hub *hub, int port1,
55208c2ecf20Sopenharmony_ci					u16 portstatus, u16 portchange)
55218c2ecf20Sopenharmony_ci		__must_hold(&port_dev->status_lock)
55228c2ecf20Sopenharmony_ci{
55238c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
55248c2ecf20Sopenharmony_ci	struct usb_device *udev = port_dev->child;
55258c2ecf20Sopenharmony_ci	struct usb_device_descriptor *descr;
55268c2ecf20Sopenharmony_ci	int status = -ENODEV;
55278c2ecf20Sopenharmony_ci
55288c2ecf20Sopenharmony_ci	dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
55298c2ecf20Sopenharmony_ci			portchange, portspeed(hub, portstatus));
55308c2ecf20Sopenharmony_ci
55318c2ecf20Sopenharmony_ci	if (hub->has_indicators) {
55328c2ecf20Sopenharmony_ci		set_port_led(hub, port1, HUB_LED_AUTO);
55338c2ecf20Sopenharmony_ci		hub->indicator[port1-1] = INDICATOR_AUTO;
55348c2ecf20Sopenharmony_ci	}
55358c2ecf20Sopenharmony_ci
55368c2ecf20Sopenharmony_ci#ifdef	CONFIG_USB_OTG
55378c2ecf20Sopenharmony_ci	/* during HNP, don't repeat the debounce */
55388c2ecf20Sopenharmony_ci	if (hub->hdev->bus->is_b_host)
55398c2ecf20Sopenharmony_ci		portchange &= ~(USB_PORT_STAT_C_CONNECTION |
55408c2ecf20Sopenharmony_ci				USB_PORT_STAT_C_ENABLE);
55418c2ecf20Sopenharmony_ci#endif
55428c2ecf20Sopenharmony_ci
55438c2ecf20Sopenharmony_ci	/* Try to resuscitate an existing device */
55448c2ecf20Sopenharmony_ci	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
55458c2ecf20Sopenharmony_ci			udev->state != USB_STATE_NOTATTACHED) {
55468c2ecf20Sopenharmony_ci		if (portstatus & USB_PORT_STAT_ENABLE) {
55478c2ecf20Sopenharmony_ci			/*
55488c2ecf20Sopenharmony_ci			 * USB-3 connections are initialized automatically by
55498c2ecf20Sopenharmony_ci			 * the hostcontroller hardware. Therefore check for
55508c2ecf20Sopenharmony_ci			 * changed device descriptors before resuscitating the
55518c2ecf20Sopenharmony_ci			 * device.
55528c2ecf20Sopenharmony_ci			 */
55538c2ecf20Sopenharmony_ci			descr = usb_get_device_descriptor(udev);
55548c2ecf20Sopenharmony_ci			if (IS_ERR(descr)) {
55558c2ecf20Sopenharmony_ci				dev_dbg(&udev->dev,
55568c2ecf20Sopenharmony_ci						"can't read device descriptor %ld\n",
55578c2ecf20Sopenharmony_ci						PTR_ERR(descr));
55588c2ecf20Sopenharmony_ci			} else {
55598c2ecf20Sopenharmony_ci				if (descriptors_changed(udev, descr,
55608c2ecf20Sopenharmony_ci						udev->bos)) {
55618c2ecf20Sopenharmony_ci					dev_dbg(&udev->dev,
55628c2ecf20Sopenharmony_ci							"device descriptor has changed\n");
55638c2ecf20Sopenharmony_ci				} else {
55648c2ecf20Sopenharmony_ci					status = 0; /* Nothing to do */
55658c2ecf20Sopenharmony_ci				}
55668c2ecf20Sopenharmony_ci				kfree(descr);
55678c2ecf20Sopenharmony_ci			}
55688c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
55698c2ecf20Sopenharmony_ci		} else if (udev->state == USB_STATE_SUSPENDED &&
55708c2ecf20Sopenharmony_ci				udev->persist_enabled) {
55718c2ecf20Sopenharmony_ci			/* For a suspended device, treat this as a
55728c2ecf20Sopenharmony_ci			 * remote wakeup event.
55738c2ecf20Sopenharmony_ci			 */
55748c2ecf20Sopenharmony_ci			usb_unlock_port(port_dev);
55758c2ecf20Sopenharmony_ci			status = usb_remote_wakeup(udev);
55768c2ecf20Sopenharmony_ci			usb_lock_port(port_dev);
55778c2ecf20Sopenharmony_ci#endif
55788c2ecf20Sopenharmony_ci		} else {
55798c2ecf20Sopenharmony_ci			/* Don't resuscitate */;
55808c2ecf20Sopenharmony_ci		}
55818c2ecf20Sopenharmony_ci	}
55828c2ecf20Sopenharmony_ci	clear_bit(port1, hub->change_bits);
55838c2ecf20Sopenharmony_ci
55848c2ecf20Sopenharmony_ci	/* successfully revalidated the connection */
55858c2ecf20Sopenharmony_ci	if (status == 0)
55868c2ecf20Sopenharmony_ci		return;
55878c2ecf20Sopenharmony_ci
55888c2ecf20Sopenharmony_ci	usb_unlock_port(port_dev);
55898c2ecf20Sopenharmony_ci	hub_port_connect(hub, port1, portstatus, portchange);
55908c2ecf20Sopenharmony_ci	usb_lock_port(port_dev);
55918c2ecf20Sopenharmony_ci}
55928c2ecf20Sopenharmony_ci
55938c2ecf20Sopenharmony_ci/* Handle notifying userspace about hub over-current events */
55948c2ecf20Sopenharmony_cistatic void port_over_current_notify(struct usb_port *port_dev)
55958c2ecf20Sopenharmony_ci{
55968c2ecf20Sopenharmony_ci	char *envp[3];
55978c2ecf20Sopenharmony_ci	struct device *hub_dev;
55988c2ecf20Sopenharmony_ci	char *port_dev_path;
55998c2ecf20Sopenharmony_ci
56008c2ecf20Sopenharmony_ci	sysfs_notify(&port_dev->dev.kobj, NULL, "over_current_count");
56018c2ecf20Sopenharmony_ci
56028c2ecf20Sopenharmony_ci	hub_dev = port_dev->dev.parent;
56038c2ecf20Sopenharmony_ci
56048c2ecf20Sopenharmony_ci	if (!hub_dev)
56058c2ecf20Sopenharmony_ci		return;
56068c2ecf20Sopenharmony_ci
56078c2ecf20Sopenharmony_ci	port_dev_path = kobject_get_path(&port_dev->dev.kobj, GFP_KERNEL);
56088c2ecf20Sopenharmony_ci	if (!port_dev_path)
56098c2ecf20Sopenharmony_ci		return;
56108c2ecf20Sopenharmony_ci
56118c2ecf20Sopenharmony_ci	envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path);
56128c2ecf20Sopenharmony_ci	if (!envp[0])
56138c2ecf20Sopenharmony_ci		goto exit_path;
56148c2ecf20Sopenharmony_ci
56158c2ecf20Sopenharmony_ci	envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u",
56168c2ecf20Sopenharmony_ci			port_dev->over_current_count);
56178c2ecf20Sopenharmony_ci	if (!envp[1])
56188c2ecf20Sopenharmony_ci		goto exit;
56198c2ecf20Sopenharmony_ci
56208c2ecf20Sopenharmony_ci	envp[2] = NULL;
56218c2ecf20Sopenharmony_ci	kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);
56228c2ecf20Sopenharmony_ci
56238c2ecf20Sopenharmony_ci	kfree(envp[1]);
56248c2ecf20Sopenharmony_ciexit:
56258c2ecf20Sopenharmony_ci	kfree(envp[0]);
56268c2ecf20Sopenharmony_ciexit_path:
56278c2ecf20Sopenharmony_ci	kfree(port_dev_path);
56288c2ecf20Sopenharmony_ci}
56298c2ecf20Sopenharmony_ci
56308c2ecf20Sopenharmony_cistatic void port_event(struct usb_hub *hub, int port1)
56318c2ecf20Sopenharmony_ci		__must_hold(&port_dev->status_lock)
56328c2ecf20Sopenharmony_ci{
56338c2ecf20Sopenharmony_ci	int connect_change;
56348c2ecf20Sopenharmony_ci	struct usb_port *port_dev = hub->ports[port1 - 1];
56358c2ecf20Sopenharmony_ci	struct usb_device *udev = port_dev->child;
56368c2ecf20Sopenharmony_ci	struct usb_device *hdev = hub->hdev;
56378c2ecf20Sopenharmony_ci	u16 portstatus, portchange;
56388c2ecf20Sopenharmony_ci
56398c2ecf20Sopenharmony_ci	connect_change = test_bit(port1, hub->change_bits);
56408c2ecf20Sopenharmony_ci	clear_bit(port1, hub->event_bits);
56418c2ecf20Sopenharmony_ci	clear_bit(port1, hub->wakeup_bits);
56428c2ecf20Sopenharmony_ci
56438c2ecf20Sopenharmony_ci	if (hub_port_status(hub, port1, &portstatus, &portchange) < 0)
56448c2ecf20Sopenharmony_ci		return;
56458c2ecf20Sopenharmony_ci
56468c2ecf20Sopenharmony_ci	if (portchange & USB_PORT_STAT_C_CONNECTION) {
56478c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
56488c2ecf20Sopenharmony_ci		connect_change = 1;
56498c2ecf20Sopenharmony_ci	}
56508c2ecf20Sopenharmony_ci
56518c2ecf20Sopenharmony_ci	if (portchange & USB_PORT_STAT_C_ENABLE) {
56528c2ecf20Sopenharmony_ci		if (!connect_change)
56538c2ecf20Sopenharmony_ci			dev_dbg(&port_dev->dev, "enable change, status %08x\n",
56548c2ecf20Sopenharmony_ci					portstatus);
56558c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
56568c2ecf20Sopenharmony_ci
56578c2ecf20Sopenharmony_ci		/*
56588c2ecf20Sopenharmony_ci		 * EM interference sometimes causes badly shielded USB devices
56598c2ecf20Sopenharmony_ci		 * to be shutdown by the hub, this hack enables them again.
56608c2ecf20Sopenharmony_ci		 * Works at least with mouse driver.
56618c2ecf20Sopenharmony_ci		 */
56628c2ecf20Sopenharmony_ci		if (!(portstatus & USB_PORT_STAT_ENABLE)
56638c2ecf20Sopenharmony_ci		    && !connect_change && udev) {
56648c2ecf20Sopenharmony_ci			dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n");
56658c2ecf20Sopenharmony_ci			connect_change = 1;
56668c2ecf20Sopenharmony_ci		}
56678c2ecf20Sopenharmony_ci	}
56688c2ecf20Sopenharmony_ci
56698c2ecf20Sopenharmony_ci	if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
56708c2ecf20Sopenharmony_ci		u16 status = 0, unused;
56718c2ecf20Sopenharmony_ci		port_dev->over_current_count++;
56728c2ecf20Sopenharmony_ci		port_over_current_notify(port_dev);
56738c2ecf20Sopenharmony_ci
56748c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "over-current change #%u\n",
56758c2ecf20Sopenharmony_ci			port_dev->over_current_count);
56768c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port1,
56778c2ecf20Sopenharmony_ci				USB_PORT_FEAT_C_OVER_CURRENT);
56788c2ecf20Sopenharmony_ci		msleep(100);	/* Cool down */
56798c2ecf20Sopenharmony_ci		hub_power_on(hub, true);
56808c2ecf20Sopenharmony_ci		hub_port_status(hub, port1, &status, &unused);
56818c2ecf20Sopenharmony_ci		if (status & USB_PORT_STAT_OVERCURRENT)
56828c2ecf20Sopenharmony_ci			dev_err(&port_dev->dev, "over-current condition\n");
56838c2ecf20Sopenharmony_ci	}
56848c2ecf20Sopenharmony_ci
56858c2ecf20Sopenharmony_ci	if (portchange & USB_PORT_STAT_C_RESET) {
56868c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "reset change\n");
56878c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET);
56888c2ecf20Sopenharmony_ci	}
56898c2ecf20Sopenharmony_ci	if ((portchange & USB_PORT_STAT_C_BH_RESET)
56908c2ecf20Sopenharmony_ci	    && hub_is_superspeed(hdev)) {
56918c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "warm reset change\n");
56928c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port1,
56938c2ecf20Sopenharmony_ci				USB_PORT_FEAT_C_BH_PORT_RESET);
56948c2ecf20Sopenharmony_ci	}
56958c2ecf20Sopenharmony_ci	if (portchange & USB_PORT_STAT_C_LINK_STATE) {
56968c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "link state change\n");
56978c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port1,
56988c2ecf20Sopenharmony_ci				USB_PORT_FEAT_C_PORT_LINK_STATE);
56998c2ecf20Sopenharmony_ci	}
57008c2ecf20Sopenharmony_ci	if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
57018c2ecf20Sopenharmony_ci		dev_warn(&port_dev->dev, "config error\n");
57028c2ecf20Sopenharmony_ci		usb_clear_port_feature(hdev, port1,
57038c2ecf20Sopenharmony_ci				USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
57048c2ecf20Sopenharmony_ci	}
57058c2ecf20Sopenharmony_ci
57068c2ecf20Sopenharmony_ci	/* skip port actions that require the port to be powered on */
57078c2ecf20Sopenharmony_ci	if (!pm_runtime_active(&port_dev->dev))
57088c2ecf20Sopenharmony_ci		return;
57098c2ecf20Sopenharmony_ci
57108c2ecf20Sopenharmony_ci	if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))
57118c2ecf20Sopenharmony_ci		connect_change = 1;
57128c2ecf20Sopenharmony_ci
57138c2ecf20Sopenharmony_ci	/*
57148c2ecf20Sopenharmony_ci	 * Warm reset a USB3 protocol port if it's in
57158c2ecf20Sopenharmony_ci	 * SS.Inactive state.
57168c2ecf20Sopenharmony_ci	 */
57178c2ecf20Sopenharmony_ci	if (hub_port_warm_reset_required(hub, port1, portstatus)) {
57188c2ecf20Sopenharmony_ci		dev_dbg(&port_dev->dev, "do warm reset\n");
57198c2ecf20Sopenharmony_ci		if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
57208c2ecf20Sopenharmony_ci				|| udev->state == USB_STATE_NOTATTACHED) {
57218c2ecf20Sopenharmony_ci			if (hub_port_reset(hub, port1, NULL,
57228c2ecf20Sopenharmony_ci					HUB_BH_RESET_TIME, true) < 0)
57238c2ecf20Sopenharmony_ci				hub_port_disable(hub, port1, 1);
57248c2ecf20Sopenharmony_ci		} else {
57258c2ecf20Sopenharmony_ci			usb_unlock_port(port_dev);
57268c2ecf20Sopenharmony_ci			usb_lock_device(udev);
57278c2ecf20Sopenharmony_ci			usb_reset_device(udev);
57288c2ecf20Sopenharmony_ci			usb_unlock_device(udev);
57298c2ecf20Sopenharmony_ci			usb_lock_port(port_dev);
57308c2ecf20Sopenharmony_ci			connect_change = 0;
57318c2ecf20Sopenharmony_ci		}
57328c2ecf20Sopenharmony_ci	}
57338c2ecf20Sopenharmony_ci
57348c2ecf20Sopenharmony_ci	if (connect_change)
57358c2ecf20Sopenharmony_ci		hub_port_connect_change(hub, port1, portstatus, portchange);
57368c2ecf20Sopenharmony_ci}
57378c2ecf20Sopenharmony_ci
57388c2ecf20Sopenharmony_cistatic void hub_event(struct work_struct *work)
57398c2ecf20Sopenharmony_ci{
57408c2ecf20Sopenharmony_ci	struct usb_device *hdev;
57418c2ecf20Sopenharmony_ci	struct usb_interface *intf;
57428c2ecf20Sopenharmony_ci	struct usb_hub *hub;
57438c2ecf20Sopenharmony_ci	struct device *hub_dev;
57448c2ecf20Sopenharmony_ci	u16 hubstatus;
57458c2ecf20Sopenharmony_ci	u16 hubchange;
57468c2ecf20Sopenharmony_ci	int i, ret;
57478c2ecf20Sopenharmony_ci
57488c2ecf20Sopenharmony_ci	hub = container_of(work, struct usb_hub, events);
57498c2ecf20Sopenharmony_ci	hdev = hub->hdev;
57508c2ecf20Sopenharmony_ci	hub_dev = hub->intfdev;
57518c2ecf20Sopenharmony_ci	intf = to_usb_interface(hub_dev);
57528c2ecf20Sopenharmony_ci
57538c2ecf20Sopenharmony_ci	kcov_remote_start_usb((u64)hdev->bus->busnum);
57548c2ecf20Sopenharmony_ci
57558c2ecf20Sopenharmony_ci	dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
57568c2ecf20Sopenharmony_ci			hdev->state, hdev->maxchild,
57578c2ecf20Sopenharmony_ci			/* NOTE: expects max 15 ports... */
57588c2ecf20Sopenharmony_ci			(u16) hub->change_bits[0],
57598c2ecf20Sopenharmony_ci			(u16) hub->event_bits[0]);
57608c2ecf20Sopenharmony_ci
57618c2ecf20Sopenharmony_ci	/* Lock the device, then check to see if we were
57628c2ecf20Sopenharmony_ci	 * disconnected while waiting for the lock to succeed. */
57638c2ecf20Sopenharmony_ci	usb_lock_device(hdev);
57648c2ecf20Sopenharmony_ci	if (unlikely(hub->disconnected))
57658c2ecf20Sopenharmony_ci		goto out_hdev_lock;
57668c2ecf20Sopenharmony_ci
57678c2ecf20Sopenharmony_ci	/* If the hub has died, clean up after it */
57688c2ecf20Sopenharmony_ci	if (hdev->state == USB_STATE_NOTATTACHED) {
57698c2ecf20Sopenharmony_ci		hub->error = -ENODEV;
57708c2ecf20Sopenharmony_ci		hub_quiesce(hub, HUB_DISCONNECT);
57718c2ecf20Sopenharmony_ci		goto out_hdev_lock;
57728c2ecf20Sopenharmony_ci	}
57738c2ecf20Sopenharmony_ci
57748c2ecf20Sopenharmony_ci	/* Autoresume */
57758c2ecf20Sopenharmony_ci	ret = usb_autopm_get_interface(intf);
57768c2ecf20Sopenharmony_ci	if (ret) {
57778c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
57788c2ecf20Sopenharmony_ci		goto out_hdev_lock;
57798c2ecf20Sopenharmony_ci	}
57808c2ecf20Sopenharmony_ci
57818c2ecf20Sopenharmony_ci	/* If this is an inactive hub, do nothing */
57828c2ecf20Sopenharmony_ci	if (hub->quiescing)
57838c2ecf20Sopenharmony_ci		goto out_autopm;
57848c2ecf20Sopenharmony_ci
57858c2ecf20Sopenharmony_ci	if (hub->error) {
57868c2ecf20Sopenharmony_ci		dev_dbg(hub_dev, "resetting for error %d\n", hub->error);
57878c2ecf20Sopenharmony_ci
57888c2ecf20Sopenharmony_ci		ret = usb_reset_device(hdev);
57898c2ecf20Sopenharmony_ci		if (ret) {
57908c2ecf20Sopenharmony_ci			dev_dbg(hub_dev, "error resetting hub: %d\n", ret);
57918c2ecf20Sopenharmony_ci			goto out_autopm;
57928c2ecf20Sopenharmony_ci		}
57938c2ecf20Sopenharmony_ci
57948c2ecf20Sopenharmony_ci		hub->nerrors = 0;
57958c2ecf20Sopenharmony_ci		hub->error = 0;
57968c2ecf20Sopenharmony_ci	}
57978c2ecf20Sopenharmony_ci
57988c2ecf20Sopenharmony_ci	/* deal with port status changes */
57998c2ecf20Sopenharmony_ci	for (i = 1; i <= hdev->maxchild; i++) {
58008c2ecf20Sopenharmony_ci		struct usb_port *port_dev = hub->ports[i - 1];
58018c2ecf20Sopenharmony_ci
58028c2ecf20Sopenharmony_ci		if (test_bit(i, hub->event_bits)
58038c2ecf20Sopenharmony_ci				|| test_bit(i, hub->change_bits)
58048c2ecf20Sopenharmony_ci				|| test_bit(i, hub->wakeup_bits)) {
58058c2ecf20Sopenharmony_ci			/*
58068c2ecf20Sopenharmony_ci			 * The get_noresume and barrier ensure that if
58078c2ecf20Sopenharmony_ci			 * the port was in the process of resuming, we
58088c2ecf20Sopenharmony_ci			 * flush that work and keep the port active for
58098c2ecf20Sopenharmony_ci			 * the duration of the port_event().  However,
58108c2ecf20Sopenharmony_ci			 * if the port is runtime pm suspended
58118c2ecf20Sopenharmony_ci			 * (powered-off), we leave it in that state, run
58128c2ecf20Sopenharmony_ci			 * an abbreviated port_event(), and move on.
58138c2ecf20Sopenharmony_ci			 */
58148c2ecf20Sopenharmony_ci			pm_runtime_get_noresume(&port_dev->dev);
58158c2ecf20Sopenharmony_ci			pm_runtime_barrier(&port_dev->dev);
58168c2ecf20Sopenharmony_ci			usb_lock_port(port_dev);
58178c2ecf20Sopenharmony_ci			port_event(hub, i);
58188c2ecf20Sopenharmony_ci			usb_unlock_port(port_dev);
58198c2ecf20Sopenharmony_ci			pm_runtime_put_sync(&port_dev->dev);
58208c2ecf20Sopenharmony_ci		}
58218c2ecf20Sopenharmony_ci	}
58228c2ecf20Sopenharmony_ci
58238c2ecf20Sopenharmony_ci	/* deal with hub status changes */
58248c2ecf20Sopenharmony_ci	if (test_and_clear_bit(0, hub->event_bits) == 0)
58258c2ecf20Sopenharmony_ci		;	/* do nothing */
58268c2ecf20Sopenharmony_ci	else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
58278c2ecf20Sopenharmony_ci		dev_err(hub_dev, "get_hub_status failed\n");
58288c2ecf20Sopenharmony_ci	else {
58298c2ecf20Sopenharmony_ci		if (hubchange & HUB_CHANGE_LOCAL_POWER) {
58308c2ecf20Sopenharmony_ci			dev_dbg(hub_dev, "power change\n");
58318c2ecf20Sopenharmony_ci			clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
58328c2ecf20Sopenharmony_ci			if (hubstatus & HUB_STATUS_LOCAL_POWER)
58338c2ecf20Sopenharmony_ci				/* FIXME: Is this always true? */
58348c2ecf20Sopenharmony_ci				hub->limited_power = 1;
58358c2ecf20Sopenharmony_ci			else
58368c2ecf20Sopenharmony_ci				hub->limited_power = 0;
58378c2ecf20Sopenharmony_ci		}
58388c2ecf20Sopenharmony_ci		if (hubchange & HUB_CHANGE_OVERCURRENT) {
58398c2ecf20Sopenharmony_ci			u16 status = 0;
58408c2ecf20Sopenharmony_ci			u16 unused;
58418c2ecf20Sopenharmony_ci
58428c2ecf20Sopenharmony_ci			dev_dbg(hub_dev, "over-current change\n");
58438c2ecf20Sopenharmony_ci			clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
58448c2ecf20Sopenharmony_ci			msleep(500);	/* Cool down */
58458c2ecf20Sopenharmony_ci			hub_power_on(hub, true);
58468c2ecf20Sopenharmony_ci			hub_hub_status(hub, &status, &unused);
58478c2ecf20Sopenharmony_ci			if (status & HUB_STATUS_OVERCURRENT)
58488c2ecf20Sopenharmony_ci				dev_err(hub_dev, "over-current condition\n");
58498c2ecf20Sopenharmony_ci		}
58508c2ecf20Sopenharmony_ci	}
58518c2ecf20Sopenharmony_ci
58528c2ecf20Sopenharmony_ciout_autopm:
58538c2ecf20Sopenharmony_ci	/* Balance the usb_autopm_get_interface() above */
58548c2ecf20Sopenharmony_ci	usb_autopm_put_interface_no_suspend(intf);
58558c2ecf20Sopenharmony_ciout_hdev_lock:
58568c2ecf20Sopenharmony_ci	usb_unlock_device(hdev);
58578c2ecf20Sopenharmony_ci
58588c2ecf20Sopenharmony_ci	/* Balance the stuff in kick_hub_wq() and allow autosuspend */
58598c2ecf20Sopenharmony_ci	usb_autopm_put_interface(intf);
58608c2ecf20Sopenharmony_ci	kref_put(&hub->kref, hub_release);
58618c2ecf20Sopenharmony_ci
58628c2ecf20Sopenharmony_ci	kcov_remote_stop();
58638c2ecf20Sopenharmony_ci}
58648c2ecf20Sopenharmony_ci
58658c2ecf20Sopenharmony_cistatic const struct usb_device_id hub_id_table[] = {
58668c2ecf20Sopenharmony_ci    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
58678c2ecf20Sopenharmony_ci                   | USB_DEVICE_ID_MATCH_PRODUCT
58688c2ecf20Sopenharmony_ci                   | USB_DEVICE_ID_MATCH_INT_CLASS,
58698c2ecf20Sopenharmony_ci      .idVendor = USB_VENDOR_SMSC,
58708c2ecf20Sopenharmony_ci      .idProduct = USB_PRODUCT_USB5534B,
58718c2ecf20Sopenharmony_ci      .bInterfaceClass = USB_CLASS_HUB,
58728c2ecf20Sopenharmony_ci      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
58738c2ecf20Sopenharmony_ci    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
58748c2ecf20Sopenharmony_ci                   | USB_DEVICE_ID_MATCH_PRODUCT,
58758c2ecf20Sopenharmony_ci      .idVendor = USB_VENDOR_CYPRESS,
58768c2ecf20Sopenharmony_ci      .idProduct = USB_PRODUCT_CY7C65632,
58778c2ecf20Sopenharmony_ci      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
58788c2ecf20Sopenharmony_ci    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
58798c2ecf20Sopenharmony_ci			| USB_DEVICE_ID_MATCH_INT_CLASS,
58808c2ecf20Sopenharmony_ci      .idVendor = USB_VENDOR_GENESYS_LOGIC,
58818c2ecf20Sopenharmony_ci      .bInterfaceClass = USB_CLASS_HUB,
58828c2ecf20Sopenharmony_ci      .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
58838c2ecf20Sopenharmony_ci    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
58848c2ecf20Sopenharmony_ci			| USB_DEVICE_ID_MATCH_PRODUCT,
58858c2ecf20Sopenharmony_ci      .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
58868c2ecf20Sopenharmony_ci      .idProduct = USB_PRODUCT_TUSB8041_USB2,
58878c2ecf20Sopenharmony_ci      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
58888c2ecf20Sopenharmony_ci    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
58898c2ecf20Sopenharmony_ci			| USB_DEVICE_ID_MATCH_PRODUCT,
58908c2ecf20Sopenharmony_ci      .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
58918c2ecf20Sopenharmony_ci      .idProduct = USB_PRODUCT_TUSB8041_USB3,
58928c2ecf20Sopenharmony_ci      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
58938c2ecf20Sopenharmony_ci    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
58948c2ecf20Sopenharmony_ci      .bDeviceClass = USB_CLASS_HUB},
58958c2ecf20Sopenharmony_ci    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
58968c2ecf20Sopenharmony_ci      .bInterfaceClass = USB_CLASS_HUB},
58978c2ecf20Sopenharmony_ci    { }						/* Terminating entry */
58988c2ecf20Sopenharmony_ci};
58998c2ecf20Sopenharmony_ci
59008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, hub_id_table);
59018c2ecf20Sopenharmony_ci
59028c2ecf20Sopenharmony_cistatic struct usb_driver hub_driver = {
59038c2ecf20Sopenharmony_ci	.name =		"hub",
59048c2ecf20Sopenharmony_ci	.probe =	hub_probe,
59058c2ecf20Sopenharmony_ci	.disconnect =	hub_disconnect,
59068c2ecf20Sopenharmony_ci	.suspend =	hub_suspend,
59078c2ecf20Sopenharmony_ci	.resume =	hub_resume,
59088c2ecf20Sopenharmony_ci	.reset_resume =	hub_reset_resume,
59098c2ecf20Sopenharmony_ci	.pre_reset =	hub_pre_reset,
59108c2ecf20Sopenharmony_ci	.post_reset =	hub_post_reset,
59118c2ecf20Sopenharmony_ci	.unlocked_ioctl = hub_ioctl,
59128c2ecf20Sopenharmony_ci	.id_table =	hub_id_table,
59138c2ecf20Sopenharmony_ci	.supports_autosuspend =	1,
59148c2ecf20Sopenharmony_ci};
59158c2ecf20Sopenharmony_ci
59168c2ecf20Sopenharmony_ciint usb_hub_init(void)
59178c2ecf20Sopenharmony_ci{
59188c2ecf20Sopenharmony_ci	if (usb_register(&hub_driver) < 0) {
59198c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: can't register hub driver\n",
59208c2ecf20Sopenharmony_ci			usbcore_name);
59218c2ecf20Sopenharmony_ci		return -1;
59228c2ecf20Sopenharmony_ci	}
59238c2ecf20Sopenharmony_ci
59248c2ecf20Sopenharmony_ci	/*
59258c2ecf20Sopenharmony_ci	 * The workqueue needs to be freezable to avoid interfering with
59268c2ecf20Sopenharmony_ci	 * USB-PERSIST port handover. Otherwise it might see that a full-speed
59278c2ecf20Sopenharmony_ci	 * device was gone before the EHCI controller had handed its port
59288c2ecf20Sopenharmony_ci	 * over to the companion full-speed controller.
59298c2ecf20Sopenharmony_ci	 */
59308c2ecf20Sopenharmony_ci	hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);
59318c2ecf20Sopenharmony_ci	if (hub_wq)
59328c2ecf20Sopenharmony_ci		return 0;
59338c2ecf20Sopenharmony_ci
59348c2ecf20Sopenharmony_ci	/* Fall through if kernel_thread failed */
59358c2ecf20Sopenharmony_ci	usb_deregister(&hub_driver);
59368c2ecf20Sopenharmony_ci	pr_err("%s: can't allocate workqueue for usb hub\n", usbcore_name);
59378c2ecf20Sopenharmony_ci
59388c2ecf20Sopenharmony_ci	return -1;
59398c2ecf20Sopenharmony_ci}
59408c2ecf20Sopenharmony_ci
59418c2ecf20Sopenharmony_civoid usb_hub_cleanup(void)
59428c2ecf20Sopenharmony_ci{
59438c2ecf20Sopenharmony_ci	destroy_workqueue(hub_wq);
59448c2ecf20Sopenharmony_ci
59458c2ecf20Sopenharmony_ci	/*
59468c2ecf20Sopenharmony_ci	 * Hub resources are freed for us by usb_deregister. It calls
59478c2ecf20Sopenharmony_ci	 * usb_driver_purge on every device which in turn calls that
59488c2ecf20Sopenharmony_ci	 * devices disconnect function if it is using this driver.
59498c2ecf20Sopenharmony_ci	 * The hub_disconnect function takes care of releasing the
59508c2ecf20Sopenharmony_ci	 * individual hub resources. -greg
59518c2ecf20Sopenharmony_ci	 */
59528c2ecf20Sopenharmony_ci	usb_deregister(&hub_driver);
59538c2ecf20Sopenharmony_ci} /* usb_hub_cleanup() */
59548c2ecf20Sopenharmony_ci
59558c2ecf20Sopenharmony_ci/**
59568c2ecf20Sopenharmony_ci * usb_reset_and_verify_device - perform a USB port reset to reinitialize a device
59578c2ecf20Sopenharmony_ci * @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
59588c2ecf20Sopenharmony_ci *
59598c2ecf20Sopenharmony_ci * WARNING - don't use this routine to reset a composite device
59608c2ecf20Sopenharmony_ci * (one with multiple interfaces owned by separate drivers)!
59618c2ecf20Sopenharmony_ci * Use usb_reset_device() instead.
59628c2ecf20Sopenharmony_ci *
59638c2ecf20Sopenharmony_ci * Do a port reset, reassign the device's address, and establish its
59648c2ecf20Sopenharmony_ci * former operating configuration.  If the reset fails, or the device's
59658c2ecf20Sopenharmony_ci * descriptors change from their values before the reset, or the original
59668c2ecf20Sopenharmony_ci * configuration and altsettings cannot be restored, a flag will be set
59678c2ecf20Sopenharmony_ci * telling hub_wq to pretend the device has been disconnected and then
59688c2ecf20Sopenharmony_ci * re-connected.  All drivers will be unbound, and the device will be
59698c2ecf20Sopenharmony_ci * re-enumerated and probed all over again.
59708c2ecf20Sopenharmony_ci *
59718c2ecf20Sopenharmony_ci * Return: 0 if the reset succeeded, -ENODEV if the device has been
59728c2ecf20Sopenharmony_ci * flagged for logical disconnection, or some other negative error code
59738c2ecf20Sopenharmony_ci * if the reset wasn't even attempted.
59748c2ecf20Sopenharmony_ci *
59758c2ecf20Sopenharmony_ci * Note:
59768c2ecf20Sopenharmony_ci * The caller must own the device lock and the port lock, the latter is
59778c2ecf20Sopenharmony_ci * taken by usb_reset_device().  For example, it's safe to use
59788c2ecf20Sopenharmony_ci * usb_reset_device() from a driver probe() routine after downloading
59798c2ecf20Sopenharmony_ci * new firmware.  For calls that might not occur during probe(), drivers
59808c2ecf20Sopenharmony_ci * should lock the device using usb_lock_device_for_reset().
59818c2ecf20Sopenharmony_ci *
59828c2ecf20Sopenharmony_ci * Locking exception: This routine may also be called from within an
59838c2ecf20Sopenharmony_ci * autoresume handler.  Such usage won't conflict with other tasks
59848c2ecf20Sopenharmony_ci * holding the device lock because these tasks should always call
59858c2ecf20Sopenharmony_ci * usb_autopm_resume_device(), thereby preventing any unwanted
59868c2ecf20Sopenharmony_ci * autoresume.  The autoresume handler is expected to have already
59878c2ecf20Sopenharmony_ci * acquired the port lock before calling this routine.
59888c2ecf20Sopenharmony_ci */
59898c2ecf20Sopenharmony_cistatic int usb_reset_and_verify_device(struct usb_device *udev)
59908c2ecf20Sopenharmony_ci{
59918c2ecf20Sopenharmony_ci	struct usb_device		*parent_hdev = udev->parent;
59928c2ecf20Sopenharmony_ci	struct usb_hub			*parent_hub;
59938c2ecf20Sopenharmony_ci	struct usb_hcd			*hcd = bus_to_hcd(udev->bus);
59948c2ecf20Sopenharmony_ci	struct usb_device_descriptor	descriptor;
59958c2ecf20Sopenharmony_ci	struct usb_host_bos		*bos;
59968c2ecf20Sopenharmony_ci	int				i, j, ret = 0;
59978c2ecf20Sopenharmony_ci	int				port1 = udev->portnum;
59988c2ecf20Sopenharmony_ci
59998c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_NOTATTACHED ||
60008c2ecf20Sopenharmony_ci			udev->state == USB_STATE_SUSPENDED) {
60018c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
60028c2ecf20Sopenharmony_ci				udev->state);
60038c2ecf20Sopenharmony_ci		return -EINVAL;
60048c2ecf20Sopenharmony_ci	}
60058c2ecf20Sopenharmony_ci
60068c2ecf20Sopenharmony_ci	if (!parent_hdev)
60078c2ecf20Sopenharmony_ci		return -EISDIR;
60088c2ecf20Sopenharmony_ci
60098c2ecf20Sopenharmony_ci	parent_hub = usb_hub_to_struct_hub(parent_hdev);
60108c2ecf20Sopenharmony_ci
60118c2ecf20Sopenharmony_ci	/* Disable USB2 hardware LPM.
60128c2ecf20Sopenharmony_ci	 * It will be re-enabled by the enumeration process.
60138c2ecf20Sopenharmony_ci	 */
60148c2ecf20Sopenharmony_ci	usb_disable_usb2_hardware_lpm(udev);
60158c2ecf20Sopenharmony_ci
60168c2ecf20Sopenharmony_ci	/* Disable LPM while we reset the device and reinstall the alt settings.
60178c2ecf20Sopenharmony_ci	 * Device-initiated LPM, and system exit latency settings are cleared
60188c2ecf20Sopenharmony_ci	 * when the device is reset, so we have to set them up again.
60198c2ecf20Sopenharmony_ci	 */
60208c2ecf20Sopenharmony_ci	ret = usb_unlocked_disable_lpm(udev);
60218c2ecf20Sopenharmony_ci	if (ret) {
60228c2ecf20Sopenharmony_ci		dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__);
60238c2ecf20Sopenharmony_ci		goto re_enumerate_no_bos;
60248c2ecf20Sopenharmony_ci	}
60258c2ecf20Sopenharmony_ci
60268c2ecf20Sopenharmony_ci	bos = udev->bos;
60278c2ecf20Sopenharmony_ci	udev->bos = NULL;
60288c2ecf20Sopenharmony_ci
60298c2ecf20Sopenharmony_ci	mutex_lock(hcd->address0_mutex);
60308c2ecf20Sopenharmony_ci
60318c2ecf20Sopenharmony_ci	for (i = 0; i < PORT_INIT_TRIES; ++i) {
60328c2ecf20Sopenharmony_ci
60338c2ecf20Sopenharmony_ci		/* ep0 maxpacket size may change; let the HCD know about it.
60348c2ecf20Sopenharmony_ci		 * Other endpoints will be handled by re-enumeration. */
60358c2ecf20Sopenharmony_ci		usb_ep0_reinit(udev);
60368c2ecf20Sopenharmony_ci		ret = hub_port_init(parent_hub, udev, port1, i, &descriptor);
60378c2ecf20Sopenharmony_ci		if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
60388c2ecf20Sopenharmony_ci			break;
60398c2ecf20Sopenharmony_ci	}
60408c2ecf20Sopenharmony_ci	mutex_unlock(hcd->address0_mutex);
60418c2ecf20Sopenharmony_ci
60428c2ecf20Sopenharmony_ci	if (ret < 0)
60438c2ecf20Sopenharmony_ci		goto re_enumerate;
60448c2ecf20Sopenharmony_ci
60458c2ecf20Sopenharmony_ci	/* Device might have changed firmware (DFU or similar) */
60468c2ecf20Sopenharmony_ci	if (descriptors_changed(udev, &descriptor, bos)) {
60478c2ecf20Sopenharmony_ci		dev_info(&udev->dev, "device firmware changed\n");
60488c2ecf20Sopenharmony_ci		goto re_enumerate;
60498c2ecf20Sopenharmony_ci	}
60508c2ecf20Sopenharmony_ci
60518c2ecf20Sopenharmony_ci	/* Restore the device's previous configuration */
60528c2ecf20Sopenharmony_ci	if (!udev->actconfig)
60538c2ecf20Sopenharmony_ci		goto done;
60548c2ecf20Sopenharmony_ci
60558c2ecf20Sopenharmony_ci	mutex_lock(hcd->bandwidth_mutex);
60568c2ecf20Sopenharmony_ci	ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
60578c2ecf20Sopenharmony_ci	if (ret < 0) {
60588c2ecf20Sopenharmony_ci		dev_warn(&udev->dev,
60598c2ecf20Sopenharmony_ci				"Busted HC?  Not enough HCD resources for "
60608c2ecf20Sopenharmony_ci				"old configuration.\n");
60618c2ecf20Sopenharmony_ci		mutex_unlock(hcd->bandwidth_mutex);
60628c2ecf20Sopenharmony_ci		goto re_enumerate;
60638c2ecf20Sopenharmony_ci	}
60648c2ecf20Sopenharmony_ci	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
60658c2ecf20Sopenharmony_ci			USB_REQ_SET_CONFIGURATION, 0,
60668c2ecf20Sopenharmony_ci			udev->actconfig->desc.bConfigurationValue, 0,
60678c2ecf20Sopenharmony_ci			NULL, 0, USB_CTRL_SET_TIMEOUT);
60688c2ecf20Sopenharmony_ci	if (ret < 0) {
60698c2ecf20Sopenharmony_ci		dev_err(&udev->dev,
60708c2ecf20Sopenharmony_ci			"can't restore configuration #%d (error=%d)\n",
60718c2ecf20Sopenharmony_ci			udev->actconfig->desc.bConfigurationValue, ret);
60728c2ecf20Sopenharmony_ci		mutex_unlock(hcd->bandwidth_mutex);
60738c2ecf20Sopenharmony_ci		goto re_enumerate;
60748c2ecf20Sopenharmony_ci	}
60758c2ecf20Sopenharmony_ci	mutex_unlock(hcd->bandwidth_mutex);
60768c2ecf20Sopenharmony_ci	usb_set_device_state(udev, USB_STATE_CONFIGURED);
60778c2ecf20Sopenharmony_ci
60788c2ecf20Sopenharmony_ci	/* Put interfaces back into the same altsettings as before.
60798c2ecf20Sopenharmony_ci	 * Don't bother to send the Set-Interface request for interfaces
60808c2ecf20Sopenharmony_ci	 * that were already in altsetting 0; besides being unnecessary,
60818c2ecf20Sopenharmony_ci	 * many devices can't handle it.  Instead just reset the host-side
60828c2ecf20Sopenharmony_ci	 * endpoint state.
60838c2ecf20Sopenharmony_ci	 */
60848c2ecf20Sopenharmony_ci	for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
60858c2ecf20Sopenharmony_ci		struct usb_host_config *config = udev->actconfig;
60868c2ecf20Sopenharmony_ci		struct usb_interface *intf = config->interface[i];
60878c2ecf20Sopenharmony_ci		struct usb_interface_descriptor *desc;
60888c2ecf20Sopenharmony_ci
60898c2ecf20Sopenharmony_ci		desc = &intf->cur_altsetting->desc;
60908c2ecf20Sopenharmony_ci		if (desc->bAlternateSetting == 0) {
60918c2ecf20Sopenharmony_ci			usb_disable_interface(udev, intf, true);
60928c2ecf20Sopenharmony_ci			usb_enable_interface(udev, intf, true);
60938c2ecf20Sopenharmony_ci			ret = 0;
60948c2ecf20Sopenharmony_ci		} else {
60958c2ecf20Sopenharmony_ci			/* Let the bandwidth allocation function know that this
60968c2ecf20Sopenharmony_ci			 * device has been reset, and it will have to use
60978c2ecf20Sopenharmony_ci			 * alternate setting 0 as the current alternate setting.
60988c2ecf20Sopenharmony_ci			 */
60998c2ecf20Sopenharmony_ci			intf->resetting_device = 1;
61008c2ecf20Sopenharmony_ci			ret = usb_set_interface(udev, desc->bInterfaceNumber,
61018c2ecf20Sopenharmony_ci					desc->bAlternateSetting);
61028c2ecf20Sopenharmony_ci			intf->resetting_device = 0;
61038c2ecf20Sopenharmony_ci		}
61048c2ecf20Sopenharmony_ci		if (ret < 0) {
61058c2ecf20Sopenharmony_ci			dev_err(&udev->dev, "failed to restore interface %d "
61068c2ecf20Sopenharmony_ci				"altsetting %d (error=%d)\n",
61078c2ecf20Sopenharmony_ci				desc->bInterfaceNumber,
61088c2ecf20Sopenharmony_ci				desc->bAlternateSetting,
61098c2ecf20Sopenharmony_ci				ret);
61108c2ecf20Sopenharmony_ci			goto re_enumerate;
61118c2ecf20Sopenharmony_ci		}
61128c2ecf20Sopenharmony_ci		/* Resetting also frees any allocated streams */
61138c2ecf20Sopenharmony_ci		for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++)
61148c2ecf20Sopenharmony_ci			intf->cur_altsetting->endpoint[j].streams = 0;
61158c2ecf20Sopenharmony_ci	}
61168c2ecf20Sopenharmony_ci
61178c2ecf20Sopenharmony_cidone:
61188c2ecf20Sopenharmony_ci	/* Now that the alt settings are re-installed, enable LTM and LPM. */
61198c2ecf20Sopenharmony_ci	usb_enable_usb2_hardware_lpm(udev);
61208c2ecf20Sopenharmony_ci	usb_unlocked_enable_lpm(udev);
61218c2ecf20Sopenharmony_ci	usb_enable_ltm(udev);
61228c2ecf20Sopenharmony_ci	usb_release_bos_descriptor(udev);
61238c2ecf20Sopenharmony_ci	udev->bos = bos;
61248c2ecf20Sopenharmony_ci	return 0;
61258c2ecf20Sopenharmony_ci
61268c2ecf20Sopenharmony_cire_enumerate:
61278c2ecf20Sopenharmony_ci	usb_release_bos_descriptor(udev);
61288c2ecf20Sopenharmony_ci	udev->bos = bos;
61298c2ecf20Sopenharmony_cire_enumerate_no_bos:
61308c2ecf20Sopenharmony_ci	/* LPM state doesn't matter when we're about to destroy the device. */
61318c2ecf20Sopenharmony_ci	hub_port_logical_disconnect(parent_hub, port1);
61328c2ecf20Sopenharmony_ci	return -ENODEV;
61338c2ecf20Sopenharmony_ci}
61348c2ecf20Sopenharmony_ci
61358c2ecf20Sopenharmony_ci/**
61368c2ecf20Sopenharmony_ci * usb_reset_device - warn interface drivers and perform a USB port reset
61378c2ecf20Sopenharmony_ci * @udev: device to reset (not in NOTATTACHED state)
61388c2ecf20Sopenharmony_ci *
61398c2ecf20Sopenharmony_ci * Warns all drivers bound to registered interfaces (using their pre_reset
61408c2ecf20Sopenharmony_ci * method), performs the port reset, and then lets the drivers know that
61418c2ecf20Sopenharmony_ci * the reset is over (using their post_reset method).
61428c2ecf20Sopenharmony_ci *
61438c2ecf20Sopenharmony_ci * Return: The same as for usb_reset_and_verify_device().
61448c2ecf20Sopenharmony_ci * However, if a reset is already in progress (for instance, if a
61458c2ecf20Sopenharmony_ci * driver doesn't have pre_reset() or post_reset() callbacks, and while
61468c2ecf20Sopenharmony_ci * being unbound or re-bound during the ongoing reset its disconnect()
61478c2ecf20Sopenharmony_ci * or probe() routine tries to perform a second, nested reset), the
61488c2ecf20Sopenharmony_ci * routine returns -EINPROGRESS.
61498c2ecf20Sopenharmony_ci *
61508c2ecf20Sopenharmony_ci * Note:
61518c2ecf20Sopenharmony_ci * The caller must own the device lock.  For example, it's safe to use
61528c2ecf20Sopenharmony_ci * this from a driver probe() routine after downloading new firmware.
61538c2ecf20Sopenharmony_ci * For calls that might not occur during probe(), drivers should lock
61548c2ecf20Sopenharmony_ci * the device using usb_lock_device_for_reset().
61558c2ecf20Sopenharmony_ci *
61568c2ecf20Sopenharmony_ci * If an interface is currently being probed or disconnected, we assume
61578c2ecf20Sopenharmony_ci * its driver knows how to handle resets.  For all other interfaces,
61588c2ecf20Sopenharmony_ci * if the driver doesn't have pre_reset and post_reset methods then
61598c2ecf20Sopenharmony_ci * we attempt to unbind it and rebind afterward.
61608c2ecf20Sopenharmony_ci */
61618c2ecf20Sopenharmony_ciint usb_reset_device(struct usb_device *udev)
61628c2ecf20Sopenharmony_ci{
61638c2ecf20Sopenharmony_ci	int ret;
61648c2ecf20Sopenharmony_ci	int i;
61658c2ecf20Sopenharmony_ci	unsigned int noio_flag;
61668c2ecf20Sopenharmony_ci	struct usb_port *port_dev;
61678c2ecf20Sopenharmony_ci	struct usb_host_config *config = udev->actconfig;
61688c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
61698c2ecf20Sopenharmony_ci
61708c2ecf20Sopenharmony_ci	if (udev->state == USB_STATE_NOTATTACHED) {
61718c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
61728c2ecf20Sopenharmony_ci				udev->state);
61738c2ecf20Sopenharmony_ci		return -EINVAL;
61748c2ecf20Sopenharmony_ci	}
61758c2ecf20Sopenharmony_ci
61768c2ecf20Sopenharmony_ci	if (!udev->parent) {
61778c2ecf20Sopenharmony_ci		/* this requires hcd-specific logic; see ohci_restart() */
61788c2ecf20Sopenharmony_ci		dev_dbg(&udev->dev, "%s for root hub!\n", __func__);
61798c2ecf20Sopenharmony_ci		return -EISDIR;
61808c2ecf20Sopenharmony_ci	}
61818c2ecf20Sopenharmony_ci
61828c2ecf20Sopenharmony_ci	if (udev->reset_in_progress)
61838c2ecf20Sopenharmony_ci		return -EINPROGRESS;
61848c2ecf20Sopenharmony_ci	udev->reset_in_progress = 1;
61858c2ecf20Sopenharmony_ci
61868c2ecf20Sopenharmony_ci	port_dev = hub->ports[udev->portnum - 1];
61878c2ecf20Sopenharmony_ci
61888c2ecf20Sopenharmony_ci	/*
61898c2ecf20Sopenharmony_ci	 * Don't allocate memory with GFP_KERNEL in current
61908c2ecf20Sopenharmony_ci	 * context to avoid possible deadlock if usb mass
61918c2ecf20Sopenharmony_ci	 * storage interface or usbnet interface(iSCSI case)
61928c2ecf20Sopenharmony_ci	 * is included in current configuration. The easist
61938c2ecf20Sopenharmony_ci	 * approach is to do it for every device reset,
61948c2ecf20Sopenharmony_ci	 * because the device 'memalloc_noio' flag may have
61958c2ecf20Sopenharmony_ci	 * not been set before reseting the usb device.
61968c2ecf20Sopenharmony_ci	 */
61978c2ecf20Sopenharmony_ci	noio_flag = memalloc_noio_save();
61988c2ecf20Sopenharmony_ci
61998c2ecf20Sopenharmony_ci	/* Prevent autosuspend during the reset */
62008c2ecf20Sopenharmony_ci	usb_autoresume_device(udev);
62018c2ecf20Sopenharmony_ci
62028c2ecf20Sopenharmony_ci	if (config) {
62038c2ecf20Sopenharmony_ci		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
62048c2ecf20Sopenharmony_ci			struct usb_interface *cintf = config->interface[i];
62058c2ecf20Sopenharmony_ci			struct usb_driver *drv;
62068c2ecf20Sopenharmony_ci			int unbind = 0;
62078c2ecf20Sopenharmony_ci
62088c2ecf20Sopenharmony_ci			if (cintf->dev.driver) {
62098c2ecf20Sopenharmony_ci				drv = to_usb_driver(cintf->dev.driver);
62108c2ecf20Sopenharmony_ci				if (drv->pre_reset && drv->post_reset)
62118c2ecf20Sopenharmony_ci					unbind = (drv->pre_reset)(cintf);
62128c2ecf20Sopenharmony_ci				else if (cintf->condition ==
62138c2ecf20Sopenharmony_ci						USB_INTERFACE_BOUND)
62148c2ecf20Sopenharmony_ci					unbind = 1;
62158c2ecf20Sopenharmony_ci				if (unbind)
62168c2ecf20Sopenharmony_ci					usb_forced_unbind_intf(cintf);
62178c2ecf20Sopenharmony_ci			}
62188c2ecf20Sopenharmony_ci		}
62198c2ecf20Sopenharmony_ci	}
62208c2ecf20Sopenharmony_ci
62218c2ecf20Sopenharmony_ci	usb_lock_port(port_dev);
62228c2ecf20Sopenharmony_ci	ret = usb_reset_and_verify_device(udev);
62238c2ecf20Sopenharmony_ci	usb_unlock_port(port_dev);
62248c2ecf20Sopenharmony_ci
62258c2ecf20Sopenharmony_ci	if (config) {
62268c2ecf20Sopenharmony_ci		for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
62278c2ecf20Sopenharmony_ci			struct usb_interface *cintf = config->interface[i];
62288c2ecf20Sopenharmony_ci			struct usb_driver *drv;
62298c2ecf20Sopenharmony_ci			int rebind = cintf->needs_binding;
62308c2ecf20Sopenharmony_ci
62318c2ecf20Sopenharmony_ci			if (!rebind && cintf->dev.driver) {
62328c2ecf20Sopenharmony_ci				drv = to_usb_driver(cintf->dev.driver);
62338c2ecf20Sopenharmony_ci				if (drv->post_reset)
62348c2ecf20Sopenharmony_ci					rebind = (drv->post_reset)(cintf);
62358c2ecf20Sopenharmony_ci				else if (cintf->condition ==
62368c2ecf20Sopenharmony_ci						USB_INTERFACE_BOUND)
62378c2ecf20Sopenharmony_ci					rebind = 1;
62388c2ecf20Sopenharmony_ci				if (rebind)
62398c2ecf20Sopenharmony_ci					cintf->needs_binding = 1;
62408c2ecf20Sopenharmony_ci			}
62418c2ecf20Sopenharmony_ci		}
62428c2ecf20Sopenharmony_ci
62438c2ecf20Sopenharmony_ci		/* If the reset failed, hub_wq will unbind drivers later */
62448c2ecf20Sopenharmony_ci		if (ret == 0)
62458c2ecf20Sopenharmony_ci			usb_unbind_and_rebind_marked_interfaces(udev);
62468c2ecf20Sopenharmony_ci	}
62478c2ecf20Sopenharmony_ci
62488c2ecf20Sopenharmony_ci	usb_autosuspend_device(udev);
62498c2ecf20Sopenharmony_ci	memalloc_noio_restore(noio_flag);
62508c2ecf20Sopenharmony_ci	udev->reset_in_progress = 0;
62518c2ecf20Sopenharmony_ci	return ret;
62528c2ecf20Sopenharmony_ci}
62538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_reset_device);
62548c2ecf20Sopenharmony_ci
62558c2ecf20Sopenharmony_ci
62568c2ecf20Sopenharmony_ci/**
62578c2ecf20Sopenharmony_ci * usb_queue_reset_device - Reset a USB device from an atomic context
62588c2ecf20Sopenharmony_ci * @iface: USB interface belonging to the device to reset
62598c2ecf20Sopenharmony_ci *
62608c2ecf20Sopenharmony_ci * This function can be used to reset a USB device from an atomic
62618c2ecf20Sopenharmony_ci * context, where usb_reset_device() won't work (as it blocks).
62628c2ecf20Sopenharmony_ci *
62638c2ecf20Sopenharmony_ci * Doing a reset via this method is functionally equivalent to calling
62648c2ecf20Sopenharmony_ci * usb_reset_device(), except for the fact that it is delayed to a
62658c2ecf20Sopenharmony_ci * workqueue. This means that any drivers bound to other interfaces
62668c2ecf20Sopenharmony_ci * might be unbound, as well as users from usbfs in user space.
62678c2ecf20Sopenharmony_ci *
62688c2ecf20Sopenharmony_ci * Corner cases:
62698c2ecf20Sopenharmony_ci *
62708c2ecf20Sopenharmony_ci * - Scheduling two resets at the same time from two different drivers
62718c2ecf20Sopenharmony_ci *   attached to two different interfaces of the same device is
62728c2ecf20Sopenharmony_ci *   possible; depending on how the driver attached to each interface
62738c2ecf20Sopenharmony_ci *   handles ->pre_reset(), the second reset might happen or not.
62748c2ecf20Sopenharmony_ci *
62758c2ecf20Sopenharmony_ci * - If the reset is delayed so long that the interface is unbound from
62768c2ecf20Sopenharmony_ci *   its driver, the reset will be skipped.
62778c2ecf20Sopenharmony_ci *
62788c2ecf20Sopenharmony_ci * - This function can be called during .probe().  It can also be called
62798c2ecf20Sopenharmony_ci *   during .disconnect(), but doing so is pointless because the reset
62808c2ecf20Sopenharmony_ci *   will not occur.  If you really want to reset the device during
62818c2ecf20Sopenharmony_ci *   .disconnect(), call usb_reset_device() directly -- but watch out
62828c2ecf20Sopenharmony_ci *   for nested unbinding issues!
62838c2ecf20Sopenharmony_ci */
62848c2ecf20Sopenharmony_civoid usb_queue_reset_device(struct usb_interface *iface)
62858c2ecf20Sopenharmony_ci{
62868c2ecf20Sopenharmony_ci	if (schedule_work(&iface->reset_ws))
62878c2ecf20Sopenharmony_ci		usb_get_intf(iface);
62888c2ecf20Sopenharmony_ci}
62898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_queue_reset_device);
62908c2ecf20Sopenharmony_ci
62918c2ecf20Sopenharmony_ci/**
62928c2ecf20Sopenharmony_ci * usb_hub_find_child - Get the pointer of child device
62938c2ecf20Sopenharmony_ci * attached to the port which is specified by @port1.
62948c2ecf20Sopenharmony_ci * @hdev: USB device belonging to the usb hub
62958c2ecf20Sopenharmony_ci * @port1: port num to indicate which port the child device
62968c2ecf20Sopenharmony_ci *	is attached to.
62978c2ecf20Sopenharmony_ci *
62988c2ecf20Sopenharmony_ci * USB drivers call this function to get hub's child device
62998c2ecf20Sopenharmony_ci * pointer.
63008c2ecf20Sopenharmony_ci *
63018c2ecf20Sopenharmony_ci * Return: %NULL if input param is invalid and
63028c2ecf20Sopenharmony_ci * child's usb_device pointer if non-NULL.
63038c2ecf20Sopenharmony_ci */
63048c2ecf20Sopenharmony_cistruct usb_device *usb_hub_find_child(struct usb_device *hdev,
63058c2ecf20Sopenharmony_ci		int port1)
63068c2ecf20Sopenharmony_ci{
63078c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
63088c2ecf20Sopenharmony_ci
63098c2ecf20Sopenharmony_ci	if (port1 < 1 || port1 > hdev->maxchild)
63108c2ecf20Sopenharmony_ci		return NULL;
63118c2ecf20Sopenharmony_ci	return hub->ports[port1 - 1]->child;
63128c2ecf20Sopenharmony_ci}
63138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_hub_find_child);
63148c2ecf20Sopenharmony_ci
63158c2ecf20Sopenharmony_civoid usb_hub_adjust_deviceremovable(struct usb_device *hdev,
63168c2ecf20Sopenharmony_ci		struct usb_hub_descriptor *desc)
63178c2ecf20Sopenharmony_ci{
63188c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
63198c2ecf20Sopenharmony_ci	enum usb_port_connect_type connect_type;
63208c2ecf20Sopenharmony_ci	int i;
63218c2ecf20Sopenharmony_ci
63228c2ecf20Sopenharmony_ci	if (!hub)
63238c2ecf20Sopenharmony_ci		return;
63248c2ecf20Sopenharmony_ci
63258c2ecf20Sopenharmony_ci	if (!hub_is_superspeed(hdev)) {
63268c2ecf20Sopenharmony_ci		for (i = 1; i <= hdev->maxchild; i++) {
63278c2ecf20Sopenharmony_ci			struct usb_port *port_dev = hub->ports[i - 1];
63288c2ecf20Sopenharmony_ci
63298c2ecf20Sopenharmony_ci			connect_type = port_dev->connect_type;
63308c2ecf20Sopenharmony_ci			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
63318c2ecf20Sopenharmony_ci				u8 mask = 1 << (i%8);
63328c2ecf20Sopenharmony_ci
63338c2ecf20Sopenharmony_ci				if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) {
63348c2ecf20Sopenharmony_ci					dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");
63358c2ecf20Sopenharmony_ci					desc->u.hs.DeviceRemovable[i/8]	|= mask;
63368c2ecf20Sopenharmony_ci				}
63378c2ecf20Sopenharmony_ci			}
63388c2ecf20Sopenharmony_ci		}
63398c2ecf20Sopenharmony_ci	} else {
63408c2ecf20Sopenharmony_ci		u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable);
63418c2ecf20Sopenharmony_ci
63428c2ecf20Sopenharmony_ci		for (i = 1; i <= hdev->maxchild; i++) {
63438c2ecf20Sopenharmony_ci			struct usb_port *port_dev = hub->ports[i - 1];
63448c2ecf20Sopenharmony_ci
63458c2ecf20Sopenharmony_ci			connect_type = port_dev->connect_type;
63468c2ecf20Sopenharmony_ci			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
63478c2ecf20Sopenharmony_ci				u16 mask = 1 << i;
63488c2ecf20Sopenharmony_ci
63498c2ecf20Sopenharmony_ci				if (!(port_removable & mask)) {
63508c2ecf20Sopenharmony_ci					dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");
63518c2ecf20Sopenharmony_ci					port_removable |= mask;
63528c2ecf20Sopenharmony_ci				}
63538c2ecf20Sopenharmony_ci			}
63548c2ecf20Sopenharmony_ci		}
63558c2ecf20Sopenharmony_ci
63568c2ecf20Sopenharmony_ci		desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable);
63578c2ecf20Sopenharmony_ci	}
63588c2ecf20Sopenharmony_ci}
63598c2ecf20Sopenharmony_ci
63608c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
63618c2ecf20Sopenharmony_ci/**
63628c2ecf20Sopenharmony_ci * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
63638c2ecf20Sopenharmony_ci * @hdev: USB device belonging to the usb hub
63648c2ecf20Sopenharmony_ci * @port1: port num of the port
63658c2ecf20Sopenharmony_ci *
63668c2ecf20Sopenharmony_ci * Return: Port's acpi handle if successful, %NULL if params are
63678c2ecf20Sopenharmony_ci * invalid.
63688c2ecf20Sopenharmony_ci */
63698c2ecf20Sopenharmony_ciacpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
63708c2ecf20Sopenharmony_ci	int port1)
63718c2ecf20Sopenharmony_ci{
63728c2ecf20Sopenharmony_ci	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
63738c2ecf20Sopenharmony_ci
63748c2ecf20Sopenharmony_ci	if (!hub)
63758c2ecf20Sopenharmony_ci		return NULL;
63768c2ecf20Sopenharmony_ci
63778c2ecf20Sopenharmony_ci	return ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
63788c2ecf20Sopenharmony_ci}
63798c2ecf20Sopenharmony_ci#endif
6380