Skip to content

Commit

Permalink
Merge tag 'usb-6.9-rc7' 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 driver fixes from Greg KH:
 "Here are some small USB driver fixes for reported problems for
  6.9-rc7. Included in here are:

   - usb core fixes for found issues

   - typec driver fixes for reported problems

   - usb gadget driver fixes for reported problems

   - xhci build fixes

   - dwc3 driver fixes for reported issues

  All of these have been in linux-next this past week with no reported
  problems"

* tag 'usb-6.9-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: typec: tcpm: Check for port partner validity before consuming it
  usb: typec: tcpm: enforce ready state when queueing alt mode vdm
  usb: typec: tcpm: unregister existing source caps before re-registration
  usb: typec: tcpm: clear pd_event queue in PORT_RESET
  usb: typec: tcpm: queue correct sop type in tcpm_queue_vdm_unlocked
  usb: Fix regression caused by invalid ep0 maxpacket in virtual SuperSpeed device
  usb: ohci: Prevent missed ohci interrupts
  usb: typec: qcom-pmic: fix pdphy start() error handling
  usb: typec: qcom-pmic: fix use-after-free on late probe errors
  usb: gadget: f_fs: Fix a race condition when processing setup packets.
  USB: core: Fix access violation during port device removal
  usb: dwc3: core: Prevent phy suspend during init
  usb: xhci-plat: Don't include xhci.h
  usb: gadget: uvc: use correct buffer size when parsing configfs lists
  usb: gadget: composite: fix OS descriptors w_value logic
  usb: gadget: f_fs: Fix race between aio_cancel() and AIO request complete
  • Loading branch information
torvalds committed May 5, 2024
2 parents 3f1d086 + ae11f04 commit 3c15237
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 79 deletions.
5 changes: 3 additions & 2 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -5110,9 +5110,10 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
}
if (usb_endpoint_maxp(&udev->ep0.desc) == i) {
; /* Initial ep0 maxpacket guess is right */
} else if ((udev->speed == USB_SPEED_FULL ||
} else if (((udev->speed == USB_SPEED_FULL ||
udev->speed == USB_SPEED_HIGH) &&
(i == 8 || i == 16 || i == 32 || i == 64)) {
(i == 8 || i == 16 || i == 32 || i == 64)) ||
(udev->speed >= USB_SPEED_SUPER && i > 0)) {
/* Initial guess is wrong; use the descriptor's value */
if (udev->speed == USB_SPEED_FULL)
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
Expand Down
8 changes: 6 additions & 2 deletions drivers/usb/core/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ static ssize_t disable_show(struct device *dev,
struct usb_port *port_dev = to_usb_port(dev);
struct usb_device *hdev = to_usb_device(dev->parent->parent);
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
struct usb_interface *intf = to_usb_interface(hub->intfdev);
struct usb_interface *intf = to_usb_interface(dev->parent);
int port1 = port_dev->portnum;
u16 portstatus, unused;
bool disabled;
int rc;
struct kernfs_node *kn;

if (!hub)
return -ENODEV;
hub_get(hub);
rc = usb_autopm_get_interface(intf);
if (rc < 0)
Expand Down Expand Up @@ -101,12 +103,14 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
struct usb_port *port_dev = to_usb_port(dev);
struct usb_device *hdev = to_usb_device(dev->parent->parent);
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
struct usb_interface *intf = to_usb_interface(hub->intfdev);
struct usb_interface *intf = to_usb_interface(dev->parent);
int port1 = port_dev->portnum;
bool disabled;
int rc;
struct kernfs_node *kn;

if (!hub)
return -ENODEV;
rc = kstrtobool(buf, &disabled);
if (rc)
return rc;
Expand Down
90 changes: 38 additions & 52 deletions drivers/usb/dwc3/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,27 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
return 0;
}

void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
{
u32 reg;

reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
if (enable && !dwc->dis_u3_susphy_quirk)
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
else
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;

dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);

reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (enable && !dwc->dis_u2_susphy_quirk)
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
else
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;

dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}

void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
{
u32 reg;
Expand Down Expand Up @@ -585,11 +606,8 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
*/
static int dwc3_phy_setup(struct dwc3 *dwc)
{
unsigned int hw_mode;
u32 reg;

hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);

reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));

