Skip to content

Commit

Permalink
Merge tag 'usb-6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are some small USB driver fixes for some reported issues. These
  contain:

   - typec driver fixes

   - dwc3 driver fixes

   - xhci driver fixes

   - renesas controller fixes

   - gadget driver fixes

   - a new USB quirk added

  All of these have been in linux-next with no reported issues"

* tag 'usb-6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: typec: ucsi: Fix NULL pointer access
  usb: quirks: Add DELAY_INIT and NO_LPM for Prolific Mass Storage Card Reader
  usb: xhci: Fix host controllers "dying" after suspend and resume
  usb: dwc3: Set SUSPENDENABLE soon after phy init
  usb: hub: lack of clearing xHC resources
  usb: renesas_usbhs: Flush the notify_hotplug_work
  usb: renesas_usbhs: Use devm_usb_get_phy()
  usb: renesas_usbhs: Call clk_put()
  usb: dwc3: gadget: Prevent irq storm when TH re-executes
  usb: gadget: Check bmAttributes only if configuration is valid
  xhci: Restrict USB4 tunnel detection for USB3 devices to Intel hosts
  usb: xhci: Enable the TRB overfetch quirk on VIA VL805
  usb: gadget: Fix setting self-powered state on suspend
  usb: typec: ucsi: increase timeout for PPM reset operations
  acpi: typec: ucsi: Introduce a ->poll_cci method
  usb: typec: tcpci_rt1711h: Unmask alert interrupts to fix functionality
  usb: gadget: Set self-powered based on MaxPower and bmAttributes
  usb: gadget: u_ether: Set is_suspend flag if remote wakeup fails
  usb: atm: cxacru: fix a flaw in existing endpoint checks
  • Loading branch information
Linus Torvalds committed Mar 9, 2025
2 parents 51b38f3 + b13abcb commit 0dc1f31
Show file tree
Hide file tree
Showing 24 changed files with 189 additions and 83 deletions.
13 changes: 7 additions & 6 deletions drivers/usb/atm/cxacru.c
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,10 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
struct cxacru_data *instance;
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD];
struct usb_endpoint_descriptor *in, *out;
static const u8 ep_addrs[] = {
CXACRU_EP_CMD + USB_DIR_IN,
CXACRU_EP_CMD + USB_DIR_OUT,
0};
int ret;

/* instance init */
Expand Down Expand Up @@ -1179,13 +1182,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
}

if (usb_endpoint_xfer_int(&cmd_ep->desc))
ret = usb_find_common_endpoints(intf->cur_altsetting,
NULL, NULL, &in, &out);
ret = usb_check_int_endpoints(intf, ep_addrs);
else
ret = usb_find_common_endpoints(intf->cur_altsetting,
&in, &out, NULL, NULL);
ret = usb_check_bulk_endpoints(intf, ep_addrs);

if (ret) {
if (!ret) {
usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n");
ret = -ENODEV;
goto fail;
Expand Down
33 changes: 33 additions & 0 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -6065,6 +6065,36 @@ void usb_hub_cleanup(void)
usb_deregister(&hub_driver);
} /* usb_hub_cleanup() */

/**
* hub_hc_release_resources - clear resources used by host controller
* @udev: pointer to device being released
*
* Context: task context, might sleep
*
* Function releases the host controller resources in correct order before
* making any operation on resuming usb device. The host controller resources
* allocated for devices in tree should be released starting from the last
* usb device in tree toward the root hub. This function is used only during
* resuming device when usb device require reinitialization – that is, when
* flag udev->reset_resume is set.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
static void hub_hc_release_resources(struct usb_device *udev)
{
struct usb_hub *hub = usb_hub_to_struct_hub(udev);
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
int i;

/* Release up resources for all children before this device */
for (i = 0; i < udev->maxchild; i++)
if (hub->ports[i]->child)
hub_hc_release_resources(hub->ports[i]->child);

if (hcd->driver->reset_device)
hcd->driver->reset_device(hcd, udev);
}

/**
* usb_reset_and_verify_device - perform a USB port reset to reinitialize a device
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
Expand Down Expand Up @@ -6129,6 +6159,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
bos = udev->bos;
udev->bos = NULL;

if (udev->reset_resume)
hub_hc_release_resources(udev);

mutex_lock(hcd->address0_mutex);

for (i = 0; i < PORT_INIT_TRIES; ++i) {
Expand Down
4 changes: 4 additions & 0 deletions drivers/usb/core/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
USB_QUIRK_STRING_FETCH_255 },

/* Prolific Single-LUN Mass Storage Card Reader */
{ USB_DEVICE(0x067b, 0x2731), .driver_info = USB_QUIRK_DELAY_INIT |
USB_QUIRK_NO_LPM },

