Merge tag 'usb-5.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Jan 2022 13:17:20 +0000 (15:17 +0200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Jan 2022 13:17:20 +0000 (15:17 +0200)
Pull USB driver fixes from Greg KH:
 "Here are some small USB driver fixes for 5.17-rc2 that resolve a
  number of reported problems. These include:

   - typec driver fixes

   - xhci platform driver fixes for suspending

   - ulpi core fix

   - role.h build fix

   - new device ids

   - syzbot-reported bugfixes

   - gadget driver fixes

   - dwc3 driver fixes

   - other small fixes

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

* tag 'usb-5.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: cdnsp: Fix segmentation fault in cdns_lost_power function
  usb: dwc2: gadget: don't try to disable ep0 in dwc2_hsotg_suspend
  usb: gadget: at91_udc: fix incorrect print type
  usb: dwc3: xilinx: Fix error handling when getting USB3 PHY
  usb: dwc3: xilinx: Skip resets and USB3 register settings for USB2.0 mode
  usb: xhci-plat: fix crash when suspend if remote wake enable
  usb: common: ulpi: Fix crash in ulpi_match()
  usb: gadget: f_sourcesink: Fix isoc transfer for USB_SPEED_SUPER_PLUS
  ucsi_ccg: Check DEV_INT bit only when starting CCG4
  USB: core: Fix hang in usb_kill_urb by adding memory barriers
  usb-storage: Add unusual-devs entry for VL817 USB-SATA bridge
  usb: typec: tcpm: Do not disconnect when receiving VSAFE0V
  usb: typec: tcpm: Do not disconnect while receiving VBUS off
  usb: typec: Don't try to register component master without components
  usb: typec: Only attempt to link USB ports if there is fwnode
  usb: typec: tcpci: don't touch CC line if it's Vconn source
  usb: roles: fix include/linux/usb/role.h compile issue

16 files changed:
drivers/usb/cdns3/drd.c
drivers/usb/common/ulpi.c
drivers/usb/core/hcd.c
drivers/usb/core/urb.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/dwc3-xilinx.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/host/xhci-plat.c
drivers/usb/storage/unusual_devs.h
drivers/usb/typec/port-mapper.c
drivers/usb/typec/tcpm/tcpci.c
drivers/usb/typec/tcpm/tcpci.h
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/ucsi_ccg.c
include/linux/usb/role.h

