Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit ff789a2

Browse files
committed
Merge tag 'usb-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB fixes from Greg KH: "Here are a bunch of small USB fixes for reported problems and regressions for 6.9-rc2. Included in here are: - deadlock fixes for long-suffering issues - USB phy driver revert for reported problem - typec fixes for reported problems - duplicate id in dwc3 dropped - dwc2 driver fixes - udc driver warning fix - cdc-wdm race bugfix - other tiny USB bugfixes All of these have been in linux-next this past week with no reported issues" * tag 'usb-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (26 commits) USB: core: Fix deadlock in port "disable" sysfs attribute USB: core: Add hub_get() and hub_put() routines usb: typec: ucsi: Check capabilities before cable and identity discovery usb: typec: ucsi: Clear UCSI_CCI_RESET_COMPLETE before reset usb: typec: ucsi_acpi: Refactor and fix DELL quirk usb: typec: ucsi: Ack unsupported commands usb: typec: ucsi: Check for notifications after init usb: typec: ucsi: Clear EVENT_PENDING under PPM lock usb: typec: Return size of buffer if pd_set operation succeeds usb: udc: remove warning when queue disabled ep usb: dwc3: pci: Drop duplicate ID usb: dwc3: Properly set system wakeup Revert "usb: phy: generic: Get the vbus supply" usb: cdc-wdm: close race between read and workqueue usb: dwc2: gadget: LPM flow fix usb: dwc2: gadget: Fix exiting from clock gating usb: dwc2: host: Fix ISOC flow in DDMA mode usb: dwc2: host: Fix remote wakeup from hibernation usb: dwc2: host: Fix hibernation flow USB: core: Fix deadlock in usb_deauthorize_interface() ...
2 parents 4e6e422 + f4d1960 commit ff789a2

File tree

27 files changed

+376
-160
lines changed

27 files changed

+376
-160
lines changed

drivers/usb/class/cdc-wdm.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ static ssize_t wdm_write
485485
static int service_outstanding_interrupt(struct wdm_device *desc)
486486
{
487487
int rv = 0;
488+
int used;
488489

489490
/* submit read urb only if the device is waiting for it */
490491
if (!desc->resp_count || !--desc->resp_count)
@@ -499,7 +500,10 @@ static int service_outstanding_interrupt(struct wdm_device *desc)
499500
goto out;
500501
}
501502

502-
set_bit(WDM_RESPONDING, &desc->flags);
503+
used = test_and_set_bit(WDM_RESPONDING, &desc->flags);
504+
if (used)
505+
goto out;
506+
503507
spin_unlock_irq(&desc->iuspin);
504508
rv = usb_submit_urb(desc->response, GFP_KERNEL);
505509
spin_lock_irq(&desc->iuspin);

drivers/usb/core/hub.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
130130
#define HUB_DEBOUNCE_STEP 25
131131
#define HUB_DEBOUNCE_STABLE 100
132132

133-
static void hub_release(struct kref *kref);
134133
static int usb_reset_and_verify_device(struct usb_device *udev);
135134
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
136135
static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
@@ -720,14 +719,14 @@ static void kick_hub_wq(struct usb_hub *hub)
720719
*/
721720
intf = to_usb_interface(hub->intfdev);
722721
usb_autopm_get_interface_no_resume(intf);
723-
kref_get(&hub->kref);
722+
hub_get(hub);
724723

725724
if (queue_work(hub_wq, &hub->events))
726725
return;
727726

728727
/* the work has already been scheduled */
729728
usb_autopm_put_interface_async(intf);
730-
kref_put(&hub->kref, hub_release);
729+
hub_put(hub);
731730
}
732731

733732
void usb_kick_hub_wq(struct usb_device *hdev)
@@ -1095,7 +1094,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
10951094
goto init2;
10961095
goto init3;
10971096
}
1098-
kref_get(&hub->kref);
1097+
hub_get(hub);
10991098

11001099
/* The superspeed hub except for root hub has to use Hub Depth
11011100
* value as an offset into the route string to locate the bits
@@ -1343,7 +1342,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
13431342
device_unlock(&hdev->dev);
13441343
}
13451344

1346-
kref_put(&hub->kref, hub_release);
1345+
hub_put(hub);
13471346
}
13481347

13491348
/* Implement the continuations for the delays above */
@@ -1759,6 +1758,16 @@ static void hub_release(struct kref *kref)
17591758
kfree(hub);
17601759
}
17611760

1761+
void hub_get(struct usb_hub *hub)
1762+
{
1763+
kref_get(&hub->kref);
1764+
}
1765+
1766+
void hub_put(struct usb_hub *hub)
1767+
{
1768+
kref_put(&hub->kref, hub_release);
1769+
}
1770+
17621771
static unsigned highspeed_hubs;
17631772

17641773
static void hub_disconnect(struct usb_interface *intf)
@@ -1807,7 +1816,7 @@ static void hub_disconnect(struct usb_interface *intf)
18071816

18081817
onboard_hub_destroy_pdevs(&hub->onboard_hub_devs);
18091818

1810-
kref_put(&hub->kref, hub_release);
1819+
hub_put(hub);
18111820
}
18121821

18131822
static bool hub_descriptor_is_sane(struct usb_host_interface *desc)
@@ -5934,7 +5943,7 @@ static void hub_event(struct work_struct *work)
59345943

59355944
/* Balance the stuff in kick_hub_wq() and allow autosuspend */
59365945
usb_autopm_put_interface(intf);
5937-
kref_put(&hub->kref, hub_release);
5946+
hub_put(hub);
59385947

59395948
kcov_remote_stop();
59405949
}

drivers/usb/core/hub.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ extern void usb_hub_remove_port_device(struct usb_hub *hub,
129129
extern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
130130
int port1, bool set);
131131
extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
132+
extern void hub_get(struct usb_hub *hub);
133+
extern void hub_put(struct usb_hub *hub);
132134
extern int hub_port_debounce(struct usb_hub *hub, int port1,
133135
bool must_be_connected);
134136
extern int usb_clear_port_feature(struct usb_device *hdev,

drivers/usb/core/port.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,22 @@ static ssize_t disable_show(struct device *dev,
5656
u16 portstatus, unused;
5757
bool disabled;
5858
int rc;
59+
struct kernfs_node *kn;
5960

61+
hub_get(hub);
6062
rc = usb_autopm_get_interface(intf);
6163
if (rc < 0)
62-
return rc;
64+
goto out_hub_get;
6365

66+
/*
67+
* Prevent deadlock if another process is concurrently
68+
* trying to unregister hdev.
69+
*/
70+
kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
71+
if (!kn) {
72+
rc = -ENODEV;
73+
goto out_autopm;
74+
}
6475
usb_lock_device(hdev);
6576
if (hub->disconnected) {
6677
rc = -ENODEV;
@@ -70,9 +81,13 @@ static ssize_t disable_show(struct device *dev,
7081
usb_hub_port_status(hub, port1, &portstatus, &unused);
7182
disabled = !usb_port_is_power_on(hub, portstatus);
7283

73-
out_hdev_lock:
84+
out_hdev_lock:
7485
usb_unlock_device(hdev);
86+
sysfs_unbreak_active_protection(kn);
87+
out_autopm:
7588
usb_autopm_put_interface(intf);
89+
out_hub_get:
90+
hub_put(hub);
7691

7792
if (rc)
7893
return rc;
@@ -90,15 +105,26 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
90105
int port1 = port_dev->portnum;
91106
bool disabled;
92107
int rc;
108+
struct kernfs_node *kn;
93109

94110
rc = kstrtobool(buf, &disabled);
95111
if (rc)
96112
return rc;
97113

114+
hub_get(hub);
98115
rc = usb_autopm_get_interface(intf);
99116
if (rc < 0)
100-
return rc;
117+
goto out_hub_get;
101118

119+
/*
120+
* Prevent deadlock if another process is concurrently
121+
* trying to unregister hdev.
122+
*/
123+
kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
124+
if (!kn) {
125+
rc = -ENODEV;
126+
goto out_autopm;
127+
}
102128
usb_lock_device(hdev);
103129
if (hub->disconnected) {
104130
rc = -ENODEV;
@@ -119,9 +145,13 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
119145
if (!rc)
120146
rc = count;
121147

122-
out_hdev_lock:
148+
out_hdev_lock:
123149
usb_unlock_device(hdev);
150+
sysfs_unbreak_active_protection(kn);
151+
out_autopm:
124152
usb_autopm_put_interface(intf);
153+
out_hub_get:
154+
hub_put(hub);
125155

126156
return rc;
127157
}

drivers/usb/core/sysfs.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,14 +1217,24 @@ static ssize_t interface_authorized_store(struct device *dev,
12171217
{
12181218
struct usb_interface *intf = to_usb_interface(dev);
12191219
bool val;
1220+
struct kernfs_node *kn;
12201221

12211222
if (kstrtobool(buf, &val) != 0)
12221223
return -EINVAL;
12231224

1224-
if (val)
1225+
if (val) {
12251226
usb_authorize_interface(intf);
1226-
else
1227-
usb_deauthorize_interface(intf);
1227+
} else {
1228+
/*
1229+
* Prevent deadlock if another process is concurrently
1230+
* trying to unregister intf.
1231+
*/
1232+
kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
1233+
if (kn) {
1234+
usb_deauthorize_interface(intf);
1235+
sysfs_unbreak_active_protection(kn);
1236+
}
1237+
}
12281238

12291239
return count;
12301240
}

drivers/usb/dwc2/core.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,17 +729,29 @@ struct dwc2_dregs_backup {
729729
* struct dwc2_hregs_backup - Holds host registers state before
730730
* entering partial power down
731731
* @hcfg: Backup of HCFG register
732+
* @hflbaddr: Backup of HFLBADDR register
732733
* @haintmsk: Backup of HAINTMSK register
734+
* @hcchar: Backup of HCCHAR register
735+
* @hcsplt: Backup of HCSPLT register
733736
* @hcintmsk: Backup of HCINTMSK register
737+
* @hctsiz: Backup of HCTSIZ register
738+
* @hdma: Backup of HCDMA register
739+
* @hcdmab: Backup of HCDMAB register
734740
* @hprt0: Backup of HPTR0 register
735741
* @hfir: Backup of HFIR register
736742
* @hptxfsiz: Backup of HPTXFSIZ register
737743
* @valid: True if registers values backuped.
738744
*/
739745
struct dwc2_hregs_backup {
740746
u32 hcfg;
747+
u32 hflbaddr;
741748
u32 haintmsk;
749+
u32 hcchar[MAX_EPS_CHANNELS];
750+
u32 hcsplt[MAX_EPS_CHANNELS];
742751
u32 hcintmsk[MAX_EPS_CHANNELS];
752+
u32 hctsiz[MAX_EPS_CHANNELS];
753+
u32 hcidma[MAX_EPS_CHANNELS];
754+
u32 hcidmab[MAX_EPS_CHANNELS];
743755
u32 hprt0;
744756
u32 hfir;
745757
u32 hptxfsiz;
@@ -1086,6 +1098,7 @@ struct dwc2_hsotg {
10861098
bool needs_byte_swap;
10871099

10881100
/* DWC OTG HW Release versions */
1101+
#define DWC2_CORE_REV_4_30a 0x4f54430a
10891102
#define DWC2_CORE_REV_2_71a 0x4f54271a
10901103
#define DWC2_CORE_REV_2_72a 0x4f54272a
10911104
#define DWC2_CORE_REV_2_80a 0x4f54280a
@@ -1323,6 +1336,7 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg);
13231336
int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg);
13241337

13251338
void dwc2_enable_acg(struct dwc2_hsotg *hsotg);
1339+
void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg, bool remotewakeup);
13261340

13271341
/* This function should be called on every hardware interrupt. */
13281342
irqreturn_t dwc2_handle_common_intr(int irq, void *dev);

drivers/usb/dwc2/core_intr.c

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
297297

298298
/* Exit gadget mode clock gating. */
299299
if (hsotg->params.power_down ==
300-
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
300+
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended &&
301+
!hsotg->params.no_clock_gating)
301302
dwc2_gadget_exit_clock_gating(hsotg, 0);
302303
}
303304

@@ -322,10 +323,11 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
322323
* @hsotg: Programming view of DWC_otg controller
323324
*
324325
*/
325-
static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
326+
void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg, bool remotewakeup)
326327
{
327328
u32 glpmcfg;
328-
u32 i = 0;
329+
u32 pcgctl;
330+
u32 dctl;
329331

330332
if (hsotg->lx_state != DWC2_L1) {
331333
dev_err(hsotg->dev, "Core isn't in DWC2_L1 state\n");
@@ -334,37 +336,57 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
334336

335337
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
336338
if (dwc2_is_device_mode(hsotg)) {
337-
dev_dbg(hsotg->dev, "Exit from L1 state\n");
339+
dev_dbg(hsotg->dev, "Exit from L1 state, remotewakeup=%d\n", remotewakeup);
338340
glpmcfg &= ~GLPMCFG_ENBLSLPM;
339-
glpmcfg &= ~GLPMCFG_HIRD_THRES_EN;
341+
glpmcfg &= ~GLPMCFG_HIRD_THRES_MASK;
340342
dwc2_writel(hsotg, glpmcfg, GLPMCFG);
341343

342-
do {
343-
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
344+
pcgctl = dwc2_readl(hsotg, PCGCTL);
345+
pcgctl &= ~PCGCTL_ENBL_SLEEP_GATING;
346+
dwc2_writel(hsotg, pcgctl, PCGCTL);
344347

345-
if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK |
346-
GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS)))
347-
break;
348+
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
349+
if (glpmcfg & GLPMCFG_ENBESL) {
350+
glpmcfg |= GLPMCFG_RSTRSLPSTS;
351+
dwc2_writel(hsotg, glpmcfg, GLPMCFG);
352+
}
353+
354+
if (remotewakeup) {
355+
if (dwc2_hsotg_wait_bit_set(hsotg, GLPMCFG, GLPMCFG_L1RESUMEOK, 1000)) {
356+
dev_warn(hsotg->dev, "%s: timeout GLPMCFG_L1RESUMEOK\n", __func__);
357+
goto fail;
358+
return;
359+
}
360+
361+
dctl = dwc2_readl(hsotg, DCTL);
362+
dctl |= DCTL_RMTWKUPSIG;
363+
dwc2_writel(hsotg, dctl, DCTL);
348364

349-
udelay(1);
350-
} while (++i < 200);
365+
if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_WKUPINT, 1000)) {
366+
dev_warn(hsotg->dev, "%s: timeout GINTSTS_WKUPINT\n", __func__);
367+
goto fail;
368+
return;
369+
}
370+
}
351371

352-
if (i == 200) {
353-
dev_err(hsotg->dev, "Failed to exit L1 sleep state in 200us.\n");
372+
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
373+
if (glpmcfg & GLPMCFG_COREL1RES_MASK || glpmcfg & GLPMCFG_SLPSTS ||
374+
glpmcfg & GLPMCFG_L1RESUMEOK) {
375+
goto fail;
354376
return;
355377
}
356-
dwc2_gadget_init_lpm(hsotg);
378+
379+
/* Inform gadget to exit from L1 */
380+
call_gadget(hsotg, resume);
381+
/* Change to L0 state */
382+
hsotg->lx_state = DWC2_L0;
383+
hsotg->bus_suspended = false;
384+
fail: dwc2_gadget_init_lpm(hsotg);
357385
} else {
358386
/* TODO */
359387
dev_err(hsotg->dev, "Host side LPM is not supported.\n");
360388
return;
361389
}
362-
363-
/* Change to L0 state */
364-
hsotg->lx_state = DWC2_L0;
365-
366-
/* Inform gadget to exit from L1 */
367-
call_gadget(hsotg, resume);
368390
}
369391

370392
/*
@@ -385,7 +407,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
385407
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
386408

387409
if (hsotg->lx_state == DWC2_L1) {
388-
dwc2_wakeup_from_lpm_l1(hsotg);
410+
dwc2_wakeup_from_lpm_l1(hsotg, false);
389411
return;
390412
}
391413

@@ -408,7 +430,8 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
408430

409431
/* Exit gadget mode clock gating. */
410432
if (hsotg->params.power_down ==
411-
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
433+
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended &&
434+
!hsotg->params.no_clock_gating)
412435
dwc2_gadget_exit_clock_gating(hsotg, 0);
413436
} else {
414437
/* Change to L0 state */
@@ -425,7 +448,8 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
425448
}
426449

427450
if (hsotg->params.power_down ==
428-
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
451+
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended &&
452+
!hsotg->params.no_clock_gating)
429453
dwc2_host_exit_clock_gating(hsotg, 1);
430454

431455
/*

0 commit comments

Comments
 (0)