Commit 28318f53 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull USB fixes from Greg KH:
 "Here are a number of small USB driver fixes for 5.11-rc3.

  Include in here are:

   - USB gadget driver fixes for reported issues

   - new usb-serial driver ids

   - dma from stack bugfixes

   - typec bugfixes

   - dwc3 bugfixes

   - xhci driver bugfixes

   - other small misc usb driver bugfixes

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

* tag 'usb-5.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (35 commits)
  usb: dwc3: gadget: Clear wait flag on dequeue
  usb: typec: Send uevent for num_altmodes update
  usb: typec: Fix copy paste error for NVIDIA alt-mode description
  usb: gadget: enable super speed plus
  kcov, usb: hide in_serving_softirq checks in __usb_hcd_giveback_urb
  usb: uas: Add PNY USB Portable SSD to unusual_uas
  usb: gadget: configfs: Preserve function ordering after bind failure
  usb: gadget: select CONFIG_CRC32
  usb: gadget: core: change the comment for usb_gadget_connect
  usb: gadget: configfs: Fix use-after-free issue with udc_name
  usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup
  usb: usbip: vhci_hcd: protect shift size
  USB: usblp: fix DMA to stack
  USB: serial: iuu_phoenix: fix DMA from stack
  USB: serial: option: add LongSung M5710 module support
  USB: serial: option: add Quectel EM160R-GL
  USB: Gadget: dummy-hcd: Fix shift-out-of-bounds bug
  usb: gadget: f_uac2: reset wMaxPacketSize
  usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression
  usb: dwc3: ulpi: Replace CPU-based busyloop with Protocol-based one
  ...