/* Saitek Cyborg Gold Joystick */
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
Expand Down
85 changes: 48 additions & 37 deletions drivers/usb/dwc3/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,24 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
}
}

void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
{
unsigned int hw_mode;
u32 reg;

reg = dwc3_readl(dwc->regs, DWC3_GCTL);

/*
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and
* GUSB2PHYCFG.SUSPHY should be cleared during mode switching,
* and they can be set after core initialization.
*/
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !ignore_susphy) {
if (DWC3_GCTL_PRTCAP(reg) != mode)
dwc3_enable_susphy(dwc, false);
}

reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(mode);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
Expand Down Expand Up @@ -216,7 +229,7 @@ static void __dwc3_set_mode(struct work_struct *work)

spin_lock_irqsave(&dwc->lock, flags);

dwc3_set_prtcap(dwc, desired_dr_role);
dwc3_set_prtcap(dwc, desired_dr_role, false);

spin_unlock_irqrestore(&dwc->lock, flags);

Expand Down Expand Up @@ -658,16 +671,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
*/
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;

/*
* Above DWC_usb3.0 1.94a, it is recommended to set
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
* So default value will be '0' when the core is reset. Application
* needs to set it to '1' after the core initialization is completed.
*
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
* cleared after power-on reset, and it can be set after core
* initialization.
*/
/* Ensure the GUSB3PIPECTL.SUSPENDENABLE is cleared prior to phy init. */
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;

if (dwc->u2ss_inp3_quirk)
Expand Down Expand Up @@ -747,15 +751,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
break;
}

/*
* Above DWC_usb3.0 1.94a, it is recommended to set
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
* So default value will be '0' when the core is reset. Application
* needs to set it to '1' after the core initialization is completed.
*
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
* after power-on reset, and it can be set after core initialization.
*/
/* Ensure the GUSB2PHYCFG.SUSPHY is cleared prior to phy init. */
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;

if (dwc->dis_enblslpm_quirk)
Expand Down Expand Up @@ -830,6 +826,25 @@ static int dwc3_phy_init(struct dwc3 *dwc)
goto err_exit_usb3_phy;
}

/*
* Above DWC_usb3.0 1.94a, it is recommended to set
* DWC3_GUSB3PIPECTL_SUSPHY and DWC3_GUSB2PHYCFG_SUSPHY to '0' during
* coreConsultant configuration. So default value will be '0' when the
* core is reset. Application needs to set it to '1' after the core
* initialization is completed.
*
* Certain phy requires to be in P0 power state during initialization.
* Make sure GUSB3PIPECTL.SUSPENDENABLE and GUSB2PHYCFG.SUSPHY are clear
* prior to phy init to maintain in the P0 state.
*
* After phy initialization, some phy operations can only be executed
* while in lower P states. Ensure GUSB3PIPECTL.SUSPENDENABLE and
* GUSB2PHYCFG.SUSPHY are set soon after initialization to avoid
* blocking phy ops.
*/
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
dwc3_enable_susphy(dwc, true);

return 0;

err_exit_usb3_phy:
Expand Down Expand Up @@ -1588,7 +1603,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)

switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, false);

if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
Expand All @@ -1600,7 +1615,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
return dev_err_probe(dev, ret, "failed to initialize gadget\n");
break;
case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, false);

if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
Expand Down Expand Up @@ -1645,7 +1660,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
}

/* de-assert DRVVBUS for HOST and OTG mode */
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
}

static void dwc3_get_software_properties(struct dwc3 *dwc)
Expand Down Expand Up @@ -1835,8 +1850,6 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
dwc->tx_max_burst_prd = tx_max_burst_prd;

dwc->imod_interval = 0;

dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
}

Expand All @@ -1854,21 +1867,19 @@ static void dwc3_check_params(struct dwc3 *dwc)
unsigned int hwparam_gen =
DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3);

/* Check for proper value of imod_interval */
if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
dev_warn(dwc->dev, "Interrupt moderation not supported\n");
dwc->imod_interval = 0;
}

/*
* Enable IMOD for all supporting controllers.
*
* Particularly, DWC_usb3 v3.00a must enable this feature for
* the following reason:
*
* Workaround for STAR 9000961433 which affects only version
* 3.00a of the DWC_usb3 core. This prevents the controller
* interrupt from being masked while handling events. IMOD
* allows us to work around this issue. Enable it for the
* affected version.
*/
if (!dwc->imod_interval &&
DWC3_VER_IS(DWC3, 300A))
if (dwc3_has_imod((dwc)))
dwc->imod_interval = 1;