/*
Expand All @@ -599,21 +617,16 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;

/*
* Above 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.
*/
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
reg |= DWC3_GUSB3PIPECTL_SUSPHY;

/*
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
* power-on reset, and it can be set after core initialization, which is
* after device soft-reset during initialization.
* 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.
*/
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;

if (dwc->u2ss_inp3_quirk)
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
Expand All @@ -639,9 +652,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->tx_de_emphasis_quirk)
reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);

if (dwc->dis_u3_susphy_quirk)
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;

if (dwc->dis_del_phy_power_chg_quirk)
reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;

Expand Down Expand Up @@ -689,24 +699,15 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
}

/*
* Above 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.
*/
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
reg |= DWC3_GUSB2PHYCFG_SUSPHY;

/*
* For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
* power-on reset, and it can be set after core initialization, which is
* after device soft-reset during initialization.
* 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.
*/
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;

if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;

if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
Expand Down Expand Up @@ -1227,21 +1228,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (ret)
goto err_exit_phy;

if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
if (!dwc->dis_u3_susphy_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
}

if (!dwc->dis_u2_susphy_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
}

dwc3_core_setup_global_control(dwc);
dwc3_core_num_eps(dwc);

Expand Down
1 change: 1 addition & 0 deletions drivers/usb/dwc3/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,7 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc);
void dwc3_event_buffers_cleanup(struct dwc3 *dwc);

int dwc3_core_soft_reset(struct dwc3 *dwc);
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable);

#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_host_init(struct dwc3 *dwc);
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -2924,6 +2924,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
dwc3_ep0_out_start(dwc);

dwc3_gadget_enable_irq(dwc);
dwc3_enable_susphy(dwc, true);

return 0;

Expand Down Expand Up @@ -4690,6 +4691,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
if (!dwc->gadget)
return;

dwc3_enable_susphy(dwc, false);
usb_del_gadget(dwc->gadget);
dwc3_gadget_free_endpoints(dwc);
usb_put_gadget(dwc->gadget);
Expand Down
27 changes: 27 additions & 0 deletions drivers/usb/dwc3/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>

#include "../host/xhci-port.h"
#include "../host/xhci-ext-caps.h"
#include "../host/xhci-caps.h"
#include "../host/xhci-plat.h"
#include "core.h"

#define XHCI_HCSPARAMS1 0x4
Expand Down Expand Up @@ -57,6 +60,24 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc)
}
}

static void dwc3_xhci_plat_start(struct usb_hcd *hcd)
{
struct platform_device *pdev;
struct dwc3 *dwc;

if (!usb_hcd_is_primary_hcd(hcd))
return;

pdev = to_platform_device(hcd->self.controller);
dwc = dev_get_drvdata(pdev->dev.parent);

dwc3_enable_susphy(dwc, true);
}

static const struct xhci_plat_priv dwc3_xhci_plat_quirk = {
.plat_start = dwc3_xhci_plat_start,
};

static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
int irq, char *name)
{
Expand Down Expand Up @@ -167,6 +188,11 @@ int dwc3_host_init(struct dwc3 *dwc)
}
}

ret = platform_device_add_data(xhci, &dwc3_xhci_plat_quirk,
sizeof(struct xhci_plat_priv));
if (ret)
goto err;

ret = platform_device_add(xhci);
if (ret) {
dev_err(dwc->dev, "failed to register xHCI device\n");
Expand All @@ -192,6 +218,7 @@ void dwc3_host_exit(struct dwc3 *dwc)
if (dwc->sys_wakeup)
device_init_wakeup(&dwc->xhci->dev, false);

dwc3_enable_susphy(dwc, false);
platform_device_unregister(dwc->xhci);
dwc->xhci = NULL;
}
6 changes: 3 additions & 3 deletions drivers/usb/gadget/composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -2112,7 +2112,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
buf[5] = 0x01;
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
if (w_index != 0x4 || (w_value >> 8))
if (w_index != 0x4 || (w_value & 0xff))
break;
buf[6] = w_index;
/* Number of ext compat interfaces */
Expand All @@ -2128,9 +2128,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
break;
case USB_RECIP_INTERFACE:
if (w_index != 0x5 || (w_value >> 8))
if (w_index != 0x5 || (w_value & 0xff))
break;
interface = w_value & 0xFF;
interface = w_value >> 8;
if (interface >= MAX_CONFIG_INTERFACES ||
!os_desc_cfg->interface[interface])
break;
Expand Down
9 changes: 7 additions & 2 deletions drivers/usb/gadget/function/f_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
work);
int ret = io_data->status;
bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
unsigned long flags;