parents 4ad9a28f a5c7682a
...@@ -11,8 +11,12 @@ maintainers: ...@@ -11,8 +11,12 @@ maintainers:
properties: properties:
compatible: compatible:
items: oneOf:
- const: ti,j721e-usb - const: ti,j721e-usb
- const: ti,am64-usb
- items:
- const: ti,j721e-usb
- const: ti,am64-usb
reg: reg:
description: module registers description: module registers
......
...@@ -3883,7 +3883,7 @@ F: drivers/mtd/nand/raw/cadence-nand-controller.c ...@@ -3883,7 +3883,7 @@ F: drivers/mtd/nand/raw/cadence-nand-controller.c
CADENCE USB3 DRD IP DRIVER CADENCE USB3 DRD IP DRIVER
M: Peter Chen <peter.chen@nxp.com> M: Peter Chen <peter.chen@nxp.com>
M: Pawel Laszczak <pawell@cadence.com> M: Pawel Laszczak <pawell@cadence.com>
M: Roger Quadros <rogerq@ti.com> R: Roger Quadros <rogerq@kernel.org>
R: Aswath Govindraju <a-govindraju@ti.com> R: Aswath Govindraju <a-govindraju@ti.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
......
...@@ -139,9 +139,13 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) ...@@ -139,9 +139,13 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
misc_pdev = of_find_device_by_node(args.np); misc_pdev = of_find_device_by_node(args.np);
of_node_put(args.np); of_node_put(args.np);
if (!misc_pdev || !platform_get_drvdata(misc_pdev)) if (!misc_pdev)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
if (!platform_get_drvdata(misc_pdev)) {
put_device(&misc_pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
data->dev = &misc_pdev->dev; data->dev = &misc_pdev->dev;
/* /*
......
...@@ -1895,6 +1895,10 @@ static const struct usb_device_id acm_ids[] = { ...@@ -1895,6 +1895,10 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x04d8, 0xfd08), { USB_DEVICE(0x04d8, 0xfd08),
.driver_info = IGNORE_DEVICE, .driver_info = IGNORE_DEVICE,
}, },
{ USB_DEVICE(0x04d8, 0xf58b),
.driver_info = IGNORE_DEVICE,
},
#endif #endif
/*Samsung phone in firmware update mode */ /*Samsung phone in firmware update mode */
......
...@@ -465,13 +465,23 @@ static int service_outstanding_interrupt(struct wdm_device *desc) ...@@ -465,13 +465,23 @@ static int service_outstanding_interrupt(struct wdm_device *desc)
if (!desc->resp_count || !--desc->resp_count) if (!desc->resp_count || !--desc->resp_count)
goto out; goto out;
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
rv = -ENODEV;
goto out;
}
if (test_bit(WDM_RESETTING, &desc->flags)) {
rv = -EIO;
goto out;
}
set_bit(WDM_RESPONDING, &desc->flags); set_bit(WDM_RESPONDING, &desc->flags);
spin_unlock_irq(&desc->iuspin); spin_unlock_irq(&desc->iuspin);
rv = usb_submit_urb(desc->response, GFP_KERNEL); rv = usb_submit_urb(desc->response, GFP_KERNEL);
spin_lock_irq(&desc->iuspin); spin_lock_irq(&desc->iuspin);
if (rv) { if (rv) {
dev_err(&desc->intf->dev, if (!test_bit(WDM_DISCONNECTING, &desc->flags))
"usb_submit_urb failed with result %d\n", rv); dev_err(&desc->intf->dev,
"usb_submit_urb failed with result %d\n", rv);
/* make sure the next notification trigger a submit */ /* make sure the next notification trigger a submit */
clear_bit(WDM_RESPONDING, &desc->flags); clear_bit(WDM_RESPONDING, &desc->flags);
...@@ -1027,9 +1037,9 @@ static void wdm_disconnect(struct usb_interface *intf) ...@@ -1027,9 +1037,9 @@ static void wdm_disconnect(struct usb_interface *intf)
wake_up_all(&desc->wait); wake_up_all(&desc->wait);
mutex_lock(&desc->rlock); mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock); mutex_lock(&desc->wlock);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->rxwork);
cancel_work_sync(&desc->service_outs_intr); cancel_work_sync(&desc->service_outs_intr);
kill_urbs(desc);
mutex_unlock(&desc->wlock); mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock); mutex_unlock(&desc->rlock);
......
...@@ -274,8 +274,25 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i ...@@ -274,8 +274,25 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
#define usblp_reset(usblp)\ #define usblp_reset(usblp)\
usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
#define usblp_hp_channel_change_request(usblp, channel, buffer) \ static int usblp_hp_channel_change_request(struct usblp *usblp, int channel, u8 *new_channel)
usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) {
u8 *buf;
int ret;
buf = kzalloc(1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST,
USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE,
channel, buf, 1);
if (ret == 0)
*new_channel = buf[0];
kfree(buf);
return ret;
}
/* /*
* See the description for usblp_select_alts() below for the usage * See the description for usblp_select_alts() below for the usage
......
...@@ -1649,14 +1649,12 @@ static void __usb_hcd_giveback_urb(struct urb *urb) ...@@ -1649,14 +1649,12 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
urb->status = status; urb->status = status;
/* /*
* This function can be called in task context inside another remote * This function can be called in task context inside another remote
* coverage collection section, but KCOV doesn't support that kind of * coverage collection section, but kcov doesn't support that kind of
* recursion yet. Only collect coverage in softirq context for now. * recursion yet. Only collect coverage in softirq context for now.
*/ */
if (in_serving_softirq()) kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum);
kcov_remote_start_usb((u64)urb->dev->bus->busnum);
urb->complete(urb); urb->complete(urb);
if (in_serving_softirq()) kcov_remote_stop_softirq();
kcov_remote_stop();
usb_anchor_resume_wakeups(anchor); usb_anchor_resume_wakeups(anchor);
atomic_dec(&urb->use_count); atomic_dec(&urb->use_count);
......
...@@ -285,6 +285,7 @@ ...@@ -285,6 +285,7 @@
/* Global USB2 PHY Vendor Control Register */ /* Global USB2 PHY Vendor Control Register */
#define DWC3_GUSB2PHYACC_NEWREGREQ BIT(25) #define DWC3_GUSB2PHYACC_NEWREGREQ BIT(25)
#define DWC3_GUSB2PHYACC_DONE BIT(24)
#define DWC3_GUSB2PHYACC_BUSY BIT(23) #define DWC3_GUSB2PHYACC_BUSY BIT(23)
#define DWC3_GUSB2PHYACC_WRITE BIT(22) #define DWC3_GUSB2PHYACC_WRITE BIT(22)
#define DWC3_GUSB2PHYACC_ADDR(n) (n << 16) #define DWC3_GUSB2PHYACC_ADDR(n) (n << 16)
......
...@@ -754,7 +754,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) ...@@ -754,7 +754,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
ret = priv->drvdata->setup_regmaps(priv, base); ret = priv->drvdata->setup_regmaps(priv, base);
if (ret) if (ret)
return ret; goto err_disable_clks;
if (priv->vbus) { if (priv->vbus) {
ret = regulator_enable(priv->vbus); ret = regulator_enable(priv->vbus);
......
...@@ -1763,6 +1763,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -1763,6 +1763,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
list_for_each_entry_safe(r, t, &dep->started_list, list) list_for_each_entry_safe(r, t, &dep->started_list, list)
dwc3_gadget_move_cancelled_request(r); dwc3_gadget_move_cancelled_request(r);
dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE;
goto out; goto out;
} }
} }
...@@ -2083,6 +2085,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) ...@@ -2083,6 +2085,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
static void dwc3_gadget_disable_irq(struct dwc3 *dwc); static void dwc3_gadget_disable_irq(struct dwc3 *dwc);
static void __dwc3_gadget_stop(struct dwc3 *dwc); static void __dwc3_gadget_stop(struct dwc3 *dwc);
static int __dwc3_gadget_start(struct dwc3 *dwc);
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
{ {
...@@ -2145,6 +2148,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) ...@@ -2145,6 +2148,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) % dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) %
dwc->ev_buf->length; dwc->ev_buf->length;
} }
} else {
__dwc3_gadget_start(dwc);
} }
ret = dwc3_gadget_run_stop(dwc, is_on, false); ret = dwc3_gadget_run_stop(dwc, is_on, false);
...@@ -2319,10 +2324,6 @@ static int dwc3_gadget_start(struct usb_gadget *g, ...@@ -2319,10 +2324,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
} }
dwc->gadget_driver = driver; dwc->gadget_driver = driver;
if (pm_runtime_active(dwc->dev))
__dwc3_gadget_start(dwc);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
return 0; return 0;
...@@ -2348,13 +2349,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g) ...@@ -2348,13 +2349,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
if (pm_runtime_suspended(dwc->dev))
goto out;
__dwc3_gadget_stop(dwc);
out:
dwc->gadget_driver = NULL; dwc->gadget_driver = NULL;
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
*/ */
#include <linux/delay.h>
#include <linux/time64.h>
#include <linux/ulpi/regs.h> #include <linux/ulpi/regs.h>
#include "core.h" #include "core.h"
...@@ -17,14 +19,28 @@ ...@@ -17,14 +19,28 @@
DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \ DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a)) DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
static int dwc3_ulpi_busyloop(struct dwc3 *dwc) #define DWC3_ULPI_BASE_DELAY DIV_ROUND_UP(NSEC_PER_SEC, 60000000L)
static int dwc3_ulpi_busyloop(struct dwc3 *dwc, u8 addr, bool read)
{ {
unsigned int count = 1000; unsigned long ns = 5L * DWC3_ULPI_BASE_DELAY;
unsigned int count = 10000;
u32 reg; u32 reg;
if (addr >= ULPI_EXT_VENDOR_SPECIFIC)
ns += DWC3_ULPI_BASE_DELAY;
if (read)
ns += DWC3_ULPI_BASE_DELAY;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (reg & DWC3_GUSB2PHYCFG_SUSPHY)
usleep_range(1000, 1200);
while (count--) { while (count--) {
ndelay(ns);
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0)); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
if (!(reg & DWC3_GUSB2PHYACC_BUSY)) if (reg & DWC3_GUSB2PHYACC_DONE)
return 0; return 0;
cpu_relax(); cpu_relax();
} }
...@@ -38,16 +54,10 @@ static int dwc3_ulpi_read(struct device *dev, u8 addr) ...@@ -38,16 +54,10 @@ static int dwc3_ulpi_read(struct device *dev, u8 addr)
u32 reg; u32 reg;
int ret; int ret;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
ret = dwc3_ulpi_busyloop(dwc); ret = dwc3_ulpi_busyloop(dwc, addr, true);
if (ret) if (ret)
return ret; return ret;
...@@ -61,17 +71,11 @@ static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val) ...@@ -61,17 +71,11 @@ static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
struct dwc3 *dwc = dev_get_drvdata(dev); struct dwc3 *dwc = dev_get_drvdata(dev);
u32 reg; u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
reg |= DWC3_GUSB2PHYACC_WRITE | val; reg |= DWC3_GUSB2PHYACC_WRITE | val;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
return dwc3_ulpi_busyloop(dwc); return dwc3_ulpi_busyloop(dwc, addr, false);
} }
static const struct ulpi_ops dwc3_ulpi_ops = { static const struct ulpi_ops dwc3_ulpi_ops = {
......
...@@ -265,6 +265,7 @@ config USB_CONFIGFS_NCM ...@@ -265,6 +265,7 @@ config USB_CONFIGFS_NCM
depends on NET depends on NET
select USB_U_ETHER select USB_U_ETHER
select USB_F_NCM select USB_F_NCM
select CRC32
help help
NCM is an advanced protocol for Ethernet encapsulation, allows NCM is an advanced protocol for Ethernet encapsulation, allows
grouping of several ethernet frames into one USB transfer and grouping of several ethernet frames into one USB transfer and
...@@ -314,6 +315,7 @@ config USB_CONFIGFS_EEM ...@@ -314,6 +315,7 @@ config USB_CONFIGFS_EEM
depends on NET depends on NET
select USB_U_ETHER select USB_U_ETHER
select USB_F_EEM select USB_F_EEM
select CRC32
help help
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
and therefore can be supported by more hardware. Technically ECM and and therefore can be supported by more hardware. Technically ECM and
......
...@@ -392,8 +392,11 @@ int usb_function_deactivate(struct usb_function *function) ...@@ -392,8 +392,11 @@ int usb_function_deactivate(struct usb_function *function)
spin_lock_irqsave(&cdev->lock, flags); spin_lock_irqsave(&cdev->lock, flags);
if (cdev->deactivations == 0) if (cdev->deactivations == 0) {
spin_unlock_irqrestore(&cdev->lock, flags);
status = usb_gadget_deactivate(cdev->gadget); status = usb_gadget_deactivate(cdev->gadget);
spin_lock_irqsave(&cdev->lock, flags);
}
if (status == 0) if (status == 0)
cdev->deactivations++; cdev->deactivations++;
...@@ -424,8 +427,11 @@ int usb_function_activate(struct usb_function *function) ...@@ -424,8 +427,11 @@ int usb_function_activate(struct usb_function *function)
status = -EINVAL; status = -EINVAL;
else { else {
cdev->deactivations--; cdev->deactivations--;
if (cdev->deactivations == 0) if (cdev->deactivations == 0) {
spin_unlock_irqrestore(&cdev->lock, flags);
status = usb_gadget_activate(cdev->gadget); status = usb_gadget_activate(cdev->gadget);
spin_lock_irqsave(&cdev->lock, flags);
}
} }
spin_unlock_irqrestore(&cdev->lock, flags); spin_unlock_irqrestore(&cdev->lock, flags);
......
...@@ -221,9 +221,16 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct config_item *item, ...@@ -221,9 +221,16 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct config_item *item,
static ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page) static ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page)
{ {
char *udc_name = to_gadget_info(item)->composite.gadget_driver.udc_name; struct gadget_info *gi = to_gadget_info(item);
char *udc_name;
int ret;
mutex_lock(&gi->lock);
udc_name = gi->composite.gadget_driver.udc_name;
ret = sprintf(page, "%s\n", udc_name ?: "");
mutex_unlock(&gi->lock);
return sprintf(page, "%s\n", udc_name ?: ""); return ret;
} }
static int unregister_gadget(struct gadget_info *gi) static int unregister_gadget(struct gadget_info *gi)
...@@ -1248,9 +1255,9 @@ static void purge_configs_funcs(struct gadget_info *gi) ...@@ -1248,9 +1255,9 @@ static void purge_configs_funcs(struct gadget_info *gi)
cfg = container_of(c, struct config_usb_cfg, c); cfg = container_of(c, struct config_usb_cfg, c);
list_for_each_entry_safe(f, tmp, &c->functions, list) { list_for_each_entry_safe_reverse(f, tmp, &c->functions, list) {
list_move_tail(&f->list, &cfg->func_list); list_move(&f->list, &cfg->func_list);
if (f->unbind) { if (f->unbind) {
dev_dbg(&gi->cdev.gadget->dev, dev_dbg(&gi->cdev.gadget->dev,
"unbind function '%s'/%p\n", "unbind function '%s'/%p\n",
...@@ -1536,7 +1543,7 @@ static const struct usb_gadget_driver configfs_driver_template = { ...@@ -1536,7 +1543,7 @@ static const struct usb_gadget_driver configfs_driver_template = {
.suspend = configfs_composite_suspend, .suspend = configfs_composite_suspend,
.resume = configfs_composite_resume, .resume = configfs_composite_resume,
.max_speed = USB_SPEED_SUPER, .max_speed = USB_SPEED_SUPER_PLUS,
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "configfs-gadget", .name = "configfs-gadget",
...@@ -1576,7 +1583,7 @@ static struct config_group *gadgets_make( ...@@ -1576,7 +1583,7 @@ static struct config_group *gadgets_make(
gi->composite.unbind = configfs_do_nothing; gi->composite.unbind = configfs_do_nothing;
gi->composite.suspend = NULL; gi->composite.suspend = NULL;
gi->composite.resume = NULL; gi->composite.resume = NULL;
gi->composite.max_speed = USB_SPEED_SUPER; gi->composite.max_speed = USB_SPEED_SUPER_PLUS;
spin_lock_init(&gi->spinlock); spin_lock_init(&gi->spinlock);
mutex_init(&gi->lock); mutex_init(&gi->lock);
......
...@@ -1162,6 +1162,7 @@ static int printer_func_bind(struct usb_configuration *c, ...@@ -1162,6 +1162,7 @@ static int printer_func_bind(struct usb_configuration *c,
printer_req_free(dev->in_ep, req); printer_req_free(dev->in_ep, req);
} }
usb_free_all_descriptors(f);
return ret; return ret;
} }
......
...@@ -271,7 +271,7 @@ static struct usb_endpoint_descriptor fs_epout_desc = { ...@@ -271,7 +271,7 @@ static struct usb_endpoint_descriptor fs_epout_desc = {
.bEndpointAddress = USB_DIR_OUT, .bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
.wMaxPacketSize = cpu_to_le16(1023), /* .wMaxPacketSize = DYNAMIC */
.bInterval = 1, .bInterval = 1,
}; };
...@@ -280,7 +280,7 @@ static struct usb_endpoint_descriptor hs_epout_desc = { ...@@ -280,7 +280,7 @@ static struct usb_endpoint_descriptor hs_epout_desc = {
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
.wMaxPacketSize = cpu_to_le16(1024), /* .wMaxPacketSize = DYNAMIC */
.bInterval = 4, .bInterval = 4,
}; };
...@@ -348,7 +348,7 @@ static struct usb_endpoint_descriptor fs_epin_desc = { ...@@ -348,7 +348,7 @@ static struct usb_endpoint_descriptor fs_epin_desc = {
.bEndpointAddress = USB_DIR_IN, .bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
.wMaxPacketSize = cpu_to_le16(1023), /* .wMaxPacketSize = DYNAMIC */
.bInterval = 1, .bInterval = 1,
}; };
...@@ -357,7 +357,7 @@ static struct usb_endpoint_descriptor hs_epin_desc = { ...@@ -357,7 +357,7 @@ static struct usb_endpoint_descriptor hs_epin_desc = {
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
.wMaxPacketSize = cpu_to_le16(1024), /* .wMaxPacketSize = DYNAMIC */
.bInterval = 4, .bInterval = 4,
}; };
...@@ -444,12 +444,28 @@ struct cntrl_range_lay3 { ...@@ -444,12 +444,28 @@ struct cntrl_range_lay3 {
__le32 dRES; __le32 dRES;
} __packed; } __packed;
static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
struct usb_endpoint_descriptor *ep_desc, struct usb_endpoint_descriptor *ep_desc,
unsigned int factor, bool is_playback) enum usb_device_speed speed, bool is_playback)
{ {
int chmask, srate, ssize; int chmask, srate, ssize;
u16 max_packet_size; u16 max_size_bw, max_size_ep;
unsigned int factor;
switch (speed) {
case USB_SPEED_FULL:
max_size_ep = 1023;
factor = 1000;
break;
case USB_SPEED_HIGH:
max_size_ep = 1024;
factor = 8000;
break;
default:
return -EINVAL;
}
if (is_playback) { if (is_playback) {
chmask = uac2_opts->p_chmask; chmask = uac2_opts->p_chmask;
...@@ -461,10 +477,12 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, ...@@ -461,10 +477,12 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
ssize = uac2_opts->c_ssize; ssize = uac2_opts->c_ssize;
} }
max_packet_size = num_channels(chmask) * ssize * max_size_bw = num_channels(chmask) * ssize *
DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_packet_size, ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
le16_to_cpu(ep_desc->wMaxPacketSize))); max_size_ep));
return 0;
} }
/* Use macro to overcome line length limitation */ /* Use macro to overcome line length limitation */
...@@ -670,10 +688,33 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) ...@@ -670,10 +688,33 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
} }
/* Calculate wMaxPacketSize according to audio bandwidth */ /* Calculate wMaxPacketSize according to audio bandwidth */
set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL,
set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false); true);
set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); if (ret < 0) {
set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
ret = set_ep_max_packet_size(uac2_opts, &fs_epout_desc, USB_SPEED_FULL,
false);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
ret = set_ep_max_packet_size(uac2_opts, &hs_epin_desc, USB_SPEED_HIGH,
true);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
ret = set_ep_max_packet_size(uac2_opts, &hs_epout_desc, USB_SPEED_HIGH,
false);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
if (EPOUT_EN(uac2_opts)) { if (EPOUT_EN(uac2_opts)) {
agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
......
...@@ -45,9 +45,10 @@ ...@@ -45,9 +45,10 @@
#define UETH__VERSION "29-May-2008" #define UETH__VERSION "29-May-2008"
/* Experiments show that both Linux and Windows hosts allow up to 16k /* Experiments show that both Linux and Windows hosts allow up to 16k
* frame sizes. Set the max size to 15k+52 to prevent allocating 32k * frame sizes. Set the max MTU size to 15k+52 to prevent allocating 32k
* blocks and still have efficient handling. */ * blocks and still have efficient handling. */
#define GETHER_MAX_ETH_FRAME_LEN 15412 #define GETHER_MAX_MTU_SIZE 15412
#define GETHER_MAX_ETH_FRAME_LEN (GETHER_MAX_MTU_SIZE + ETH_HLEN)
struct eth_dev { struct eth_dev {
/* lock is held while accessing port_usb /* lock is held while accessing port_usb
...@@ -786,7 +787,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, ...@@ -786,7 +787,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
/* MTU range: 14 - 15412 */ /* MTU range: 14 - 15412 */
net->min_mtu = ETH_HLEN; net->min_mtu = ETH_HLEN;
net->max_mtu = GETHER_MAX_ETH_FRAME_LEN; net->max_mtu = GETHER_MAX_MTU_SIZE;
dev->gadget = g; dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev); SET_NETDEV_DEV(net, &g->dev);
...@@ -848,7 +849,7 @@ struct net_device *gether_setup_name_default(const char *netname) ...@@ -848,7 +849,7 @@ struct net_device *gether_setup_name_default(const char *netname)
/* MTU range: 14 - 15412 */ /* MTU range: 14 - 15412 */
net->min_mtu = ETH_HLEN; net->min_mtu = ETH_HLEN;
net->max_mtu = GETHER_MAX_ETH_FRAME_LEN; net->max_mtu = GETHER_MAX_MTU_SIZE;
return net; return net;
} }
......
...@@ -200,8 +200,10 @@ static int acm_ms_bind(struct usb_composite_dev *cdev) ...@@ -200,8 +200,10 @@ static int acm_ms_bind(struct usb_composite_dev *cdev)
struct usb_descriptor_header *usb_desc; struct usb_descriptor_header *usb_desc;
usb_desc = usb_otg_descriptor_alloc(gadget); usb_desc = usb_otg_descriptor_alloc(gadget);
if (!usb_desc) if (!usb_desc) {
status = -ENOMEM;
goto fail_string_ids; goto fail_string_ids;
}
usb_otg_descriptor_init(gadget, usb_desc); usb_otg_descriptor_init(gadget, usb_desc);
otg_desc[0] = usb_desc; otg_desc[0] = usb_desc;
otg_desc[1] = NULL; otg_desc[1] = NULL;
......
...@@ -90,7 +90,7 @@ config USB_BCM63XX_UDC ...@@ -90,7 +90,7 @@ config USB_BCM63XX_UDC
config USB_FSL_USB2 config USB_FSL_USB2
tristate "Freescale Highspeed USB DR Peripheral Controller" tristate "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC || ARCH_MXC depends on FSL_SOC
help help
Some of Freescale PowerPC and i.MX processors have a High Speed Some of Freescale PowerPC and i.MX processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode. Dual-Role(DR) USB controller, which supports device mode.
......
...@@ -23,7 +23,6 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o ...@@ -23,7 +23,6 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
fsl_usb2_udc-y := fsl_udc_core.o fsl_usb2_udc-y := fsl_udc_core.o
fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
obj-$(CONFIG_USB_TEGRA_XUDC) += tegra-xudc.o obj-$(CONFIG_USB_TEGRA_XUDC) += tegra-xudc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
......
...@@ -659,8 +659,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); ...@@ -659,8 +659,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
* *
* Enables the D+ (or potentially D-) pullup. The host will start * Enables the D+ (or potentially D-) pullup. The host will start
* enumerating this gadget when the pullup is active and a VBUS session * enumerating this gadget when the pullup is active and a VBUS session
* is active (the link is powered). This pullup is always enabled unless * is active (the link is powered).
* usb_gadget_disconnect() has been used to disable it.
* *
* Returns zero on success, else negative errno. * Returns zero on success, else negative errno.
*/ */
......
...@@ -2118,9 +2118,21 @@ static int dummy_hub_control( ...@@ -2118,9 +2118,21 @@ static int dummy_hub_control(
dum_hcd->port_status &= ~USB_PORT_STAT_POWER; dum_hcd->port_status &= ~USB_PORT_STAT_POWER;
set_link_state(dum_hcd); set_link_state(dum_hcd);
break; break;
default: case USB_PORT_FEAT_ENABLE:
case USB_PORT_FEAT_C_ENABLE:
case USB_PORT_FEAT_C_SUSPEND:
/* Not allowed for USB-3 */
if (hcd->speed == HCD_USB3)
goto error;
fallthrough;
case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_RESET:
dum_hcd->port_status &= ~(1 << wValue); dum_hcd->port_status &= ~(1 << wValue);
set_link_state(dum_hcd); set_link_state(dum_hcd);
break;
default:
/* Disallow INDICATOR and C_OVER_CURRENT */
goto error;
} }
break; break;
case GetHubDescriptor: case GetHubDescriptor:
...@@ -2281,18 +2293,17 @@ static int dummy_hub_control( ...@@ -2281,18 +2293,17 @@ static int dummy_hub_control(
*/ */
dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
fallthrough; fallthrough;
case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_RESET:
case USB_PORT_FEAT_C_ENABLE:
case USB_PORT_FEAT_C_SUSPEND:
/* Not allowed for USB-3, and ignored for USB-2 */
if (hcd->speed == HCD_USB3)
goto error;
break;
default: default:
if (hcd->speed == HCD_USB3) { /* Disallow TEST, INDICATOR, and C_OVER_CURRENT */
if ((dum_hcd->port_status & goto error;
USB_SS_PORT_STAT_POWER) != 0) {
dum_hcd->port_status |= (1 << wValue);
}
} else
if ((dum_hcd->port_status &
USB_PORT_STAT_POWER) != 0) {
dum_hcd->port_status |= (1 << wValue);
}
set_link_state(dum_hcd);
} }
break; break;
case GetPortErrorCount: case GetPortErrorCount:
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2009
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
*
* Description:
* Helper routines for i.MX3x SoCs from Freescale, needed by the fsl_usb2_udc.c
* driver to function correctly on these systems.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fsl_devices.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include "fsl_usb2_udc.h"
static struct clk *mxc_ahb_clk;
static struct clk *mxc_per_clk;
static struct clk *mxc_ipg_clk;
/* workaround ENGcm09152 for i.MX35 */
#define MX35_USBPHYCTRL_OFFSET 0x600
#define USBPHYCTRL_OTGBASE_OFFSET 0x8
#define USBPHYCTRL_EVDO (1 << 23)
int fsl_udc_clk_init(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata;
unsigned long freq;
int ret;
pdata = dev_get_platdata(&pdev->dev);
mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(mxc_ipg_clk)) {
dev_err(&pdev->dev, "clk_get(\"ipg\") failed\n");
return PTR_ERR(mxc_ipg_clk);
}
mxc_ahb_clk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(mxc_ahb_clk)) {
dev_err(&pdev->dev, "clk_get(\"ahb\") failed\n");
return PTR_ERR(mxc_ahb_clk);
}
mxc_per_clk = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(mxc_per_clk)) {
dev_err(&pdev->dev, "clk_get(\"per\") failed\n");
return PTR_ERR(mxc_per_clk);
}
clk_prepare_enable(mxc_ipg_clk);
clk_prepare_enable(mxc_ahb_clk);
clk_prepare_enable(mxc_per_clk);
/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
if (!strcmp(pdev->id_entry->name, "imx-udc-mx27")) {
freq = clk_get_rate(mxc_per_clk);
if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
(freq < 59999000 || freq > 60001000)) {
dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
ret = -EINVAL;
goto eclkrate;
}
}
return 0;
eclkrate:
clk_disable_unprepare(mxc_ipg_clk);
clk_disable_unprepare(mxc_ahb_clk);
clk_disable_unprepare(mxc_per_clk);
mxc_per_clk = NULL;
return ret;
}
int fsl_udc_clk_finalize(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
int ret = 0;
/* workaround ENGcm09152 for i.MX35 */
if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
unsigned int v;
struct resource *res = platform_get_resource
(pdev, IORESOURCE_MEM, 0);
void __iomem *phy_regs = ioremap(res->start +
MX35_USBPHYCTRL_OFFSET, 512);
if (!phy_regs) {
dev_err(&pdev->dev, "ioremap for phy address fails\n");
ret = -EINVAL;
goto ioremap_err;
}
v = readl(phy_regs + USBPHYCTRL_OTGBASE_OFFSET);
writel(v | USBPHYCTRL_EVDO,
phy_regs + USBPHYCTRL_OTGBASE_OFFSET);
iounmap(phy_regs);
}
ioremap_err:
/* ULPI transceivers don't need usbpll */
if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
clk_disable_unprepare(mxc_per_clk);
mxc_per_clk = NULL;
}
return ret;
}
void fsl_udc_clk_release(void)
{
if (mxc_per_clk)
clk_disable_unprepare(mxc_per_clk);
clk_disable_unprepare(mxc_ahb_clk);
clk_disable_unprepare(mxc_ipg_clk);
}
...@@ -4770,19 +4770,19 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci, ...@@ -4770,19 +4770,19 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci,
{ {
unsigned long long timeout_ns; unsigned long long timeout_ns;
if (xhci->quirks & XHCI_INTEL_HOST)
timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
else
timeout_ns = udev->u1_params.sel;
/* Prevent U1 if service interval is shorter than U1 exit latency */ /* Prevent U1 if service interval is shorter than U1 exit latency */
if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) { if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) {
if (xhci_service_interval_to_ns(desc) <= udev->u1_params.mel) { if (xhci_service_interval_to_ns(desc) <= timeout_ns) {
dev_dbg(&udev->dev, "Disable U1, ESIT shorter than exit latency\n"); dev_dbg(&udev->dev, "Disable U1, ESIT shorter than exit latency\n");
return USB3_LPM_DISABLED; return USB3_LPM_DISABLED;
} }
} }
if (xhci->quirks & XHCI_INTEL_HOST)
timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
else
timeout_ns = udev->u1_params.sel;
/* The U1 timeout is encoded in 1us intervals. /* The U1 timeout is encoded in 1us intervals.
* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. * Don't return a timeout of zero, because that's USB3_LPM_DISABLED.
*/ */
...@@ -4834,19 +4834,19 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci, ...@@ -4834,19 +4834,19 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci,
{ {
unsigned long long timeout_ns; unsigned long long timeout_ns;
if (xhci->quirks & XHCI_INTEL_HOST)
timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc);
else
timeout_ns = udev->u2_params.sel;
/* Prevent U2 if service interval is shorter than U2 exit latency */ /* Prevent U2 if service interval is shorter than U2 exit latency */
if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) { if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) {
if (xhci_service_interval_to_ns(desc) <= udev->u2_params.mel) { if (xhci_service_interval_to_ns(desc) <= timeout_ns) {
dev_dbg(&udev->dev, "Disable U2, ESIT shorter than exit latency\n"); dev_dbg(&udev->dev, "Disable U2, ESIT shorter than exit latency\n");
return USB3_LPM_DISABLED; return USB3_LPM_DISABLED;
} }
} }
if (xhci->quirks & XHCI_INTEL_HOST)
timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc);
else
timeout_ns = udev->u2_params.sel;
/* The U2 timeout is encoded in 256us intervals */ /* The U2 timeout is encoded in 256us intervals */
timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000); timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000);
/* If the necessary timeout value is bigger than what we can set in the /* If the necessary timeout value is bigger than what we can set in the
......
...@@ -496,6 +496,9 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, ...@@ -496,6 +496,9 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
timeout = schedule_timeout(YUREX_WRITE_TIMEOUT); timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
finish_wait(&dev->waitq, &wait); finish_wait(&dev->waitq, &wait);
/* make sure URB is idle after timeout or (spurious) CMD_ACK */
usb_kill_urb(dev->cntl_urb);
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
if (retval < 0) { if (retval < 0) {
......
...@@ -532,23 +532,29 @@ static int iuu_uart_flush(struct usb_serial_port *port) ...@@ -532,23 +532,29 @@ static int iuu_uart_flush(struct usb_serial_port *port)
struct device *dev = &port->dev; struct device *dev = &port->dev;
int i; int i;
int status; int status;
u8 rxcmd = IUU_UART_RX; u8 *rxcmd;
struct iuu_private *priv = usb_get_serial_port_data(port); struct iuu_private *priv = usb_get_serial_port_data(port);
if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
return -EIO; return -EIO;
rxcmd = kmalloc(1, GFP_KERNEL);
if (!rxcmd)
return -ENOMEM;
rxcmd[0] = IUU_UART_RX;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
status = bulk_immediate(port, &rxcmd, 1); status = bulk_immediate(port, rxcmd, 1);
if (status != IUU_OPERATION_OK) { if (status != IUU_OPERATION_OK) {
dev_dbg(dev, "%s - uart_flush_write error\n", __func__); dev_dbg(dev, "%s - uart_flush_write error\n", __func__);
return status; goto out_free;
} }
status = read_immediate(port, &priv->len, 1); status = read_immediate(port, &priv->len, 1);
if (status != IUU_OPERATION_OK) { if (status != IUU_OPERATION_OK) {
dev_dbg(dev, "%s - uart_flush_read error\n", __func__); dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
return status; goto out_free;
} }
if (priv->len > 0) { if (priv->len > 0) {
...@@ -556,12 +562,16 @@ static int iuu_uart_flush(struct usb_serial_port *port) ...@@ -556,12 +562,16 @@ static int iuu_uart_flush(struct usb_serial_port *port)
status = read_immediate(port, priv->buf, priv->len); status = read_immediate(port, priv->buf, priv->len);
if (status != IUU_OPERATION_OK) { if (status != IUU_OPERATION_OK) {
dev_dbg(dev, "%s - uart_flush_read error\n", __func__); dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
return status; goto out_free;
} }
} }
} }
dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__); dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__);
iuu_led(port, 0, 0xF000, 0, 0xFF); iuu_led(port, 0, 0xF000, 0, 0xFF);
out_free:
kfree(rxcmd);
return status; return status;
} }
......
...@@ -1117,6 +1117,8 @@ static const struct usb_device_id option_ids[] = { ...@@ -1117,6 +1117,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff), { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff),
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, 0x0620, 0xff, 0xff, 0x30) }, /* EM160R-GL */
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, 0x0620, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x30) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x10), { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x10),
...@@ -2057,6 +2059,7 @@ static const struct usb_device_id option_ids[] = { ...@@ -2057,6 +2059,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */
.driver_info = RSVD(6) }, .driver_info = RSVD(6) },
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */
......
...@@ -90,6 +90,13 @@ UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999, ...@@ -90,6 +90,13 @@ UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
USB_SC_DEVICE, USB_PR_DEVICE, NULL, USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_BROKEN_FUA), US_FL_BROKEN_FUA),
/* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */
UNUSUAL_DEV(0x154b, 0xf00b, 0x0000, 0x9999,
"PNY",
"Pro Elite SSD",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_ATA_1X),
/* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */ /* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */
UNUSUAL_DEV(0x154b, 0xf00d, 0x0000, 0x9999, UNUSUAL_DEV(0x154b, 0xf00d, 0x0000, 0x9999,
"PNY", "PNY",
......
...@@ -20,6 +20,6 @@ config TYPEC_NVIDIA_ALTMODE ...@@ -20,6 +20,6 @@ config TYPEC_NVIDIA_ALTMODE
to enable support for VirtualLink devices with NVIDIA GPUs. to enable support for VirtualLink devices with NVIDIA GPUs.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called typec_displayport. module will be called typec_nvidia.
endmenu endmenu
...@@ -766,6 +766,7 @@ int typec_partner_set_num_altmodes(struct typec_partner *partner, int num_altmod ...@@ -766,6 +766,7 @@ int typec_partner_set_num_altmodes(struct typec_partner *partner, int num_altmod
return ret; return ret;
sysfs_notify(&partner->dev.kobj, NULL, "number_of_alternate_modes"); sysfs_notify(&partner->dev.kobj, NULL, "number_of_alternate_modes");
kobject_uevent(&partner->dev.kobj, KOBJ_CHANGE);
return 0; return 0;
} }
...@@ -923,6 +924,7 @@ int typec_plug_set_num_altmodes(struct typec_plug *plug, int num_altmodes) ...@@ -923,6 +924,7 @@ int typec_plug_set_num_altmodes(struct typec_plug *plug, int num_altmodes)
return ret; return ret;
sysfs_notify(&plug->dev.kobj, NULL, "number_of_alternate_modes"); sysfs_notify(&plug->dev.kobj, NULL, "number_of_alternate_modes");
kobject_uevent(&plug->dev.kobj, KOBJ_CHANGE);
return 0; return 0;
} }
......
...@@ -207,10 +207,21 @@ static int ...@@ -207,10 +207,21 @@ static int
pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_displayport_data *dp) pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_displayport_data *dp)
{ {
u8 msg[2] = { }; u8 msg[2] = { };
int ret;
msg[0] = PMC_USB_DP_HPD; msg[0] = PMC_USB_DP_HPD;
msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
/* Configure HPD first if HPD,IRQ comes together */
if (!IOM_PORT_HPD_ASSERTED(port->iom_status) &&
dp->status & DP_STATUS_IRQ_HPD &&
dp->status & DP_STATUS_HPD_STATE) {
msg[1] = PMC_USB_DP_HPD_LVL;
ret = pmc_usb_command(port, msg, sizeof(msg));
if (ret)
return ret;
}
if (dp->status & DP_STATUS_IRQ_HPD) if (dp->status & DP_STATUS_IRQ_HPD)
msg[1] = PMC_USB_DP_HPD_IRQ; msg[1] = PMC_USB_DP_HPD_IRQ;
......
...@@ -396,6 +396,8 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -396,6 +396,8 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
default: default:
usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n", usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
wValue); wValue);
if (wValue >= 32)
goto error;
vhci_hcd->port_status[rhport] &= ~(1 << wValue); vhci_hcd->port_status[rhport] &= ~(1 << wValue);
break; break;
} }
......
...@@ -52,6 +52,25 @@ static inline void kcov_remote_start_usb(u64 id) ...@@ -52,6 +52,25 @@ static inline void kcov_remote_start_usb(u64 id)
kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_USB, id)); kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_USB, id));
} }
/*
* The softirq flavor of kcov_remote_*() functions is introduced as a temporary
* work around for kcov's lack of nested remote coverage sections support in
* task context. Adding suport for nested sections is tracked in:
* https://bugzilla.kernel.org/show_bug.cgi?id=210337
*/
static inline void kcov_remote_start_usb_softirq(u64 id)
{
if (in_serving_softirq())
kcov_remote_start_usb(id);
}
static inline void kcov_remote_stop_softirq(void)
{
if (in_serving_softirq())
kcov_remote_stop();
}
#else #else
static inline void kcov_task_init(struct task_struct *t) {} static inline void kcov_task_init(struct task_struct *t) {}
...@@ -66,6 +85,8 @@ static inline u64 kcov_common_handle(void) ...@@ -66,6 +85,8 @@ static inline u64 kcov_common_handle(void)
} }
static inline void kcov_remote_start_common(u64 id) {} static inline void kcov_remote_start_common(u64 id) {}
static inline void kcov_remote_start_usb(u64 id) {} static inline void kcov_remote_start_usb(u64 id) {}
static inline void kcov_remote_start_usb_softirq(u64 id) {}
static inline void kcov_remote_stop_softirq(void) {}
#endif /* CONFIG_KCOV */ #endif /* CONFIG_KCOV */
#endif /* _LINUX_KCOV_H */ #endif /* _LINUX_KCOV_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment