Commit e67da288 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull USB / Thunderbolt fixes from Greg KH:
 "Here are a number of small USB and Thunderbolt driver fixes and new
  device id changes for 6.2-rc5. Included in here are:

   - thunderbolt bugfixes for reported problems

   - new usb-serial driver ids added

   - onboard_hub usb driver fixes for much-reported problems

   - xhci bugfixes

   - typec bugfixes

   - ehci-fsl driver module alias fix

   - iowarrior header size fix

   - usb gadget driver fixes

  All of these, except for the iowarrior fix, have been in linux-next
  with no reported issues. The iowarrior fix passed the 0-day testing
  and is a one digit change based on a reported problem in the driver
  (which was written to a spec, not the real device that is now
  available)"

* tag 'usb-6.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (40 commits)
  USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100
  usb: host: ehci-fsl: Fix module alias
  usb: dwc3: fix extcon dependency
  usb: core: hub: disable autosuspend for TI TUSB8041
  USB: fix misleading usb_set_intfdata() kernel doc
  usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate()
  USB: gadget: Add ID numbers to configfs-gadget driver names
  usb: typec: tcpm: Fix altmode re-registration causes sysfs create fail
  usb: gadget: g_webcam: Send color matching descriptor per frame
  usb: typec: altmodes/displayport: Use proper macro for pin assignment check
  usb: typec: altmodes/displayport: Fix pin assignment calculation
  usb: typec: altmodes/displayport: Add pin assignment helper
  usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
  usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
  usb: misc: onboard_hub: Move 'attach' work to the driver
  usb: misc: onboard_hub: Invert driver registration order
  usb: ucsi: Ensure connector delayed work items are flushed
  usb: musb: fix error return code in omap2430_probe()
  usb: chipidea: core: fix possible constant 0 if use IS_ERR(ci->role_switch)
  xhci: Detect lpm incapable xHC USB3 roothub ports from ACPI tables
  ...
