USB fixes for 6.8-rc6

Here are some small USB fixes for 6.8-rc6 to resolve some reported
 problems.  These include:
   - regression fixes with typec tpcm code as reported by many
   - cdnsp and cdns3 driver fixes
   - usb role setting code bugfixes
   - build fix for uhci driver
   - ncm gadget driver bugfix
   - MAINTAINERS entry update
 
 All of these have been in linux-next all week with no reported issues
 and there is at least one fix in here that is in Thorsten's regression
 list that is being tracked.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZdtGEA8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymzsgCg2IsWqIR72XUGsa5rrbRnskOP/G4An24BmUb6
 t34d0VjiHagZTFlfRx6g
 =eOL1
 -----END PGP SIGNATURE-----

Merge tag 'usb-6.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are some small USB fixes for 6.8-rc6 to resolve some reported
  problems. These include:

   - regression fixes with typec tpcm code as reported by many

   - cdnsp and cdns3 driver fixes

   - usb role setting code bugfixes

   - build fix for uhci driver

   - ncm gadget driver bugfix

   - MAINTAINERS entry update

  All of these have been in linux-next all week with no reported issues
  and there is at least one fix in here that is in Thorsten's regression
  list that is being tracked"

* tag 'usb-6.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: typec: tpcm: Fix issues with power being removed during reset
  MAINTAINERS: Drop myself as maintainer of TYPEC port controller drivers
  usb: gadget: ncm: Avoid dropping datagrams of properly parsed NTBs
  Revert "usb: typec: tcpm: reset counter when enter into unattached state after try role"
  usb: gadget: omap_udc: fix USB gadget regression on Palm TE
  usb: dwc3: gadget: Don't disconnect if not started
  usb: cdns3: fix memory double free when handle zero packet
  usb: cdns3: fixed memory use after free at cdns3_gadget_ep_disable()
  usb: roles: don't get/set_role() when usb_role_switch is unregistered
  usb: roles: fix NULL pointer issue when put module's reference
  usb: cdnsp: fixed issue with incorrect detecting CDNSP family controllers
  usb: cdnsp: blocked some cdns3 specific code
  usb: uhci-grlib: Explicitly include linux/platform_device.h
This commit is contained in:
Linus Torvalds 2024-02-25 10:41:57 -08:00
commit c46ac50ebe
12 changed files with 75 additions and 26 deletions

View file

@ -22880,9 +22880,8 @@ S: Maintained
F: drivers/usb/typec/mux/pi3usb30532.c
USB TYPEC PORT CONTROLLER DRIVERS
M: Guenter Roeck <linux@roeck-us.net>
L: linux-usb@vger.kernel.org
S: Maintained
S: Orphan
F: drivers/usb/typec/tcpm/
USB UHCI DRIVER

View file

@ -828,7 +828,11 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
return;
}
if (request->complete) {
/*
* zlp request is appended by driver, needn't call usb_gadget_giveback_request() to notify
* gadget composite driver.
*/
if (request->complete && request->buf != priv_dev->zlp_buf) {
spin_unlock(&priv_dev->lock);
usb_gadget_giveback_request(&priv_ep->endpoint,
request);
@ -2540,11 +2544,11 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep)
while (!list_empty(&priv_ep->wa2_descmiss_req_list)) {
priv_req = cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list);
list_del_init(&priv_req->list);
kfree(priv_req->request.buf);
cdns3_gadget_ep_free_request(&priv_ep->endpoint,
&priv_req->request);
list_del_init(&priv_req->list);
--priv_ep->wa2_counter;
}

View file