if (io_data->read && ret > 0) {
kthread_use_mm(io_data->mm);
Expand All @@ -864,6 +865,11 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd);

spin_lock_irqsave(&io_data->ffs->eps_lock, flags);
usb_ep_free_request(io_data->ep, io_data->req);
io_data->req = NULL;
spin_unlock_irqrestore(&io_data->ffs->eps_lock, flags);

if (io_data->read)
kfree(io_data->to_free);
ffs_free_buffer(io_data);
Expand All @@ -877,7 +883,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
struct ffs_data *ffs = io_data->ffs;

io_data->status = req->status ? req->status : req->actual;
usb_ep_free_request(_ep, req);

INIT_WORK(&io_data->work, ffs_user_copy_worker);
queue_work(ffs->io_completion_wq, &io_data->work);
Expand Down Expand Up @@ -3806,7 +3811,7 @@ static int ffs_func_setup(struct usb_function *f,
__ffs_event_add(ffs, FUNCTIONFS_SETUP);
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);

return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
return ffs->ev.setup.wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
}

static bool ffs_func_req_match(struct usb_function *f,
Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/gadget/function/uvc_configfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ static int __uvcg_iter_item_entries(const char *page, size_t len,

while (pg - page < len) {
i = 0;
while (i < sizeof(buf) && (pg - page < len) &&
while (i < bufsize && (pg - page < len) &&
*pg != '\0' && *pg != '\n')
buf[i++] = *pg++;
if (i == sizeof(buf)) {
if (i == bufsize) {
ret = -EINVAL;
goto out_free_buf;
}
Expand Down
8 changes: 8 additions & 0 deletions drivers/usb/host/ohci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
/* Check for an all 1's result which is a typical consequence
* of dead, unclocked, or unplugged (CardBus...) devices
*/
again:
if (ints == ~(u32)0) {
ohci->rh_state = OHCI_RH_HALTED;
ohci_dbg (ohci, "device removed!\n");
Expand Down Expand Up @@ -982,6 +983,13 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
}
spin_unlock(&ohci->lock);

/* repeat until all enabled interrupts are handled */
if (ohci->rh_state != OHCI_RH_HALTED) {
ints = ohci_readl(ohci, &regs->intrstatus);
if (ints && (ints & ohci_readl(ohci, &regs->intrenable)))
goto again;
}

return IRQ_HANDLED;
}

Expand Down
4 changes: 3 additions & 1 deletion drivers/usb/host/xhci-plat.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#ifndef _XHCI_PLAT_H
#define _XHCI_PLAT_H

#include "xhci.h" /* for hcd_to_xhci() */
struct device;
struct platform_device;
struct usb_hcd;

struct xhci_plat_priv {
const char *firmware_name;
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/host/xhci-rzv2m.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include <linux/usb/rzv2m_usb3drd.h>
#include "xhci.h"
#include "xhci-plat.h"
#include "xhci-rzv2m.h"

Expand Down
8 changes: 6 additions & 2 deletions drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,18 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)

ret = tcpm->port_start(tcpm, tcpm->tcpm_port);
if (ret)
goto fwnode_remove;
goto port_unregister;

ret = tcpm->pdphy_start(tcpm, tcpm->tcpm_port);
if (ret)
goto fwnode_remove;
goto port_stop;

return 0;

port_stop:
tcpm->port_stop(tcpm);
port_unregister:
tcpm_unregister_port(tcpm->tcpm_port);
fwnode_remove:
fwnode_remove_software_node(tcpm->tcpc.fwnode);

Expand Down
Loading

0 comments on commit 3c15237

Please sign in to comment.