Skip to content

Commit aea7c84

Browse files
committed
Merge tag 'usb-7.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/Thunderbolt fixes from Greg KH: "Here are a bunch of USB and Thunderbolt fixes (most all are USB) for 7.0-rc7. More than I normally like this late in the release cycle, partly due to my recent travels, and partly due to people banging away on the USB gadget interfaces and apis more than normal (big shoutout to Android for getting the vendors to actually work upstream on this, that's a huge win overall for everyone here) Included in here are: - Small thunderbolt fix - new USB serial driver ids added - typec driver fixes - gadget driver fixes for some disconnect issues - other usb gadget driver fixes for reported problems with binding and unbinding devices as happens when a gadget device connects / disconnects from a system it is plugged into (or it switches device mode at a user's request, these things are complex little beasts...) - usb offload fixes (where USB audio tunnels through the controller while the main CPU is asleep) for when EMP spikes hit the system causing disconnects to happen (as often happens with static electricity in the winter months). This has been much reported by at least one vendor, and resolves the issues they have been seeing with this codepath. Can't wait for the "formal methods are the answer!" people to try to model that one properly... - Other small usb driver fixes for issues reported. All of these have been in linux-next this week, and before, with no reported issues, and I've personally been stressing these harder than normal on my systems here with no problems" * tag 'usb-7.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (39 commits) usb: gadget: f_hid: move list and spinlock inits from bind to alloc usb: host: xhci-sideband: delegate offload_usage tracking to class drivers usb: core: use dedicated spinlock for offload state usb: cdns3: gadget: fix state inconsistency on gadget init failure usb: dwc3: imx8mp: fix memory leak on probe failure path usb: gadget: f_uac1_legacy: validate control request size usb: ulpi: fix double free in ulpi_register_interface() error path usb: misc: usbio: Fix URB memory leak on submit failure USB: core: add NO_LPM quirk for Razer Kiyo Pro webcam usb: cdns3: gadget: fix NULL pointer dereference in ep_queue usb: core: phy: avoid double use of 'usb3-phy' USB: serial: option: add MeiG Smart SRM825WN usb: gadget: f_rndis: Fix net_device lifecycle with device_move usb: gadget: f_subset: Fix net_device lifecycle with device_move usb: gadget: f_eem: Fix net_device lifecycle with device_move usb: gadget: f_ecm: Fix net_device lifecycle with device_move usb: gadget: u_ncm: Add kernel-doc comments for struct f_ncm_opts usb: gadget: f_rndis: Protect RNDIS options with mutex usb: gadget: f_subset: Fix unbalanced refcnt in geth_free dt-bindings: connector: add pd-disable dependency ...
2 parents 3aae938 + bf3781a commit aea7c84

43 files changed

Lines changed: 509 additions & 279 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Documentation/devicetree/bindings/connector/usb-connector.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ properties:
301301
maxItems: 4
302302

303303
dependencies:
304+
pd-disable: [typec-power-opmode]
304305
sink-vdos-v1: [ sink-vdos ]
305306
sink-vdos: [ sink-vdos-v1 ]
306307

drivers/thunderbolt/nhi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ static bool nhi_wake_supported(struct pci_dev *pdev)
10201020
* If power rails are sustainable for wakeup from S4 this
10211021
* property is set by the BIOS.
10221022
*/
1023-
if (device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
1023+
if (!device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
10241024
return !!val;
10251025

10261026
return true;

drivers/usb/cdns3/cdns3-gadget.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2589,6 +2589,9 @@ static int __cdns3_gadget_ep_queue(struct usb_ep *ep,
25892589
struct cdns3_request *priv_req;
25902590
int ret = 0;
25912591

2592+
if (!ep->desc)
2593+
return -ESHUTDOWN;
2594+
25922595
request->actual = 0;
25932596
request->status = -EINPROGRESS;
25942597
priv_req = to_cdns3_request(request);
@@ -3428,6 +3431,7 @@ static int __cdns3_gadget_init(struct cdns *cdns)
34283431
ret = cdns3_gadget_start(cdns);
34293432
if (ret) {
34303433
pm_runtime_put_sync(cdns->dev);
3434+
cdns_drd_gadget_off(cdns);
34313435
return ret;
34323436
}
34333437

drivers/usb/class/cdc-acm.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,12 @@ static int acm_probe(struct usb_interface *intf,
12251225
if (!data_interface || !control_interface)
12261226
return -ENODEV;
12271227
goto skip_normal_probe;
1228+
} else if (quirks == NO_UNION_12) {
1229+
data_interface = usb_ifnum_to_if(usb_dev, 2);
1230+
control_interface = usb_ifnum_to_if(usb_dev, 1);
1231+
if (!data_interface || !control_interface)
1232+
return -ENODEV;
1233+
goto skip_normal_probe;
12281234
}
12291235

12301236
/* normal probing*/
@@ -1748,6 +1754,9 @@ static const struct usb_device_id acm_ids[] = {
17481754
{ USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */
17491755
.driver_info = DISABLE_ECHO, /* Don't echo banner */
17501756
},
1757+
{ USB_DEVICE(0x04b8, 0x0d12), /* EPSON HMD Com&Sens */
1758+
.driver_info = NO_UNION_12, /* union descriptor is garbage */
1759+
},
17511760
{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
17521761
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
17531762
},

drivers/usb/class/cdc-acm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,4 @@ struct acm {
114114
#define SEND_ZERO_PACKET BIT(6)
115115
#define DISABLE_ECHO BIT(7)
116116
#define MISSING_CAP_BRK BIT(8)
117+
#define NO_UNION_12 BIT(9)

drivers/usb/class/usbtmc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ static int usbtmc_release(struct inode *inode, struct file *file)
254254
list_del(&file_data->file_elem);
255255

256256
spin_unlock_irq(&file_data->data->dev_lock);
257+
258+
/* flush anchored URBs */
259+
usbtmc_draw_down(file_data);
257260
mutex_unlock(&file_data->data->io_mutex);
258261

259262
kref_put(&file_data->data->kref, usbtmc_delete);

drivers/usb/common/ulpi.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,9 @@ struct ulpi *ulpi_register_interface(struct device *dev,
331331
ulpi->ops = ops;
332332

333333
ret = ulpi_register(dev, ulpi);
334-
if (ret) {
335-
kfree(ulpi);
334+
if (ret)
336335
return ERR_PTR(ret);
337-
}
336+
338337

339338
return ulpi;
340339
}

drivers/usb/core/driver.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,14 +1415,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
14151415
int status = 0;
14161416
int i = 0, n = 0;
14171417
struct usb_interface *intf;
1418+
bool offload_active = false;
14181419

14191420
if (udev->state == USB_STATE_NOTATTACHED ||
14201421
udev->state == USB_STATE_SUSPENDED)
14211422
goto done;
14221423

1424+
usb_offload_set_pm_locked(udev, true);
14231425
if (msg.event == PM_EVENT_SUSPEND && usb_offload_check(udev)) {
14241426
dev_dbg(&udev->dev, "device offloaded, skip suspend.\n");
1425-
udev->offload_at_suspend = 1;
1427+
offload_active = true;
14261428
}
14271429

14281430
/* Suspend all the interfaces and then udev itself */
@@ -1436,8 +1438,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
14361438
* interrupt urbs, allowing interrupt events to be
14371439
* handled during system suspend.
14381440
*/
1439-
if (udev->offload_at_suspend &&
1440-
intf->needs_remote_wakeup) {
1441+
if (offload_active && intf->needs_remote_wakeup) {
14411442
dev_dbg(&intf->dev,
14421443
"device offloaded, skip suspend.\n");
14431444
continue;
@@ -1452,7 +1453,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
14521453
}
14531454
}
14541455
if (status == 0) {
1455-
if (!udev->offload_at_suspend)
1456+
if (!offload_active)
14561457
status = usb_suspend_device(udev, msg);
14571458

14581459
/*
@@ -1498,7 +1499,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
14981499
*/
14991500
} else {
15001501
udev->can_submit = 0;
1501-
if (!udev->offload_at_suspend) {
1502+
if (!offload_active) {
15021503
for (i = 0; i < 16; ++i) {
15031504
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
15041505
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
@@ -1507,6 +1508,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
15071508
}
15081509

15091510
done:
1511+
if (status != 0)
1512+
usb_offload_set_pm_locked(udev, false);
15101513
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
15111514
return status;
15121515
}
@@ -1536,16 +1539,19 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
15361539
int status = 0;
15371540
int i;
15381541
struct usb_interface *intf;
1542+
bool offload_active = false;
15391543

15401544
if (udev->state == USB_STATE_NOTATTACHED) {
15411545
status = -ENODEV;
15421546
goto done;
15431547
}
15441548
udev->can_submit = 1;
1549+
if (msg.event == PM_EVENT_RESUME)
1550+
offload_active = usb_offload_check(udev);
15451551

15461552
/* Resume the device */
15471553
if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume) {
1548-
if (!udev->offload_at_suspend)
1554+
if (!offload_active)
15491555
status = usb_resume_device(udev, msg);
15501556
else
15511557
dev_dbg(&udev->dev,
@@ -1562,8 +1568,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
15621568
* pending interrupt urbs, allowing interrupt events
15631569
* to be handled during system suspend.
15641570
*/
1565-
if (udev->offload_at_suspend &&
1566-
intf->needs_remote_wakeup) {
1571+
if (offload_active && intf->needs_remote_wakeup) {
15671572
dev_dbg(&intf->dev,
15681573
"device offloaded, skip resume.\n");
15691574
continue;
@@ -1572,11 +1577,11 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
15721577
udev->reset_resume);
15731578
}
15741579
}
1575-
udev->offload_at_suspend = 0;
15761580
usb_mark_last_busy(udev);
15771581

15781582
done:
15791583
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
1584+
usb_offload_set_pm_locked(udev, false);
15801585
if (!status)
15811586
udev->reset_resume = 0;
15821587
return status;

drivers/usb/core/hcd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2403,7 +2403,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
24032403
if (hcd->rh_registered) {
24042404
pm_wakeup_event(&hcd->self.root_hub->dev, 0);
24052405
set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
2406-
queue_work(pm_wq, &hcd->wakeup_work);
2406+
queue_work(system_freezable_wq, &hcd->wakeup_work);
24072407
}
24082408
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
24092409
}

drivers/usb/core/offload.c

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,30 @@
2525
*/
2626
int usb_offload_get(struct usb_device *udev)
2727
{
28-
int ret;
28+
int ret = 0;
2929

30-
usb_lock_device(udev);
31-
if (udev->state == USB_STATE_NOTATTACHED) {
32-
usb_unlock_device(udev);
30+
if (!usb_get_dev(udev))
3331
return -ENODEV;
34-
}
3532

36-
if (udev->state == USB_STATE_SUSPENDED ||
37-
udev->offload_at_suspend) {
38-
usb_unlock_device(udev);
39-
return -EBUSY;
33+
if (pm_runtime_get_if_active(&udev->dev) != 1) {
34+
ret = -EBUSY;
35+
goto err_rpm;
4036
}
4137

42-
/*
43-
* offload_usage could only be modified when the device is active, since
44-
* it will alter the suspend flow of the device.
45-
*/
46-
ret = usb_autoresume_device(udev);
47-
if (ret < 0) {
48-
usb_unlock_device(udev);
49-
return ret;
38+
spin_lock(&udev->offload_lock);
39+
40+
if (udev->offload_pm_locked) {
41+
ret = -EAGAIN;
42+
goto err;
5043
}
5144

5245
udev->offload_usage++;
53-
usb_autosuspend_device(udev);
54-
usb_unlock_device(udev);
46+
47+
err:
48+
spin_unlock(&udev->offload_lock);
49+
pm_runtime_put_autosuspend(&udev->dev);
50+
err_rpm:
51+
usb_put_dev(udev);
5552

5653
return ret;
5754
}
@@ -69,35 +66,32 @@ EXPORT_SYMBOL_GPL(usb_offload_get);
6966
*/
7067
int usb_offload_put(struct usb_device *udev)
7168
{
72-
int ret;
69+
int ret = 0;
7370

74-
usb_lock_device(udev);
75-
if (udev->state == USB_STATE_NOTATTACHED) {
76-
usb_unlock_device(udev);
71+
if (!usb_get_dev(udev))
7772
return -ENODEV;
78-
}
7973

80-
if (udev->state == USB_STATE_SUSPENDED ||
81-
udev->offload_at_suspend) {
82-
usb_unlock_device(udev);
83-
return -EBUSY;
74+
if (pm_runtime_get_if_active(&udev->dev) != 1) {
75+
ret = -EBUSY;
76+
goto err_rpm;
8477
}
8578

86-
/*
87-
* offload_usage could only be modified when the device is active, since
88-
* it will alter the suspend flow of the device.
89-
*/
90-
ret = usb_autoresume_device(udev);
91-
if (ret < 0) {
92-
usb_unlock_device(udev);
93-
return ret;
79+
spin_lock(&udev->offload_lock);
80+
81+
if (udev->offload_pm_locked) {
82+
ret = -EAGAIN;
83+
goto err;
9484
}
9585

9686
/* Drop the count when it wasn't 0, ignore the operation otherwise. */
9787
if (udev->offload_usage)
9888
udev->offload_usage--;
99-
usb_autosuspend_device(udev);
100-
usb_unlock_device(udev);
89+
90+
err:
91+
spin_unlock(&udev->offload_lock);
92+
pm_runtime_put_autosuspend(&udev->dev);
93+
err_rpm:
94+
usb_put_dev(udev);
10195

10296
return ret;
10397
}
@@ -112,25 +106,47 @@ EXPORT_SYMBOL_GPL(usb_offload_put);
112106
* management.
113107
*
114108
* The caller must hold @udev's device lock. In addition, the caller should
115-
* ensure downstream usb devices are all either suspended or marked as
116-
* "offload_at_suspend" to ensure the correctness of the return value.
109+
* ensure the device itself and the downstream usb devices are all marked as
110+
* "offload_pm_locked" to ensure the correctness of the return value.
117111
*
118112
* Returns true on any offload activity, false otherwise.
119113
*/
120114
bool usb_offload_check(struct usb_device *udev) __must_hold(&udev->dev->mutex)
121115
{
122116
struct usb_device *child;
123-
bool active;
117+
bool active = false;
124118
int port1;
125119

120+
if (udev->offload_usage)
121+
return true;
122+
126123
usb_hub_for_each_child(udev, port1, child) {
127124
usb_lock_device(child);
128125
active = usb_offload_check(child);
129126
usb_unlock_device(child);
127+
130128
if (active)
131-
return true;
129+
break;
132130
}
133131

134-
return !!udev->offload_usage;
132+
return active;
135133
}
136134
EXPORT_SYMBOL_GPL(usb_offload_check);
135+
136+
/**
137+
* usb_offload_set_pm_locked - set the PM lock state of a USB device
138+
* @udev: the USB device to modify
139+
* @locked: the new lock state
140+
*
141+
* Setting @locked to true prevents offload_usage from being modified. This
142+
* ensures that offload activities cannot be started or stopped during critical
143+
* power management transitions, maintaining a stable state for the duration
144+
* of the transition.
145+
*/
146+
void usb_offload_set_pm_locked(struct usb_device *udev, bool locked)
147+
{
148+
spin_lock(&udev->offload_lock);
149+
udev->offload_pm_locked = locked;
150+
spin_unlock(&udev->offload_lock);
151+
}
152+
EXPORT_SYMBOL_GPL(usb_offload_set_pm_locked);

0 commit comments

Comments
 (0)