Merge tag 'usb-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB updates from Greg KH: "Here is the big USB drivers update for 4.5-rc1. Lots of gadget driver updates and fixes, like usual, and a mix of other USB driver updates as well. Full details in the shortlog. All of these have been in linux-next for a while" * tag 'usb-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (191 commits) MAINTAINERS: change my email address USB: usbmon: remove assignment from IS_ERR argument USB: mxu11x0: drop redundant function name from error messages USB: mxu11x0: fix debug-message typos USB: mxu11x0: rename usb-serial driver USB: mxu11x0: fix modem-control handling on B0-transitions USB: mxu11x0: fix memory leak on firmware download USB: mxu11x0: fix memory leak in port-probe error path USB: serial: add Moxa UPORT 11x0 driver USB: cp210x: add ID for ELV Marble Sound Board 1 usb: chipidea: otg: use usb autosuspend to suspend bus for HNP usb: chipidea: host: set host to be null after hcd is freed usb: chipidea: removing of_find_property usb: chipidea: implement platform shutdown callback usb: chipidea: clean up CONFIG_USB_CHIPIDEA_DEBUG reference usb: chipidea: delete static debug support usb: chipidea: support debugfs without CONFIG_USB_CHIPIDEA_DEBUG usb: chipidea: udc: improve error handling on _hardware_enqueue usb: chipidea: udc: _ep_queue and _hw_queue cleanup usb: dwc3: of-simple: fix build warning on !PM ...
This commit is contained in:
@@ -100,6 +100,11 @@ static bool usbfs_snoop;
|
||||
module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
|
||||
|
||||
static unsigned usbfs_snoop_max = 65536;
|
||||
module_param(usbfs_snoop_max, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(usbfs_snoop_max,
|
||||
"maximum number of bytes to print while snooping");
|
||||
|
||||
#define snoop(dev, format, arg...) \
|
||||
do { \
|
||||
if (usbfs_snoop) \
|
||||
@@ -368,6 +373,7 @@ static void snoop_urb(struct usb_device *udev,
|
||||
ep, t, d, length, timeout_or_status);
|
||||
}
|
||||
|
||||
data_len = min(data_len, usbfs_snoop_max);
|
||||
if (data && data_len > 0) {
|
||||
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
|
||||
data, data_len, 1);
|
||||
@@ -378,7 +384,8 @@ static void snoop_urb_data(struct urb *urb, unsigned len)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
if (!usbfs_snoop)
|
||||
len = min(len, usbfs_snoop_max);
|
||||
if (!usbfs_snoop || len == 0)
|
||||
return;
|
||||
|
||||
if (urb->num_sgs == 0) {
|
||||
@@ -1685,8 +1692,12 @@ static struct async *reap_as(struct usb_dev_state *ps)
|
||||
static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
|
||||
{
|
||||
struct async *as = reap_as(ps);
|
||||
|
||||
if (as) {
|
||||
int retval = processcompl(as, (void __user * __user *)arg);
|
||||
int retval;
|
||||
|
||||
snoop(&ps->dev->dev, "reap %p\n", as->userurb);
|
||||
retval = processcompl(as, (void __user * __user *)arg);
|
||||
free_async(as);
|
||||
return retval;
|
||||
}
|
||||
@@ -1702,6 +1713,7 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
|
||||
|
||||
as = async_getcompleted(ps);
|
||||
if (as) {
|
||||
snoop(&ps->dev->dev, "reap %p\n", as->userurb);
|
||||
retval = processcompl(as, (void __user * __user *)arg);
|
||||
free_async(as);
|
||||
} else {
|
||||
@@ -1828,8 +1840,12 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
|
||||
static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
|
||||
{
|
||||
struct async *as = reap_as(ps);
|
||||
|
||||
if (as) {
|
||||
int retval = processcompl_compat(as, (void __user * __user *)arg);
|
||||
int retval;
|
||||
|
||||
snoop(&ps->dev->dev, "reap %p\n", as->userurb);
|
||||
retval = processcompl_compat(as, (void __user * __user *)arg);
|
||||
free_async(as);
|
||||
return retval;
|
||||
}
|
||||
@@ -1845,6 +1861,7 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
|
||||
|
||||
as = async_getcompleted(ps);
|
||||
if (as) {
|
||||
snoop(&ps->dev->dev, "reap %p\n", as->userurb);
|
||||
retval = processcompl_compat(as, (void __user * __user *)arg);
|
||||
free_async(as);
|
||||
} else {
|
||||
@@ -2249,7 +2266,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
||||
#endif
|
||||
|
||||
case USBDEVFS_DISCARDURB:
|
||||
snoop(&dev->dev, "%s: DISCARDURB\n", __func__);
|
||||
snoop(&dev->dev, "%s: DISCARDURB %p\n", __func__, p);
|
||||
ret = proc_unlinkurb(ps, p);
|
||||
break;
|
||||
|
||||
|
@@ -3000,7 +3000,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
|
||||
|
||||
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
|
||||
|
||||
struct usb_mon_operations *mon_ops;
|
||||
const struct usb_mon_operations *mon_ops;
|
||||
|
||||
/*
|
||||
* The registration is unlocked.
|
||||
@@ -3010,7 +3010,7 @@ struct usb_mon_operations *mon_ops;
|
||||
* symbols from usbcore, usbcore gets referenced and cannot be unloaded first.
|
||||
*/
|
||||
|
||||
int usb_mon_register (struct usb_mon_operations *ops)
|
||||
int usb_mon_register(const struct usb_mon_operations *ops)
|
||||
{
|
||||
|
||||
if (mon_ops)
|
||||
|
@@ -3324,7 +3324,7 @@ static int finish_port_resume(struct usb_device *udev)
|
||||
/*
|
||||
* There are some SS USB devices which take longer time for link training.
|
||||
* XHCI specs 4.19.4 says that when Link training is successful, port
|
||||
* sets CSC bit to 1. So if SW reads port status before successful link
|
||||
* sets CCS bit to 1. So if SW reads port status before successful link
|
||||
* training, then it will not find device to be present.
|
||||
* USB Analyzer log with such buggy devices show that in some cases
|
||||
* device switch on the RX termination after long delay of host enabling
|
||||
@@ -3335,14 +3335,17 @@ static int finish_port_resume(struct usb_device *udev)
|
||||
* routine implements a 2000 ms timeout for link training. If in a case
|
||||
* link trains before timeout, loop will exit earlier.
|
||||
*
|
||||
* There are also some 2.0 hard drive based devices and 3.0 thumb
|
||||
* drives that, when plugged into a 2.0 only port, take a long
|
||||
* time to set CCS after VBUS enable.
|
||||
*
|
||||
* FIXME: If a device was connected before suspend, but was removed
|
||||
* while system was asleep, then the loop in the following routine will
|
||||
* only exit at timeout.
|
||||
*
|
||||
* This routine should only be called when persist is enabled for a SS
|
||||
* device.
|
||||
* This routine should only be called when persist is enabled.
|
||||
*/
|
||||
static int wait_for_ss_port_enable(struct usb_device *udev,
|
||||
static int wait_for_connected(struct usb_device *udev,
|
||||
struct usb_hub *hub, int *port1,
|
||||
u16 *portchange, u16 *portstatus)
|
||||
{
|
||||
@@ -3355,6 +3358,7 @@ static int wait_for_ss_port_enable(struct usb_device *udev,
|
||||
delay_ms += 20;
|
||||
status = hub_port_status(hub, *port1, portstatus, portchange);
|
||||
}
|
||||
dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -3454,8 +3458,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
||||
}
|
||||
}
|
||||
|
||||
if (udev->persist_enabled && hub_is_superspeed(hub->hdev))
|
||||
status = wait_for_ss_port_enable(udev, hub, &port1, &portchange,
|
||||
if (udev->persist_enabled)
|
||||
status = wait_for_connected(udev, hub, &port1, &portchange,
|
||||
&portstatus);
|
||||
|
||||
status = check_port_resume_type(udev,
|
||||
@@ -3895,17 +3899,30 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_set_lpm_timeout(udev, state, timeout))
|
||||
if (usb_set_lpm_timeout(udev, state, timeout)) {
|
||||
/* If we can't set the parent hub U1/U2 timeout,
|
||||
* device-initiated LPM won't be allowed either, so let the xHCI
|
||||
* host know that this link state won't be enabled.
|
||||
*/
|
||||
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
|
||||
} else {
|
||||
/* Only a configured device will accept the Set Feature
|
||||
* U1/U2_ENABLE
|
||||
*/
|
||||
if (udev->actconfig)
|
||||
usb_set_device_initiated_lpm(udev, state, true);
|
||||
|
||||
/* Only a configured device will accept the Set Feature U1/U2_ENABLE */
|
||||
else if (udev->actconfig)
|
||||
usb_set_device_initiated_lpm(udev, state, true);
|
||||
|
||||
/* As soon as usb_set_lpm_timeout(timeout) returns 0, the
|
||||
* hub-initiated LPM is enabled. Thus, LPM is enabled no
|
||||
* matter the result of usb_set_device_initiated_lpm().
|
||||
* The only difference is whether device is able to initiate
|
||||
* LPM.
|
||||
*/
|
||||
if (state == USB3_LPM_U1)
|
||||
udev->usb3_lpm_u1_enabled = 1;
|
||||
else if (state == USB3_LPM_U2)
|
||||
udev->usb3_lpm_u2_enabled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3945,6 +3962,18 @@ static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
|
||||
"bus schedule bandwidth may be impacted.\n",
|
||||
usb3_lpm_names[state]);
|
||||
|
||||
/* As soon as usb_set_lpm_timeout(0) return 0, hub initiated LPM
|
||||
* is disabled. Hub will disallows link to enter U1/U2 as well,
|
||||
* even device is initiating LPM. Hence LPM is disabled if hub LPM
|
||||
* timeout set to 0, no matter device-initiated LPM is disabled or
|
||||
* not.
|
||||
*/
|
||||
if (state == USB3_LPM_U1)
|
||||
udev->usb3_lpm_u1_enabled = 0;
|
||||
else if (state == USB3_LPM_U2)
|
||||
udev->usb3_lpm_u2_enabled = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3979,8 +4008,6 @@ int usb_disable_lpm(struct usb_device *udev)
|
||||
if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
|
||||
goto enable_lpm;
|
||||
|
||||
udev->usb3_lpm_enabled = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
enable_lpm:
|
||||
@@ -4017,6 +4044,8 @@ EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
|
||||
void usb_enable_lpm(struct usb_device *udev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct usb_hub *hub;
|
||||
struct usb_port *port_dev;
|
||||
|
||||
if (!udev || !udev->parent ||
|
||||
udev->speed != USB_SPEED_SUPER ||
|
||||
@@ -4036,10 +4065,17 @@ void usb_enable_lpm(struct usb_device *udev)
|
||||
if (udev->lpm_disable_count > 0)
|
||||
return;
|
||||
|
||||
usb_enable_link_state(hcd, udev, USB3_LPM_U1);
|
||||
usb_enable_link_state(hcd, udev, USB3_LPM_U2);
|
||||
hub = usb_hub_to_struct_hub(udev->parent);
|
||||
if (!hub)
|
||||
return;
|
||||
|
||||
udev->usb3_lpm_enabled = 1;
|
||||
port_dev = hub->ports[udev->portnum - 1];
|
||||
|
||||
if (port_dev->usb3_lpm_u1_permit)
|
||||
usb_enable_link_state(hcd, udev, USB3_LPM_U1);
|
||||
|
||||
if (port_dev->usb3_lpm_u2_permit)
|
||||
usb_enable_link_state(hcd, udev, USB3_LPM_U2);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_enable_lpm);
|
||||
|
||||
|
@@ -92,6 +92,8 @@ struct usb_hub {
|
||||
* @status_lock: synchronize port_event() vs usb_port_{suspend|resume}
|
||||
* @portnum: port index num based one
|
||||
* @is_superspeed cache super-speed status
|
||||
* @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
|
||||
* @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
|
||||
*/
|
||||
struct usb_port {
|
||||
struct usb_device *child;
|
||||
@@ -104,6 +106,8 @@ struct usb_port {
|
||||
struct mutex status_lock;
|
||||
u8 portnum;
|
||||
unsigned int is_superspeed:1;
|
||||
unsigned int usb3_lpm_u1_permit:1;
|
||||
unsigned int usb3_lpm_u2_permit:1;
|
||||
};
|
||||
|
||||
#define to_usb_port(_dev) \
|
||||
@@ -155,4 +159,3 @@ static inline int hub_port_debounce_be_stable(struct usb_hub *hub,
|
||||
{
|
||||
return hub_port_debounce(hub, port1, false);
|
||||
}
|
||||
|
||||
|
@@ -50,6 +50,72 @@ static ssize_t connect_type_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(connect_type);
|
||||
|
||||
static ssize_t usb3_lpm_permit_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
const char *p;
|
||||
|
||||
if (port_dev->usb3_lpm_u1_permit) {
|
||||
if (port_dev->usb3_lpm_u2_permit)
|
||||
p = "u1_u2";
|
||||
else
|
||||
p = "u1";
|
||||
} else {
|
||||
if (port_dev->usb3_lpm_u2_permit)
|
||||
p = "u2";
|
||||
else
|
||||
p = "0";
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", p);
|
||||
}
|
||||
|
||||
static ssize_t usb3_lpm_permit_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
struct usb_device *udev = port_dev->child;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
if (!strncmp(buf, "u1_u2", 5)) {
|
||||
port_dev->usb3_lpm_u1_permit = 1;
|
||||
port_dev->usb3_lpm_u2_permit = 1;
|
||||
|
||||
} else if (!strncmp(buf, "u1", 2)) {
|
||||
port_dev->usb3_lpm_u1_permit = 1;
|
||||
port_dev->usb3_lpm_u2_permit = 0;
|
||||
|
||||
} else if (!strncmp(buf, "u2", 2)) {
|
||||
port_dev->usb3_lpm_u1_permit = 0;
|
||||
port_dev->usb3_lpm_u2_permit = 1;
|
||||
|
||||
} else if (!strncmp(buf, "0", 1)) {
|
||||
port_dev->usb3_lpm_u1_permit = 0;
|
||||
port_dev->usb3_lpm_u2_permit = 0;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
/* If device is connected to the port, disable or enable lpm
|
||||
* to make new u1 u2 setting take effect immediately.
|
||||
*/
|
||||
if (udev) {
|
||||
hcd = bus_to_hcd(udev->bus);
|
||||
if (!hcd)
|
||||
return -EINVAL;
|
||||
usb_lock_device(udev);
|
||||
mutex_lock(hcd->bandwidth_mutex);
|
||||
if (!usb_disable_lpm(udev))
|
||||
usb_enable_lpm(udev);
|
||||
mutex_unlock(hcd->bandwidth_mutex);
|
||||
usb_unlock_device(udev);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(usb3_lpm_permit);
|
||||
|
||||
static struct attribute *port_dev_attrs[] = {
|
||||
&dev_attr_connect_type.attr,
|
||||
NULL,
|
||||
@@ -64,6 +130,21 @@ static const struct attribute_group *port_dev_group[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *port_dev_usb3_attrs[] = {
|
||||
&dev_attr_usb3_lpm_permit.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group port_dev_usb3_attr_grp = {
|
||||
.attrs = port_dev_usb3_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *port_dev_usb3_group[] = {
|
||||
&port_dev_attr_grp,
|
||||
&port_dev_usb3_attr_grp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void usb_port_device_release(struct device *dev)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
@@ -401,6 +482,7 @@ static void find_and_link_peer(struct usb_hub *hub, int port1)
|
||||
int usb_hub_create_port_device(struct usb_hub *hub, int port1)
|
||||
{
|
||||
struct usb_port *port_dev;
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int retval;
|
||||
|
||||
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
|
||||
@@ -417,7 +499,12 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
|
||||
port_dev->portnum = port1;
|
||||
set_bit(port1, hub->power_bits);
|
||||
port_dev->dev.parent = hub->intfdev;
|
||||
port_dev->dev.groups = port_dev_group;
|
||||
if (hub_is_superspeed(hdev)) {
|
||||
port_dev->usb3_lpm_u1_permit = 1;
|
||||
port_dev->usb3_lpm_u2_permit = 1;
|
||||
port_dev->dev.groups = port_dev_usb3_group;
|
||||
} else
|
||||
port_dev->dev.groups = port_dev_group;
|
||||
port_dev->dev.type = &usb_port_device_type;
|
||||
port_dev->dev.driver = &usb_port_driver;
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
|
@@ -531,7 +531,7 @@ static ssize_t usb2_lpm_besl_store(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RW(usb2_lpm_besl);
|
||||
|
||||
static ssize_t usb3_hardware_lpm_show(struct device *dev,
|
||||
static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
@@ -539,7 +539,7 @@ static ssize_t usb3_hardware_lpm_show(struct device *dev,
|
||||
|
||||
usb_lock_device(udev);
|
||||
|
||||
if (udev->usb3_lpm_enabled)
|
||||
if (udev->usb3_lpm_u1_enabled)
|
||||
p = "enabled";
|
||||
else
|
||||
p = "disabled";
|
||||
@@ -548,7 +548,26 @@ static ssize_t usb3_hardware_lpm_show(struct device *dev,
|
||||
|
||||
return sprintf(buf, "%s\n", p);
|
||||
}
|
||||
static DEVICE_ATTR_RO(usb3_hardware_lpm);
|
||||
static DEVICE_ATTR_RO(usb3_hardware_lpm_u1);
|
||||
|
||||
static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
const char *p;
|
||||
|
||||
usb_lock_device(udev);
|
||||
|
||||
if (udev->usb3_lpm_u2_enabled)
|
||||
p = "enabled";
|
||||
else
|
||||
p = "disabled";
|
||||
|
||||
usb_unlock_device(udev);
|
||||
|
||||
return sprintf(buf, "%s\n", p);
|
||||
}
|
||||
static DEVICE_ATTR_RO(usb3_hardware_lpm_u2);
|
||||
|
||||
static struct attribute *usb2_hardware_lpm_attr[] = {
|
||||
&dev_attr_usb2_hardware_lpm.attr,
|
||||
@@ -562,7 +581,8 @@ static struct attribute_group usb2_hardware_lpm_attr_group = {
|
||||
};
|
||||
|
||||
static struct attribute *usb3_hardware_lpm_attr[] = {
|
||||
&dev_attr_usb3_hardware_lpm.attr,
|
||||
&dev_attr_usb3_hardware_lpm_u1.attr,
|
||||
&dev_attr_usb3_hardware_lpm_u2.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group usb3_hardware_lpm_attr_group = {
|
||||
@@ -592,7 +612,8 @@ static int add_power_attributes(struct device *dev)
|
||||
if (udev->usb2_hw_lpm_capable == 1)
|
||||
rc = sysfs_merge_group(&dev->kobj,
|
||||
&usb2_hardware_lpm_attr_group);
|
||||
if (udev->lpm_capable == 1)
|
||||
if (udev->speed == USB_SPEED_SUPER &&
|
||||
udev->lpm_capable == 1)
|
||||
rc = sysfs_merge_group(&dev->kobj,
|
||||
&usb3_hardware_lpm_attr_group);
|
||||
}
|
||||
|
@@ -49,12 +49,7 @@ const char *usbcore_name = "usbcore";
|
||||
|
||||
static bool nousb; /* Disable USB when built into kernel image */
|
||||
|
||||
/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
|
||||
#ifdef MODULE
|
||||
module_param(nousb, bool, 0444);
|
||||
#else
|
||||
core_param(nousb, nousb, bool, 0444);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* for external read access to <nousb>
|
||||
|
Reference in New Issue
Block a user