/* Check the maximum_speed parameter */
Expand Down Expand Up @@ -2457,15 +2468,15 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
if (ret)
return ret;

dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
dwc3_gadget_resume(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
ret = dwc3_core_init_for_resume(dwc);
if (ret)
return ret;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, true);
break;
}
/* Restore GUSB2PHYCFG bits that were modified in suspend */
Expand Down Expand Up @@ -2494,7 +2505,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
if (ret)
return ret;

dwc3_set_prtcap(dwc, dwc->current_dr_role);
dwc3_set_prtcap(dwc, dwc->current_dr_role, true);

dwc3_otg_init(dwc);
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/dwc3/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1558,7 +1558,7 @@ struct dwc3_gadget_ep_cmd_params {
#define DWC3_HAS_OTG BIT(3)

/* prototypes */
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy);
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);

Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/dwc3/drd.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ void dwc3_otg_init(struct dwc3 *dwc)
* block "Initialize GCTL for OTG operation".
*/
/* GCTL.PrtCapDir=2'b11 */
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
/* GUSB2PHYCFG0.SusPHY=0 */
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
Expand Down Expand Up @@ -556,7 +556,7 @@ int dwc3_drd_init(struct dwc3 *dwc)

dwc3_drd_update(dwc);
} else {
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);

/* use OTG block to get ID event */
irq = dwc3_otg_get_irq(dwc);
Expand Down
10 changes: 7 additions & 3 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -4501,14 +4501,18 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_SIZE(evt->length));

evt->flags &= ~DWC3_EVENT_PENDING;
/*
* Add an explicit write memory barrier to make sure that the update of
* clearing DWC3_EVENT_PENDING is observed in dwc3_check_event_buf()
*/
wmb();

if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
}

/* Keep the clearing of DWC3_EVENT_PENDING at the end */
evt->flags &= ~DWC3_EVENT_PENDING;

return ret;
}

Expand Down
17 changes: 12 additions & 5 deletions drivers/usb/gadget/composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,10 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev,
else
usb_gadget_set_remote_wakeup(gadget, 0);
done:
if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
usb_gadget_set_selfpowered(gadget);
else
if (power > USB_SELF_POWER_VBUS_MAX_DRAW ||
(c && !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER)))
usb_gadget_clear_selfpowered(gadget);
else
usb_gadget_set_selfpowered(gadget);

usb_gadget_vbus_draw(gadget, power);
if (result >= 0 && cdev->delayed_status)
Expand Down Expand Up @@ -2615,7 +2616,10 @@ void composite_suspend(struct usb_gadget *gadget)

cdev->suspended = 1;

usb_gadget_set_selfpowered(gadget);
if (cdev->config &&
cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)
usb_gadget_set_selfpowered(gadget);

usb_gadget_vbus_draw(gadget, 2);
}

Expand Down Expand Up @@ -2649,8 +2653,11 @@ void composite_resume(struct usb_gadget *gadget)
else
maxpower = min(maxpower, 900U);

if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW)
if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW ||
!(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER))
usb_gadget_clear_selfpowered(gadget);
else
usb_gadget_set_selfpowered(gadget);

usb_gadget_vbus_draw(gadget, maxpower);
} else {
Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/gadget/function/u_ether.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,8 +1052,8 @@ void gether_suspend(struct gether *link)
* There is a transfer in progress. So we trigger a remote
* wakeup to inform the host.
*/
ether_wakeup_host(dev->port_usb);
return;
if (!ether_wakeup_host(dev->port_usb))
return;
}
spin_lock_irqsave(&dev->lock, flags);
link->is_suspend = true;
Expand Down
8 changes: 8 additions & 0 deletions drivers/usb/host/xhci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/unaligned.h>
#include <linux/bitfield.h>
#include <linux/pci.h>

#include "xhci.h"
#include "xhci-trace.h"
Expand Down Expand Up @@ -770,9 +771,16 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
struct xhci_port *port)
{
struct usb_hcd *hcd;
void __iomem *base;
u32 offset;

/* Don't try and probe this capability for non-Intel hosts */
hcd = xhci_to_hcd(xhci);
if (!dev_is_pci(hcd->self.controller) ||
to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
return USB_LINK_UNKNOWN;

base = &xhci->cap_regs->hc_capbase;
offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);

Expand Down
Loading

0 comments on commit 0dc1f31

Please sign in to comment.