mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
USB fixes for 6.10-rc6
Here are a handful of small USB driver fixes for 6.10-rc6 to resolve some reported issues. Included in here are: - typec driver bugfixes - usb gadget driver reverts for commits that were reported to have problems - resource leak bugfix - gadget driver bugfixes - dwc3 driver bugfixes - usb atm driver bugfix for when syzbot got loose on it All of these have been in linux-next this week with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZoFnUA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ym3ggCgyM2B+cIOH4FtyWi7FfXj8XjDsjIAoKzX45+o TO/pSGQhRwx9PeFfDISM =pFEO -----END PGP SIGNATURE----- Merge tag 'usb-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a handful of small USB driver fixes for 6.10-rc6 to resolve some reported issues. Included in here are: - typec driver bugfixes - usb gadget driver reverts for commits that were reported to have problems - resource leak bugfix - gadget driver bugfixes - dwc3 driver bugfixes - usb atm driver bugfix for when syzbot got loose on it All of these have been in linux-next this week with no reported issues" * tag 'usb-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: usb: dwc3: core: Workaround for CSR read timeout Revert "usb: gadget: u_ether: Replace netif_stop_queue with netif_device_detach" Revert "usb: gadget: u_ether: Re-attach netif device to mirror detachment" usb: gadget: aspeed_udc: fix device address configuration usb: dwc3: core: remove lock of otg mode during gadget suspend/resume to avoid deadlock usb: typec: ucsi: glink: fix child node release in probe function usb: musb: da8xx: fix a resource leak in probe() usb: typec: ucsi_acpi: Add LG Gram quirk usb: ucsi: stm32: fix command completion handling usb: atm: cxacru: fix endpoint checking in cxacru_bind() usb: gadget: printer: fix races against disable usb: gadget: printer: SS+ support
This commit is contained in:
commit
2c01c3d552
@ -1131,6 +1131,7 @@ 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;
|
||||
int ret;
|
||||
|
||||
/* instance init */
|
||||
@ -1177,6 +1178,19 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_int(&cmd_ep->desc))
|
||||
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
||||
NULL, NULL, &in, &out);
|
||||
else
|
||||
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
||||
&in, &out, NULL, NULL);
|
||||
|
||||
if (ret) {
|
||||
usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((cmd_ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
== USB_ENDPOINT_XFER_INT) {
|
||||
usb_fill_int_urb(instance->rcv_urb,
|
||||
|
@ -957,12 +957,16 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
|
||||
|
||||
static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned int power_opt;
|
||||
unsigned int hw_mode;
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
||||
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
|
||||
power_opt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
|
||||
|
||||
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
|
||||
switch (power_opt) {
|
||||
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
|
||||
/**
|
||||
* WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
|
||||
@ -995,6 +999,20 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a workaround for STAR#4846132, which only affects
|
||||
* DWC_usb31 version2.00a operating in host mode.
|
||||
*
|
||||
* There is a problem in DWC_usb31 version 2.00a operating
|
||||
* in host mode that would cause a CSR read timeout When CSR
|
||||
* read coincides with RAM Clock Gating Entry. By disable
|
||||
* Clock Gating, sacrificing power consumption for normal
|
||||
* operation.
|
||||
*/
|
||||
if (power_opt != DWC3_GHWPARAMS1_EN_PWROPT_NO &&
|
||||
hw_mode != DWC3_GHWPARAMS0_MODE_GADGET && DWC3_VER_IS(DWC31, 200A))
|
||||
reg |= DWC3_GCTL_DSBLCLKGTNG;
|
||||
|
||||
/* check if current dwc3 is on simulation board */
|
||||
if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
|
||||
dev_info(dwc->dev, "Running with FPGA optimizations\n");
|
||||
@ -2250,7 +2268,6 @@ assert_reset:
|
||||
|
||||
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
@ -2293,9 +2310,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
||||
break;
|
||||
|
||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_gadget_suspend(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
synchronize_irq(dwc->irq_gadget);
|
||||
}
|
||||
|
||||
@ -2312,7 +2327,6 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
||||
|
||||
static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
u32 reg;
|
||||
int i;
|
||||
@ -2366,9 +2380,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
|
||||
dwc3_otg_host_init(dwc);
|
||||
} else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_gadget_resume(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -213,6 +213,7 @@ static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget,
|
||||
struct usb_endpoint_descriptor *ss)
|
||||
{
|
||||
switch (gadget->speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
case USB_SPEED_SUPER:
|
||||
return ss;
|
||||
case USB_SPEED_HIGH:
|
||||
@ -449,11 +450,8 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||
mutex_lock(&dev->lock_printer_io);
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
if (dev->interface < 0) {
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
mutex_unlock(&dev->lock_printer_io);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
|
||||
/* We will use this flag later to check if a printer reset happened
|
||||
* after we turn interrupts back on.
|
||||
@ -461,6 +459,9 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||
dev->reset_printer = 0;
|
||||
|
||||
setup_rx_reqs(dev);
|
||||
/* this dropped the lock - need to retest */
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
|
||||
bytes_copied = 0;
|
||||
current_rx_req = dev->current_rx_req;
|
||||
@ -494,6 +495,8 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||
wait_event_interruptible(dev->rx_wait,
|
||||
(likely(!list_empty(&dev->rx_buffers))));
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
}
|
||||
|
||||
/* We have data to return then copy it to the caller's buffer.*/
|
||||
@ -537,6 +540,9 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
|
||||
/* If we not returning all the data left in this RX request
|
||||
* buffer then adjust the amount of data left in the buffer.
|
||||
* Othewise if we are done with this RX request buffer then
|
||||
@ -566,6 +572,11 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||
return bytes_copied;
|
||||
else
|
||||
return -EAGAIN;
|
||||
|
||||
out_disabled:
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
mutex_unlock(&dev->lock_printer_io);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -586,11 +597,8 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
mutex_lock(&dev->lock_printer_io);
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
if (dev->interface < 0) {
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
mutex_unlock(&dev->lock_printer_io);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
|
||||
/* Check if a printer reset happens while we have interrupts on */
|
||||
dev->reset_printer = 0;
|
||||
@ -613,6 +621,8 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
wait_event_interruptible(dev->tx_wait,
|
||||
(likely(!list_empty(&dev->tx_reqs))));
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
}
|
||||
|
||||
while (likely(!list_empty(&dev->tx_reqs)) && len) {
|
||||
@ -662,6 +672,9 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
|
||||
list_add(&req->list, &dev->tx_reqs_active);
|
||||
|
||||
/* here, we unlock, and only unlock, to avoid deadlock. */
|
||||
@ -674,6 +687,8 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
mutex_unlock(&dev->lock_printer_io);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (dev->interface < 0)
|
||||
goto out_disabled;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
@ -685,6 +700,11 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
return bytes_copied;
|
||||
else
|
||||
return -EAGAIN;
|
||||
|
||||
out_disabled:
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
mutex_unlock(&dev->lock_printer_io);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1163,8 +1163,6 @@ struct net_device *gether_connect(struct gether *link)
|
||||
if (netif_running(dev->net))
|
||||
eth_start(dev, GFP_ATOMIC);
|
||||
|
||||
netif_device_attach(dev->net);
|
||||
|
||||
/* on error, disable any endpoints */
|
||||
} else {
|
||||
(void) usb_ep_disable(link->out_ep);
|
||||
@ -1202,7 +1200,7 @@ void gether_disconnect(struct gether *link)
|
||||
|
||||
DBG(dev, "%s\n", __func__);
|
||||
|
||||
netif_device_detach(dev->net);
|
||||
netif_stop_queue(dev->net);
|
||||
netif_carrier_off(dev->net);
|
||||
|
||||
/* disable endpoints, forcing (synchronous) completion
|
||||
|
@ -66,8 +66,8 @@
|
||||
#define USB_UPSTREAM_EN BIT(0)
|
||||
|
||||
/* Main config reg */
|
||||
#define UDC_CFG_SET_ADDR(x) ((x) & 0x3f)
|
||||
#define UDC_CFG_ADDR_MASK (0x3f)
|
||||
#define UDC_CFG_SET_ADDR(x) ((x) & UDC_CFG_ADDR_MASK)
|
||||
#define UDC_CFG_ADDR_MASK GENMASK(6, 0)
|
||||
|
||||
/* Interrupt ctrl & status reg */
|
||||
#define UDC_IRQ_EP_POOL_NAK BIT(17)
|
||||
|
@ -556,7 +556,7 @@ static int da8xx_probe(struct platform_device *pdev)
|
||||
ret = of_platform_populate(pdev->dev.of_node, NULL,
|
||||
da8xx_auxdata_lookup, &pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_unregister_phy;
|
||||
|
||||
pinfo = da8xx_dev_info;
|
||||
pinfo.parent = &pdev->dev;
|
||||
@ -571,9 +571,13 @@ static int da8xx_probe(struct platform_device *pdev)
|
||||
ret = PTR_ERR_OR_ZERO(glue->musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);
|
||||
usb_phy_generic_unregister(glue->usb_phy);
|
||||
goto err_unregister_phy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_phy:
|
||||
usb_phy_generic_unregister(glue->usb_phy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ struct ucsi_acpi {
|
||||
unsigned long flags;
|
||||
#define UCSI_ACPI_COMMAND_PENDING 1
|
||||
#define UCSI_ACPI_ACK_PENDING 2
|
||||
#define UCSI_ACPI_CHECK_BOGUS_EVENT 3
|
||||
guid_t guid;
|
||||
u64 cmd;
|
||||
};
|
||||
@ -128,6 +129,58 @@ static const struct ucsi_operations ucsi_zenbook_ops = {
|
||||
.async_write = ucsi_acpi_async_write
|
||||
};
|
||||
|
||||
static int ucsi_gram_read(struct ucsi *ucsi, unsigned int offset,
|
||||
void *val, size_t val_len)
|
||||
{
|
||||
u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE |
|
||||
UCSI_CONSTAT_PDOS_CHANGE;
|
||||
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||
struct ucsi_connector_status *status;
|
||||
int ret;
|
||||
|
||||
ret = ucsi_acpi_read(ucsi, offset, val, val_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS &&
|
||||
test_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags) &&
|
||||
offset == UCSI_MESSAGE_IN) {
|
||||
status = (struct ucsi_connector_status *)val;
|
||||
|
||||
/* Clear the bogus change */
|
||||
if (status->change == bogus_change)
|
||||
status->change = 0;
|
||||
|
||||
clear_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ucsi_gram_sync_write(struct ucsi *ucsi, unsigned int offset,
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||
int ret;
|
||||
|
||||
ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_PDOS &&
|
||||
ua->cmd & UCSI_GET_PDOS_PARTNER_PDO(1) &&
|
||||
ua->cmd & UCSI_GET_PDOS_SRC_PDOS)
|
||||
set_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ucsi_operations ucsi_gram_ops = {
|
||||
.read = ucsi_gram_read,
|
||||
.sync_write = ucsi_gram_sync_write,
|
||||
.async_write = ucsi_acpi_async_write
|
||||
};
|
||||
|
||||
static const struct dmi_system_id ucsi_acpi_quirks[] = {
|
||||
{
|
||||
.matches = {
|
||||
@ -136,6 +189,14 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = {
|
||||
},
|
||||
.driver_data = (void *)&ucsi_zenbook_ops,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "LG gram PC"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "90Q"),
|
||||
},
|
||||
.driver_data = (void *)&ucsi_gram_ops,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -372,6 +372,7 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
|
||||
ret = fwnode_property_read_u32(fwnode, "reg", &port);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "missing reg property of %pOFn\n", fwnode);
|
||||
fwnode_handle_put(fwnode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -386,9 +387,11 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
|
||||
if (!desc)
|
||||
continue;
|
||||
|
||||
if (IS_ERR(desc))
|
||||
if (IS_ERR(desc)) {
|
||||
fwnode_handle_put(fwnode);
|
||||
return dev_err_probe(dev, PTR_ERR(desc),
|
||||
"unable to acquire orientation gpio\n");
|
||||
}
|
||||
ucsi->port_orientation[port] = desc;
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@ struct ucsi_stm32g0 {
|
||||
struct device *dev;
|
||||
unsigned long flags;
|
||||
#define COMMAND_PENDING 1
|
||||
#define ACK_PENDING 2
|
||||
const char *fw_name;
|
||||
struct ucsi *ucsi;
|
||||
bool suspended;
|
||||
@ -396,9 +397,13 @@ static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const
|
||||
size_t len)
|
||||
{
|
||||
struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi);
|
||||
bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI;
|
||||
int ret;
|
||||
|
||||
set_bit(COMMAND_PENDING, &g0->flags);
|
||||
if (ack)
|
||||
set_bit(ACK_PENDING, &g0->flags);
|
||||
else
|
||||
set_bit(COMMAND_PENDING, &g0->flags);
|
||||
|
||||
ret = ucsi_stm32g0_async_write(ucsi, offset, val, len);
|
||||
if (ret)
|
||||
@ -406,9 +411,14 @@ static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const
|
||||
|
||||
if (!wait_for_completion_timeout(&g0->complete, msecs_to_jiffies(5000)))
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
return 0;
|
||||
|
||||
out_clear_bit:
|
||||
clear_bit(COMMAND_PENDING, &g0->flags);
|
||||
if (ack)
|
||||
clear_bit(ACK_PENDING, &g0->flags);
|
||||
else
|
||||
clear_bit(COMMAND_PENDING, &g0->flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -429,8 +439,9 @@ static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data)
|
||||
if (UCSI_CCI_CONNECTOR(cci))
|
||||
ucsi_connector_change(g0->ucsi, UCSI_CCI_CONNECTOR(cci));
|
||||
|
||||
if (test_bit(COMMAND_PENDING, &g0->flags) &&
|
||||
cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
|
||||
if (cci & UCSI_CCI_ACK_COMPLETE && test_and_clear_bit(ACK_PENDING, &g0->flags))
|
||||
complete(&g0->complete);
|
||||
if (cci & UCSI_CCI_COMMAND_COMPLETE && test_and_clear_bit(COMMAND_PENDING, &g0->flags))
|
||||
complete(&g0->complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
Loading…
Reference in New Issue
Block a user