@ -395,7 +395,6 @@ static int cdns_role_set(struct usb_role_switch *sw, enum usb_role role)
return ret;
}
/**
* cdns_wakeup_irq - interrupt handler for wakeup events
* @irq: irq number for cdns3/cdnsp core device

View file

@ -156,7 +156,8 @@ bool cdns_is_device(struct cdns *cdns)
*/
static void cdns_otg_disable_irq(struct cdns *cdns)
{
writel(0, &cdns->otg_irq_regs->ien);
if (cdns->version)
writel(0, &cdns->otg_irq_regs->ien);
}
/**
@ -422,15 +423,20 @@ int cdns_drd_init(struct cdns *cdns)
cdns->otg_regs = (void __iomem *)&cdns->otg_v1_regs->cmd;
if (readl(&cdns->otg_cdnsp_regs->did) == OTG_CDNSP_DID) {
state = readl(&cdns->otg_cdnsp_regs->did);
if (OTG_CDNSP_CHECK_DID(state)) {
cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *)
&cdns->otg_cdnsp_regs->ien;
cdns->version = CDNSP_CONTROLLER_V2;
} else {
} else if (OTG_CDNS3_CHECK_DID(state)) {
cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *)
&cdns->otg_v1_regs->ien;
writel(1, &cdns->otg_v1_regs->simulate);
cdns->version = CDNS3_CONTROLLER_V1;
} else {
dev_err(cdns->dev, "not supporte DID=0x%08x\n", state);
return -EINVAL;
}
dev_dbg(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
@ -483,7 +489,6 @@ int cdns_drd_exit(struct cdns *cdns)
return 0;
}
/* Indicate the cdns3 core was power lost before */
bool cdns_power_is_lost(struct cdns *cdns)
{

View file

@ -79,7 +79,11 @@ struct cdnsp_otg_regs {
__le32 susp_timing_ctrl;
};
#define OTG_CDNSP_DID 0x0004034E
/* CDNSP driver supports 0x000403xx Cadence USB controller family. */
#define OTG_CDNSP_CHECK_DID(did) (((did) & GENMASK(31, 8)) == 0x00040300)
/* CDNS3 driver supports 0x000402xx Cadence USB controller family. */
#define OTG_CDNS3_CHECK_DID(did) (((did) & GENMASK(31, 8)) == 0x00040200)
/*
* Common registers interface for both CDNS3 and CDNSP version of DRD.

View file

@ -18,6 +18,11 @@
#include "../host/xhci.h"
#include "../host/xhci-plat.h"
/*
* The XECP_PORT_CAP_REG and XECP_AUX_CTRL_REG1 exist only
* in Cadence USB3 dual-role controller, so it can't be used
* with Cadence CDNSP dual-role controller.
*/
#define XECP_PORT_CAP_REG 0x8000
#define XECP_AUX_CTRL_REG1 0x8120
@ -57,6 +62,8 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
.resume_quirk = xhci_cdns3_resume_quirk,
};
static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
static int __cdns_host_init(struct cdns *cdns)
{
struct platform_device *xhci;
@ -81,8 +88,13 @@ static int __cdns_host_init(struct cdns *cdns)
goto err1;
}
cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
sizeof(struct xhci_plat_priv), GFP_KERNEL);
if (cdns->version < CDNSP_CONTROLLER_V2)
cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
sizeof(struct xhci_plat_priv), GFP_KERNEL);
else
cdns->xhci_plat_data = kmemdup(&xhci_plat_cdnsp_xhci,
sizeof(struct xhci_plat_priv), GFP_KERNEL);
if (!cdns->xhci_plat_data) {
ret = -ENOMEM;
goto err1;

View file

@ -2650,6 +2650,11 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
int ret;
spin_lock_irqsave(&dwc->lock, flags);
if (!dwc->pullups_connected) {
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
dwc->connected = false;
/*

View file

@ -1338,7 +1338,15 @@ static int ncm_unwrap_ntb(struct gether *port,
"Parsed NTB with %d frames\n", dgram_counter);
to_process -= block_len;
if (to_process != 0) {
/*
* Windows NCM driver avoids USB ZLPs by adding a 1-byte
* zero pad as needed.
*/
if (to_process == 1 &&
(*(unsigned char *)(ntb_ptr + block_len) == 0x00)) {
to_process--;
} else if (to_process > 0) {
ntb_ptr = (unsigned char *)(ntb_ptr + block_len);
goto parse_ntb;
}

View file

@ -2036,7 +2036,8 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
static inline int machine_without_vbus_sense(void)
{
return machine_is_omap_osk() || machine_is_sx1();
return machine_is_omap_osk() || machine_is_omap_palmte() ||
machine_is_sx1();
}
static int omap_udc_start(struct usb_gadget *g,

View file

@ -22,6 +22,7 @@
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
static int uhci_grlib_init(struct usb_hcd *hcd)
{

View file

@ -21,7 +21,9 @@ static const struct class role_class = {
struct usb_role_switch {
struct device dev;
struct mutex lock; /* device lock*/
struct module *module; /* the module this device depends on */
enum usb_role role;
bool registered;
/* From descriptor */
struct device *usb2_port;
@ -48,6 +50,9 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
if (IS_ERR_OR_NULL(sw))
return 0;
if (!sw->registered)
return -EOPNOTSUPP;
mutex_lock(&sw->lock);
ret = sw->set(sw, role);
@ -73,7 +78,7 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
{
enum usb_role role;
if (IS_ERR_OR_NULL(sw))
if (IS_ERR_OR_NULL(sw) || !sw->registered)
return USB_ROLE_NONE;
mutex_lock(&sw->lock);
@ -135,7 +140,7 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev)
usb_role_switch_match);
if (!IS_ERR_OR_NULL(sw))
WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
WARN_ON(!try_module_get(sw->module));
return sw;
}
@ -157,7 +162,7 @@ struct usb_role_switch *fwnode_usb_role_switch_get(struct fwnode_handle *fwnode)
sw = fwnode_connection_find_match(fwnode, "usb-role-switch",
NULL, usb_role_switch_match);
if (!IS_ERR_OR_NULL(sw))
WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
WARN_ON(!try_module_get(sw->module));
return sw;
}
@ -172,7 +177,7 @@ EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get);
void usb_role_switch_put(struct usb_role_switch *sw)
{
if (!IS_ERR_OR_NULL(sw)) {
module_put(sw->dev.parent->driver->owner);
module_put(sw->module);
put_device(&sw->dev);
}
}
@ -189,15 +194,18 @@ struct usb_role_switch *
usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode)
{
struct device *dev;
struct usb_role_switch *sw = NULL;
if (!fwnode)
return NULL;
dev = class_find_device_by_fwnode(&role_class, fwnode);
if (dev)
WARN_ON(!try_module_get(dev->parent->driver->owner));
if (dev) {
sw = to_role_switch(dev);
WARN_ON(!try_module_get(sw->module));
}
return dev ? to_role_switch(dev) : NULL;
return sw;
}
EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode);
@ -338,6 +346,7 @@ usb_role_switch_register(struct device *parent,
sw->set = desc->set;
sw->get = desc->get;
sw->module = parent->driver->owner;
sw->dev.parent = parent;
sw->dev.fwnode = desc->fwnode;
sw->dev.class = &role_class;
@ -352,6 +361,8 @@ usb_role_switch_register(struct device *parent,
return ERR_PTR(ret);
}
sw->registered = true;
/* TODO: Symlinks for the host port and the device controller. */
return sw;
@ -366,8 +377,10 @@ EXPORT_SYMBOL_GPL(usb_role_switch_register);
*/
void usb_role_switch_unregister(struct usb_role_switch *sw)
{
if (!IS_ERR_OR_NULL(sw))
if (!IS_ERR_OR_NULL(sw)) {
sw->registered = false;
device_unregister(&sw->dev);
}
}
EXPORT_SYMBOL_GPL(usb_role_switch_unregister);

View file

@ -3743,9 +3743,6 @@ static void tcpm_detach(struct tcpm_port *port)
if (tcpm_port_is_disconnected(port))
port->hard_reset_count = 0;
port->try_src_count = 0;
port->try_snk_count = 0;
if (!port->attached)
return;
@ -4876,7 +4873,8 @@ static void run_state_machine(struct tcpm_port *port)
break;
case PORT_RESET:
tcpm_reset_port(port);
tcpm_set_cc(port, TYPEC_CC_OPEN);
tcpm_set_cc(port, tcpm_default_state(port) == SNK_UNATTACHED ?
TYPEC_CC_RD : tcpm_rp_cc(port));
tcpm_set_state(port, PORT_RESET_WAIT_OFF,
PD_T_ERROR_RECOVERY);
break;