index 55c73b1..d00ff98 100644 (file)
@@ -483,11 +483,11 @@ int cdns_drd_exit(struct cdns *cdns)
 /* Indicate the cdns3 core was power lost before */
 bool cdns_power_is_lost(struct cdns *cdns)
 {
-       if (cdns->version == CDNS3_CONTROLLER_V1) {
-               if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
+       if (cdns->version == CDNS3_CONTROLLER_V0) {
+               if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
                        return true;
        } else {
-               if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
+               if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
                        return true;
        }
        return false;
index 4169cf4..8f8405b 100644 (file)
@@ -39,8 +39,11 @@ static int ulpi_match(struct device *dev, struct device_driver *driver)
        struct ulpi *ulpi = to_ulpi_dev(dev);
        const struct ulpi_device_id *id;
 
-       /* Some ULPI devices don't have a vendor id so rely on OF match */
-       if (ulpi->id.vendor == 0)
+       /*
+        * Some ULPI devices don't have a vendor id
+        * or provide an id_table so rely on OF match.
+        */
+       if (ulpi->id.vendor == 0 || !drv->id_table)
                return of_driver_match_device(dev, driver);
 
        for (id = drv->id_table; id->vendor; id++)
index 3e01dd6..d9712c2 100644 (file)
@@ -1563,6 +1563,13 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
                urb->hcpriv = NULL;
                INIT_LIST_HEAD(&urb->urb_list);
                atomic_dec(&urb->use_count);
+               /*
+                * Order the write of urb->use_count above before the read
+                * of urb->reject below.  Pairs with the memory barriers in
+                * usb_kill_urb() and usb_poison_urb().
+                */
+               smp_mb__after_atomic();
+
                atomic_dec(&urb->dev->urbnum);
                if (atomic_read(&urb->reject))
                        wake_up(&usb_kill_urb_queue);
@@ -1665,6 +1672,13 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
 
        usb_anchor_resume_wakeups(anchor);
        atomic_dec(&urb->use_count);
+       /*
+        * Order the write of urb->use_count above before the read
+        * of urb->reject below.  Pairs with the memory barriers in
+        * usb_kill_urb() and usb_poison_urb().
+        */
+       smp_mb__after_atomic();
+
        if (unlikely(atomic_read(&urb->reject)))
                wake_up(&usb_kill_urb_queue);
        usb_put_urb(urb);
index 3072772..33d62d7 100644 (file)
@@ -715,6 +715,12 @@ void usb_kill_urb(struct urb *urb)
        if (!(urb && urb->dev && urb->ep))
                return;
        atomic_inc(&urb->reject);
+       /*
+        * Order the write of urb->reject above before the read
+        * of urb->use_count below.  Pairs with the barriers in
+        * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+        */
+       smp_mb__after_atomic();
 
        usb_hcd_unlink_urb(urb, -ENOENT);
        wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
@@ -756,6 +762,12 @@ void usb_poison_urb(struct urb *urb)
        if (!urb)
                return;
        atomic_inc(&urb->reject);
+       /*
+        * Order the write of urb->reject above before the read
+        * of urb->use_count below.  Pairs with the barriers in
+        * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+        */
+       smp_mb__after_atomic();
 
        if (!urb->dev || !urb->ep)
                return;
index 2bc03f4..eee3504 100644 (file)
@@ -5097,7 +5097,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
                hsotg->gadget.speed = USB_SPEED_UNKNOWN;
                spin_unlock_irqrestore(&hsotg->lock, flags);
 
-               for (ep = 0; ep < hsotg->num_of_eps; ep++) {
+               for (ep = 1; ep < hsotg->num_of_eps; ep++) {
                        if (hsotg->eps_in[ep])
                                dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
                        if (hsotg->eps_out[ep])
index 9cc3ad7..e14ac15 100644 (file)
@@ -102,14 +102,26 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
        int                     ret;
        u32                     reg;
 
-       usb3_phy = devm_phy_get(dev, "usb3-phy");
-       if (PTR_ERR(usb3_phy) == -EPROBE_DEFER) {
-               ret = -EPROBE_DEFER;
+       usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
+       if (IS_ERR(usb3_phy)) {
+               ret = PTR_ERR(usb3_phy);
+               dev_err_probe(dev, ret,
+                             "failed to get USB3 PHY\n");
                goto err;
-       } else if (IS_ERR(usb3_phy)) {
-               usb3_phy = NULL;
        }
 
+       /*
+        * The following core resets are not required unless a USB3 PHY
+        * is used, and the subsequent register settings are not required
+        * unless a core reset is performed (they should be set properly
+        * by the first-stage boot loader, but may be reverted by a core
+        * reset). They may also break the configuration if USB3 is actually
+        * in use but the usb3-phy entry is missing from the device tree.
+        * Therefore, skip these operations in this case.
+        */
+       if (!usb3_phy)
+               goto skip_usb3_phy;
+
        crst = devm_reset_control_get_exclusive(dev, "usb_crst");
        if (IS_ERR(crst)) {
                ret = PTR_ERR(crst);
@@ -188,6 +200,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
                goto err;
        }
 
+skip_usb3_phy:
        /*
         * This routes the USB DMA traffic to go through FPD path instead
         * of reaching DDR directly. This traffic routing is needed to
index 1abf08e..6803cd6 100644 (file)
@@ -584,6 +584,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 
        if (is_iso) {
                switch (speed) {
+               case USB_SPEED_SUPER_PLUS:
                case USB_SPEED_SUPER:
                        size = ss->isoc_maxpacket *
                                        (ss->isoc_mult + 1) *
index dd0819d..9040a05 100644 (file)
@@ -1895,7 +1895,7 @@ static int at91udc_probe(struct platform_device *pdev)
                                        at91_vbus_irq, 0, driver_name, udc);
                        if (retval) {
                                DBG("request vbus irq %d failed\n",
-                                   udc->board.vbus_pin);
+                                   desc_to_gpio(udc->board.vbus_pin));
                                goto err_unprepare_iclk;
                        }
                }
index c1edcc9..dc570ce 100644 (file)
@@ -437,6 +437,9 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int ret;
 
+       if (pm_runtime_suspended(dev))
+               pm_runtime_resume(dev);
+
        ret = xhci_priv_suspend_quirk(hcd);
        if (ret)
                return ret;
index 29191d3..1a05e3d 100644 (file)
@@ -2301,6 +2301,16 @@ UNUSUAL_DEV(  0x2027, 0xa001, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
                US_FL_SCM_MULT_TARG ),
 
+/*
+ * Reported by DocMAX <mail@vacharakis.de>
+ * and Thomas Weißschuh <linux@weissschuh.net>
+ */
+UNUSUAL_DEV( 0x2109, 0x0715, 0x9999, 0x9999,
+               "VIA Labs, Inc.",
+               "VL817 SATA Bridge",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_UAS),
+
 UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
                "ST",
                "2A",
index 07d3074..a7d5078 100644 (file)
@@ -56,7 +56,12 @@ int typec_link_ports(struct typec_port *con)
 {
        struct each_port_arg arg = { .port = con, .match = NULL };
 
+       if (!has_acpi_companion(&con->dev))
+               return 0;
+
        bus_for_each_dev(&acpi_bus_type, NULL, &arg, typec_port_match);
+       if (!arg.match)
+               return 0;
 
        /*
         * REVISIT: Now each connector can have only a single component master.
@@ -74,5 +79,6 @@ int typec_link_ports(struct typec_port *con)
 
 void typec_unlink_ports(struct typec_port *con)
 {
-       component_master_del(&con->dev, &typec_aggregate_ops);
+       if (has_acpi_companion(&con->dev))
+               component_master_del(&con->dev, &typec_aggregate_ops);
 }
index 35a1307..e07d26a 100644 (file)
@@ -75,9 +75,25 @@ static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
 static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+       bool vconn_pres;
+       enum typec_cc_polarity polarity = TYPEC_POLARITY_CC1;
        unsigned int reg;
        int ret;
 
+       ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, &reg);
+       if (ret < 0)
+               return ret;
+
+       vconn_pres = !!(reg & TCPC_POWER_STATUS_VCONN_PRES);
+       if (vconn_pres) {
+               ret = regmap_read(tcpci->regmap, TCPC_TCPC_CTRL, &reg);
+               if (ret < 0)
+                       return ret;
+
+               if (reg & TCPC_TCPC_CTRL_ORIENTATION)
+                       polarity = TYPEC_POLARITY_CC2;
+       }
+
        switch (cc) {
        case TYPEC_CC_RA:
                reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) |
@@ -112,6 +128,16 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
                break;
        }
 
+       if (vconn_pres) {
+               if (polarity == TYPEC_POLARITY_CC2) {
+                       reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT);
+                       reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT);
+               } else {
+                       reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT);
+                       reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT);
+               }
+       }
+
        ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
        if (ret < 0)
                return ret;
index 2be7a77..b2edd45 100644 (file)
@@ -98,6 +98,7 @@
 #define TCPC_POWER_STATUS_SOURCING_VBUS        BIT(4)
 #define TCPC_POWER_STATUS_VBUS_DET     BIT(3)
 #define TCPC_POWER_STATUS_VBUS_PRES    BIT(2)
+#define TCPC_POWER_STATUS_VCONN_PRES   BIT(1)
 #define TCPC_POWER_STATUS_SINKING_VBUS BIT(0)
 
 #define TCPC_FAULT_STATUS              0x1f
index 59d4fa2..5fce795 100644 (file)
@@ -5156,7 +5156,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
        case SNK_TRYWAIT_DEBOUNCE:
                break;
        case SNK_ATTACH_WAIT:
-               tcpm_set_state(port, SNK_UNATTACHED, 0);
+       case SNK_DEBOUNCED:
+               /* Do nothing, as TCPM is still waiting for vbus to reaach VSAFE5V to connect */
                break;
 
        case SNK_NEGOTIATE_CAPABILITIES:
@@ -5263,6 +5264,10 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
        case PR_SWAP_SNK_SRC_SOURCE_ON:
                /* Do nothing, vsafe0v is expected during transition */
                break;
+       case SNK_ATTACH_WAIT:
+       case SNK_DEBOUNCED:
+               /*Do nothing, still waiting for VSAFE5V for connect */
+               break;
        default:
                if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled)
                        tcpm_set_state(port, SNK_UNATTACHED, 0);
index bff96d6..6db7c8d 100644 (file)
@@ -325,7 +325,7 @@ static int ucsi_ccg_init(struct ucsi_ccg *uc)
                if (status < 0)
                        return status;
 
-               if (!data)
+               if (!(data & DEV_INT))
                        return 0;
 
                status = ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
index 031f148..b5deafd 100644 (file)
@@ -91,6 +91,12 @@ fwnode_usb_role_switch_get(struct fwnode_handle *node)
 
 static inline void usb_role_switch_put(struct usb_role_switch *sw) { }
 
+static inline struct usb_role_switch *
+usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode)
+{
+       return NULL;
+}
+
 static inline struct usb_role_switch *
 usb_role_switch_register(struct device *parent,
                         const struct usb_role_switch_desc *desc)