parents 83cd5fd0 14ff7460
...@@ -427,13 +427,6 @@ int tb_retimer_scan(struct tb_port *port, bool add) ...@@ -427,13 +427,6 @@ int tb_retimer_scan(struct tb_port *port, bool add)
{ {
u32 status[TB_MAX_RETIMER_INDEX + 1] = {}; u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
int ret, i, last_idx = 0; int ret, i, last_idx = 0;
struct usb4_port *usb4;
usb4 = port->usb4;
if (!usb4)
return 0;
pm_runtime_get_sync(&usb4->dev);
/* /*
* Send broadcast RT to make sure retimer indices facing this * Send broadcast RT to make sure retimer indices facing this
...@@ -441,7 +434,7 @@ int tb_retimer_scan(struct tb_port *port, bool add) ...@@ -441,7 +434,7 @@ int tb_retimer_scan(struct tb_port *port, bool add)
*/ */
ret = usb4_port_enumerate_retimers(port); ret = usb4_port_enumerate_retimers(port);
if (ret) if (ret)
goto out; return ret;
/* /*
* Enable sideband channel for each retimer. We can do this * Enable sideband channel for each retimer. We can do this
...@@ -471,12 +464,11 @@ int tb_retimer_scan(struct tb_port *port, bool add) ...@@ -471,12 +464,11 @@ int tb_retimer_scan(struct tb_port *port, bool add)
break; break;
} }
if (!last_idx) { if (!last_idx)
ret = 0; return 0;
goto out;
}
/* Add on-board retimers if they do not exist already */ /* Add on-board retimers if they do not exist already */
ret = 0;
for (i = 1; i <= last_idx; i++) { for (i = 1; i <= last_idx; i++) {
struct tb_retimer *rt; struct tb_retimer *rt;
...@@ -490,10 +482,6 @@ int tb_retimer_scan(struct tb_port *port, bool add) ...@@ -490,10 +482,6 @@ int tb_retimer_scan(struct tb_port *port, bool add)
} }
} }
out:
pm_runtime_mark_last_busy(&usb4->dev);
pm_runtime_put_autosuspend(&usb4->dev);
return ret; return ret;
} }
......
...@@ -628,11 +628,15 @@ static void tb_scan_port(struct tb_port *port) ...@@ -628,11 +628,15 @@ static void tb_scan_port(struct tb_port *port)
* Downstream switch is reachable through two ports. * Downstream switch is reachable through two ports.
* Only scan on the primary port (link_nr == 0). * Only scan on the primary port (link_nr == 0).
*/ */
if (port->usb4)
pm_runtime_get_sync(&port->usb4->dev);
if (tb_wait_for_port(port, false) <= 0) if (tb_wait_for_port(port, false) <= 0)
return; goto out_rpm_put;
if (port->remote) { if (port->remote) {
tb_port_dbg(port, "port already has a remote\n"); tb_port_dbg(port, "port already has a remote\n");
return; goto out_rpm_put;
} }
tb_retimer_scan(port, true); tb_retimer_scan(port, true);
...@@ -647,12 +651,12 @@ static void tb_scan_port(struct tb_port *port) ...@@ -647,12 +651,12 @@ static void tb_scan_port(struct tb_port *port)
*/ */
if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL) if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL)
tb_scan_xdomain(port); tb_scan_xdomain(port);
return; goto out_rpm_put;
} }
if (tb_switch_configure(sw)) { if (tb_switch_configure(sw)) {
tb_switch_put(sw); tb_switch_put(sw);
return; goto out_rpm_put;
} }
/* /*
...@@ -681,7 +685,7 @@ static void tb_scan_port(struct tb_port *port) ...@@ -681,7 +685,7 @@ static void tb_scan_port(struct tb_port *port)
if (tb_switch_add(sw)) { if (tb_switch_add(sw)) {
tb_switch_put(sw); tb_switch_put(sw);
return; goto out_rpm_put;
} }
/* Link the switches using both links if available */ /* Link the switches using both links if available */
...@@ -733,6 +737,12 @@ static void tb_scan_port(struct tb_port *port) ...@@ -733,6 +737,12 @@ static void tb_scan_port(struct tb_port *port)
tb_add_dp_resources(sw); tb_add_dp_resources(sw);
tb_scan_switch(sw); tb_scan_switch(sw);
out_rpm_put:
if (port->usb4) {
pm_runtime_mark_last_busy(&port->usb4->dev);
pm_runtime_put_autosuspend(&port->usb4->dev);
}
} }
static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel) static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
......
...@@ -1275,7 +1275,7 @@ static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel, ...@@ -1275,7 +1275,7 @@ static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel,
return; return;
} else if (!ret) { } else if (!ret) {
/* Use maximum link rate if the link valid is not set */ /* Use maximum link rate if the link valid is not set */
ret = usb4_usb3_port_max_link_rate(tunnel->src_port); ret = tb_usb3_max_link_rate(tunnel->dst_port, tunnel->src_port);
if (ret < 0) { if (ret < 0) {
tb_tunnel_warn(tunnel, "failed to read maximum link rate\n"); tb_tunnel_warn(tunnel, "failed to read maximum link rate\n");
return; return;
......
...@@ -1419,12 +1419,19 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd) ...@@ -1419,12 +1419,19 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
* registered, we notify the userspace that it has changed. * registered, we notify the userspace that it has changed.
*/ */
if (!update) { if (!update) {
struct tb_port *port; /*
* Now disable lane 1 if bonding was not enabled. Do
* this only if bonding was possible at the beginning
* (that is we are the connection manager and there are
* two lanes).
*/
if (xd->bonding_possible) {
struct tb_port *port;
/* Now disable lane 1 if bonding was not enabled */ port = tb_port_at(xd->route, tb_xdomain_parent(xd));
port = tb_port_at(xd->route, tb_xdomain_parent(xd)); if (!port->bonded)
if (!port->bonded) tb_port_disable(port->dual_link_port);
tb_port_disable(port->dual_link_port); }
if (device_add(&xd->dev)) { if (device_add(&xd->dev)) {
dev_err(&xd->dev, "failed to add XDomain device\n"); dev_err(&xd->dev, "failed to add XDomain device\n");
......
...@@ -2614,6 +2614,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -2614,6 +2614,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
u8 req_on_hw_ring = 0; u8 req_on_hw_ring = 0;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
int val;
if (!ep || !request || !ep->desc) if (!ep || !request || !ep->desc)
return -EINVAL; return -EINVAL;
...@@ -2649,6 +2650,13 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -2649,6 +2650,13 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
/* Update ring only if removed request is on pending_req_list list */ /* Update ring only if removed request is on pending_req_list list */
if (req_on_hw_ring && link_trb) { if (req_on_hw_ring && link_trb) {
/* Stop DMA */
writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd);
/* wait for DFLUSH cleared */
readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
!(val & EP_CMD_DFLUSH), 1, 1000);
link_trb->buffer = cpu_to_le32(TRB_BUFFER(priv_ep->trb_pool_dma + link_trb->buffer = cpu_to_le32(TRB_BUFFER(priv_ep->trb_pool_dma +
((priv_req->end_trb + 1) * TRB_SIZE))); ((priv_req->end_trb + 1) * TRB_SIZE)));
link_trb->control = cpu_to_le32((le32_to_cpu(link_trb->control) & TRB_CYCLE) | link_trb->control = cpu_to_le32((le32_to_cpu(link_trb->control) & TRB_CYCLE) |
...@@ -2660,6 +2668,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -2660,6 +2668,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET); cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
req = cdns3_next_request(&priv_ep->pending_req_list);
if (req)
cdns3_rearm_transfer(priv_ep, 1);
not_found: not_found:
spin_unlock_irqrestore(&priv_dev->lock, flags); spin_unlock_irqrestore(&priv_dev->lock, flags);
return ret; return ret;
......
...@@ -1294,12 +1294,12 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci) ...@@ -1294,12 +1294,12 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
cable_id = &ci->platdata->id_extcon; cable_id = &ci->platdata->id_extcon;
cable_vbus = &ci->platdata->vbus_extcon; cable_vbus = &ci->platdata->vbus_extcon;
if ((!IS_ERR(cable_id->edev) || !IS_ERR(ci->role_switch)) if ((!IS_ERR(cable_id->edev) || ci->role_switch)
&& ci->is_otg && && ci->is_otg &&
(otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
ci_irq(ci); ci_irq(ci);
if ((!IS_ERR(cable_vbus->edev) || !IS_ERR(ci->role_switch)) if ((!IS_ERR(cable_vbus->edev) || ci->role_switch)
&& ci->is_otg && && ci->is_otg &&
(otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
ci_irq(ci); ci_irq(ci);
......
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
#define USB_PRODUCT_USB5534B 0x5534 #define USB_PRODUCT_USB5534B 0x5534
#define USB_VENDOR_CYPRESS 0x04b4 #define USB_VENDOR_CYPRESS 0x04b4
#define USB_PRODUCT_CY7C65632 0x6570 #define USB_PRODUCT_CY7C65632 0x6570
#define USB_VENDOR_TEXAS_INSTRUMENTS 0x0451
#define USB_PRODUCT_TUSB8041_USB3 0x8140
#define USB_PRODUCT_TUSB8041_USB2 0x8142
#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01
#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02 #define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02
...@@ -5854,6 +5857,16 @@ static const struct usb_device_id hub_id_table[] = { ...@@ -5854,6 +5857,16 @@ static const struct usb_device_id hub_id_table[] = {
.idVendor = USB_VENDOR_GENESYS_LOGIC, .idVendor = USB_VENDOR_GENESYS_LOGIC,
.bInterfaceClass = USB_CLASS_HUB, .bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_PRODUCT,
.idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
.idProduct = USB_PRODUCT_TUSB8041_USB2,
.driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_PRODUCT,
.idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
.idProduct = USB_PRODUCT_TUSB8041_USB3,
.driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB}, .bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
......
...@@ -37,6 +37,71 @@ bool usb_acpi_power_manageable(struct usb_device *hdev, int index) ...@@ -37,6 +37,71 @@ bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
} }
EXPORT_SYMBOL_GPL(usb_acpi_power_manageable); EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
#define UUID_USB_CONTROLLER_DSM "ce2ee385-00e6-48cb-9f05-2edb927c4899"
#define USB_DSM_DISABLE_U1_U2_FOR_PORT 5
/**
* usb_acpi_port_lpm_incapable - check if lpm should be disabled for a port.
* @hdev: USB device belonging to the usb hub
* @index: zero based port index
*
* Some USB3 ports may not support USB3 link power management U1/U2 states
* due to different retimer setup. ACPI provides _DSM method which returns 0x01
* if U1 and U2 states should be disabled. Evaluate _DSM with:
* Arg0: UUID = ce2ee385-00e6-48cb-9f05-2edb927c4899
* Arg1: Revision ID = 0
* Arg2: Function Index = 5
* Arg3: (empty)
*
* Return 1 if USB3 port is LPM incapable, negative on error, otherwise 0
*/
int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
{
union acpi_object *obj;
acpi_handle port_handle;
int port1 = index + 1;
guid_t guid;
int ret;
ret = guid_parse(UUID_USB_CONTROLLER_DSM, &guid);
if (ret)
return ret;
port_handle = usb_get_hub_port_acpi_handle(hdev, port1);
if (!port_handle) {
dev_dbg(&hdev->dev, "port-%d no acpi handle\n", port1);
return -ENODEV;
}
if (!acpi_check_dsm(port_handle, &guid, 0,
BIT(USB_DSM_DISABLE_U1_U2_FOR_PORT))) {
dev_dbg(&hdev->dev, "port-%d no _DSM function %d\n",
port1, USB_DSM_DISABLE_U1_U2_FOR_PORT);
return -ENODEV;
}
obj = acpi_evaluate_dsm(port_handle, &guid, 0,
USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL);
if (!obj)
return -ENODEV;
if (obj->type != ACPI_TYPE_INTEGER) {
dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
ACPI_FREE(obj);
return -EINVAL;
}
if (obj->integer.value == 0x01)
ret = 1;
ACPI_FREE(obj);
return ret;
}
EXPORT_SYMBOL_GPL(usb_acpi_port_lpm_incapable);
/** /**
* usb_acpi_set_power_state - control usb port's power via acpi power * usb_acpi_set_power_state - control usb port's power via acpi power
* resource * resource
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
config USB_DWC3 config USB_DWC3
tristate "DesignWare USB3 DRD Core Support" tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET) && HAS_DMA depends on (USB || USB_GADGET) && HAS_DMA
depends on (EXTCON || EXTCON=n)
select USB_XHCI_PLATFORM if USB_XHCI_HCD select USB_XHCI_PLATFORM if USB_XHCI_HCD
select USB_ROLE_SWITCH if USB_DWC3_DUAL_ROLE select USB_ROLE_SWITCH if USB_DWC3_DUAL_ROLE
help help
...@@ -44,7 +45,6 @@ config USB_DWC3_GADGET ...@@ -44,7 +45,6 @@ config USB_DWC3_GADGET
config USB_DWC3_DUAL_ROLE config USB_DWC3_DUAL_ROLE
bool "Dual Role mode" bool "Dual Role mode"
depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3)) depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
depends on (EXTCON=y || EXTCON=USB_DWC3)
help help
This is the default mode of working of DWC3 controller where This is the default mode of working of DWC3 controller where
both host and gadget features are enabled. both host and gadget features are enabled.
......
...@@ -393,6 +393,7 @@ static void gadget_info_attr_release(struct config_item *item) ...@@ -393,6 +393,7 @@ static void gadget_info_attr_release(struct config_item *item)
WARN_ON(!list_empty(&gi->string_list)); WARN_ON(!list_empty(&gi->string_list));
WARN_ON(!list_empty(&gi->available_func)); WARN_ON(!list_empty(&gi->available_func));
kfree(gi->composite.gadget_driver.function); kfree(gi->composite.gadget_driver.function);
kfree(gi->composite.gadget_driver.driver.name);
kfree(gi); kfree(gi);
} }
...@@ -1572,7 +1573,6 @@ static const struct usb_gadget_driver configfs_driver_template = { ...@@ -1572,7 +1573,6 @@ static const struct usb_gadget_driver configfs_driver_template = {
.max_speed = USB_SPEED_SUPER_PLUS, .max_speed = USB_SPEED_SUPER_PLUS,
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "configfs-gadget",
}, },
.match_existing_only = 1, .match_existing_only = 1,
}; };
...@@ -1623,13 +1623,21 @@ static struct config_group *gadgets_make( ...@@ -1623,13 +1623,21 @@ static struct config_group *gadgets_make(
gi->composite.gadget_driver = configfs_driver_template; gi->composite.gadget_driver = configfs_driver_template;
gi->composite.gadget_driver.driver.name = kasprintf(GFP_KERNEL,
"configfs-gadget.%s", name);
if (!gi->composite.gadget_driver.driver.name)
goto err;
gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL); gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
gi->composite.name = gi->composite.gadget_driver.function; gi->composite.name = gi->composite.gadget_driver.function;
if (!gi->composite.gadget_driver.function) if (!gi->composite.gadget_driver.function)
goto err; goto out_free_driver_name;
return &gi->group; return &gi->group;
out_free_driver_name:
kfree(gi->composite.gadget_driver.driver.name);
err: err:
kfree(gi); kfree(gi);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -279,6 +279,9 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) ...@@ -279,6 +279,9 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
struct usb_request *req = ffs->ep0req; struct usb_request *req = ffs->ep0req;
int ret; int ret;
if (!req)
return -EINVAL;
req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); req->zero = len < le16_to_cpu(ffs->ev.setup.wLength);
spin_unlock_irq(&ffs->ev.waitq.lock); spin_unlock_irq(&ffs->ev.waitq.lock);
...@@ -1892,10 +1895,14 @@ static void functionfs_unbind(struct ffs_data *ffs) ...@@ -1892,10 +1895,14 @@ static void functionfs_unbind(struct ffs_data *ffs)
ENTER(); ENTER();
if (!WARN_ON(!ffs->gadget)) { if (!WARN_ON(!ffs->gadget)) {
/* dequeue before freeing ep0req */
usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req);
mutex_lock(&ffs->mutex);
usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
ffs->ep0req = NULL; ffs->ep0req = NULL;
ffs->gadget = NULL; ffs->gadget = NULL;
clear_bit(FFS_FL_BOUND, &ffs->flags); clear_bit(FFS_FL_BOUND, &ffs->flags);
mutex_unlock(&ffs->mutex);
ffs_data_put(ffs); ffs_data_put(ffs);
} }
} }
......
...@@ -83,7 +83,9 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) ...@@ -83,7 +83,9 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
/* peak (theoretical) bulk transfer rate in bits-per-second */ /* peak (theoretical) bulk transfer rate in bits-per-second */
static inline unsigned ncm_bitrate(struct usb_gadget *g) static inline unsigned ncm_bitrate(struct usb_gadget *g)
{ {
if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS) if (!g)
return 0;
else if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
return 4250000000U; return 4250000000U;
else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
return 3750000000U; return 3750000000U;
......
...@@ -229,6 +229,7 @@ static void put_ep (struct ep_data *data) ...@@ -229,6 +229,7 @@ static void put_ep (struct ep_data *data)
*/ */
static const char *CHIP; static const char *CHIP;
static DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
...@@ -2010,13 +2011,20 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc) ...@@ -2010,13 +2011,20 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
{ {
struct inode *inode; struct inode *inode;
struct dev_data *dev; struct dev_data *dev;
int rc;
if (the_device) mutex_lock(&sb_mutex);
return -ESRCH;
if (the_device) {
rc = -ESRCH;
goto Done;
}
CHIP = usb_get_gadget_udc_name(); CHIP = usb_get_gadget_udc_name();
if (!CHIP) if (!CHIP) {
return -ENODEV; rc = -ENODEV;
goto Done;
}
/* superblock */ /* superblock */
sb->s_blocksize = PAGE_SIZE; sb->s_blocksize = PAGE_SIZE;
...@@ -2053,13 +2061,17 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc) ...@@ -2053,13 +2061,17 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
* from binding to a controller. * from binding to a controller.
*/ */
the_device = dev; the_device = dev;
return 0; rc = 0;
goto Done;
Enomem: Enomem:
kfree(CHIP); kfree(CHIP);
CHIP = NULL; CHIP = NULL;
rc = -ENOMEM;
return -ENOMEM; Done:
mutex_unlock(&sb_mutex);
return rc;
} }
/* "mount -t gadgetfs path /dev/gadget" ends up here */ /* "mount -t gadgetfs path /dev/gadget" ends up here */
...@@ -2081,6 +2093,7 @@ static int gadgetfs_init_fs_context(struct fs_context *fc) ...@@ -2081,6 +2093,7 @@ static int gadgetfs_init_fs_context(struct fs_context *fc)
static void static void
gadgetfs_kill_sb (struct super_block *sb) gadgetfs_kill_sb (struct super_block *sb)
{ {
mutex_lock(&sb_mutex);
kill_litter_super (sb); kill_litter_super (sb);
if (the_device) { if (the_device) {
put_dev (the_device); put_dev (the_device);
...@@ -2088,6 +2101,7 @@ gadgetfs_kill_sb (struct super_block *sb) ...@@ -2088,6 +2101,7 @@ gadgetfs_kill_sb (struct super_block *sb)
} }
kfree(CHIP); kfree(CHIP);
CHIP = NULL; CHIP = NULL;
mutex_unlock(&sb_mutex);
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
......
...@@ -293,6 +293,7 @@ static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = { ...@@ -293,6 +293,7 @@ static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_format_yuv,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching,
(const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_format_mjpg,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
...@@ -305,6 +306,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { ...@@ -305,6 +306,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_format_yuv,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching,
(const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_format_mjpg,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
...@@ -317,6 +319,7 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { ...@@ -317,6 +319,7 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_format_yuv,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
(const struct uvc_descriptor_header *) &uvc_color_matching,
(const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_format_mjpg,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "ehci-fsl.h" #include "ehci-fsl.h"
#define DRIVER_DESC "Freescale EHCI Host controller driver" #define DRIVER_DESC "Freescale EHCI Host controller driver"
#define DRV_NAME "ehci-fsl" #define DRV_NAME "fsl-ehci"
static struct hc_driver __read_mostly fsl_ehci_hc_driver; static struct hc_driver __read_mostly fsl_ehci_hc_driver;
......
...@@ -78,9 +78,12 @@ static const char hcd_name[] = "xhci_hcd"; ...@@ -78,9 +78,12 @@ static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver; static struct hc_driver __read_mostly xhci_pci_hc_driver;
static int xhci_pci_setup(struct usb_hcd *hcd); static int xhci_pci_setup(struct usb_hcd *hcd);
static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
.reset = xhci_pci_setup, .reset = xhci_pci_setup,
.update_hub_device = xhci_pci_update_hub_device,
}; };
/* called after powerup, by probe or system-pm "wakeup" */ /* called after powerup, by probe or system-pm "wakeup" */
...@@ -352,8 +355,38 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) ...@@ -352,8 +355,38 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
NULL); NULL);
ACPI_FREE(obj); ACPI_FREE(obj);
} }
static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_hub *rhub = &xhci->usb3_rhub;
int ret;
int i;
/* This is not the usb3 roothub we are looking for */
if (hcd != rhub->hcd)
return;
if (hdev->maxchild > rhub->num_ports) {
dev_err(&hdev->dev, "USB3 roothub port number mismatch\n");
return;
}
for (i = 0; i < hdev->maxchild; i++) {
ret = usb_acpi_port_lpm_incapable(hdev, i);
dev_dbg(&hdev->dev, "port-%d disable U1/U2 _DSM: %d\n", i + 1, ret);
if (ret >= 0) {
rhub->ports[i]->lpm_incapable = ret;
continue;
}
}
}
#else #else
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { } static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev) { }
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
/* called during probe() after chip reset completes */ /* called during probe() after chip reset completes */
...@@ -386,6 +419,16 @@ static int xhci_pci_setup(struct usb_hcd *hcd) ...@@ -386,6 +419,16 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
return xhci_pci_reinit(xhci, pdev); return xhci_pci_reinit(xhci, pdev);
} }
static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags)
{
/* Check if acpi claims some USB3 roothub ports are lpm incapable */
if (!hdev->parent)
xhci_find_lpm_incapable_ports(hcd, hdev);
return xhci_update_hub_device(hcd, hdev, tt, mem_flags);
}
/* /*
* We need to register our own PCI probe function (instead of the USB core's * We need to register our own PCI probe function (instead of the USB core's
* function) in order to create a second roothub under xHCI. * function) in order to create a second roothub under xHCI.
...@@ -455,6 +498,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -455,6 +498,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW) if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
pm_runtime_allow(&dev->dev); pm_runtime_allow(&dev->dev);
dma_set_max_seg_size(&dev->dev, UINT_MAX);
return 0; return 0;
put_usb3_hcd: put_usb3_hcd:
......
...@@ -1169,7 +1169,10 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, ...@@ -1169,7 +1169,10 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
struct xhci_virt_ep *ep; struct xhci_virt_ep *ep;
struct xhci_ring *ring; struct xhci_ring *ring;
ep = &xhci->devs[slot_id]->eps[ep_index]; ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
if (!ep)
return;
if ((ep->ep_state & EP_HAS_STREAMS) || if ((ep->ep_state & EP_HAS_STREAMS) ||
(ep->ep_state & EP_GETTING_NO_STREAMS)) { (ep->ep_state & EP_GETTING_NO_STREAMS)) {
int stream_id; int stream_id;
......
...@@ -3974,6 +3974,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -3974,6 +3974,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_virt_device *virt_dev; struct xhci_virt_device *virt_dev;
struct xhci_slot_ctx *slot_ctx; struct xhci_slot_ctx *slot_ctx;
unsigned long flags;
int i, ret; int i, ret;
/* /*
...@@ -4000,7 +4001,11 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -4000,7 +4001,11 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING; virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING;
virt_dev->udev = NULL; virt_dev->udev = NULL;
xhci_disable_slot(xhci, udev->slot_id); xhci_disable_slot(xhci, udev->slot_id);
spin_lock_irqsave(&xhci->lock, flags);
xhci_free_virt_device(xhci, udev->slot_id); xhci_free_virt_device(xhci, udev->slot_id);
spin_unlock_irqrestore(&xhci->lock, flags);
} }
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
...@@ -5044,6 +5049,7 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, ...@@ -5044,6 +5049,7 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
struct usb_device *udev, enum usb3_link_state state) struct usb_device *udev, enum usb3_link_state state)
{ {
struct xhci_hcd *xhci; struct xhci_hcd *xhci;
struct xhci_port *port;
u16 hub_encoded_timeout; u16 hub_encoded_timeout;
int mel; int mel;
int ret; int ret;
...@@ -5060,6 +5066,13 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, ...@@ -5060,6 +5066,13 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
if (xhci_check_tier_policy(xhci, udev, state) < 0) if (xhci_check_tier_policy(xhci, udev, state) < 0)
return USB3_LPM_DISABLED; return USB3_LPM_DISABLED;
/* If connected to root port then check port can handle lpm */
if (udev->parent && !udev->parent->parent) {
port = xhci->usb3_rhub.ports[udev->portnum - 1];
if (port->lpm_incapable)
return USB3_LPM_DISABLED;
}
hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state); hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout); mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
if (mel < 0) { if (mel < 0) {
...@@ -5119,7 +5132,7 @@ static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, ...@@ -5119,7 +5132,7 @@ static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
/* Once a hub descriptor is fetched for a device, we need to update the xHC's /* Once a hub descriptor is fetched for a device, we need to update the xHC's
* internal data structures for the device. * internal data structures for the device.
*/ */
static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags) struct usb_tt *tt, gfp_t mem_flags)
{ {
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
...@@ -5219,6 +5232,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, ...@@ -5219,6 +5232,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
xhci_free_command(xhci, config_cmd); xhci_free_command(xhci, config_cmd);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(xhci_update_hub_device);
static int xhci_get_frame(struct usb_hcd *hcd) static int xhci_get_frame(struct usb_hcd *hcd)
{ {
...@@ -5502,6 +5516,8 @@ void xhci_init_driver(struct hc_driver *drv, ...@@ -5502,6 +5516,8 @@ void xhci_init_driver(struct hc_driver *drv,
drv->check_bandwidth = over->check_bandwidth; drv->check_bandwidth = over->check_bandwidth;
if (over->reset_bandwidth) if (over->reset_bandwidth)
drv->reset_bandwidth = over->reset_bandwidth; drv->reset_bandwidth = over->reset_bandwidth;
if (over->update_hub_device)
drv->update_hub_device = over->update_hub_device;
} }
} }
EXPORT_SYMBOL_GPL(xhci_init_driver); EXPORT_SYMBOL_GPL(xhci_init_driver);
......
...@@ -1735,6 +1735,7 @@ struct xhci_port { ...@@ -1735,6 +1735,7 @@ struct xhci_port {
int hcd_portnum; int hcd_portnum;
struct xhci_hub *rhub; struct xhci_hub *rhub;
struct xhci_port_cap *port_cap; struct xhci_port_cap *port_cap;
unsigned int lpm_incapable:1;
}; };
struct xhci_hub { struct xhci_hub {
...@@ -1943,6 +1944,8 @@ struct xhci_driver_overrides { ...@@ -1943,6 +1944,8 @@ struct xhci_driver_overrides {
struct usb_host_endpoint *ep); struct usb_host_endpoint *ep);
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
int (*update_hub_device)(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
}; };
#define XHCI_CFC_DELAY 10 #define XHCI_CFC_DELAY 10
...@@ -2122,6 +2125,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -2122,6 +2125,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep); struct usb_host_endpoint *ep);
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
int xhci_ext_cap_init(struct xhci_hcd *xhci); int xhci_ext_cap_init(struct xhci_hcd *xhci);
......
...@@ -814,7 +814,7 @@ static int iowarrior_probe(struct usb_interface *interface, ...@@ -814,7 +814,7 @@ static int iowarrior_probe(struct usb_interface *interface,
break; break;
case USB_DEVICE_ID_CODEMERCS_IOW100: case USB_DEVICE_ID_CODEMERCS_IOW100:
dev->report_size = 13; dev->report_size = 12;
break; break;
} }
} }
......
...@@ -27,7 +27,10 @@ ...@@ -27,7 +27,10 @@
#include "onboard_usb_hub.h" #include "onboard_usb_hub.h"
static void onboard_hub_attach_usb_driver(struct work_struct *work);
static struct usb_device_driver onboard_hub_usbdev_driver; static struct usb_device_driver onboard_hub_usbdev_driver;
static DECLARE_WORK(attach_usb_driver_work, onboard_hub_attach_usb_driver);
/************************** Platform driver **************************/ /************************** Platform driver **************************/
...@@ -45,7 +48,6 @@ struct onboard_hub { ...@@ -45,7 +48,6 @@ struct onboard_hub {
bool is_powered_on; bool is_powered_on;
bool going_away; bool going_away;
struct list_head udev_list; struct list_head udev_list;
struct work_struct attach_usb_driver_work;
struct mutex lock; struct mutex lock;
}; };
...@@ -271,8 +273,7 @@ static int onboard_hub_probe(struct platform_device *pdev) ...@@ -271,8 +273,7 @@ static int onboard_hub_probe(struct platform_device *pdev)
* This needs to be done deferred to avoid self-deadlocks on systems * This needs to be done deferred to avoid self-deadlocks on systems
* with nested onboard hubs. * with nested onboard hubs.
*/ */
INIT_WORK(&hub->attach_usb_driver_work, onboard_hub_attach_usb_driver); schedule_work(&attach_usb_driver_work);
schedule_work(&hub->attach_usb_driver_work);
return 0; return 0;
} }
...@@ -285,9 +286,6 @@ static int onboard_hub_remove(struct platform_device *pdev) ...@@ -285,9 +286,6 @@ static int onboard_hub_remove(struct platform_device *pdev)
hub->going_away = true; hub->going_away = true;
if (&hub->attach_usb_driver_work != current_work())
cancel_work_sync(&hub->attach_usb_driver_work);
mutex_lock(&hub->lock); mutex_lock(&hub->lock);
/* unbind the USB devices to avoid dangling references to this device */ /* unbind the USB devices to avoid dangling references to this device */
...@@ -433,13 +431,13 @@ static int __init onboard_hub_init(void) ...@@ -433,13 +431,13 @@ static int __init onboard_hub_init(void)
{ {
int ret; int ret;
ret = platform_driver_register(&onboard_hub_driver); ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE);
if (ret) if (ret)
return ret; return ret;
ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE); ret = platform_driver_register(&onboard_hub_driver);
if (ret) if (ret)
platform_driver_unregister(&onboard_hub_driver); usb_deregister_device_driver(&onboard_hub_usbdev_driver);
return ret; return ret;
} }
...@@ -449,6 +447,8 @@ static void __exit onboard_hub_exit(void) ...@@ -449,6 +447,8 @@ static void __exit onboard_hub_exit(void)
{ {
usb_deregister_device_driver(&onboard_hub_usbdev_driver); usb_deregister_device_driver(&onboard_hub_usbdev_driver);
platform_driver_unregister(&onboard_hub_driver); platform_driver_unregister(&onboard_hub_driver);
cancel_work_sync(&attach_usb_driver_work);
} }
module_exit(onboard_hub_exit); module_exit(onboard_hub_exit);
......
...@@ -411,8 +411,10 @@ static int omap2430_probe(struct platform_device *pdev) ...@@ -411,8 +411,10 @@ static int omap2430_probe(struct platform_device *pdev)
memset(musb_res, 0, sizeof(*musb_res) * ARRAY_SIZE(musb_res)); memset(musb_res, 0, sizeof(*musb_res) * ARRAY_SIZE(musb_res));
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res) {
ret = -EINVAL;
goto err2; goto err2;
}
musb_res[i].start = res->start; musb_res[i].start = res->start;
musb_res[i].end = res->end; musb_res[i].end = res->end;
......
...@@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = { ...@@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */ { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
{ USB_DEVICE(0x0908, 0x0070) }, /* Siemens SCALANCE LPE-9000 USB Serial Console */
{ USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */ { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
{ USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */ { USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */
{ USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */ { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
......
...@@ -255,10 +255,16 @@ static void option_instat_callback(struct urb *urb); ...@@ -255,10 +255,16 @@ static void option_instat_callback(struct urb *urb);
#define QUECTEL_PRODUCT_EP06 0x0306 #define QUECTEL_PRODUCT_EP06 0x0306
#define QUECTEL_PRODUCT_EM05G 0x030a #define QUECTEL_PRODUCT_EM05G 0x030a
#define QUECTEL_PRODUCT_EM060K 0x030b #define QUECTEL_PRODUCT_EM060K 0x030b
#define QUECTEL_PRODUCT_EM05G_CS 0x030c
#define QUECTEL_PRODUCT_EM05CN_SG 0x0310
#define QUECTEL_PRODUCT_EM05G_SG 0x0311 #define QUECTEL_PRODUCT_EM05G_SG 0x0311
#define QUECTEL_PRODUCT_EM05CN 0x0312
#define QUECTEL_PRODUCT_EM05G_GR 0x0313
#define QUECTEL_PRODUCT_EM05G_RS 0x0314
#define QUECTEL_PRODUCT_EM12 0x0512 #define QUECTEL_PRODUCT_EM12 0x0512
#define QUECTEL_PRODUCT_RM500Q 0x0800 #define QUECTEL_PRODUCT_RM500Q 0x0800
#define QUECTEL_PRODUCT_RM520N 0x0801 #define QUECTEL_PRODUCT_RM520N 0x0801
#define QUECTEL_PRODUCT_EC200U 0x0901
#define QUECTEL_PRODUCT_EC200S_CN 0x6002 #define QUECTEL_PRODUCT_EC200S_CN 0x6002
#define QUECTEL_PRODUCT_EC200T 0x6026 #define QUECTEL_PRODUCT_EC200T 0x6026
#define QUECTEL_PRODUCT_RM500K 0x7001 #define QUECTEL_PRODUCT_RM500K 0x7001
...@@ -1159,8 +1165,18 @@ static const struct usb_device_id option_ids[] = { ...@@ -1159,8 +1165,18 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff), { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 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_EP06, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN, 0xff),
.driver_info = RSVD(6) | ZLP },
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN_SG, 0xff),
.driver_info = RSVD(6) | ZLP },
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff), { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff),
.driver_info = RSVD(6) | ZLP }, .driver_info = RSVD(6) | ZLP },
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_CS, 0xff),
.driver_info = RSVD(6) | ZLP },
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_GR, 0xff),
.driver_info = RSVD(6) | ZLP },
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_RS, 0xff),
.driver_info = RSVD(6) | ZLP },
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_SG, 0xff), { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_SG, 0xff),
.driver_info = RSVD(6) | ZLP }, .driver_info = RSVD(6) | ZLP },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) },
...@@ -1180,6 +1196,7 @@ static const struct usb_device_id option_ids[] = { ...@@ -1180,6 +1196,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) },
......
...@@ -116,6 +116,19 @@ static int uas_use_uas_driver(struct usb_interface *intf, ...@@ -116,6 +116,19 @@ static int uas_use_uas_driver(struct usb_interface *intf,
if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2) if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2)
flags |= US_FL_NO_ATA_1X; flags |= US_FL_NO_ATA_1X;
/*
* RTL9210-based enclosure from HIKSEMI, MD202 reportedly have issues
* with UAS. This isn't distinguishable with just idVendor and
* idProduct, use manufacturer and product too.
*
* Reported-by: Hongling Zeng <zenghongling@kylinos.cn>
*/
if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bda &&
le16_to_cpu(udev->descriptor.idProduct) == 0x9210 &&
(udev->manufacturer && !strcmp(udev->manufacturer, "HIKSEMI")) &&
(udev->product && !strcmp(udev->product, "MD202")))
flags |= US_FL_IGNORE_UAS;
usb_stor_adjust_quirks(udev, &flags); usb_stor_adjust_quirks(udev, &flags);
if (flags & US_FL_IGNORE_UAS) { if (flags & US_FL_IGNORE_UAS) {
......
...@@ -83,13 +83,6 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, ...@@ -83,13 +83,6 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
USB_SC_DEVICE, USB_PR_DEVICE, NULL, USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_REPORT_LUNS), US_FL_NO_REPORT_LUNS),
/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */
UNUSUAL_DEV(0x0bda, 0x9210, 0x0000, 0x9999,
"Hiksemi",
"External HDD",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_UAS),
/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */ /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
"Initio Corporation", "Initio Corporation",
......
...@@ -419,6 +419,18 @@ static const char * const pin_assignments[] = { ...@@ -419,6 +419,18 @@ static const char * const pin_assignments[] = {
[DP_PIN_ASSIGN_F] = "F", [DP_PIN_ASSIGN_F] = "F",
}; };
/*
* Helper function to extract a peripheral's currently supported
* Pin Assignments from its DisplayPort alternate mode state.
*/
static u8 get_current_pin_assignments(struct dp_altmode *dp)
{
if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_UFP_U_AS_DFP_D)
return DP_CAP_PIN_ASSIGN_DFP_D(dp->alt->vdo);
else
return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo);
}
static ssize_t static ssize_t
pin_assignment_store(struct device *dev, struct device_attribute *attr, pin_assignment_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t size) const char *buf, size_t size)
...@@ -445,10 +457,7 @@ pin_assignment_store(struct device *dev, struct device_attribute *attr, ...@@ -445,10 +457,7 @@ pin_assignment_store(struct device *dev, struct device_attribute *attr,
goto out_unlock; goto out_unlock;
} }
if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D) assignments = get_current_pin_assignments(dp);
assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
else
assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) { if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) {
ret = -EINVAL; ret = -EINVAL;
...@@ -485,10 +494,7 @@ static ssize_t pin_assignment_show(struct device *dev, ...@@ -485,10 +494,7 @@ static ssize_t pin_assignment_show(struct device *dev,
cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf)); cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D) assignments = get_current_pin_assignments(dp);
assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
else
assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
for (i = 0; assignments; assignments >>= 1, i++) { for (i = 0; assignments; assignments >>= 1, i++) {
if (assignments & 1) { if (assignments & 1) {
......
...@@ -4594,14 +4594,13 @@ static void run_state_machine(struct tcpm_port *port) ...@@ -4594,14 +4594,13 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ready_state(port), 0); tcpm_set_state(port, ready_state(port), 0);
break; break;
case DR_SWAP_CHANGE_DR: case DR_SWAP_CHANGE_DR:
if (port->data_role == TYPEC_HOST) { tcpm_unregister_altmodes(port);
tcpm_unregister_altmodes(port); if (port->data_role == TYPEC_HOST)
tcpm_set_roles(port, true, port->pwr_role, tcpm_set_roles(port, true, port->pwr_role,
TYPEC_DEVICE); TYPEC_DEVICE);
} else { else
tcpm_set_roles(port, true, port->pwr_role, tcpm_set_roles(port, true, port->pwr_role,
TYPEC_HOST); TYPEC_HOST);
}
tcpm_ams_finish(port); tcpm_ams_finish(port);
tcpm_set_state(port, ready_state(port), 0); tcpm_set_state(port, ready_state(port), 0);
break; break;
......
...@@ -187,6 +187,7 @@ EXPORT_SYMBOL_GPL(ucsi_send_command); ...@@ -187,6 +187,7 @@ EXPORT_SYMBOL_GPL(ucsi_send_command);
struct ucsi_work { struct ucsi_work {
struct delayed_work work; struct delayed_work work;
struct list_head node;
unsigned long delay; unsigned long delay;
unsigned int count; unsigned int count;
struct ucsi_connector *con; struct ucsi_connector *con;
...@@ -202,6 +203,7 @@ static void ucsi_poll_worker(struct work_struct *work) ...@@ -202,6 +203,7 @@ static void ucsi_poll_worker(struct work_struct *work)
mutex_lock(&con->lock); mutex_lock(&con->lock);
if (!con->partner) { if (!con->partner) {
list_del(&uwork->node);
mutex_unlock(&con->lock); mutex_unlock(&con->lock);
kfree(uwork); kfree(uwork);
return; return;
...@@ -209,10 +211,12 @@ static void ucsi_poll_worker(struct work_struct *work) ...@@ -209,10 +211,12 @@ static void ucsi_poll_worker(struct work_struct *work)
ret = uwork->cb(con); ret = uwork->cb(con);
if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT)) if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT)) {
queue_delayed_work(con->wq, &uwork->work, uwork->delay); queue_delayed_work(con->wq, &uwork->work, uwork->delay);
else } else {
list_del(&uwork->node);
kfree(uwork); kfree(uwork);
}
mutex_unlock(&con->lock); mutex_unlock(&con->lock);
} }
...@@ -236,6 +240,7 @@ static int ucsi_partner_task(struct ucsi_connector *con, ...@@ -236,6 +240,7 @@ static int ucsi_partner_task(struct ucsi_connector *con,
uwork->con = con; uwork->con = con;
uwork->cb = cb; uwork->cb = cb;
list_add_tail(&uwork->node, &con->partner_tasks);
queue_delayed_work(con->wq, &uwork->work, delay); queue_delayed_work(con->wq, &uwork->work, delay);
return 0; return 0;
...@@ -1056,6 +1061,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ...@@ -1056,6 +1061,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
INIT_WORK(&con->work, ucsi_handle_connector_change); INIT_WORK(&con->work, ucsi_handle_connector_change);
init_completion(&con->complete); init_completion(&con->complete);
mutex_init(&con->lock); mutex_init(&con->lock);
INIT_LIST_HEAD(&con->partner_tasks);
con->num = index + 1; con->num = index + 1;
con->ucsi = ucsi; con->ucsi = ucsi;
...@@ -1420,8 +1426,20 @@ void ucsi_unregister(struct ucsi *ucsi) ...@@ -1420,8 +1426,20 @@ void ucsi_unregister(struct ucsi *ucsi)
ucsi_unregister_altmodes(&ucsi->connector[i], ucsi_unregister_altmodes(&ucsi->connector[i],
UCSI_RECIPIENT_CON); UCSI_RECIPIENT_CON);
ucsi_unregister_port_psy(&ucsi->connector[i]); ucsi_unregister_port_psy(&ucsi->connector[i]);
if (ucsi->connector[i].wq)
if (ucsi->connector[i].wq) {
struct ucsi_work *uwork;
mutex_lock(&ucsi->connector[i].lock);
/*
* queue delayed items immediately so they can execute
* and free themselves before the wq is destroyed
*/
list_for_each_entry(uwork, &ucsi->connector[i].partner_tasks, node)
mod_delayed_work(ucsi->connector[i].wq, &uwork->work, 0);
mutex_unlock(&ucsi->connector[i].lock);
destroy_workqueue(ucsi->connector[i].wq); destroy_workqueue(ucsi->connector[i].wq);
}
typec_unregister_port(ucsi->connector[i].port); typec_unregister_port(ucsi->connector[i].port);
} }
......
...@@ -322,6 +322,7 @@ struct ucsi_connector { ...@@ -322,6 +322,7 @@ struct ucsi_connector {
struct work_struct work; struct work_struct work;
struct completion complete; struct completion complete;
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct list_head partner_tasks;
struct typec_port *port; struct typec_port *port;
struct typec_partner *partner; struct typec_partner *partner;
......
...@@ -267,16 +267,15 @@ static inline void *usb_get_intfdata(struct usb_interface *intf) ...@@ -267,16 +267,15 @@ static inline void *usb_get_intfdata(struct usb_interface *intf)
} }
/** /**
* usb_set_intfdata() - associate driver-specific data with the interface * usb_set_intfdata() - associate driver-specific data with an interface
* @intf: the usb interface * @intf: USB interface
* @data: pointer to the device priv structure or %NULL * @data: driver data
* *
* Drivers should use this function in their probe() to associate their * Drivers can use this function in their probe() callbacks to associate
* driver-specific data with the usb interface. * driver-specific data with an interface.
* *
* When disconnecting, the core will take care of setting @intf back to %NULL, * Note that there is generally no need to clear the driver-data pointer even
* so no actions are needed on the driver side. The interface should not be set * if some drivers do so for historical or implementation-specific reasons.
* to %NULL before all actions completed (e.g. no outsanding URB remaining).
*/ */
static inline void usb_set_intfdata(struct usb_interface *intf, void *data) static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
{ {
...@@ -774,11 +773,14 @@ extern struct device *usb_intf_get_dma_device(struct usb_interface *intf); ...@@ -774,11 +773,14 @@ extern struct device *usb_intf_get_dma_device(struct usb_interface *intf);
extern int usb_acpi_set_power_state(struct usb_device *hdev, int index, extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
bool enable); bool enable);
extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index); extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index);
extern int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index);
#else #else
static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index, static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index,
bool enable) { return 0; } bool enable) { return 0; }
static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index) static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
{ return true; } { return true; }
static inline int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
{ return 0; }
#endif #endif
/* USB autosuspend and autoresume */ /* USB autosuspend and autoresume */
......
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