Commit ff789a26 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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()
  ...
parents 4e6e4229 f4d19607
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -485,6 +485,7 @@ static ssize_t wdm_write
static int service_outstanding_interrupt(struct wdm_device *desc)
{
	int rv = 0;
	int used;

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

	set_bit(WDM_RESPONDING, &desc->flags);
	used = test_and_set_bit(WDM_RESPONDING, &desc->flags);
	if (used)
		goto out;

	spin_unlock_irq(&desc->iuspin);
	rv = usb_submit_urb(desc->response, GFP_KERNEL);
	spin_lock_irq(&desc->iuspin);
+16 −7
Original line number Diff line number Diff line
@@ -130,7 +130,6 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
#define HUB_DEBOUNCE_STEP	  25
#define HUB_DEBOUNCE_STABLE	 100

static void hub_release(struct kref *kref);
static int usb_reset_and_verify_device(struct usb_device *udev);
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
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)
	 */
	intf = to_usb_interface(hub->intfdev);
	usb_autopm_get_interface_no_resume(intf);
	kref_get(&hub->kref);
	hub_get(hub);

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

	/* the work has already been scheduled */
	usb_autopm_put_interface_async(intf);
	kref_put(&hub->kref, hub_release);
	hub_put(hub);
}

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)
			goto init2;
		goto init3;
	}
	kref_get(&hub->kref);
	hub_get(hub);

	/* The superspeed hub except for root hub has to use Hub Depth
	 * 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)
		device_unlock(&hdev->dev);
	}

	kref_put(&hub->kref, hub_release);
	hub_put(hub);
}

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

void hub_get(struct usb_hub *hub)
{
	kref_get(&hub->kref);
}

void hub_put(struct usb_hub *hub)
{
	kref_put(&hub->kref, hub_release);
}

static unsigned highspeed_hubs;

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

	onboard_hub_destroy_pdevs(&hub->onboard_hub_devs);

	kref_put(&hub->kref, hub_release);
	hub_put(hub);
}

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

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

	kcov_remote_stop();
}
+2 −0
Original line number Diff line number Diff line
@@ -129,6 +129,8 @@ extern void usb_hub_remove_port_device(struct usb_hub *hub,
extern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
		int port1, bool set);
extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
extern void hub_get(struct usb_hub *hub);
extern void hub_put(struct usb_hub *hub);
extern int hub_port_debounce(struct usb_hub *hub, int port1,
		bool must_be_connected);
extern int usb_clear_port_feature(struct usb_device *hdev,
+34 −4
Original line number Diff line number Diff line
@@ -56,11 +56,22 @@ static ssize_t disable_show(struct device *dev,
	u16 portstatus, unused;
	bool disabled;
	int rc;
	struct kernfs_node *kn;

	hub_get(hub);
	rc = usb_autopm_get_interface(intf);
	if (rc < 0)
		return rc;
		goto out_hub_get;

	/*
	 * Prevent deadlock if another process is concurrently
	 * trying to unregister hdev.
	 */
	kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
	if (!kn) {
		rc = -ENODEV;
		goto out_autopm;
	}
	usb_lock_device(hdev);
	if (hub->disconnected) {
		rc = -ENODEV;
@@ -72,7 +83,11 @@ static ssize_t disable_show(struct device *dev,

 out_hdev_lock:
	usb_unlock_device(hdev);
	sysfs_unbreak_active_protection(kn);
 out_autopm:
	usb_autopm_put_interface(intf);
 out_hub_get:
	hub_put(hub);

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

	rc = kstrtobool(buf, &disabled);
	if (rc)
		return rc;

	hub_get(hub);
	rc = usb_autopm_get_interface(intf);
	if (rc < 0)
		return rc;
		goto out_hub_get;

	/*
	 * Prevent deadlock if another process is concurrently
	 * trying to unregister hdev.
	 */
	kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
	if (!kn) {
		rc = -ENODEV;
		goto out_autopm;
	}
	usb_lock_device(hdev);
	if (hub->disconnected) {
		rc = -ENODEV;
@@ -121,7 +147,11 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,

 out_hdev_lock:
	usb_unlock_device(hdev);
	sysfs_unbreak_active_protection(kn);
 out_autopm:
	usb_autopm_put_interface(intf);
 out_hub_get:
	hub_put(hub);

	return rc;
}
+13 −3
Original line number Diff line number Diff line
@@ -1217,14 +1217,24 @@ static ssize_t interface_authorized_store(struct device *dev,
{
	struct usb_interface *intf = to_usb_interface(dev);
	bool val;
	struct kernfs_node *kn;

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

	if (val)
	if (val) {
		usb_authorize_interface(intf);
	else
	} else {
		/*
		 * Prevent deadlock if another process is concurrently
		 * trying to unregister intf.
		 */
		kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
		if (kn) {
			usb_deauthorize_interface(intf);
			sysfs_unbreak_active_protection(kn);
		}
	}

	return count;
}
Loading