summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/configfs-usb-gadget-uvc64
-rw-r--r--Documentation/ABI/testing/sysfs-class-typec27
-rw-r--r--Documentation/devicetree/bindings/connector/usb-connector.yaml46
-rw-r--r--Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml42
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml2
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml5
-rw-r--r--Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml6
-rw-r--r--Documentation/devicetree/bindings/usb/generic-ehci.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/generic-ohci.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/genesys,gl850g.yaml9
-rw-r--r--Documentation/devicetree/bindings/usb/maxim,max33359.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml7
-rw-r--r--Documentation/devicetree/bindings/usb/qcom,dwc3.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/renesas,usbhs.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml6
-rw-r--r--Documentation/devicetree/bindings/usb/ti,tusb1046.yaml49
-rw-r--r--Documentation/devicetree/bindings/usb/ti,tusb73x0-pci.yaml55
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/phy/realtek/phy-rtk-usb2.c2
-rw-r--r--drivers/phy/realtek/phy-rtk-usb3.c2
-rw-r--r--drivers/thunderbolt/debugfs.c504
-rw-r--r--drivers/thunderbolt/nhi.c12
-rw-r--r--drivers/thunderbolt/sb_regs.h32
-rw-r--r--drivers/thunderbolt/tb.h16
-rw-r--r--drivers/thunderbolt/usb4.c18
-rw-r--r--drivers/usb/atm/ueagle-atm.c6
-rw-r--r--drivers/usb/atm/usbatm.c2
-rw-r--r--drivers/usb/c67x00/c67x00-drv.c2
-rw-r--r--drivers/usb/cdns3/cdns3-imx.c2
-rw-r--r--drivers/usb/cdns3/cdns3-pci-wrap.c4
-rw-r--r--drivers/usb/cdns3/cdns3-plat.c2
-rw-r--r--drivers/usb/cdns3/cdns3-starfive.c2
-rw-r--r--drivers/usb/cdns3/cdns3-ti.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-pci.c26
-rw-r--r--drivers/usb/chipidea/ci.h2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c3
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_npcm.c2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_tegra.c2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_usb2.c2
-rw-r--r--drivers/usb/chipidea/core.c6
-rw-r--r--drivers/usb/chipidea/udc.c178
-rw-r--r--drivers/usb/chipidea/udc.h2
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c4
-rw-r--r--drivers/usb/common/common.c3
-rw-r--r--drivers/usb/common/usb-conn-gpio.c2
-rw-r--r--drivers/usb/core/config.c2
-rw-r--r--drivers/usb/core/devio.c5
-rw-r--r--drivers/usb/core/driver.c24
-rw-r--r--drivers/usb/core/endpoint.c11
-rw-r--r--drivers/usb/core/ledtrig-usbport.c3
-rw-r--r--drivers/usb/core/port.c11
-rw-r--r--drivers/usb/core/usb.h2
-rw-r--r--drivers/usb/dwc2/platform.c2
-rw-r--r--drivers/usb/dwc3/core.c16
-rw-r--r--drivers/usb/dwc3/core.h14
-rw-r--r--drivers/usb/dwc3/dwc3-am62.c2
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c2
-rw-r--r--drivers/usb/dwc3/dwc3-imx8mp.c2
-rw-r--r--drivers/usb/dwc3/dwc3-keystone.c2
-rw-r--r--drivers/usb/dwc3/dwc3-meson-g12a.c2
-rw-r--r--drivers/usb/dwc3/dwc3-octeon.c2
-rw-r--r--drivers/usb/dwc3/dwc3-of-simple.c2
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c4
-rw-r--r--drivers/usb/dwc3/dwc3-qcom.c4
-rw-r--r--drivers/usb/dwc3/dwc3-rtk.c2
-rw-r--r--drivers/usb/dwc3/dwc3-st.c2
-rw-r--r--drivers/usb/dwc3/dwc3-xilinx.c2
-rw-r--r--drivers/usb/dwc3/ep0.c4
-rw-r--r--drivers/usb/dwc3/gadget.c152
-rw-r--r--drivers/usb/dwc3/host.c2
-rw-r--r--drivers/usb/fotg210/fotg210-core.c2
-rw-r--r--drivers/usb/gadget/composite.c30
-rw-r--r--drivers/usb/gadget/config.c4
-rw-r--r--drivers/usb/gadget/configfs.c2
-rw-r--r--drivers/usb/gadget/function/Makefile4
-rw-r--r--drivers/usb/gadget/function/f_fs.c6
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c8
-rw-r--r--drivers/usb/gadget/function/f_midi.c8
-rw-r--r--drivers/usb/gadget/function/f_midi2.c4
-rw-r--r--drivers/usb/gadget/function/f_uvc.c4
-rw-r--r--drivers/usb/gadget/function/uvc.h13
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c348
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.h16
-rw-r--r--drivers/usb/gadget/function/uvc_queue.c26
-rw-r--r--drivers/usb/gadget/function/uvc_queue.h2
-rw-r--r--drivers/usb/gadget/function/uvc_trace.c11
-rw-r--r--drivers/usb/gadget/function/uvc_trace.h60
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c66
-rw-r--r--drivers/usb/gadget/function/uvc_video.c268
-rw-r--r--drivers/usb/gadget/legacy/hid.c2
-rw-r--r--drivers/usb/gadget/legacy/raw_gadget.c4
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/core.c2
-rw-r--r--drivers/usb/gadget/udc/aspeed_udc.c4
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c2
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c2
-rw-r--r--drivers/usb/gadget/udc/bcm63xx_udc.c2
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_core.c2
-rw-r--r--drivers/usb/gadget/udc/cdns2/cdns2-pci.c3
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c6
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c8
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/fusb300_udc.c4
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c2
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c2
-rw-r--r--drivers/usb/gadget/udc/m66592-udc.c2
-rw-r--r--drivers/usb/gadget/udc/mv_u3d_core.c2
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/net2272.c4
-rw-r--r--drivers/usb/gadget/udc/omap_udc.c6
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c2
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/udc/r8a66597-udc.c2
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c2
-rw-r--r--drivers/usb/gadget/udc/renesas_usbf.c4
-rw-r--r--drivers/usb/gadget/udc/rzv2m_usb3drd.c2
-rw-r--r--drivers/usb/gadget/udc/snps_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/snps_udc_plat.c2
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c2
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c2
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/host/bcma-hcd.c1
-rw-r--r--drivers/usb/host/ehci-atmel.c2
-rw-r--r--drivers/usb/host/ehci-brcm.c2
-rw-r--r--drivers/usb/host/ehci-exynos.c2
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-grlib.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-mv.c2
-rw-r--r--drivers/usb/host/ehci-npcm7xx.c2
-rw-r--r--drivers/usb/host/ehci-omap.c2
-rw-r--r--drivers/usb/host/ehci-orion.c2
-rw-r--r--drivers/usb/host/ehci-platform.c2
-rw-r--r--drivers/usb/host/ehci-ppc-of.c2
-rw-r--r--drivers/usb/host/ehci-sh.c2
-rw-r--r--drivers/usb/host/ehci-spear.c9
-rw-r--r--drivers/usb/host/ehci-st.c2
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c2
-rw-r--r--drivers/usb/host/fhci-hcd.c2
-rw-r--r--drivers/usb/host/fhci-sched.c4
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c2
-rw-r--r--drivers/usb/host/isp116x-hcd.c2
-rw-r--r--drivers/usb/host/isp1362-hcd.c2
-rw-r--r--drivers/usb/host/octeon-hcd.c6
-rw-r--r--drivers/usb/host/ohci-at91.c2
-rw-r--r--drivers/usb/host/ohci-da8xx.c2
-rw-r--r--drivers/usb/host/ohci-exynos.c2
-rw-r--r--drivers/usb/host/ohci-nxp.c2
-rw-r--r--drivers/usb/host/ohci-omap.c4
-rw-r--r--drivers/usb/host/ohci-platform.c2
-rw-r--r--drivers/usb/host/ohci-ppc-of.c2
-rw-r--r--drivers/usb/host/ohci-pxa27x.c2
-rw-r--r--drivers/usb/host/ohci-s3c2410.c2
-rw-r--r--drivers/usb/host/ohci-sm501.c2
-rw-r--r--drivers/usb/host/ohci-spear.c2
-rw-r--r--drivers/usb/host/ohci-st.c2
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c8
-rw-r--r--drivers/usb/host/r8a66597-hcd.c6
-rw-r--r--drivers/usb/host/sl811-hcd.c2
-rw-r--r--drivers/usb/host/uhci-grlib.c2
-rw-r--r--drivers/usb/host/uhci-platform.c2
-rw-r--r--drivers/usb/host/xhci-dbgcap.c13
-rw-r--r--drivers/usb/host/xhci-debugfs.c10
-rw-r--r--drivers/usb/host/xhci-histb.c2
-rw-r--r--drivers/usb/host/xhci-hub.c6
-rw-r--r--drivers/usb/host/xhci-mem.c235
-rw-r--r--drivers/usb/host/xhci-mtk.c2
-rw-r--r--drivers/usb/host/xhci-pci.c45
-rw-r--r--drivers/usb/host/xhci-plat.c2
-rw-r--r--drivers/usb/host/xhci-rcar.c2
-rw-r--r--drivers/usb/host/xhci-ring.c302
-rw-r--r--drivers/usb/host/xhci-tegra.c2
-rw-r--r--drivers/usb/host/xhci-trace.h79
-rw-r--r--drivers/usb/host/xhci.c123
-rw-r--r--drivers/usb/host/xhci.h51
-rw-r--r--drivers/usb/isp1760/isp1760-if.c2
-rw-r--r--drivers/usb/misc/chaoskey.c35
-rw-r--r--drivers/usb/misc/iowarrior.c50
-rw-r--r--drivers/usb/misc/onboard_usb_dev.c2
-rw-r--r--drivers/usb/misc/qcom_eud.c2
-rw-r--r--drivers/usb/misc/usb-ljca.c20
-rw-r--r--drivers/usb/misc/usb3503.c2
-rw-r--r--drivers/usb/misc/usbtest.c3
-rw-r--r--drivers/usb/misc/yurex.c5
-rw-r--r--drivers/usb/mon/mon_bin.c2
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c4
-rw-r--r--drivers/usb/musb/da8xx.c2
-rw-r--r--drivers/usb/musb/jz4740.c2
-rw-r--r--drivers/usb/musb/mediatek.c2
-rw-r--r--drivers/usb/musb/mpfs.c2
-rw-r--r--drivers/usb/musb/musb_core.c4
-rw-r--r--drivers/usb/musb/musb_dsps.c2
-rw-r--r--drivers/usb/musb/musb_gadget.c13
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c2
-rw-r--r--drivers/usb/musb/musb_host.c5
-rw-r--r--drivers/usb/musb/omap2430.c2
-rw-r--r--drivers/usb/musb/sunxi.c2
-rw-r--r--drivers/usb/musb/tusb6010.c2
-rw-r--r--drivers/usb/musb/ux500.c2
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c2
-rw-r--r--drivers/usb/phy/phy-am335x.c2
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c2
-rw-r--r--drivers/usb/phy/phy-generic.c2
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c2
-rw-r--r--drivers/usb/phy/phy-isp1301.c2
-rw-r--r--drivers/usb/phy/phy-keystone.c2
-rw-r--r--drivers/usb/phy/phy-mv-usb.c2
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c2
-rw-r--r--drivers/usb/phy/phy-tahvo.c2
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c2
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c2
-rw-r--r--drivers/usb/phy/phy.c2
-rw-r--r--drivers/usb/renesas_usbhs/common.c4
-rw-r--r--drivers/usb/roles/intel-xhci-usb-role-switch.c2
-rw-r--r--drivers/usb/serial/bus.c4
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/usb/serial/pl2303.c38
-rw-r--r--drivers/usb/serial/sierra.c2
-rw-r--r--drivers/usb/serial/usb-serial.c4
-rw-r--r--drivers/usb/storage/ene_ub6250.c8
-rw-r--r--drivers/usb/storage/realtek_cr.c4
-rw-r--r--drivers/usb/storage/sddr09.c4
-rw-r--r--drivers/usb/storage/sddr55.c8
-rw-r--r--drivers/usb/storage/transport.c2
-rw-r--r--drivers/usb/typec/altmodes/displayport.c2
-rw-r--r--drivers/usb/typec/class.c205
-rw-r--r--drivers/usb/typec/class.h3
-rw-r--r--drivers/usb/typec/mux/Kconfig9
-rw-r--r--drivers/usb/typec/mux/Makefile1
-rw-r--r--drivers/usb/typec/mux/gpio-sbu-mux.c2
-rw-r--r--drivers/usb/typec/mux/intel_pmc_mux.c2
-rw-r--r--drivers/usb/typec/mux/tusb1046.c196
-rw-r--r--drivers/usb/typec/stusb160x.c7
-rw-r--r--drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c2
-rw-r--r--drivers/usb/typec/tcpm/tcpci_mt6360.c2
-rw-r--r--drivers/usb/typec/tcpm/tcpci_mt6370.c2
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c96
-rw-r--r--drivers/usb/typec/tcpm/wcove.c2
-rw-r--r--drivers/usb/typec/ucsi/debugfs.c1
-rw-r--r--drivers/usb/typec/ucsi/psy.c28
-rw-r--r--drivers/usb/typec/ucsi/trace.h28
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c153
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h241
-rw-r--r--drivers/usb/typec/ucsi/ucsi_acpi.c65
-rw-r--r--drivers/usb/typec/ucsi/ucsi_ccg.c5
-rw-r--r--drivers/usb/typec/ucsi/ucsi_glink.c21
-rw-r--r--drivers/usb/usbip/vhci_hcd.c2
-rw-r--r--drivers/usb/usbip/vudc_main.c2
-rw-r--r--include/linux/pci_ids.h4
-rw-r--r--include/linux/usb.h7
-rw-r--r--include/linux/usb/chipidea.h1
-rw-r--r--include/linux/usb/storage.h2
-rw-r--r--include/linux/usb/typec.h22
-rw-r--r--include/uapi/linux/usb/video.h58
257 files changed, 3502 insertions, 1349 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc
index 4feb692c4c1d..b6720768d63d 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uvc
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc
@@ -342,6 +342,70 @@ Description: Specific uncompressed frame descriptors
support
========================= =====================================
+What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased
+Date: Sept 2024
+KernelVersion: 5.15
+Description: Framebased format descriptors
+
+What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name
+Date: Sept 2024
+KernelVersion: 5.15
+Description: Specific framebased format descriptors
+
+ ================== =======================================
+ bFormatIndex unique id for this format descriptor;
+ only defined after parent header is
+ linked into the streaming class;
+ read-only
+ bmaControls this format's data for bmaControls in
+ the streaming header
+ bmInterlaceFlags specifies interlace information,
+ read-only
+ bAspectRatioY the X dimension of the picture aspect
+ ratio, read-only
+ bAspectRatioX the Y dimension of the picture aspect
+ ratio, read-only
+ bDefaultFrameIndex optimum frame index for this stream
+ bBitsPerPixel number of bits per pixel used to
+ specify color in the decoded video
+ frame
+ guidFormat globally unique id used to identify
+ stream-encoding format
+ ================== =======================================
+
+What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name/name
+Date: Sept 2024
+KernelVersion: 5.15
+Description: Specific framebased frame descriptors
+
+ ========================= =====================================
+ bFrameIndex unique id for this framedescriptor;
+ only defined after parent format is
+ linked into the streaming header;
+ read-only
+ dwFrameInterval indicates how frame interval can be
+ programmed; a number of values
+ separated by newline can be specified
+ dwDefaultFrameInterval the frame interval the device would
+ like to use as default
+ dwBytesPerLine Specifies the number of bytes per line
+ of video for packed fixed frame size
+ formats, allowing the receiver to
+ perform stride alignment of the video.
+ If the bVariableSize value (above) is
+ TRUE (1), or if the format does not
+ permit such alignment, this value shall
+ be set to zero (0).
+ dwMaxBitRate the maximum bit rate at the shortest
+ frame interval in bps
+ dwMinBitRate the minimum bit rate at the longest
+ frame interval in bps
+ wHeight height of decoded bitmap frame in px
+ wWidth width of decoded bitmam frame in px
+ bmCapabilities still image support, fixed frame-rate
+ support
+ ========================= =====================================
+
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header
Date: Dec 2014
KernelVersion: 4.0
diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec
index 281b995beb05..38e101c17a00 100644
--- a/Documentation/ABI/testing/sysfs-class-typec
+++ b/Documentation/ABI/testing/sysfs-class-typec
@@ -149,6 +149,19 @@ Description:
advertise to the partner. The currently used capabilities are in
brackets. Selection happens by writing to the file.
+What: /sys/class/typec/<port>/usb_capability
+Date: November 2024
+Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description: Lists the supported USB Modes. The default USB mode that is used
+ next time with the Enter_USB Message is in brackets. The default
+ mode can be changed by writing to the file when supported by the
+ driver.
+
+ Valid values:
+ - usb2 (USB 2.0)
+ - usb3 (USB 3.2)
+ - usb4 (USB4)
+
USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
What: /sys/class/typec/<port>-partner/accessory_mode
@@ -220,6 +233,20 @@ Description:
directory exists, it will have an attribute file for every VDO
in Discover Identity command result.
+What: /sys/class/typec/<port>-partner/usb_mode
+Date: November 2024
+Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description: The USB Modes that the partner device supports. The active mode
+ is displayed in brackets. The active USB mode can be changed by
+ writing to this file when the port driver is able to send Data
+ Reset Message to the partner. That requires USB Power Delivery
+ contract between the partner and the port.
+
+ Valid values:
+ - usb2 (USB 2.0)
+ - usb3 (USB 3.2)
+ - usb4 (USB4)
+
USB Type-C cable devices (eg. /sys/class/typec/port0-cable/)
Note: Electronically Marked Cables will have a device also for one cable plug
diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml
index fb216ce68bb3..67700440e23b 100644
--- a/Documentation/devicetree/bindings/connector/usb-connector.yaml
+++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml
@@ -253,6 +253,46 @@ properties:
additionalProperties: false
+ sink-wait-cap-time-ms:
+ description: Represents the max time in ms that USB Type-C port (in sink
+ role) should wait for the port partner (source role) to send source caps.
+ SinkWaitCap timer starts when port in sink role attaches to the source.
+ This timer will stop when sink receives PD source cap advertisement before
+ timeout in which case it'll move to capability negotiation stage. A
+ timeout leads to a hard reset message by the port.
+ minimum: 310
+ maximum: 620
+ default: 310
+
+ ps-source-off-time-ms:
+ description: Represents the max time in ms that a DRP in source role should
+ take to turn off power after the PsSourceOff timer starts. PsSourceOff
+ timer starts when a sink's PHY layer receives EOP of the GoodCRC message
+ (corresponding to an Accept message sent in response to a PR_Swap or a
+ FR_Swap request). This timer stops when last bit of GoodCRC EOP
+ corresponding to the received PS_RDY message is transmitted by the PHY
+ layer. A timeout shall lead to error recovery in the type-c port.
+ minimum: 750
+ maximum: 920
+ default: 920
+
+ cc-debounce-time-ms:
+ description: Represents the max time in ms that a port shall wait to
+ determine if it's attached to a partner.
+ minimum: 100
+ maximum: 200
+ default: 200
+
+ sink-bc12-completion-time-ms:
+ description: Represents the max time in ms that a port in sink role takes
+ to complete Battery Charger (BC1.2) Detection. BC1.2 detection is a
+ hardware mechanism, which in some TCPC implementations, can run in
+ parallel once the Type-C connection state machine reaches the "potential
+ connect as sink" state. In TCPCs where this causes delays to respond to
+ the incoming PD messages, sink-bc12-completion-time-ms is used to delay
+ PD negotiation till BC1.2 detection completes.
+ default: 0
+
dependencies:
sink-vdos-v1: [ sink-vdos ]
sink-vdos: [ sink-vdos-v1 ]
@@ -380,7 +420,7 @@ examples:
};
# USB-C connector attached to a typec port controller(ptn5110), which has
- # power delivery support and enables drp.
+ # power delivery support, explicitly defines time properties and enables drp.
- |
#include <dt-bindings/usb/pd.h>
typec: ptn5110 {
@@ -393,6 +433,10 @@ examples:
sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
PDO_VAR(5000, 12000, 2000)>;
op-sink-microwatt = <10000000>;
+ sink-wait-cap-time-ms = <465>;
+ ps-source-off-time-ms = <835>;
+ cc-debounce-time-ms = <101>;
+ sink-bc12-completion-time-ms = <500>;
};
};
diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml
index dc3a3f709fea..6d6d211883ae 100644
--- a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml
@@ -11,12 +11,17 @@ maintainers:
properties:
compatible:
- enum:
- - fsl,imx8mq-usb-phy
- - fsl,imx8mp-usb-phy
+ oneOf:
+ - enum:
+ - fsl,imx8mq-usb-phy
+ - fsl,imx8mp-usb-phy
+ - items:
+ - const: fsl,imx95-usb-phy
+ - const: fsl,imx8mp-usb-phy
reg:
- maxItems: 1
+ minItems: 1
+ maxItems: 2
"#phy-cells":
const: 0
@@ -89,7 +94,34 @@ required:
- clocks
- clock-names
-additionalProperties: false
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - fsl,imx95-usb-phy
+ then:
+ properties:
+ reg:
+ items:
+ - description: USB PHY Control range
+ - description: USB PHY TCA Block range
+ else:
+ properties:
+ reg:
+ maxItems: 1
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - fsl,imx95-usb-phy
+ then:
+ $ref: /schemas/usb/usb-switch.yaml#
+
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
index f1f4e4f83352..1636285fbe53 100644
--- a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml
@@ -18,6 +18,7 @@ properties:
enum:
- qcom,msm8998-qmp-usb3-phy
- qcom,qcm2290-qmp-usb3-phy
+ - qcom,qcs615-qmp-usb3-phy
- qcom,sdm660-qmp-usb3-phy
- qcom,sm6115-qmp-usb3-phy
@@ -96,6 +97,7 @@ allOf:
contains:
enum:
- qcom,msm8998-qmp-usb3-phy
+ - qcom,qcs615-qmp-usb3-phy
- qcom,sdm660-qmp-usb3-phy
then:
properties:
diff --git a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
index 95eecbaef05c..4aed4b5d65ec 100644
--- a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
@@ -25,6 +25,7 @@ properties:
- qcom,msm8996-qusb2-phy
- qcom,msm8998-qusb2-phy
- qcom,qcm2290-qusb2-phy
+ - qcom,qcs615-qusb2-phy
- qcom,sdm660-qusb2-phy
- qcom,sm4250-qusb2-phy
- qcom,sm6115-qusb2-phy
diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml
index bb5010dcefe1..7ffcd236d7bb 100644
--- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml
+++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml
@@ -25,6 +25,7 @@ properties:
- allwinner,sun20i-d1-musb
- allwinner,sun50i-a100-musb
- allwinner,sun50i-h6-musb
+ - allwinner,sun55i-a523-musb
- const: allwinner,sun8i-a33-musb
- items:
- const: allwinner,sun50i-h616-musb
diff --git a/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml b/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml
index 89fc9a434d05..0620d82508c1 100644
--- a/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml
+++ b/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml
@@ -61,18 +61,15 @@ additionalProperties: false
examples:
- |
- #include <dt-bindings/gpio/tegra194-gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
- #interrupt-cells = <2>;
typec@8 {
compatible = "cypress,cypd4226";
reg = <0x08>;
- interrupt-parent = <&gpio_aon>;
- interrupts = <TEGRA194_AON_GPIO(BB, 2) IRQ_TYPE_LEVEL_LOW>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
firmware-name = "nvidia,jetson-agx-xavier";
#address-cells = <1>;
#size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml
index 9ea1e4cd0709..baf130669c38 100644
--- a/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml
@@ -12,7 +12,11 @@ maintainers:
properties:
compatible:
- const: fsl,imx8mp-dwc3
+ oneOf:
+ - items:
+ - const: fsl,imx95-dwc3
+ - const: fsl,imx8mp-dwc3
+ - const: fsl,imx8mp-dwc3
reg:
items:
diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
index 0d797e01fc0b..223f2abd5e59 100644
--- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
@@ -32,6 +32,7 @@ properties:
- allwinner,sun50i-a64-ehci
- allwinner,sun50i-h6-ehci
- allwinner,sun50i-h616-ehci
+ - allwinner,sun55i-a523-ehci
- allwinner,sun5i-a13-ehci
- allwinner,sun6i-a31-ehci
- allwinner,sun7i-a20-ehci
diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
index cf33764553fa..3ee1586fc8b9 100644
--- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
@@ -19,6 +19,7 @@ properties:
- allwinner,sun50i-a64-ohci
- allwinner,sun50i-h6-ohci
- allwinner,sun50i-h616-ohci
+ - allwinner,sun55i-a523-ohci
- allwinner,sun5i-a13-ohci
- allwinner,sun6i-a31-ohci
- allwinner,sun7i-a20-ohci
diff --git a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
index fc833363cfb4..6fe2d356dcbd 100644
--- a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
+++ b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
@@ -62,7 +62,14 @@ allOf:
peer-hub: true
vdd-supply: true
-additionalProperties: false
+patternProperties:
+ "^.*@[0-9a-f]{1,2}$":
+ description: The hard wired USB devices
+ type: object
+ $ref: /schemas/usb/usb-device.yaml
+ additionalProperties: true
+
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
index 276bf7554215..20b62228371b 100644
--- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
+++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
@@ -69,6 +69,7 @@ examples:
PDO_FIXED_DATA_SWAP |
PDO_FIXED_DUAL_ROLE)
PDO_FIXED(9000, 2000, 0)>;
+ sink-bc12-completion-time-ms = <500>;
};
};
};
diff --git a/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml b/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
index 27b909de4992..a812317d8089 100644
--- a/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
+++ b/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
@@ -14,8 +14,11 @@ maintainers:
properties:
compatible:
- enum:
- - microchip,mpfs-musb
+ oneOf:
+ - items:
+ - const: microchip,pic64gx-musb
+ - const: microchip,mpfs-musb
+ - const: microchip,mpfs-musb
dr_mode: true
diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
index f7be05641930..935e204b607b 100644
--- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
@@ -29,6 +29,7 @@ properties:
- qcom,qcs8300-dwc3
- qcom,qdu1000-dwc3
- qcom,sa8775p-dwc3
+ - qcom,sar2130p-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
- qcom,sc8180x-dwc3
@@ -340,6 +341,7 @@ allOf:
contains:
enum:
- qcom,qcm2290-dwc3
+ - qcom,sar2130p-dwc3
- qcom,sc8180x-dwc3
- qcom,sc8180x-dwc3-mp
- qcom,sm6115-dwc3
diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
index c63db3ebd07b..b23ef29bf794 100644
--- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
+++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
@@ -76,6 +76,10 @@ properties:
Integer to use BUSWAIT register.
renesas,enable-gpio:
+ deprecated: true
+ maxItems: 1
+
+ renesas,enable-gpios:
maxItems: 1
description: |
gpio specifier to check GPIO determining if USB function should be
diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml b/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml
index c4924113f9bd..a21cc098542d 100644
--- a/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml
@@ -27,6 +27,7 @@ select:
enum:
- rockchip,rk3328-dwc3
- rockchip,rk3568-dwc3
+ - rockchip,rk3576-dwc3
- rockchip,rk3588-dwc3
required:
- compatible
@@ -37,6 +38,7 @@ properties:
- enum:
- rockchip,rk3328-dwc3
- rockchip,rk3568-dwc3
+ - rockchip,rk3576-dwc3
- rockchip,rk3588-dwc3
- const: snps,dwc3
@@ -113,7 +115,9 @@ allOf:
properties:
compatible:
contains:
- const: rockchip,rk3568-dwc3
+ enum:
+ - rockchip,rk3568-dwc3
+ - rockchip,rk3576-dwc3
then:
properties:
clocks:
diff --git a/Documentation/devicetree/bindings/usb/ti,tusb1046.yaml b/Documentation/devicetree/bindings/usb/ti,tusb1046.yaml
new file mode 100644
index 000000000000..f713cac4a8ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ti,tusb1046.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ti,tusb1046.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments TUSB1046-DCI Type-C crosspoint switch
+
+maintainers:
+ - Romain Gantois <romain.gantois@bootlin.com>
+
+allOf:
+ - $ref: usb-switch.yaml#
+
+properties:
+ compatible:
+ const: ti,tusb1046
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ typec-mux@44 {
+ compatible = "ti,tusb1046";
+ reg = <0x44>;
+
+ mode-switch;
+ orientation-switch;
+
+ port {
+ endpoint {
+ remote-endpoint = <&typec_controller>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/usb/ti,tusb73x0-pci.yaml b/Documentation/devicetree/bindings/usb/ti,tusb73x0-pci.yaml
new file mode 100644
index 000000000000..ddda734f36fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ti,tusb73x0-pci.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ti,tusb73x0-pci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TUSB73x0 USB 3.0 xHCI Host Controller (PCIe)
+
+maintainers:
+ - Francesco Dolcini <francesco.dolcini@toradex.com>
+
+description:
+ TUSB73x0 USB 3.0 xHCI Host Controller via PCIe x1 Gen2 interface.
+ The TUSB7320 supports up to two downstream ports, the TUSB7340 supports up
+ to four downstream ports, both variants share the same PCI device ID.
+
+properties:
+ compatible:
+ const: pci104c,8241
+
+ reg:
+ maxItems: 1
+
+ ti,pwron-active-high:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ Configure the polarity of the PWRONx# signals. When this is present, the
+ PWRONx# pins are active high and their internal pull-down resistors are
+ disabled. When this is absent, the PWRONx# pins are active low (default)
+ and their internal pull-down resistors are enabled.
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: usb-xhci.yaml
+
+additionalProperties: false
+
+examples:
+ - |
+ pcie@0 {
+ reg = <0x0 0x1000>;
+ ranges = <0x02000000 0x0 0x100000 0x10000000 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+
+ usb@0 {
+ compatible = "pci104c,8241";
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ ti,pwron-active-high;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 0456a33ef657..3827e5e190c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24352,6 +24352,13 @@ L: linux-usb@vger.kernel.org
S: Orphan
F: drivers/usb/typec/tcpm/
+USB TYPEC TUSB1046 MUX DRIVER
+M: Romain Gantois <romain.gantois@bootlin.com>
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/usb/ti,tusb1046.yaml
+F: drivers/usb/typec/mux/tusb1046.c
+
USB UHCI DRIVER
M: Alan Stern <stern@rowland.harvard.edu>
L: linux-usb@vger.kernel.org
diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
index c3e131a64131..248550ef98ca 100644
--- a/drivers/phy/realtek/phy-rtk-usb2.c
+++ b/drivers/phy/realtek/phy-rtk-usb2.c
@@ -1023,6 +1023,8 @@ static int rtk_usb2phy_probe(struct platform_device *pdev)
rtk_phy->dev = &pdev->dev;
rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
+ if (!rtk_phy->phy_cfg)
+ return -ENOMEM;
memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
diff --git a/drivers/phy/realtek/phy-rtk-usb3.c b/drivers/phy/realtek/phy-rtk-usb3.c
index 0cef29a7ddd9..cce453686db2 100644
--- a/drivers/phy/realtek/phy-rtk-usb3.c
+++ b/drivers/phy/realtek/phy-rtk-usb3.c
@@ -577,6 +577,8 @@ static int rtk_usb3phy_probe(struct platform_device *pdev)
rtk_phy->dev = &pdev->dev;
rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
+ if (!rtk_phy->phy_cfg)
+ return -ENOMEM;
memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c
index 350310bd0fee..a1d0d8a33f20 100644
--- a/drivers/thunderbolt/debugfs.c
+++ b/drivers/thunderbolt/debugfs.c
@@ -7,6 +7,7 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
+#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -43,6 +44,24 @@
#define MAX_DWELL_TIME 500 /* ms */
#define DWELL_SAMPLE_INTERVAL 10
+enum usb4_margin_cap_voltage_indp {
+ USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_MIN,
+ USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL,
+ USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_BOTH,
+ USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_MIN,
+ USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_BOTH,
+ USB4_MARGIN_CAP_VOLTAGE_INDP_UNKNOWN,
+};
+
+enum usb4_margin_cap_time_indp {
+ USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_MIN,
+ USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR,
+ USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_BOTH,
+ USB4_MARGIN_CAP_TIME_INDP_GEN_4_MIN,
+ USB4_MARGIN_CAP_TIME_INDP_GEN_4_BOTH,
+ USB4_MARGIN_CAP_TIME_INDP_UNKNOWN,
+};
+
/* Sideband registers and their sizes as defined in the USB4 spec */
struct sb_reg {
unsigned int reg;
@@ -395,6 +414,8 @@ out:
* @target: Sideband target
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
* @dev: Pointer to the device that is the target (USB4 port or retimer)
+ * @gen: Link generation
+ * @asym_rx: %true% if @port supports asymmetric link with 3 Rx
* @caps: Port lane margining capabilities
* @results: Last lane margining results
* @lanes: %0, %1 or %7 (all)
@@ -416,15 +437,19 @@ out:
* @time: %true if time margining is used instead of voltage
* @right_high: %false if left/low margin test is performed, %true if
* right/high
+ * @upper_eye: %false if the lower PAM3 eye is used, %true if the upper
+ * eye is used
*/
struct tb_margining {
struct tb_port *port;
enum usb4_sb_target target;
u8 index;
struct device *dev;
- u32 caps[2];
- u32 results[2];
- unsigned int lanes;
+ unsigned int gen;
+ bool asym_rx;
+ u32 caps[3];
+ u32 results[3];
+ enum usb4_margining_lane lanes;
unsigned int min_ber_level;
unsigned int max_ber_level;
unsigned int ber_level;
@@ -441,6 +466,7 @@ struct tb_margining {
bool software;
bool time;
bool right_high;
+ bool upper_eye;
};
static int margining_modify_error_counter(struct tb_margining *margining,
@@ -463,35 +489,75 @@ static int margining_modify_error_counter(struct tb_margining *margining,
static bool supports_software(const struct tb_margining *margining)
{
- return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW;
+ if (margining->gen < 4)
+ return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW;
+ return margining->caps[2] & USB4_MARGIN_CAP_2_MODES_SW;
}
static bool supports_hardware(const struct tb_margining *margining)
{
- return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW;
+ if (margining->gen < 4)
+ return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW;
+ return margining->caps[2] & USB4_MARGIN_CAP_2_MODES_HW;
}
-static bool both_lanes(const struct tb_margining *margining)
+static bool all_lanes(const struct tb_margining *margining)
{
- return margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES;
+ return margining->caps[0] & USB4_MARGIN_CAP_0_ALL_LANES;
}
-static unsigned int
+static enum usb4_margin_cap_voltage_indp
independent_voltage_margins(const struct tb_margining *margining)
{
- return FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK, margining->caps[0]);
+ if (margining->gen < 4) {
+ switch (FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK, margining->caps[0])) {
+ case USB4_MARGIN_CAP_0_VOLTAGE_MIN:
+ return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_MIN;
+ case USB4_MARGIN_CAP_0_VOLTAGE_HL:
+ return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL;
+ case USB4_MARGIN_CAP_1_TIME_BOTH:
+ return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_BOTH;
+ }
+ } else {
+ switch (FIELD_GET(USB4_MARGIN_CAP_2_VOLTAGE_INDP_MASK, margining->caps[2])) {
+ case USB4_MARGIN_CAP_2_VOLTAGE_MIN:
+ return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_MIN;
+ case USB4_MARGIN_CAP_2_VOLTAGE_BOTH:
+ return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_BOTH;
+ }
+ }
+ return USB4_MARGIN_CAP_VOLTAGE_INDP_UNKNOWN;
}
static bool supports_time(const struct tb_margining *margining)
{
- return margining->caps[0] & USB4_MARGIN_CAP_0_TIME;
+ if (margining->gen < 4)
+ return margining->caps[0] & USB4_MARGIN_CAP_0_TIME;
+ return margining->caps[2] & USB4_MARGIN_CAP_2_TIME;
}
/* Only applicable if supports_time() returns true */
-static unsigned int
+static enum usb4_margin_cap_time_indp
independent_time_margins(const struct tb_margining *margining)
{
- return FIELD_GET(USB4_MARGIN_CAP_1_TIME_INDP_MASK, margining->caps[1]);
+ if (margining->gen < 4) {
+ switch (FIELD_GET(USB4_MARGIN_CAP_1_TIME_INDP_MASK, margining->caps[1])) {
+ case USB4_MARGIN_CAP_1_TIME_MIN:
+ return USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_MIN;
+ case USB4_MARGIN_CAP_1_TIME_LR:
+ return USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR;
+ case USB4_MARGIN_CAP_1_TIME_BOTH:
+ return USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_BOTH;
+ }
+ } else {
+ switch (FIELD_GET(USB4_MARGIN_CAP_2_TIME_INDP_MASK, margining->caps[2])) {
+ case USB4_MARGIN_CAP_2_TIME_MIN:
+ return USB4_MARGIN_CAP_TIME_INDP_GEN_4_MIN;
+ case USB4_MARGIN_CAP_2_TIME_BOTH:
+ return USB4_MARGIN_CAP_TIME_INDP_GEN_4_BOTH;
+ }
+ }
+ return USB4_MARGIN_CAP_TIME_INDP_UNKNOWN;
}
static bool
@@ -570,16 +636,14 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
{
struct tb_margining *margining = s->private;
struct tb *tb = margining->port->sw->tb;
- u32 cap0, cap1;
+ int ret = 0;
if (mutex_lock_interruptible(&tb->lock))
return -ERESTARTSYS;
/* Dump the raw caps first */
- cap0 = margining->caps[0];
- seq_printf(s, "0x%08x\n", cap0);
- cap1 = margining->caps[1];
- seq_printf(s, "0x%08x\n", cap1);
+ for (int i = 0; i < ARRAY_SIZE(margining->caps); i++)
+ seq_printf(s, "0x%08x\n", margining->caps[i]);
seq_printf(s, "# software margining: %s\n",
supports_software(margining) ? "yes" : "no");
@@ -593,8 +657,8 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
seq_puts(s, "# hardware margining: no\n");
}
- seq_printf(s, "# both lanes simultaneously: %s\n",
- both_lanes(margining) ? "yes" : "no");
+ seq_printf(s, "# all lanes simultaneously: %s\n",
+ str_yes_no(all_lanes(margining)));
seq_printf(s, "# voltage margin steps: %u\n",
margining->voltage_steps);
seq_printf(s, "# maximum voltage offset: %u mV\n",
@@ -609,32 +673,54 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
}
switch (independent_voltage_margins(margining)) {
- case USB4_MARGIN_CAP_0_VOLTAGE_MIN:
+ case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_MIN:
seq_puts(s, "# returns minimum between high and low voltage margins\n");
break;
- case USB4_MARGIN_CAP_0_VOLTAGE_HL:
+ case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL:
seq_puts(s, "# returns high or low voltage margin\n");
break;
- case USB4_MARGIN_CAP_0_VOLTAGE_BOTH:
+ case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_BOTH:
seq_puts(s, "# returns both high and low margins\n");
break;
+ case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_MIN:
+ seq_puts(s, "# returns minimum between high and low voltage margins in both lower and upper eye\n");
+ break;
+ case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_BOTH:
+ seq_puts(s, "# returns both high and low margins of both upper and lower eye\n");
+ break;
+ case USB4_MARGIN_CAP_VOLTAGE_INDP_UNKNOWN:
+ tb_port_warn(margining->port,
+ "failed to parse independent voltage margining capabilities\n");
+ ret = -EIO;
+ goto out;
}
if (supports_time(margining)) {
seq_puts(s, "# time margining: yes\n");
seq_printf(s, "# time margining is destructive: %s\n",
- cap1 & USB4_MARGIN_CAP_1_TIME_DESTR ? "yes" : "no");
+ str_yes_no(margining->caps[1] & USB4_MARGIN_CAP_1_TIME_DESTR));
switch (independent_time_margins(margining)) {
- case USB4_MARGIN_CAP_1_TIME_MIN:
+ case USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_MIN:
seq_puts(s, "# returns minimum between left and right time margins\n");
break;
- case USB4_MARGIN_CAP_1_TIME_LR:
+ case USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR:
seq_puts(s, "# returns left or right margin\n");
break;
- case USB4_MARGIN_CAP_1_TIME_BOTH:
+ case USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_BOTH:
seq_puts(s, "# returns both left and right margins\n");
break;
+ case USB4_MARGIN_CAP_TIME_INDP_GEN_4_MIN:
+ seq_puts(s, "# returns minimum between left and right time margins in both lower and upper eye\n");
+ break;
+ case USB4_MARGIN_CAP_TIME_INDP_GEN_4_BOTH:
+ seq_puts(s, "# returns both left and right margins of both upper and lower eye\n");
+ break;
+ case USB4_MARGIN_CAP_TIME_INDP_UNKNOWN:
+ tb_port_warn(margining->port,
+ "failed to parse independent time margining capabilities\n");
+ ret = -EIO;
+ goto out;
}
seq_printf(s, "# time margin steps: %u\n",
@@ -645,19 +731,43 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
seq_puts(s, "# time margining: no\n");
}
+out:
mutex_unlock(&tb->lock);
- return 0;
+ return ret;
}
DEBUGFS_ATTR_RO(margining_caps);
+static const struct {
+ enum usb4_margining_lane lane;
+ const char *name;
+} lane_names[] = {
+ {
+ .lane = USB4_MARGINING_LANE_RX0,
+ .name = "0",
+ },
+ {
+ .lane = USB4_MARGINING_LANE_RX1,
+ .name = "1",
+ },
+ {
+ .lane = USB4_MARGINING_LANE_RX2,
+ .name = "2",
+ },
+ {
+ .lane = USB4_MARGINING_LANE_ALL,
+ .name = "all",
+ },
+};
+
static ssize_t
margining_lanes_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct tb_margining *margining = s->private;
- struct tb *tb = margining->port->sw->tb;
- int ret = 0;
+ struct tb_port *port = margining->port;
+ struct tb *tb = port->sw->tb;
+ int lane = -1;
char *buf;
buf = validate_and_copy_from_user(user_buf, &count);
@@ -666,57 +776,60 @@ margining_lanes_write(struct file *file, const char __user *user_buf,
buf[count - 1] = '\0';
- if (mutex_lock_interruptible(&tb->lock)) {
- ret = -ERESTARTSYS;
- goto out_free;
+ for (int i = 0; i < ARRAY_SIZE(lane_names); i++) {
+ if (!strcmp(buf, lane_names[i].name)) {
+ lane = lane_names[i].lane;
+ break;
+ }
}
- if (!strcmp(buf, "0")) {
- margining->lanes = 0;
- } else if (!strcmp(buf, "1")) {
- margining->lanes = 1;
- } else if (!strcmp(buf, "all")) {
- /* Needs to be supported */
- if (both_lanes(margining))
- margining->lanes = 7;
- else
- ret = -EINVAL;
- } else {
- ret = -EINVAL;
- }
+ free_page((unsigned long)buf);
- mutex_unlock(&tb->lock);
+ if (lane == -1)
+ return -EINVAL;
-out_free:
- free_page((unsigned long)buf);
- return ret < 0 ? ret : count;
+ scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
+ if (lane == USB4_MARGINING_LANE_ALL && !all_lanes(margining))
+ return -EINVAL;
+ /*
+ * Enabling on RX2 requires that it is supported by the
+ * USB4 port.
+ */
+ if (lane == USB4_MARGINING_LANE_RX2 && !margining->asym_rx)
+ return -EINVAL;
+
+ margining->lanes = lane;
+ }
+
+ return count;
}
static int margining_lanes_show(struct seq_file *s, void *not_used)
{
struct tb_margining *margining = s->private;
- struct tb *tb = margining->port->sw->tb;
- unsigned int lanes;
-
- if (mutex_lock_interruptible(&tb->lock))
- return -ERESTARTSYS;
+ struct tb_port *port = margining->port;
+ struct tb *tb = port->sw->tb;
- lanes = margining->lanes;
- if (both_lanes(margining)) {
- if (!lanes)
- seq_puts(s, "[0] 1 all\n");
- else if (lanes == 1)
- seq_puts(s, "0 [1] all\n");
- else
- seq_puts(s, "0 1 [all]\n");
- } else {
- if (!lanes)
- seq_puts(s, "[0] 1\n");
- else
- seq_puts(s, "0 [1]\n");
+ scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
+ for (int i = 0; i < ARRAY_SIZE(lane_names); i++) {
+ if (lane_names[i].lane == USB4_MARGINING_LANE_ALL &&
+ !all_lanes(margining))
+ continue;
+ if (lane_names[i].lane == USB4_MARGINING_LANE_RX2 &&
+ !margining->asym_rx)
+ continue;
+
+ if (i != 0)
+ seq_putc(s, ' ');
+
+ if (lane_names[i].lane == margining->lanes)
+ seq_printf(s, "[%s]", lane_names[i].name);
+ else
+ seq_printf(s, "%s", lane_names[i].name);
+ }
+ seq_puts(s, "\n");
}
- mutex_unlock(&tb->lock);
return 0;
}
DEBUGFS_ATTR_RW(margining_lanes);
@@ -1004,13 +1117,16 @@ static int margining_run_sw(struct tb_margining *margining,
if (ret)
break;
- if (margining->lanes == USB4_MARGIN_SW_LANE_0)
+ if (margining->lanes == USB4_MARGINING_LANE_RX0)
errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK,
margining->results[1]);
- else if (margining->lanes == USB4_MARGIN_SW_LANE_1)
+ else if (margining->lanes == USB4_MARGINING_LANE_RX1)
errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,
margining->results[1]);
- else if (margining->lanes == USB4_MARGIN_SW_ALL_LANES)
+ else if (margining->lanes == USB4_MARGINING_LANE_RX2)
+ errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK,
+ margining->results[1]);
+ else if (margining->lanes == USB4_MARGINING_LANE_ALL)
errors = margining->results[1];
/* Any errors stop the test */
@@ -1030,6 +1146,31 @@ out_stop:
return ret;
}
+static int validate_margining(struct tb_margining *margining)
+{
+ /*
+ * For running on RX2 the link must be asymmetric with 3
+ * receivers. Because this is can change dynamically, check it
+ * here before we start the margining and report back error if
+ * expectations are not met.
+ */
+ if (margining->lanes == USB4_MARGINING_LANE_RX2) {
+ int ret;
+
+ ret = tb_port_get_link_width(margining->port);
+ if (ret < 0)
+ return ret;
+ if (ret != TB_LINK_WIDTH_ASYM_RX) {
+ tb_port_warn(margining->port, "link is %s expected %s",
+ tb_width_name(ret),
+ tb_width_name(TB_LINK_WIDTH_ASYM_RX));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int margining_run_write(void *data, u64 val)
{
struct tb_margining *margining = data;
@@ -1050,6 +1191,10 @@ static int margining_run_write(void *data, u64 val)
goto out_rpm_put;
}
+ ret = validate_margining(margining);
+ if (ret)
+ goto out_unlock;
+
if (tb_is_upstream_port(port))
down_sw = sw;
else if (port->remote)
@@ -1080,6 +1225,7 @@ static int margining_run_write(void *data, u64 val)
.time = margining->time,
.voltage_time_offset = margining->voltage_time_offset,
.right_high = margining->right_high,
+ .upper_eye = margining->upper_eye,
.optional_voltage_offset_range = margining->optional_voltage_offset_range,
};
@@ -1095,6 +1241,7 @@ static int margining_run_write(void *data, u64 val)
.lanes = margining->lanes,
.time = margining->time,
.right_high = margining->right_high,
+ .upper_eye = margining->upper_eye,
.optional_voltage_offset_range = margining->optional_voltage_offset_range,
};
@@ -1104,7 +1251,7 @@ static int margining_run_write(void *data, u64 val)
margining->lanes);
ret = usb4_port_hw_margin(port, margining->target, margining->index, &params,
- margining->results);
+ margining->results, ARRAY_SIZE(margining->results));
}
if (down_sw)
@@ -1132,13 +1279,12 @@ static ssize_t margining_results_write(struct file *file,
return -ERESTARTSYS;
/* Just clear the results */
- margining->results[0] = 0;
- margining->results[1] = 0;
+ memset(margining->results, 0, sizeof(margining->results));
if (margining->software) {
/* Clear the error counters */
margining_modify_error_counter(margining,
- USB4_MARGIN_SW_ALL_LANES,
+ USB4_MARGINING_LANE_ALL,
USB4_MARGIN_SW_ERROR_COUNTER_CLEAR);
}
@@ -1151,10 +1297,10 @@ static void voltage_margin_show(struct seq_file *s,
{
unsigned int tmp, voltage;
- tmp = FIELD_GET(USB4_MARGIN_HW_RES_1_MARGIN_MASK, val);
+ tmp = FIELD_GET(USB4_MARGIN_HW_RES_MARGIN_MASK, val);
voltage = tmp * margining->max_voltage_offset / margining->voltage_steps;
seq_printf(s, "%u mV (%u)", voltage, tmp);
- if (val & USB4_MARGIN_HW_RES_1_EXCEEDS)
+ if (val & USB4_MARGIN_HW_RES_EXCEEDS)
seq_puts(s, " exceeds maximum");
seq_puts(s, "\n");
if (margining->optional_voltage_offset_range)
@@ -1166,14 +1312,55 @@ static void time_margin_show(struct seq_file *s,
{
unsigned int tmp, interval;
- tmp = FIELD_GET(USB4_MARGIN_HW_RES_1_MARGIN_MASK, val);
+ tmp = FIELD_GET(USB4_MARGIN_HW_RES_MARGIN_MASK, val);
interval = tmp * margining->max_time_offset / margining->time_steps;
seq_printf(s, "%u mUI (%u)", interval, tmp);
- if (val & USB4_MARGIN_HW_RES_1_EXCEEDS)
+ if (val & USB4_MARGIN_HW_RES_EXCEEDS)
seq_puts(s, " exceeds maximum");
seq_puts(s, "\n");
}
+static u8 margining_hw_result_val(const u32 *results,
+ enum usb4_margining_lane lane,
+ bool right_high)
+{
+ u32 val;
+
+ if (lane == USB4_MARGINING_LANE_RX0)
+ val = results[1];
+ else if (lane == USB4_MARGINING_LANE_RX1)
+ val = results[1] >> USB4_MARGIN_HW_RES_LANE_SHIFT;
+ else if (lane == USB4_MARGINING_LANE_RX2)
+ val = results[2];
+ else
+ val = 0;
+
+ return right_high ? val : val >> USB4_MARGIN_HW_RES_LL_SHIFT;
+}
+
+static void margining_hw_result_format(struct seq_file *s,
+ const struct tb_margining *margining,
+ enum usb4_margining_lane lane)
+{
+ u8 val;
+
+ if (margining->time) {
+ val = margining_hw_result_val(margining->results, lane, true);
+ seq_printf(s, "# lane %u right time margin: ", lane);
+ time_margin_show(s, margining, val);
+ val = margining_hw_result_val(margining->results, lane, false);
+ seq_printf(s, "# lane %u left time margin: ", lane);
+ time_margin_show(s, margining, val);
+ } else {
+ val = margining_hw_result_val(margining->results, lane, true);
+ seq_printf(s, "# lane %u high voltage margin: ", lane);
+ voltage_margin_show(s, margining, val);
+ val = margining_hw_result_val(margining->results, lane, false);
+ seq_printf(s, "# lane %u low voltage margin: ", lane);
+ voltage_margin_show(s, margining, val);
+ }
+}
+
static int margining_results_show(struct seq_file *s, void *not_used)
{
struct tb_margining *margining = s->private;
@@ -1186,69 +1373,46 @@ static int margining_results_show(struct seq_file *s, void *not_used)
seq_printf(s, "0x%08x\n", margining->results[0]);
/* Only the hardware margining has two result dwords */
if (!margining->software) {
- unsigned int val;
-
- seq_printf(s, "0x%08x\n", margining->results[1]);
-
- if (margining->time) {
- if (!margining->lanes || margining->lanes == 7) {
- val = margining->results[1];
- seq_puts(s, "# lane 0 right time margin: ");
- time_margin_show(s, margining, val);
- val = margining->results[1] >>
- USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT;
- seq_puts(s, "# lane 0 left time margin: ");
- time_margin_show(s, margining, val);
- }
- if (margining->lanes == 1 || margining->lanes == 7) {
- val = margining->results[1] >>
- USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT;
- seq_puts(s, "# lane 1 right time margin: ");
- time_margin_show(s, margining, val);
- val = margining->results[1] >>
- USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT;
- seq_puts(s, "# lane 1 left time margin: ");
- time_margin_show(s, margining, val);
- }
+ for (int i = 1; i < ARRAY_SIZE(margining->results); i++)
+ seq_printf(s, "0x%08x\n", margining->results[i]);
+
+ if (margining->lanes == USB4_MARGINING_LANE_ALL) {
+ margining_hw_result_format(s, margining,
+ USB4_MARGINING_LANE_RX0);
+ margining_hw_result_format(s, margining,
+ USB4_MARGINING_LANE_RX1);
+ if (margining->asym_rx)
+ margining_hw_result_format(s, margining,
+ USB4_MARGINING_LANE_RX2);
} else {
- if (!margining->lanes || margining->lanes == 7) {
- val = margining->results[1];
- seq_puts(s, "# lane 0 high voltage margin: ");
- voltage_margin_show(s, margining, val);
- val = margining->results[1] >>
- USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT;
- seq_puts(s, "# lane 0 low voltage margin: ");
- voltage_margin_show(s, margining, val);
- }
- if (margining->lanes == 1 || margining->lanes == 7) {
- val = margining->results[1] >>
- USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT;
- seq_puts(s, "# lane 1 high voltage margin: ");
- voltage_margin_show(s, margining, val);
- val = margining->results[1] >>
- USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT;
- seq_puts(s, "# lane 1 low voltage margin: ");
- voltage_margin_show(s, margining, val);
- }
+ margining_hw_result_format(s, margining,
+ margining->lanes);
}
} else {
u32 lane_errors, result;
seq_printf(s, "0x%08x\n", margining->results[1]);
- result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]);
- if (result == USB4_MARGIN_SW_LANE_0 ||
- result == USB4_MARGIN_SW_ALL_LANES) {
+ result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]);
+ if (result == USB4_MARGINING_LANE_RX0 ||
+ result == USB4_MARGINING_LANE_ALL) {
lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK,
margining->results[1]);
seq_printf(s, "# lane 0 errors: %u\n", lane_errors);
}
- if (result == USB4_MARGIN_SW_LANE_1 ||
- result == USB4_MARGIN_SW_ALL_LANES) {
+ if (result == USB4_MARGINING_LANE_RX1 ||
+ result == USB4_MARGINING_LANE_ALL) {
lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,
margining->results[1]);
seq_printf(s, "# lane 1 errors: %u\n", lane_errors);
}
+ if (margining->asym_rx &&
+ (result == USB4_MARGINING_LANE_RX2 ||
+ result == USB4_MARGINING_LANE_ALL)) {
+ lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK,
+ margining->results[1]);
+ seq_printf(s, "# lane 2 errors: %u\n", lane_errors);
+ }
}
mutex_unlock(&tb->lock);
@@ -1382,6 +1546,55 @@ static int margining_margin_show(struct seq_file *s, void *not_used)
}
DEBUGFS_ATTR_RW(margining_margin);
+static ssize_t margining_eye_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct tb_port *port = s->private;
+ struct usb4_port *usb4 = port->usb4;
+ struct tb *tb = port->sw->tb;
+ int ret = 0;
+ char *buf;
+
+ buf = validate_and_copy_from_user(user_buf, &count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ buf[count - 1] = '\0';
+
+ scoped_cond_guard(mutex_intr, ret = -ERESTARTSYS, &tb->lock) {
+ if (!strcmp(buf, "lower"))
+ usb4->margining->upper_eye = false;
+ else if (!strcmp(buf, "upper"))
+ usb4->margining->upper_eye = true;
+ else
+ ret = -EINVAL;
+ }
+
+ free_page((unsigned long)buf);
+ return ret ? ret : count;
+}
+
+static int margining_eye_show(struct seq_file *s, void *not_used)
+{
+ struct tb_port *port = s->private;
+ struct usb4_port *usb4 = port->usb4;
+ struct tb *tb = port->sw->tb;
+
+ scoped_guard(mutex_intr, &tb->lock) {
+ if (usb4->margining->upper_eye)
+ seq_puts(s, "lower [upper]\n");
+ else
+ seq_puts(s, "[lower] upper\n");
+
+ return 0;
+ }
+
+ return -ERESTARTSYS;
+}
+DEBUGFS_ATTR_RW(margining_eye);
+
static struct tb_margining *margining_alloc(struct tb_port *port,
struct device *dev,
enum usb4_sb_target target,
@@ -1392,6 +1605,12 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
unsigned int val;
int ret;
+ ret = tb_port_get_link_generation(port);
+ if (ret < 0) {
+ tb_port_warn(port, "failed to read link generation\n");
+ return NULL;
+ }
+
margining = kzalloc(sizeof(*margining), GFP_KERNEL);
if (!margining)
return NULL;
@@ -1400,8 +1619,11 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
margining->target = target;
margining->index = index;
margining->dev = dev;
+ margining->gen = ret;
+ margining->asym_rx = tb_port_width_supported(port, TB_LINK_WIDTH_ASYM_RX);
- ret = usb4_port_margining_caps(port, target, index, margining->caps);
+ ret = usb4_port_margining_caps(port, target, index, margining->caps,
+ ARRAY_SIZE(margining->caps));
if (ret) {
kfree(margining);
return NULL;
@@ -1411,10 +1633,17 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
if (supports_software(margining))
margining->software = true;
- val = FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK, margining->caps[0]);
- margining->voltage_steps = val;
- val = FIELD_GET(USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK, margining->caps[0]);
- margining->max_voltage_offset = 74 + val * 2;
+ if (margining->gen < 4) {
+ val = FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK, margining->caps[0]);
+ margining->voltage_steps = val;
+ val = FIELD_GET(USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK, margining->caps[0]);
+ margining->max_voltage_offset = 74 + val * 2;
+ } else {
+ val = FIELD_GET(USB4_MARGIN_CAP_2_VOLTAGE_STEPS_MASK, margining->caps[2]);
+ margining->voltage_steps = val;
+ val = FIELD_GET(USB4_MARGIN_CAP_2_MAX_VOLTAGE_OFFSET_MASK, margining->caps[2]);
+ margining->max_voltage_offset = 74 + val * 2;
+ }
if (supports_optional_voltage_offset_range(margining)) {
val = FIELD_GET(USB4_MARGIN_CAP_0_VOLT_STEPS_OPT_MASK,
@@ -1456,11 +1685,10 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
debugfs_create_file("results", 0600, dir, margining,
&margining_results_fops);
debugfs_create_file("test", 0600, dir, margining, &margining_test_fops);
- if (independent_voltage_margins(margining) == USB4_MARGIN_CAP_0_VOLTAGE_HL ||
+ if (independent_voltage_margins(margining) == USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL ||
(supports_time(margining) &&
- independent_time_margins(margining) == USB4_MARGIN_CAP_1_TIME_LR))
- debugfs_create_file("margin", 0600, dir, margining,
- &margining_margin_fops);
+ independent_time_margins(margining) == USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR))
+ debugfs_create_file("margin", 0600, dir, margining, &margining_margin_fops);
margining->error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR;
margining->dwell_time = MIN_DWELL_TIME;
@@ -1477,6 +1705,10 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
debugfs_create_file("dwell_time", DEBUGFS_MODE, dir, margining,
&margining_dwell_time_fops);
}
+
+ if (margining->gen >= 4)
+ debugfs_create_file("eye", 0600, dir, port, &margining_eye_fops);
+
return margining;
}
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index 7af2642b97cb..1257dd3ce7e6 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -1340,18 +1340,18 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (res)
return dev_err_probe(dev, res, "cannot enable PCI device, aborting\n");
- res = pcim_iomap_regions(pdev, 1 << 0, "thunderbolt");
- if (res)
- return dev_err_probe(dev, res, "cannot obtain PCI resources, aborting\n");
-
nhi = devm_kzalloc(&pdev->dev, sizeof(*nhi), GFP_KERNEL);
if (!nhi)
return -ENOMEM;
nhi->pdev = pdev;
nhi->ops = (const struct tb_nhi_ops *)id->driver_data;
- /* cannot fail - table is allocated in pcim_iomap_regions */
- nhi->iobase = pcim_iomap_table(pdev)[0];
+
+ nhi->iobase = pcim_iomap_region(pdev, 0, "thunderbolt");
+ res = PTR_ERR_OR_ZERO(nhi->iobase);
+ if (res)
+ return dev_err_probe(dev, res, "cannot obtain PCI resources, aborting\n");
+
nhi->hop_count = ioread32(nhi->iobase + REG_CAPS) & 0x3ff;
dev_dbg(dev, "total paths: %d\n", nhi->hop_count);
diff --git a/drivers/thunderbolt/sb_regs.h b/drivers/thunderbolt/sb_regs.h
index dbcad25ead50..5391502a4b87 100644
--- a/drivers/thunderbolt/sb_regs.h
+++ b/drivers/thunderbolt/sb_regs.h
@@ -49,7 +49,7 @@ enum usb4_sb_opcode {
/* USB4_SB_OPCODE_READ_LANE_MARGINING_CAP */
#define USB4_MARGIN_CAP_0_MODES_HW BIT(0)
#define USB4_MARGIN_CAP_0_MODES_SW BIT(1)
-#define USB4_MARGIN_CAP_0_2_LANES BIT(2)
+#define USB4_MARGIN_CAP_0_ALL_LANES BIT(2)
#define USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK GENMASK(4, 3)
#define USB4_MARGIN_CAP_0_VOLTAGE_MIN 0x0
#define USB4_MARGIN_CAP_0_VOLTAGE_HL 0x1
@@ -69,34 +69,44 @@ enum usb4_sb_opcode {
#define USB4_MARGIN_CAP_1_TIME_OFFSET_MASK GENMASK(20, 16)
#define USB4_MARGIN_CAP_1_MIN_BER_MASK GENMASK(25, 21)
#define USB4_MARGIN_CAP_1_MAX_BER_MASK GENMASK(30, 26)
+#define USB4_MARGIN_CAP_2_MODES_HW BIT(0)
+#define USB4_MARGIN_CAP_2_MODES_SW BIT(1)
+#define USB4_MARGIN_CAP_2_TIME BIT(2)
+#define USB4_MARGIN_CAP_2_MAX_VOLTAGE_OFFSET_MASK GENMASK(8, 3)
+#define USB4_MARGIN_CAP_2_VOLTAGE_STEPS_MASK GENMASK(15, 9)
+#define USB4_MARGIN_CAP_2_VOLTAGE_INDP_MASK GENMASK(17, 16)
+#define USB4_MARGIN_CAP_2_VOLTAGE_MIN 0x0
+#define USB4_MARGIN_CAP_2_VOLTAGE_BOTH 0x1
+#define USB4_MARGIN_CAP_2_TIME_INDP_MASK GENMASK(19, 18)
+#define USB4_MARGIN_CAP_2_TIME_MIN 0x0
+#define USB4_MARGIN_CAP_2_TIME_BOTH 0x1
/* USB4_SB_OPCODE_RUN_HW_LANE_MARGINING */
#define USB4_MARGIN_HW_TIME BIT(3)
-#define USB4_MARGIN_HW_RH BIT(4)
+#define USB4_MARGIN_HW_RHU BIT(4)
#define USB4_MARGIN_HW_BER_MASK GENMASK(9, 5)
#define USB4_MARGIN_HW_BER_SHIFT 5
#define USB4_MARGIN_HW_OPT_VOLTAGE BIT(10)
/* Applicable to all margin values */
-#define USB4_MARGIN_HW_RES_1_MARGIN_MASK GENMASK(6, 0)
-#define USB4_MARGIN_HW_RES_1_EXCEEDS BIT(7)
-/* Different lane margin shifts */
-#define USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT 8
-#define USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT 16
-#define USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT 24
+#define USB4_MARGIN_HW_RES_MARGIN_MASK GENMASK(6, 0)
+#define USB4_MARGIN_HW_RES_EXCEEDS BIT(7)
+
+/* Shifts for parsing the lane results */
+#define USB4_MARGIN_HW_RES_LANE_SHIFT 16
+#define USB4_MARGIN_HW_RES_LL_SHIFT 8
/* USB4_SB_OPCODE_RUN_SW_LANE_MARGINING */
#define USB4_MARGIN_SW_LANES_MASK GENMASK(2, 0)
-#define USB4_MARGIN_SW_LANE_0 0x0
-#define USB4_MARGIN_SW_LANE_1 0x1
-#define USB4_MARGIN_SW_ALL_LANES 0x7
#define USB4_MARGIN_SW_TIME BIT(3)
#define USB4_MARGIN_SW_RH BIT(4)
#define USB4_MARGIN_SW_OPT_VOLTAGE BIT(5)
#define USB4_MARGIN_SW_VT_MASK GENMASK(12, 6)
#define USB4_MARGIN_SW_COUNTER_MASK GENMASK(14, 13)
+#define USB4_MARGIN_SW_UPPER_EYE BIT(15)
#define USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK GENMASK(3, 0)
#define USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK GENMASK(7, 4)
+#define USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK GENMASK(11, 8)
#endif
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 6737188f2581..ddbf0cd78377 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -1367,11 +1367,18 @@ enum usb4_margin_sw_error_counter {
USB4_MARGIN_SW_ERROR_COUNTER_STOP,
};
+enum usb4_margining_lane {
+ USB4_MARGINING_LANE_RX0 = 0,
+ USB4_MARGINING_LANE_RX1 = 1,
+ USB4_MARGINING_LANE_RX2 = 2,
+ USB4_MARGINING_LANE_ALL = 7,
+};
+
/**
* struct usb4_port_margining_params - USB4 margining parameters
* @error_counter: Error counter operation for software margining
* @ber_level: Current BER level contour value
- * @lanes: %0, %1 or %7 (all)
+ * @lanes: Lanes to enable for the margining operation
* @voltage_time_offset: Offset for voltage / time for software margining
* @optional_voltage_offset_range: Enable optional extended voltage range
* @right_high: %false if left/low margin test is performed, %true if right/high
@@ -1380,18 +1387,19 @@ enum usb4_margin_sw_error_counter {
struct usb4_port_margining_params {
enum usb4_margin_sw_error_counter error_counter;
u32 ber_level;
- u32 lanes;
+ enum usb4_margining_lane lanes;
u32 voltage_time_offset;
bool optional_voltage_offset_range;
bool right_high;
+ bool upper_eye;
bool time;
};
int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
- u8 index, u32 *caps);
+ u8 index, u32 *caps, size_t ncaps);
int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
u8 index, const struct usb4_port_margining_params *params,
- u32 *results);
+ u32 *results, size_t nresults);
int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
u8 index, const struct usb4_port_margining_params *params,
u32 *results);
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 402fdf8b1cde..e51d01671d8e 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -1631,11 +1631,12 @@ int usb4_port_asym_start(struct tb_port *port)
* @target: Sideband target
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
* @caps: Array with at least two elements to hold the results
+ * @ncaps: Number of elements in the caps array
*
* Reads the USB4 port lane margining capabilities into @caps.
*/
int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
- u8 index, u32 *caps)
+ u8 index, u32 *caps, size_t ncaps)
{
int ret;
@@ -1645,7 +1646,7 @@ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
return ret;
return usb4_port_sb_read(port, target, index, USB4_SB_DATA, caps,
- sizeof(*caps) * 2);
+ sizeof(*caps) * ncaps);
}
/**
@@ -1654,14 +1655,15 @@ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
* @target: Sideband target
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
* @params: Parameters for USB4 hardware margining
- * @results: Array with at least two elements to hold the results
+ * @results: Array to hold the results
+ * @nresults: Number of elements in the results array
*
* Runs hardware lane margining on USB4 port and returns the result in
* @results.
*/
int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
u8 index, const struct usb4_port_margining_params *params,
- u32 *results)
+ u32 *results, size_t nresults)
{
u32 val;
int ret;
@@ -1672,8 +1674,8 @@ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
val = params->lanes;
if (params->time)
val |= USB4_MARGIN_HW_TIME;
- if (params->right_high)
- val |= USB4_MARGIN_HW_RH;
+ if (params->right_high || params->upper_eye)
+ val |= USB4_MARGIN_HW_RHU;
if (params->ber_level)
val |= FIELD_PREP(USB4_MARGIN_HW_BER_MASK, params->ber_level);
if (params->optional_voltage_offset_range)
@@ -1690,7 +1692,7 @@ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
return ret;
return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results,
- sizeof(*results) * 2);
+ sizeof(*results) * nresults);
}
/**
@@ -1722,6 +1724,8 @@ int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
val |= USB4_MARGIN_SW_OPT_VOLTAGE;
if (params->right_high)
val |= USB4_MARGIN_SW_RH;
+ if (params->upper_eye)
+ val |= USB4_MARGIN_SW_UPPER_EYE;
val |= FIELD_PREP(USB4_MARGIN_SW_COUNTER_MASK, params->error_counter);
val |= FIELD_PREP(USB4_MARGIN_SW_VT_MASK, params->voltage_time_offset);
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index e8e43c38aa1b..cd0f7b4bd82a 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -808,7 +808,7 @@ static int check_dsp_e4(const u8 *dsp, int len)
if (l > len)
return 1;
- /* zero is zero regardless endianes */
+ /* zero is zero regardless endianness */
} while (blockidx->NotLastBlock);
}
@@ -1276,7 +1276,7 @@ static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
sc->stats.phy.dsrate == dsrate)
return;
- /* Original timming (1Mbit/s) from ADI (used in windows driver) */
+ /* Original timing (1Mbit/s) from ADI (used in windows driver) */
timeout = (dsrate <= 1024*1024) ? 0 : 1;
ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
@@ -1972,7 +1972,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
if (cmv->bDirection != E1_MODEMTOHOST)
goto bad1;
- /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
+ /* FIXME : ADI930 reply wrong preamble (func = 2, sub = 2) to
* the first MEMACCESS cmv. Ignore it...
*/
if (cmv->bFunction != dsc->function) {
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 2da6615fbb6f..d1e622bb1406 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -1158,7 +1158,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
if (i >= num_rcv_urbs)
list_add_tail(&urb->urb_list, &channel->list);
- vdbg(&intf->dev, "%s: alloced buffer 0x%p buf size %u urb 0x%p",
+ vdbg(&intf->dev, "%s: allocated buffer 0x%p buf size %u urb 0x%p",
__func__, urb->transfer_buffer, urb->transfer_buffer_length, urb);
}
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
index bb9d5d7ffefc..8f38e2c5369a 100644
--- a/drivers/usb/c67x00/c67x00-drv.c
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -201,7 +201,7 @@ static void c67x00_drv_remove(struct platform_device *pdev)
static struct platform_driver c67x00_driver = {
.probe = c67x00_drv_probe,
- .remove_new = c67x00_drv_remove,
+ .remove = c67x00_drv_remove,
.driver = {
.name = "c67x00",
},
diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c
index 281de47e2a3b..a2f041e1707c 100644
--- a/drivers/usb/cdns3/cdns3-imx.c
+++ b/drivers/usb/cdns3/cdns3-imx.c
@@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, cdns_imx_of_match);
static struct platform_driver cdns_imx_driver = {
.probe = cdns_imx_probe,
- .remove_new = cdns_imx_remove,
+ .remove = cdns_imx_remove,
.driver = {
.name = "cdns3-imx",
.of_match_table = cdns_imx_of_match,
diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c
index 591d149de8f3..3b3b3dc75f35 100644
--- a/drivers/usb/cdns3/cdns3-pci-wrap.c
+++ b/drivers/usb/cdns3/cdns3-pci-wrap.c
@@ -37,8 +37,6 @@ struct cdns3_wrap {
#define PCI_DRIVER_NAME "cdns3-pci-usbss"
#define PLAT_DRIVER_NAME "cdns-usb3"
-#define PCI_DEVICE_ID_CDNS_USB3 0x0100
-
static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev)
{
struct pci_dev *func;
@@ -189,7 +187,7 @@ static void cdns3_pci_remove(struct pci_dev *pdev)
}
static const struct pci_device_id cdns3_pci_ids[] = {
- { PCI_VDEVICE(CDNS, PCI_DEVICE_ID_CDNS_USB3) },
+ { PCI_VDEVICE(CDNS, PCI_DEVICE_ID_CDNS_USBSS) },
{ 0, }
};
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index 3ef8e3c872a3..59ec505e198a 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -327,7 +327,7 @@ MODULE_DEVICE_TABLE(of, of_cdns3_match);
static struct platform_driver cdns3_driver = {
.probe = cdns3_plat_probe,
- .remove_new = cdns3_plat_remove,
+ .remove = cdns3_plat_remove,
.driver = {
.name = "cdns-usb3",
.of_match_table = of_match_ptr(of_cdns3_match),
diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c
index c04d196abd87..2ff7f2b48cc2 100644
--- a/drivers/usb/cdns3/cdns3-starfive.c
+++ b/drivers/usb/cdns3/cdns3-starfive.c
@@ -230,7 +230,7 @@ MODULE_DEVICE_TABLE(of, cdns_starfive_of_match);
static struct platform_driver cdns_starfive_driver = {
.probe = cdns_starfive_probe,
- .remove_new = cdns_starfive_remove,
+ .remove = cdns_starfive_remove,
.driver = {
.name = "cdns3-starfive",
.of_match_table = cdns_starfive_of_match,
diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c
index cfabc12ee0e3..040bb91e9c01 100644
--- a/drivers/usb/cdns3/cdns3-ti.c
+++ b/drivers/usb/cdns3/cdns3-ti.c
@@ -233,7 +233,7 @@ MODULE_DEVICE_TABLE(of, cdns_ti_of_match);
static struct platform_driver cdns_ti_driver = {
.probe = cdns_ti_probe,
- .remove_new = cdns_ti_remove,
+ .remove = cdns_ti_remove,
.driver = {
.name = "cdns3-ti",
.of_match_table = cdns_ti_of_match,
diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c
index 2d05368a6745..a51144504ff3 100644
--- a/drivers/usb/cdns3/cdnsp-pci.c
+++ b/drivers/usb/cdns3/cdnsp-pci.c
@@ -28,12 +28,6 @@
#define PCI_DRIVER_NAME "cdns-pci-usbssp"
#define PLAT_DRIVER_NAME "cdns-usbssp"
-#define PCI_DEVICE_ID_CDNS_USB3 0x0100
-#define PCI_DEVICE_ID_CDNS_UDC 0x0200
-
-#define PCI_CLASS_SERIAL_USB_CDNS_USB3 (PCI_CLASS_SERIAL_USB << 8 | 0x80)
-#define PCI_CLASS_SERIAL_USB_CDNS_UDC PCI_CLASS_SERIAL_USB_DEVICE
-
static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
{
/*
@@ -41,10 +35,10 @@ static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
* Platform has two function. The fist keeps resources for
* Host/Device while the secon keeps resources for DRD/OTG.
*/
- if (pdev->device == PCI_DEVICE_ID_CDNS_UDC)
- return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USB3, NULL);
- if (pdev->device == PCI_DEVICE_ID_CDNS_USB3)
- return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_UDC, NULL);
+ if (pdev->device == PCI_DEVICE_ID_CDNS_USBSSP)
+ return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USBSS, NULL);
+ if (pdev->device == PCI_DEVICE_ID_CDNS_USBSS)
+ return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USBSSP, NULL);
return NULL;
}
@@ -221,12 +215,12 @@ static const struct dev_pm_ops cdnsp_pci_pm_ops = {
};
static const struct pci_device_id cdnsp_pci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC),
- .class = PCI_CLASS_SERIAL_USB_CDNS_UDC },
- { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC),
- .class = PCI_CLASS_SERIAL_USB_CDNS_USB3 },
- { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB3),
- .class = PCI_CLASS_SERIAL_USB_CDNS_USB3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSSP),
+ .class = PCI_CLASS_SERIAL_USB_DEVICE },
+ { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSSP),
+ .class = PCI_CLASS_SERIAL_USB_CDNS },
+ { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSS),
+ .class = PCI_CLASS_SERIAL_USB_CDNS },
{ 0, }
};
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 2a38e1eb6546..97437de52ef6 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -25,6 +25,7 @@
#define TD_PAGE_COUNT 5
#define CI_HDRC_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32
+#define CI_MAX_REQ_SIZE (4 * CI_HDRC_PAGE_SIZE)
#define CI_MAX_BUF_SIZE (TD_PAGE_COUNT * CI_HDRC_PAGE_SIZE)
/******************************************************************************
@@ -260,6 +261,7 @@ struct ci_hdrc {
bool b_sess_valid_event;
bool imx28_write_fix;
bool has_portsc_pec_bug;
+ bool has_short_pkt_limit;
bool supports_runtime_pm;
bool in_lpm;
bool wakeup_int;
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index c64ab0e07ea0..f2801700be8e 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -342,6 +342,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
+ .flags = CI_HDRC_HAS_SHORT_PKT_LIMIT,
.notify_event = ci_hdrc_imx_notify_event,
};
int ret;
@@ -675,7 +676,7 @@ static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
};
static struct platform_driver ci_hdrc_imx_driver = {
.probe = ci_hdrc_imx_probe,
- .remove_new = ci_hdrc_imx_remove,
+ .remove = ci_hdrc_imx_remove,
.shutdown = ci_hdrc_imx_shutdown,
.driver = {
.name = "imx_usb",
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index 1661639cd2eb..3ab3daa78e34 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -292,7 +292,7 @@ MODULE_DEVICE_TABLE(of, msm_ci_dt_match);
static struct platform_driver ci_hdrc_msm_driver = {
.probe = ci_hdrc_msm_probe,
- .remove_new = ci_hdrc_msm_remove,
+ .remove = ci_hdrc_msm_remove,
.driver = {
.name = "msm_hsusb",
.of_match_table = msm_ci_dt_match,
diff --git a/drivers/usb/chipidea/ci_hdrc_npcm.c b/drivers/usb/chipidea/ci_hdrc_npcm.c
index 3e5e05dbda89..e52a2b05cbe2 100644
--- a/drivers/usb/chipidea/ci_hdrc_npcm.c
+++ b/drivers/usb/chipidea/ci_hdrc_npcm.c
@@ -98,7 +98,7 @@ MODULE_DEVICE_TABLE(of, npcm_udc_dt_match);
static struct platform_driver npcm_udc_driver = {
.probe = npcm_udc_probe,
- .remove_new = npcm_udc_remove,
+ .remove = npcm_udc_remove,
.driver = {
.name = "npcm_udc",
.of_match_table = npcm_udc_dt_match,
diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c
index 9538d425f0a0..372788f0f970 100644
--- a/drivers/usb/chipidea/ci_hdrc_tegra.c
+++ b/drivers/usb/chipidea/ci_hdrc_tegra.c
@@ -406,7 +406,7 @@ static struct platform_driver tegra_usb_driver = {
.pm = pm_ptr(&tegra_usb_pm),
},
.probe = tegra_usb_probe,
- .remove_new = tegra_usb_remove,
+ .remove = tegra_usb_remove,
};
module_platform_driver(tegra_usb_driver);
diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c
index 97379f653b06..8ffa1e95d8e8 100644
--- a/drivers/usb/chipidea/ci_hdrc_usb2.c
+++ b/drivers/usb/chipidea/ci_hdrc_usb2.c
@@ -116,7 +116,7 @@ static void ci_hdrc_usb2_remove(struct platform_device *pdev)
static struct platform_driver ci_hdrc_usb2_driver = {
.probe = ci_hdrc_usb2_probe,
- .remove_new = ci_hdrc_usb2_remove,
+ .remove = ci_hdrc_usb2_remove,
.driver = {
.name = "chipidea-usb2",
.of_match_table = ci_hdrc_usb2_of_match,
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 835bf2428dc6..694b4a8e4e1d 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -765,7 +765,7 @@ static int ci_get_platdata(struct device *dev,
ext_id = ERR_PTR(-ENODEV);
ext_vbus = ERR_PTR(-ENODEV);
- if (of_property_read_bool(dev->of_node, "extcon")) {
+ if (of_property_present(dev->of_node, "extcon")) {
/* Each one of them is not mandatory */
ext_vbus = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
@@ -1076,6 +1076,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
CI_HDRC_SUPPORTS_RUNTIME_PM);
ci->has_portsc_pec_bug = !!(ci->platdata->flags &
CI_HDRC_HAS_PORTSC_PEC_MISSED);
+ ci->has_short_pkt_limit = !!(ci->platdata->flags &
+ CI_HDRC_HAS_SHORT_PKT_LIMIT);
platform_set_drvdata(pdev, ci);
ret = hw_device_init(ci, base);
@@ -1495,7 +1497,7 @@ static const struct dev_pm_ops ci_pm_ops = {
static struct platform_driver ci_hdrc_driver = {
.probe = ci_hdrc_probe,
- .remove_new = ci_hdrc_remove,
+ .remove = ci_hdrc_remove,
.driver = {
.name = "ci_hdrc",
.pm = &ci_pm_ops,
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 69ef3cd8d4f8..8a9b31fd5c89 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
+#include <linux/dma-direct.h>
#include <linux/err.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
@@ -540,6 +541,126 @@ static int prepare_td_for_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
return ret;
}
+/*
+ * Verify if the scatterlist is valid by iterating each sg entry.
+ * Return invalid sg entry index which is less than num_sgs.
+ */
+static int sglist_get_invalid_entry(struct device *dma_dev, u8 dir,
+ struct usb_request *req)
+{
+ int i;
+ struct scatterlist *s = req->sg;
+
+ if (req->num_sgs == 1)
+ return 1;
+
+ dir = dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ for (i = 0; i < req->num_sgs; i++, s = sg_next(s)) {
+ /* Only small sg (generally last sg) may be bounced. If
+ * that happens. we can't ensure the addr is page-aligned
+ * after dma map.
+ */
+ if (dma_kmalloc_needs_bounce(dma_dev, s->length, dir))
+ break;
+
+ /* Make sure each sg start address (except first sg) is
+ * page-aligned and end address (except last sg) is also
+ * page-aligned.
+ */
+ if (i == 0) {
+ if (!IS_ALIGNED(s->offset + s->length,
+ CI_HDRC_PAGE_SIZE))
+ break;
+ } else {
+ if (s->offset)
+ break;
+ if (!sg_is_last(s) && !IS_ALIGNED(s->length,
+ CI_HDRC_PAGE_SIZE))
+ break;
+ }
+ }
+
+ return i;
+}
+
+static int sglist_do_bounce(struct ci_hw_req *hwreq, int index,
+ bool copy, unsigned int *bounced)
+{
+ void *buf;
+ int i, ret, nents, num_sgs;
+ unsigned int rest, rounded;
+ struct scatterlist *sg, *src, *dst;
+
+ nents = index + 1;
+ ret = sg_alloc_table(&hwreq->sgt, nents, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ sg = src = hwreq->req.sg;
+ num_sgs = hwreq->req.num_sgs;
+ rest = hwreq->req.length;
+ dst = hwreq->sgt.sgl;
+
+ for (i = 0; i < index; i++) {
+ memcpy(dst, src, sizeof(*src));
+ rest -= src->length;
+ src = sg_next(src);
+ dst = sg_next(dst);
+ }
+
+ /* create one bounce buffer */
+ rounded = round_up(rest, CI_HDRC_PAGE_SIZE);
+ buf = kmalloc(rounded, GFP_KERNEL);
+ if (!buf) {
+ sg_free_table(&hwreq->sgt);
+ return -ENOMEM;
+ }
+
+ sg_set_buf(dst, buf, rounded);
+
+ hwreq->req.sg = hwreq->sgt.sgl;
+ hwreq->req.num_sgs = nents;
+ hwreq->sgt.sgl = sg;
+ hwreq->sgt.nents = num_sgs;
+
+ if (copy)
+ sg_copy_to_buffer(src, num_sgs - index, buf, rest);
+
+ *bounced = rest;
+
+ return 0;
+}
+
+static void sglist_do_debounce(struct ci_hw_req *hwreq, bool copy)
+{
+ void *buf;
+ int i, nents, num_sgs;
+ struct scatterlist *sg, *src, *dst;
+
+ sg = hwreq->req.sg;
+ num_sgs = hwreq->req.num_sgs;
+ src = sg_last(sg, num_sgs);
+ buf = sg_virt(src);
+
+ if (copy) {
+ dst = hwreq->sgt.sgl;
+ for (i = 0; i < num_sgs - 1; i++)
+ dst = sg_next(dst);
+
+ nents = hwreq->sgt.nents - num_sgs + 1;
+ sg_copy_from_buffer(dst, nents, buf, sg_dma_len(src));
+ }
+
+ hwreq->req.sg = hwreq->sgt.sgl;
+ hwreq->req.num_sgs = hwreq->sgt.nents;
+ hwreq->sgt.sgl = sg;
+ hwreq->sgt.nents = num_sgs;
+
+ kfree(buf);
+ sg_free_table(&hwreq->sgt);
+}
+
/**
* _hardware_enqueue: configures a request at hardware level
* @hwep: endpoint
@@ -552,6 +673,8 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
struct ci_hdrc *ci = hwep->ci;
int ret = 0;
struct td_node *firstnode, *lastnode;
+ unsigned int bounced_size;
+ struct scatterlist *sg;
/* don't queue twice */
if (hwreq->req.status == -EALREADY)
@@ -559,11 +682,29 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
hwreq->req.status = -EALREADY;
+ if (hwreq->req.num_sgs && hwreq->req.length &&
+ ci->has_short_pkt_limit) {
+ ret = sglist_get_invalid_entry(ci->dev->parent, hwep->dir,
+ &hwreq->req);
+ if (ret < hwreq->req.num_sgs) {
+ ret = sglist_do_bounce(hwreq, ret, hwep->dir == TX,
+ &bounced_size);
+ if (ret)
+ return ret;
+ }
+ }
+
ret = usb_gadget_map_request_by_dev(ci->dev->parent,
&hwreq->req, hwep->dir);
if (ret)
return ret;
+ if (hwreq->sgt.sgl) {
+ /* We've mapped a bigger buffer, now recover the actual size */
+ sg = sg_last(hwreq->req.sg, hwreq->req.num_sgs);
+ sg_dma_len(sg) = min(sg_dma_len(sg), bounced_size);
+ }
+
if (hwreq->req.num_mapped_sgs)
ret = prepare_td_for_sg(hwep, hwreq);
else
@@ -612,10 +753,17 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
do {
hw_write(ci, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
tmp_stat = hw_read(ci, OP_ENDPTSTAT, BIT(n));
- } while (!hw_read(ci, OP_USBCMD, USBCMD_ATDTW));
+ } while (!hw_read(ci, OP_USBCMD, USBCMD_ATDTW) && tmp_stat);
hw_write(ci, OP_USBCMD, USBCMD_ATDTW, 0);
if (tmp_stat)
goto done;
+
+ /* OP_ENDPTSTAT will be clear by HW when the endpoint met
+ * err. This dTD don't push to dQH if current dTD point is
+ * not the last one in previous request.
+ */
+ if (hwep->qh.ptr->curr != cpu_to_le32(prevlastnode->dma))
+ goto done;
}
/* QH configuration */
@@ -676,6 +824,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
unsigned remaining_length;
unsigned actual = hwreq->req.length;
struct ci_hdrc *ci = hwep->ci;
+ bool is_isoc = hwep->type == USB_ENDPOINT_XFER_ISOC;
if (hwreq->req.status != -EALREADY)
return -EINVAL;
@@ -689,7 +838,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
int n = hw_ep_bit(hwep->num, hwep->dir);
if (ci->rev == CI_REVISION_24 ||
- ci->rev == CI_REVISION_22)
+ ci->rev == CI_REVISION_22 || is_isoc)
if (!hw_read(ci, OP_ENDPTSTAT, BIT(n)))
reprime_dtd(ci, hwep, node);
hwreq->req.status = -EALREADY;
@@ -708,11 +857,15 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
hwreq->req.status = -EPROTO;
break;
} else if ((TD_STATUS_TR_ERR & hwreq->req.status)) {
- hwreq->req.status = -EILSEQ;
- break;
+ if (is_isoc) {
+ hwreq->req.status = 0;
+ } else {
+ hwreq->req.status = -EILSEQ;
+ break;
+ }
}
- if (remaining_length) {
+ if (remaining_length && !is_isoc) {
if (hwep->dir == TX) {
hwreq->req.status = -EPROTO;
break;
@@ -733,6 +886,10 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
usb_gadget_unmap_request_by_dev(hwep->ci->dev->parent,
&hwreq->req, hwep->dir);
+ /* sglist bounced */
+ if (hwreq->sgt.sgl)
+ sglist_do_debounce(hwreq, hwep->dir == RX);
+
hwreq->req.actual += actual;
if (hwreq->req.status)
@@ -960,6 +1117,12 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
return -EMSGSIZE;
}
+ if (ci->has_short_pkt_limit &&
+ hwreq->req.length > CI_MAX_REQ_SIZE) {
+ dev_err(hwep->ci->dev, "request length too big (max 16KB)\n");
+ return -EMSGSIZE;
+ }
+
/* first nuke then test link, e.g. previous status has not sent */
if (!list_empty(&hwreq->queue)) {
dev_err(hwep->ci->dev, "request already in queue\n");
@@ -1574,6 +1737,9 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
usb_gadget_unmap_request(&hwep->ci->gadget, req, hwep->dir);
+ if (hwreq->sgt.sgl)
+ sglist_do_debounce(hwreq, false);
+
req->status = -ECONNRESET;
if (hwreq->req.complete != NULL) {
@@ -2063,7 +2229,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
}
}
- if (USBi_UI & intr)
+ if ((USBi_UI | USBi_UEI) & intr)
isr_tr_complete_handler(ci);
if ((USBi_SLI & intr) && !(ci->suspended)) {
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index 5193df1e18c7..c8a47389a46b 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -69,11 +69,13 @@ struct td_node {
* @req: request structure for gadget drivers
* @queue: link to QH list
* @tds: link to TD list
+ * @sgt: hold original sglist when bounce sglist
*/
struct ci_hw_req {
struct usb_request req;
struct list_head queue;
struct list_head tds;
+ struct sg_table sgt;
};
#ifdef CONFIG_USB_CHIPIDEA_UDC
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 173c78afd502..1394881fde5f 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -1285,6 +1285,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
.compatible = "fsl,imx7ulp-usbmisc",
.data = &imx7ulp_usbmisc_ops,
},
+ {
+ .compatible = "fsl,imx8ulp-usbmisc",
+ .data = &imx7ulp_usbmisc_ops,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index b7bea1015d7c..871cf199b6bf 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -415,6 +415,9 @@ EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
struct dentry *usb_debug_root;
EXPORT_SYMBOL_GPL(usb_debug_root);
+DEFINE_MUTEX(usb_dynids_lock);
+EXPORT_SYMBOL_GPL(usb_dynids_lock);
+
static int __init usb_common_init(void)
{
usb_debug_root = debugfs_create_dir("usb", NULL);
diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c
index 501e8bc9738e..c84b4a700084 100644
--- a/drivers/usb/common/usb-conn-gpio.c
+++ b/drivers/usb/common/usb-conn-gpio.c
@@ -340,7 +340,7 @@ MODULE_DEVICE_TABLE(of, usb_conn_dt_match);
static struct platform_driver usb_conn_driver = {
.probe = usb_conn_probe,
- .remove_new = usb_conn_remove,
+ .remove = usb_conn_remove,
.driver = {
.name = "usb-conn-gpio",
.pm = &usb_conn_pm_ops,
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 880d52c0949d..25a00f974934 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -924,7 +924,7 @@ int usb_get_configuration(struct usb_device *dev)
result = -EINVAL;
goto err;
}
- length = max((int) le16_to_cpu(desc->wTotalLength),
+ length = max_t(int, le16_to_cpu(desc->wTotalLength),
USB_DT_CONFIG_SIZE);
/* Now that we know the length, get the whole thing */
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 3beb6a862e80..f6ce6e26e0d4 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -238,6 +238,9 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
dma_addr_t dma_handle = DMA_MAPPING_ERROR;
int ret;
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EPERM;
+
ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
if (ret)
goto error;
@@ -1295,7 +1298,7 @@ static int do_proc_bulk(struct usb_dev_state *ps,
return ret;
len1 = bulk->len;
- if (len1 < 0 || len1 >= (INT_MAX - sizeof(struct urb)))
+ if (len1 >= (INT_MAX - sizeof(struct urb)))
return -EINVAL;
if (bulk->ep & USB_DIR_IN)
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 0c3f12daac79..f203fdbfb6f6 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -95,9 +95,9 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
}
}
- spin_lock(&dynids->lock);
+ mutex_lock(&usb_dynids_lock);
list_add_tail(&dynid->node, &dynids->list);
- spin_unlock(&dynids->lock);
+ mutex_unlock(&usb_dynids_lock);
retval = driver_attach(driver);
@@ -116,6 +116,7 @@ ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf)
struct usb_dynid *dynid;
size_t count = 0;
+ guard(mutex)(&usb_dynids_lock);
list_for_each_entry(dynid, &dynids->list, node)
if (dynid->id.bInterfaceClass != 0)
count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n",
@@ -160,7 +161,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
if (fields < 2)
return -EINVAL;
- spin_lock(&usb_driver->dynids.lock);
+ guard(mutex)(&usb_dynids_lock);
list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) {
struct usb_device_id *id = &dynid->id;
@@ -171,7 +172,6 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
break;
}
}
- spin_unlock(&usb_driver->dynids.lock);
return count;
}
@@ -220,27 +220,24 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
{
struct usb_dynid *dynid, *n;
- spin_lock(&usb_drv->dynids.lock);
+ guard(mutex)(&usb_dynids_lock);
list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
- spin_unlock(&usb_drv->dynids.lock);
}
static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
- struct usb_driver *drv)
+ const struct usb_driver *drv)
{
struct usb_dynid *dynid;
- spin_lock(&drv->dynids.lock);
+ guard(mutex)(&usb_dynids_lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (usb_match_one_id(intf, &dynid->id)) {
- spin_unlock(&drv->dynids.lock);
return &dynid->id;
}
}
- spin_unlock(&drv->dynids.lock);
return NULL;
}
@@ -853,7 +850,7 @@ const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
EXPORT_SYMBOL_GPL(usb_device_match_id);
bool usb_driver_applicable(struct usb_device *udev,
- struct usb_device_driver *udrv)
+ const struct usb_device_driver *udrv)
{
if (udrv->id_table && udrv->match)
return usb_device_match_id(udev, udrv->id_table) != NULL &&
@@ -873,7 +870,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) {
struct usb_device *udev;
- struct usb_device_driver *udrv;
+ const struct usb_device_driver *udrv;
/* interface drivers never match devices */
if (!is_usb_device_driver(drv))
@@ -893,7 +890,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
} else if (is_usb_interface(dev)) {
struct usb_interface *intf;
- struct usb_driver *usb_drv;
+ const struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* device drivers never match interfaces */
@@ -1076,7 +1073,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
new_driver->driver.owner = owner;
new_driver->driver.mod_name = mod_name;
new_driver->driver.dev_groups = new_driver->dev_groups;
- spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->driver);
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 4b38b87a1343..e48399401608 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/sysfs.h>
#include <linux/usb.h>
#include "usb.h"
@@ -39,7 +40,7 @@ static ssize_t field##_show(struct device *dev, \
char *buf) \
{ \
struct ep_device *ep = to_ep_device(dev); \
- return sprintf(buf, format_string, ep->desc->field); \
+ return sysfs_emit(buf, format_string, ep->desc->field); \
} \
static DEVICE_ATTR_RO(field)
@@ -52,7 +53,7 @@ static ssize_t wMaxPacketSize_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ep_device *ep = to_ep_device(dev);
- return sprintf(buf, "%04x\n", usb_endpoint_maxp(ep->desc));
+ return sysfs_emit(buf, "%04x\n", usb_endpoint_maxp(ep->desc));
}
static DEVICE_ATTR_RO(wMaxPacketSize);
@@ -76,7 +77,7 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
type = "Interrupt";
break;
}
- return sprintf(buf, "%s\n", type);
+ return sysfs_emit(buf, "%s\n", type);
}
static DEVICE_ATTR_RO(type);
@@ -95,7 +96,7 @@ static ssize_t interval_show(struct device *dev, struct device_attribute *attr,
interval /= 1000;
}
- return sprintf(buf, "%d%cs\n", interval, unit);
+ return sysfs_emit(buf, "%d%cs\n", interval, unit);
}
static DEVICE_ATTR_RO(interval);
@@ -111,7 +112,7 @@ static ssize_t direction_show(struct device *dev, struct device_attribute *attr,
direction = "in";
else
direction = "out";
- return sprintf(buf, "%s\n", direction);
+ return sysfs_emit(buf, "%s\n", direction);
}
static DEVICE_ATTR_RO(direction);
diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c
index 85c999f71ad7..5e3c515991f3 100644
--- a/drivers/usb/core/ledtrig-usbport.c
+++ b/drivers/usb/core/ledtrig-usbport.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
+#include <linux/sysfs.h>
#include <linux/usb.h>
#include <linux/usb/of.h>
@@ -87,7 +88,7 @@ static ssize_t usbport_trig_port_show(struct device *dev,
struct usbport_trig_port,
attr);
- return sprintf(buf, "%d\n", port->observed) + 1;
+ return sysfs_emit(buf, "%d\n", port->observed) + 1;
}
static ssize_t usbport_trig_port_store(struct device *dev,
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index e7da2fca11a4..45d7af00f8d1 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -9,6 +9,7 @@
#include <linux/kstrtox.h>
#include <linux/slab.h>
+#include <linux/sysfs.h>
#include <linux/pm_qos.h>
#include <linux/component.h>
#include <linux/usb/of.h>
@@ -166,7 +167,7 @@ static ssize_t location_show(struct device *dev,
{
struct usb_port *port_dev = to_usb_port(dev);
- return sprintf(buf, "0x%08x\n", port_dev->location);
+ return sysfs_emit(buf, "0x%08x\n", port_dev->location);
}
static DEVICE_ATTR_RO(location);
@@ -191,7 +192,7 @@ static ssize_t connect_type_show(struct device *dev,
break;
}
- return sprintf(buf, "%s\n", result);
+ return sysfs_emit(buf, "%s\n", result);
}
static DEVICE_ATTR_RO(connect_type);
@@ -210,7 +211,7 @@ static ssize_t over_current_count_show(struct device *dev,
{
struct usb_port *port_dev = to_usb_port(dev);
- return sprintf(buf, "%u\n", port_dev->over_current_count);
+ return sysfs_emit(buf, "%u\n", port_dev->over_current_count);
}
static DEVICE_ATTR_RO(over_current_count);
@@ -219,7 +220,7 @@ static ssize_t quirks_show(struct device *dev,
{
struct usb_port *port_dev = to_usb_port(dev);
- return sprintf(buf, "%08x\n", port_dev->quirks);
+ return sysfs_emit(buf, "%08x\n", port_dev->quirks);
}
static ssize_t quirks_store(struct device *dev, struct device_attribute *attr,
@@ -254,7 +255,7 @@ static ssize_t usb3_lpm_permit_show(struct device *dev,
p = "0";
}
- return sprintf(buf, "%s\n", p);
+ return sysfs_emit(buf, "%s\n", p);
}
static ssize_t usb3_lpm_permit_store(struct device *dev,
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index b8324ea05b20..a9b37aeb515b 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -75,7 +75,7 @@ extern int usb_match_device(struct usb_device *dev,
extern const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
const struct usb_device_id *id);
extern bool usb_driver_applicable(struct usb_device *udev,
- struct usb_device_driver *udrv);
+ const struct usb_device_driver *udrv);
extern void usb_forced_unbind_intf(struct usb_interface *intf);
extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index c1b7209b9483..91c80a92d9b8 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -756,7 +756,7 @@ static struct platform_driver dwc2_platform_driver = {
.pm = &dwc2_dev_pm_ops,
},
.probe = dwc2_driver_probe,
- .remove_new = dwc2_driver_remove,
+ .remove = dwc2_driver_remove,
.shutdown = dwc2_driver_shutdown,
};
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 98114c2827c0..f219c82e9619 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1409,7 +1409,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
/*
* When configured in HOST mode, after issuing U3/L2 exit controller
- * fails to send proper CRC checksum in CRC5 feild. Because of this
+ * fails to send proper CRC checksum in CRC5 field. Because of this
* behaviour Transaction Error is generated, resulting in reset and
* re-enumeration of usb device attached. All the termsel, xcvrsel,
* opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1
@@ -1470,9 +1470,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (hw_mode != DWC3_GHWPARAMS0_MODE_GADGET &&
(DWC3_IP_IS(DWC31)) &&
dwc->maximum_speed == USB_SPEED_SUPER) {
- reg = dwc3_readl(dwc->regs, DWC3_LLUCTL);
- reg |= DWC3_LLUCTL_FORCE_GEN1;
- dwc3_writel(dwc->regs, DWC3_LLUCTL, reg);
+ int i;
+
+ for (i = 0; i < dwc->num_usb3_ports; i++) {
+ reg = dwc3_readl(dwc->regs, DWC3_LLUCTL(i));
+ reg |= DWC3_LLUCTL_FORCE_GEN1;
+ dwc3_writel(dwc->regs, DWC3_LLUCTL(i), reg);
+ }
}
return 0;
@@ -1941,7 +1945,7 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
struct extcon_dev *edev = NULL;
const char *name;
- if (device_property_read_bool(dev, "extcon"))
+ if (device_property_present(dev, "extcon"))
return extcon_get_edev_by_phandle(dev, 0);
/*
@@ -2651,7 +2655,7 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
static struct platform_driver dwc3_driver = {
.probe = dwc3_probe,
- .remove_new = dwc3_remove,
+ .remove = dwc3_remove,
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index eab81dfdcc35..ee73789326bc 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -81,7 +81,7 @@
#define DWC3_GSNPSREV_MASK 0xffff
#define DWC3_GSNPS_ID(p) (((p) & DWC3_GSNPSID_MASK) >> 16)
-/* DWC3 registers memory space boundries */
+/* DWC3 registers memory space boundaries */
#define DWC3_XHCI_REGS_START 0x0
#define DWC3_XHCI_REGS_END 0x7fff
#define DWC3_GLOBALS_REGS_START 0xc100
@@ -179,7 +179,7 @@
#define DWC3_OEVTEN 0xcc0C
#define DWC3_OSTS 0xcc10
-#define DWC3_LLUCTL 0xd024
+#define DWC3_LLUCTL(n) (0xd024 + ((n) * 0x80))
/* Bit fields */
@@ -915,6 +915,7 @@ struct dwc3_hwparams {
#define DWC3_MODE(n) ((n) & 0x7)
/* HWPARAMS1 */
+#define DWC3_SPRAM_TYPE(n) (((n) >> 23) & 1)
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
/* HWPARAMS3 */
@@ -925,6 +926,9 @@ struct dwc3_hwparams {
#define DWC3_NUM_IN_EPS(p) (((p)->hwparams3 & \
(DWC3_NUM_IN_EPS_MASK)) >> 18)
+/* HWPARAMS6 */
+#define DWC3_RAM0_DEPTH(n) (((n) & (0xffff0000)) >> 16)
+
/* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
@@ -937,18 +941,14 @@ struct dwc3_hwparams {
* @request: struct usb_request to be transferred
* @list: a list_head used for request queueing
* @dep: struct dwc3_ep owning this request
- * @sg: pointer to first incomplete sg
* @start_sg: pointer to the sg which should be queued next
* @num_pending_sgs: counter to pending sgs
- * @num_queued_sgs: counter to the number of sgs which already got queued
* @remaining: amount of data remaining
* @status: internal dwc3 request status tracking
* @epnum: endpoint number to which this request refers
* @trb: pointer to struct dwc3_trb
* @trb_dma: DMA address of @trb
* @num_trbs: number of TRBs used by this request
- * @needs_extra_trb: true when request needs one extra TRB (either due to ZLP
- * or unaligned OUT)
* @direction: IN or OUT direction flag
* @mapped: true when request has been dma-mapped
*/
@@ -960,7 +960,6 @@ struct dwc3_request {
struct scatterlist *start_sg;
unsigned int num_pending_sgs;
- unsigned int num_queued_sgs;
unsigned int remaining;
unsigned int status;
@@ -978,7 +977,6 @@ struct dwc3_request {
unsigned int num_trbs;
- unsigned int needs_extra_trb:1;
unsigned int direction:1;
unsigned int mapped:1;
};
diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c
index fad151e78fd6..5e3d1741701f 100644
--- a/drivers/usb/dwc3/dwc3-am62.c
+++ b/drivers/usb/dwc3/dwc3-am62.c
@@ -377,7 +377,7 @@ MODULE_DEVICE_TABLE(of, dwc3_ti_of_match);
static struct platform_driver dwc3_ti_driver = {
.probe = dwc3_ti_probe,
- .remove_new = dwc3_ti_remove,
+ .remove = dwc3_ti_remove,
.driver = {
.name = "dwc3-am62",
.pm = DEV_PM_OPS,
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 9a6e988d165a..f5d963fae9e0 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -243,7 +243,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dwc3_exynos_dev_pm_ops,
static struct platform_driver dwc3_exynos_driver = {
.probe = dwc3_exynos_probe,
- .remove_new = dwc3_exynos_remove,
+ .remove = dwc3_exynos_remove,
.driver = {
.name = "exynos-dwc3",
.of_match_table = exynos_dwc3_match,
diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
index 64c0cd1995aa..356812cbcd88 100644
--- a/drivers/usb/dwc3/dwc3-imx8mp.c
+++ b/drivers/usb/dwc3/dwc3-imx8mp.c
@@ -400,7 +400,7 @@ MODULE_DEVICE_TABLE(of, dwc3_imx8mp_of_match);
static struct platform_driver dwc3_imx8mp_driver = {
.probe = dwc3_imx8mp_probe,
- .remove_new = dwc3_imx8mp_remove,
+ .remove = dwc3_imx8mp_remove,
.driver = {
.name = "imx8mp-dwc3",
.pm = pm_ptr(&dwc3_imx8mp_dev_pm_ops),
diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c
index 8899348b6276..7ee1610162b9 100644
--- a/drivers/usb/dwc3/dwc3-keystone.c
+++ b/drivers/usb/dwc3/dwc3-keystone.c
@@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(of, kdwc3_of_match);
static struct platform_driver kdwc3_driver = {
.probe = kdwc3_probe,
- .remove_new = kdwc3_remove,
+ .remove = kdwc3_remove,
.driver = {
.name = "keystone-dwc3",
.of_match_table = kdwc3_of_match,
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
index 2c07c038b584..7d80bf7b18b0 100644
--- a/drivers/usb/dwc3/dwc3-meson-g12a.c
+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -968,7 +968,7 @@ MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);
static struct platform_driver dwc3_meson_g12a_driver = {
.probe = dwc3_meson_g12a_probe,
- .remove_new = dwc3_meson_g12a_remove,
+ .remove = dwc3_meson_g12a_remove,
.driver = {
.name = "dwc3-meson-g12a",
.of_match_table = dwc3_meson_g12a_match,
diff --git a/drivers/usb/dwc3/dwc3-octeon.c b/drivers/usb/dwc3/dwc3-octeon.c
index 1a3b205367fd..42bfc14ae0c4 100644
--- a/drivers/usb/dwc3/dwc3-octeon.c
+++ b/drivers/usb/dwc3/dwc3-octeon.c
@@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, dwc3_octeon_of_match);
static struct platform_driver dwc3_octeon_driver = {
.probe = dwc3_octeon_probe,
- .remove_new = dwc3_octeon_remove,
+ .remove = dwc3_octeon_remove,
.driver = {
.name = "dwc3-octeon",
.of_match_table = dwc3_octeon_of_match,
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index be7be00ecb34..a4954a21be93 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -180,7 +180,7 @@ MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
static struct platform_driver dwc3_of_simple_driver = {
.probe = dwc3_of_simple_probe,
- .remove_new = dwc3_of_simple_remove,
+ .remove = dwc3_of_simple_remove,
.shutdown = dwc3_of_simple_shutdown,
.driver = {
.name = "dwc3-of-simple",
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 2a11fc0ee84f..b261c46124c6 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -416,7 +416,7 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
struct device_node *node = omap->dev->of_node;
struct extcon_dev *edev;
- if (of_property_read_bool(node, "extcon")) {
+ if (of_property_present(node, "extcon")) {
edev = extcon_get_edev_by_phandle(omap->dev, 0);
if (IS_ERR(edev)) {
dev_vdbg(omap->dev, "couldn't get extcon device\n");
@@ -611,7 +611,7 @@ static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
static struct platform_driver dwc3_omap_driver = {
.probe = dwc3_omap_probe,
- .remove_new = dwc3_omap_remove,
+ .remove = dwc3_omap_remove,
.driver = {
.name = "omap-dwc3",
.of_match_table = of_dwc3_match,
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index c1d4b52f25b0..58683bb672e9 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -161,7 +161,7 @@ static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
struct extcon_dev *host_edev;
int ret;
- if (!of_property_read_bool(dev->of_node, "extcon"))
+ if (!of_property_present(dev->of_node, "extcon"))
return 0;
qcom->edev = extcon_get_edev_by_phandle(dev, 0);
@@ -921,7 +921,7 @@ MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
static struct platform_driver dwc3_qcom_driver = {
.probe = dwc3_qcom_probe,
- .remove_new = dwc3_qcom_remove,
+ .remove = dwc3_qcom_remove,
.driver = {
.name = "dwc3-qcom",
.pm = &dwc3_qcom_dev_pm_ops,
diff --git a/drivers/usb/dwc3/dwc3-rtk.c b/drivers/usb/dwc3/dwc3-rtk.c
index e9c8b032c72c..56c53e0c0257 100644
--- a/drivers/usb/dwc3/dwc3-rtk.c
+++ b/drivers/usb/dwc3/dwc3-rtk.c
@@ -441,7 +441,7 @@ static const struct dev_pm_ops dwc3_rtk_dev_pm_ops = {
static struct platform_driver dwc3_rtk_driver = {
.probe = dwc3_rtk_probe,
- .remove_new = dwc3_rtk_remove,
+ .remove = dwc3_rtk_remove,
.driver = {
.name = "rtk-dwc3",
.of_match_table = rtk_dwc3_match,
diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c
index 2841021f3557..e16c3237180e 100644
--- a/drivers/usb/dwc3/dwc3-st.c
+++ b/drivers/usb/dwc3/dwc3-st.c
@@ -356,7 +356,7 @@ MODULE_DEVICE_TABLE(of, st_dwc3_match);
static struct platform_driver st_dwc3_driver = {
.probe = st_dwc3_probe,
- .remove_new = st_dwc3_remove,
+ .remove = st_dwc3_remove,
.driver = {
.name = "usb-st-dwc3",
.of_match_table = st_dwc3_match,
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index b5e5be424ce9..e3738e1610db 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -420,7 +420,7 @@ static const struct dev_pm_ops dwc3_xlnx_dev_pm_ops = {
static struct platform_driver dwc3_xlnx_driver = {
.probe = dwc3_xlnx_probe,
- .remove_new = dwc3_xlnx_remove,
+ .remove = dwc3_xlnx_remove,
.driver = {
.name = "dwc3-xilinx",
.of_match_table = dwc3_xlnx_of_match,
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index c9533a99e47c..666ac432f52d 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -145,7 +145,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
* Unfortunately we have uncovered a limitation wrt the Data Phase.
*
* Section 9.4 says we can wait for the XferNotReady(DATA) event to
- * come before issueing Start Transfer command, but if we do, we will
+ * come before issuing Start Transfer command, but if we do, we will
* miss situations where the host starts another SETUP phase instead of
* the DATA phase. Such cases happen at least on TD.7.6 of the Link
* Layer Compliance Suite.
@@ -232,7 +232,7 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
/* stall is always issued on EP0 */
dep = dwc->eps[0];
__dwc3_gadget_ep_set_halt(dep, 1, false);
- dep->flags &= DWC3_EP_RESOURCE_ALLOCATED;
+ dep->flags &= DWC3_EP_RESOURCE_ALLOCATED | DWC3_EP_TRANSFER_STARTED;
dep->flags |= DWC3_EP_ENABLED;
dwc->delayed_status = false;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 4959c26d3b71..83dc7304d701 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -197,7 +197,6 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
list_del(&req->list);
req->remaining = 0;
- req->needs_extra_trb = false;
req->num_trbs = 0;
if (req->request.status == -EINPROGRESS)
@@ -688,6 +687,44 @@ static int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult)
}
/**
+ * dwc3_gadget_calc_ram_depth - calculates the ram depth for txfifo
+ * @dwc: pointer to the DWC3 context
+ */
+static int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc)
+{
+ int ram_depth;
+ int fifo_0_start;
+ bool is_single_port_ram;
+
+ /* Check supporting RAM type by HW */
+ is_single_port_ram = DWC3_SPRAM_TYPE(dwc->hwparams.hwparams1);
+
+ /*
+ * If a single port RAM is utilized, then allocate TxFIFOs from
+ * RAM0. otherwise, allocate them from RAM1.
+ */
+ ram_depth = is_single_port_ram ? DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6) :
+ DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+
+ /*
+ * In a single port RAM configuration, the available RAM is shared
+ * between the RX and TX FIFOs. This means that the txfifo can begin
+ * at a non-zero address.
+ */
+ if (is_single_port_ram) {
+ u32 reg;
+
+ /* Check if TXFIFOs start at non-zero addr */
+ reg = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
+ fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(reg);
+
+ ram_depth -= (fifo_0_start >> 16);
+ }
+
+ return ram_depth;
+}
+
+/**
* dwc3_gadget_clear_tx_fifos - Clears txfifo allocation
* @dwc: pointer to the DWC3 context
*
@@ -753,7 +790,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
int fifo_0_start;
- int ram1_depth;
+ int ram_depth;
int fifo_size;
int min_depth;
int num_in_ep;
@@ -773,17 +810,32 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
if (dep->flags & DWC3_EP_TXFIFO_RESIZED)
return 0;
- ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+ ram_depth = dwc3_gadget_calc_ram_depth(dwc);
- if ((dep->endpoint.maxburst > 1 &&
- usb_endpoint_xfer_bulk(dep->endpoint.desc)) ||
- usb_endpoint_xfer_isoc(dep->endpoint.desc))
- num_fifos = 3;
-
- if (dep->endpoint.maxburst > 6 &&
- (usb_endpoint_xfer_bulk(dep->endpoint.desc) ||
- usb_endpoint_xfer_isoc(dep->endpoint.desc)) && DWC3_IP_IS(DWC31))
- num_fifos = dwc->tx_fifo_resize_max_num;
+ switch (dwc->gadget->speed) {
+ case USB_SPEED_SUPER_PLUS:
+ case USB_SPEED_SUPER:
+ if (usb_endpoint_xfer_bulk(dep->endpoint.desc) ||
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ num_fifos = min_t(unsigned int,
+ dep->endpoint.maxburst,
+ dwc->tx_fifo_resize_max_num);
+ break;
+ case USB_SPEED_HIGH:
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ num_fifos = min_t(unsigned int,
+ usb_endpoint_maxp_mult(dep->endpoint.desc) + 1,
+ dwc->tx_fifo_resize_max_num);
+ break;
+ }
+ fallthrough;
+ case USB_SPEED_FULL:
+ if (usb_endpoint_xfer_bulk(dep->endpoint.desc))
+ num_fifos = 2;
+ break;
+ default:
+ break;
+ }
/* FIFO size for a single buffer */
fifo = dwc3_gadget_calc_tx_fifo_size(dwc, 1);
@@ -794,7 +846,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
/* Reserve at least one FIFO for the number of IN EPs */
min_depth = num_in_ep * (fifo + 1);
- remaining = ram1_depth - min_depth - dwc->last_fifo_depth;
+ remaining = ram_depth - min_depth - dwc->last_fifo_depth;
remaining = max_t(int, 0, remaining);
/*
* We've already reserved 1 FIFO per EP, so check what we can fit in
@@ -820,9 +872,9 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
dwc->last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEP(fifo_size);
/* Check fifo size allocation doesn't exceed available RAM size. */
- if (dwc->last_fifo_depth >= ram1_depth) {
+ if (dwc->last_fifo_depth >= ram_depth) {
dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
- dwc->last_fifo_depth, ram1_depth,
+ dwc->last_fifo_depth, ram_depth,
dep->endpoint.name, fifo_size);
if (DWC3_IP_IS(DWC3))
fifo_size = DWC3_GTXFIFOSIZ_TXFDEP(fifo_size);
@@ -1177,11 +1229,14 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
* pending to be processed by the driver.
*/
if (dep->trb_enqueue == dep->trb_dequeue) {
+ struct dwc3_request *req;
+
/*
- * If there is any request remained in the started_list at
- * this point, that means there is no TRB available.
+ * If there is any request remained in the started_list with
+ * active TRBs at this point, then there is no TRB available.
*/
- if (!list_empty(&dep->started_list))
+ req = next_request(&dep->started_list);
+ if (req && req->num_trbs)
return 0;
return DWC3_TRB_NUM - 1;
@@ -1384,6 +1439,7 @@ static int dwc3_prepare_last_sg(struct dwc3_ep *dep,
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
unsigned int rem = req->request.length % maxp;
unsigned int num_trbs = 1;
+ bool needs_extra_trb;
if (dwc3_needs_extra_trb(dep, req))
num_trbs++;
@@ -1391,15 +1447,15 @@ static int dwc3_prepare_last_sg(struct dwc3_ep *dep,
if (dwc3_calc_trbs_left(dep) < num_trbs)
return 0;
- req->needs_extra_trb = num_trbs > 1;
+ needs_extra_trb = num_trbs > 1;
/* Prepare a normal TRB */
if (req->direction || req->request.length)
dwc3_prepare_one_trb(dep, req, entry_length,
- req->needs_extra_trb, node, false, false);
+ needs_extra_trb, node, false, false);
/* Prepare extra TRBs for ZLP and MPS OUT transfer alignment */
- if ((!req->direction && !req->request.length) || req->needs_extra_trb)
+ if ((!req->direction && !req->request.length) || needs_extra_trb)
dwc3_prepare_one_trb(dep, req,
req->direction ? 0 : maxp - rem,
false, 1, true, false);
@@ -1414,8 +1470,8 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep,
struct scatterlist *s;
int i;
unsigned int length = req->request.length;
- unsigned int remaining = req->request.num_mapped_sgs
- - req->num_queued_sgs;
+ unsigned int remaining = req->num_pending_sgs;
+ unsigned int num_queued_sgs = req->request.num_mapped_sgs - remaining;
unsigned int num_trbs = req->num_trbs;
bool needs_extra_trb = dwc3_needs_extra_trb(dep, req);
@@ -1423,7 +1479,7 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep,
* If we resume preparing the request, then get the remaining length of
* the request and resume where we left off.
*/
- for_each_sg(req->request.sg, s, req->num_queued_sgs, i)
+ for_each_sg(req->request.sg, s, num_queued_sgs, i)
length -= sg_dma_len(s);
for_each_sg(sg, s, remaining, i) {
@@ -1488,7 +1544,6 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep,
if (!last_sg)
req->start_sg = sg_next(s);
- req->num_queued_sgs++;
req->num_pending_sgs--;
/*
@@ -1569,9 +1624,7 @@ static int dwc3_prepare_trbs(struct dwc3_ep *dep)
if (ret)
return ret;
- req->sg = req->request.sg;
- req->start_sg = req->sg;
- req->num_queued_sgs = 0;
+ req->start_sg = req->request.sg;
req->num_pending_sgs = req->request.num_mapped_sgs;
if (req->num_pending_sgs > 0) {
@@ -3075,7 +3128,7 @@ static int dwc3_gadget_check_config(struct usb_gadget *g)
struct dwc3 *dwc = gadget_to_dwc(g);
struct usb_ep *ep;
int fifo_size = 0;
- int ram1_depth;
+ int ram_depth;
int ep_num = 0;
if (!dwc->do_fifo_resize)
@@ -3098,8 +3151,8 @@ static int dwc3_gadget_check_config(struct usb_gadget *g)
fifo_size += dwc->max_cfg_eps;
/* Check if we can fit a single fifo per endpoint */
- ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
- if (fifo_size > ram1_depth)
+ ram_depth = dwc3_gadget_calc_ram_depth(dwc);
+ if (fifo_size > ram_depth)
return -ENOMEM;
return 0;
@@ -3416,20 +3469,16 @@ static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep,
int status)
{
struct dwc3_trb *trb;
- struct scatterlist *sg = req->sg;
- struct scatterlist *s;
- unsigned int num_queued = req->num_queued_sgs;
+ unsigned int num_completed_trbs = req->num_trbs;
unsigned int i;
int ret = 0;
- for_each_sg(sg, s, num_queued, i) {
+ for (i = 0; i < num_completed_trbs; i++) {
trb = &dep->trb_pool[dep->trb_dequeue];
- req->sg = sg_next(s);
- req->num_queued_sgs--;
-
ret = dwc3_gadget_ep_reclaim_completed_trb(dep, req,
- trb, event, status, true);
+ trb, event, status,
+ !!(trb->ctrl & DWC3_TRB_CTRL_CHN));
if (ret)
break;
}
@@ -3437,19 +3486,9 @@ static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep,
return ret;
}
-static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep,
- struct dwc3_request *req, const struct dwc3_event_depevt *event,
- int status)
-{
- struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue];
-
- return dwc3_gadget_ep_reclaim_completed_trb(dep, req, trb,
- event, status, false);
-}
-
static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req)
{
- return req->num_pending_sgs == 0 && req->num_queued_sgs == 0;
+ return req->num_pending_sgs == 0 && req->num_trbs == 0;
}
static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
@@ -3459,24 +3498,13 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
int request_status;
int ret;
- if (req->request.num_mapped_sgs)
- ret = dwc3_gadget_ep_reclaim_trb_sg(dep, req, event,
- status);
- else
- ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
- status);
+ ret = dwc3_gadget_ep_reclaim_trb_sg(dep, req, event, status);
req->request.actual = req->request.length - req->remaining;
if (!dwc3_gadget_ep_request_completed(req))
goto out;
- if (req->needs_extra_trb) {
- ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
- status);
- req->needs_extra_trb = false;
- }
-
/*
* The event status only reflects the status of the TRB with IOC set.
* For the requests that don't set interrupt on completion, the driver
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index e0533cee6870..b48e108fc8fe 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -35,7 +35,7 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc)
u32 reg;
int i;
- /* xhci regs is not mapped yet, do it temperary here */
+ /* xhci regs are not mapped yet, do it temporarily here */
if (dwc->xhci_resources[0].start) {
xhci_regs = ioremap(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END);
if (!xhci_regs) {
diff --git a/drivers/usb/fotg210/fotg210-core.c b/drivers/usb/fotg210/fotg210-core.c
index 0655afe7f977..49f25a70b32e 100644
--- a/drivers/usb/fotg210/fotg210-core.c
+++ b/drivers/usb/fotg210/fotg210-core.c
@@ -195,7 +195,7 @@ static struct platform_driver fotg210_driver = {
.of_match_table = of_match_ptr(fotg210_of_match),
},
.probe = fotg210_probe,
- .remove_new = fotg210_remove,
+ .remove = fotg210_remove,
};
static int __init fotg210_init(void)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index f25dd2cb5d03..bdda8c74602d 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1844,7 +1844,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
cdev->desc.bcdUSB = cpu_to_le16(0x0200);
}
- value = min(w_length, (u16) sizeof cdev->desc);
+ value = min_t(u16, w_length, sizeof(cdev->desc));
memcpy(req->buf, &cdev->desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
@@ -1863,19 +1863,19 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_DT_CONFIG:
value = config_desc(cdev, w_value);
if (value >= 0)
- value = min(w_length, (u16) value);
+ value = min_t(u16, w_length, value);
break;
case USB_DT_STRING:
value = get_string(cdev, req->buf,
w_index, w_value & 0xff);
if (value >= 0)
- value = min(w_length, (u16) value);
+ value = min_t(u16, w_length, value);
break;
case USB_DT_BOS:
if (gadget_is_superspeed(gadget) ||
gadget->lpm_capable || cdev->use_webusb) {
value = bos_desc(cdev);
- value = min(w_length, (u16) value);
+ value = min_t(u16, w_length, value);
}
break;
case USB_DT_OTG:
@@ -1930,7 +1930,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
*(u8 *)req->buf = cdev->config->bConfigurationValue;
else
*(u8 *)req->buf = 0;
- value = min(w_length, (u16) 1);
+ value = min_t(u16, w_length, 1);
break;
/* function drivers must handle get/set altsetting */
@@ -1976,7 +1976,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (value < 0)
break;
*((u8 *)req->buf) = value;
- value = min(w_length, (u16) 1);
+ value = min_t(u16, w_length, 1);
break;
case USB_REQ_GET_STATUS:
if (gadget_is_otg(gadget) && gadget->hnp_polling_support &&
@@ -2111,8 +2111,20 @@ unknown:
memset(buf, 0, w_length);
buf[5] = 0x01;
switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ /*
+ * The Microsoft CompatID OS Descriptor Spec(w_index = 0x4) and
+ * Extended Prop OS Desc Spec(w_index = 0x5) state that the
+ * HighByte of wValue is the InterfaceNumber and the LowByte is
+ * the PageNumber. This high/low byte ordering is incorrectly
+ * documented in the Spec. USB analyzer output on the below
+ * request packets show the high/low byte inverted i.e LowByte
+ * is the InterfaceNumber and the HighByte is the PageNumber.
+ * Since we dont support >64KB CompatID/ExtendedProp descriptors,
+ * PageNumber is set to 0. Hence verify that the HighByte is 0
+ * for below two cases.
+ */
case USB_RECIP_DEVICE:
- if (w_index != 0x4 || (w_value & 0xff))
+ if (w_index != 0x4 || (w_value >> 8))
break;
buf[6] = w_index;
/* Number of ext compat interfaces */
@@ -2128,9 +2140,9 @@ unknown:
}
break;
case USB_RECIP_INTERFACE:
- if (w_index != 0x5 || (w_value & 0xff))
+ if (w_index != 0x5 || (w_value >> 8))
break;
- interface = w_value >> 8;
+ interface = w_value & 0xFF;
if (interface >= MAX_CONFIG_INTERFACES ||
!os_desc_cfg->interface[interface])
break;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index b1f625245713..95f144a54ed9 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -57,11 +57,11 @@ EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf);
* usb_gadget_config_buf - builts a complete configuration descriptor
* @config: Header for the descriptor, including characteristics such
* as power requirements and number of interfaces.
- * @desc: Null-terminated vector of pointers to the descriptors (interface,
- * endpoint, etc) defining all functions in this device configuration.
* @buf: Buffer for the resulting configuration descriptor.
* @length: Length of buffer. If this is not big enough to hold the
* entire configuration descriptor, an error code will be returned.
+ * @desc: Null-terminated vector of pointers to the descriptors (interface,
+ * endpoint, etc) defining all functions in this device configuration.
*
* This copies descriptors into the response buffer, building a descriptor
* for that configuration. It returns the buffer length or a negative
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index c82a6a0fba93..6499a88d346c 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1184,7 +1184,7 @@ static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page,
struct gadget_info *gi = os_desc_item_to_gadget_info(item);
int res, l;
- l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1);
+ l = min_t(int, len, OS_STRING_QW_SIGN_LEN >> 1);
if (page[l - 1] == '\n')
--l;
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index 87917a7d4a9b..7ce1637276f0 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -41,6 +41,10 @@ obj-$(CONFIG_USB_F_UAC1_LEGACY) += usb_f_uac1_legacy.o
usb_f_uac2-y := f_uac2.o
obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
+ifneq ($(CONFIG_TRACING),)
+ CFLAGS_uvc_trace.o := -I$(src)
+ usb_f_uvc-y += uvc_trace.o
+endif
obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o
usb_f_midi-y := f_midi.o
obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 2920f8000bbd..2ccf7f4e4db1 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -456,7 +456,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
}
/* FFS_SETUP_PENDING and not stall */
- len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+ len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
spin_unlock_irq(&ffs->ev.waitq.lock);
@@ -590,7 +590,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
/* unlocks spinlock */
return __ffs_ep0_read_events(ffs, buf,
- min(n, (size_t)ffs->ev.count));
+ min_t(size_t, n, ffs->ev.count));
case FFS_SETUP_PENDING:
if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
@@ -599,7 +599,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
goto done_mutex;
}
- len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+ len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
spin_unlock_irq(&ffs->ev.waitq.lock);
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 08e0d1c511e8..2eae8fc2e0db 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -500,7 +500,7 @@ static int fsg_setup(struct usb_function *f,
*(u8 *)req->buf = _fsg_common_get_max_lun(fsg->common);
/* Respond with data/status */
- req->length = min((u16)1, w_length);
+ req->length = min_t(u16, 1, w_length);
return ep0_queue(fsg->common);
}
@@ -655,7 +655,7 @@ static int do_read(struct fsg_common *common)
* And don't try to read past the end of the file.
*/
amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t)amount,
+ amount = min_t(loff_t, amount,
curlun->file_length - file_offset);
/* Wait for the next buffer to become available */
@@ -1005,7 +1005,7 @@ static int do_verify(struct fsg_common *common)
* And don't try to read past the end of the file.
*/
amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t)amount,
+ amount = min_t(loff_t, amount,
curlun->file_length - file_offset);
if (amount == 0) {
curlun->sense_data =
@@ -2167,7 +2167,7 @@ unknown_cmnd:
if (reply == -EINVAL)
reply = 0; /* Error reply length */
if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) {
- reply = min((u32)reply, common->data_size_from_cmnd);
+ reply = min_t(u32, reply, common->data_size_from_cmnd);
bh->inreq->length = reply;
bh->state = BUF_STATE_FULL;
common->residue -= reply;
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 1067847cc079..837fcdfa3840 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -819,9 +819,9 @@ static int f_midi_register_card(struct f_midi *midi)
goto fail;
}
- strcpy(card->driver, f_midi_longname);
- strcpy(card->longname, f_midi_longname);
- strcpy(card->shortname, f_midi_shortname);
+ strscpy(card->driver, f_midi_longname);
+ strscpy(card->longname, f_midi_longname);
+ strscpy(card->shortname, f_midi_shortname);
/* Set up rawmidi */
snd_component_add(card, "MIDI");
@@ -833,7 +833,7 @@ static int f_midi_register_card(struct f_midi *midi)
}
midi->rmidi = rmidi;
midi->in_last_port = 0;
- strcpy(rmidi->name, card->shortname);
+ strscpy(rmidi->name, card->shortname);
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c
index 8285df9ed6fd..ee3d9e3578f7 100644
--- a/drivers/usb/gadget/function/f_midi2.c
+++ b/drivers/usb/gadget/function/f_midi2.c
@@ -1285,10 +1285,8 @@ static int f_midi2_set_alt(struct usb_function *fn, unsigned int intf,
if (alt == 0)
op_mode = MIDI_OP_MODE_MIDI1;
- else if (alt == 1)
- op_mode = MIDI_OP_MODE_MIDI2;
else
- op_mode = MIDI_OP_MODE_UNSET;
+ op_mode = MIDI_OP_MODE_MIDI2;
if (midi2->operation_mode == op_mode)
return 0;
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 40187b7112e7..aa6ab666741a 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -465,7 +465,7 @@ uvc_register_video(struct uvc_device *uvc)
memcpy(mem, desc, (desc)->bLength); \
*(dst)++ = mem; \
mem += (desc)->bLength; \
- } while (0);
+ } while (0)
#define UVC_COPY_DESCRIPTORS(mem, dst, src) \
do { \
@@ -991,6 +991,8 @@ static void uvc_function_unbind(struct usb_configuration *c,
uvcg_info(f, "%s()\n", __func__);
+ kthread_cancel_work_sync(&video->hw_submit);
+
if (video->async_wq)
destroy_workqueue(video->async_wq);
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index cb35687b11e7..6f44dd732315 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -71,6 +71,11 @@ extern unsigned int uvc_gadget_trace_param;
#define UVCG_REQUEST_HEADER_LEN 12
+#define UVCG_REQ_MAX_INT_COUNT 16
+#define UVCG_REQ_MAX_ZERO_COUNT (2 * UVCG_REQ_MAX_INT_COUNT)
+
+#define UVCG_STREAMING_MIN_BUFFERS 2
+
/* ------------------------------------------------------------------------
* Structures
*/
@@ -91,16 +96,24 @@ struct uvc_video {
struct work_struct pump;
struct workqueue_struct *async_wq;
+ struct kthread_worker *kworker;
+ struct kthread_work hw_submit;
+
+ atomic_t queued;
+
/* Frame parameters */
u8 bpp;
u32 fcc;
unsigned int width;
unsigned int height;
unsigned int imagesize;
+ unsigned int interval;
struct mutex mutex; /* protects frame parameters */
unsigned int uvc_num_requests;
+ unsigned int reqs_per_frame;
+
/* Requests */
bool is_enabled; /* tracks whether video stream is enabled */
unsigned int req_size;
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 6fac696ea846..f131943254a4 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -1566,11 +1566,13 @@ static const struct uvcg_config_group_type uvcg_control_grp_type = {
/* -----------------------------------------------------------------------------
* streaming/uncompressed
* streaming/mjpeg
+ * streaming/framebased
*/
static const char * const uvcg_format_names[] = {
"uncompressed",
"mjpeg",
+ "framebased",
};
static struct uvcg_color_matching *
@@ -1777,6 +1779,9 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
target_fmt = container_of(to_config_group(target), struct uvcg_format,
group);
+ if (!target_fmt)
+ goto out;
+
uvcg_format_set_indices(to_config_group(target));
format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL);
@@ -1816,6 +1821,9 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
target_fmt = container_of(to_config_group(target), struct uvcg_format,
group);
+ if (!target_fmt)
+ goto out;
+
list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry)
if (format_ptr->fmt == target_fmt) {
list_del(&format_ptr->entry);
@@ -1826,6 +1834,7 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
--target_fmt->linked;
+out:
mutex_unlock(&opts->lock);
mutex_unlock(su_mutex);
}
@@ -2022,6 +2031,7 @@ UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32);
UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32);
UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32);
UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32);
+UVCG_FRAME_ATTR(dw_bytes_perline, dwBytesPerLine, 32);
#undef UVCG_FRAME_ATTR
@@ -2035,7 +2045,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
int result, i;
char *pg = page;
- mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent;
opts = to_f_uvc_opts(opts_item);
@@ -2105,7 +2115,7 @@ end:
UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval);
-static struct configfs_attribute *uvcg_frame_attrs[] = {
+static struct configfs_attribute *uvcg_frame_attrs1[] = {
&uvcg_frame_attr_b_frame_index,
&uvcg_frame_attr_bm_capabilities,
&uvcg_frame_attr_w_width,
@@ -2118,12 +2128,31 @@ static struct configfs_attribute *uvcg_frame_attrs[] = {
NULL,
};
-static const struct config_item_type uvcg_frame_type = {
+static struct configfs_attribute *uvcg_frame_attrs2[] = {
+ &uvcg_frame_attr_b_frame_index,
+ &uvcg_frame_attr_bm_capabilities,
+ &uvcg_frame_attr_w_width,
+ &uvcg_frame_attr_w_height,
+ &uvcg_frame_attr_dw_min_bit_rate,
+ &uvcg_frame_attr_dw_max_bit_rate,
+ &uvcg_frame_attr_dw_default_frame_interval,
+ &uvcg_frame_attr_dw_frame_interval,
+ &uvcg_frame_attr_dw_bytes_perline,
+ NULL,
+};
+
+static const struct config_item_type uvcg_frame_type1 = {
.ct_item_ops = &uvcg_config_item_ops,
- .ct_attrs = uvcg_frame_attrs,
+ .ct_attrs = uvcg_frame_attrs1,
.ct_owner = THIS_MODULE,
};
+static const struct config_item_type uvcg_frame_type2 = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_attrs = uvcg_frame_attrs2,
+ .ct_owner = THIS_MODULE,
+};
+
static struct config_item *uvcg_frame_make(struct config_group *group,
const char *name)
{
@@ -2145,6 +2174,7 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
h->frame.dw_max_bit_rate = 55296000;
h->frame.dw_max_video_frame_buffer_size = 460800;
h->frame.dw_default_frame_interval = 666666;
+ h->frame.dw_bytes_perline = 0;
opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
opts = to_f_uvc_opts(opts_item);
@@ -2157,6 +2187,9 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
} else if (fmt->type == UVCG_MJPEG) {
h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG;
h->fmt_type = UVCG_MJPEG;
+ } else if (fmt->type == UVCG_FRAMEBASED) {
+ h->frame.b_descriptor_subtype = UVC_VS_FRAME_FRAME_BASED;
+ h->fmt_type = UVCG_FRAMEBASED;
} else {
mutex_unlock(&opts->lock);
kfree(h);
@@ -2175,7 +2208,10 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
++fmt->num_frames;
mutex_unlock(&opts->lock);
- config_item_init_type_name(&h->item, name, &uvcg_frame_type);
+ if (fmt->type == UVCG_FRAMEBASED)
+ config_item_init_type_name(&h->item, name, &uvcg_frame_type2);
+ else
+ config_item_init_type_name(&h->item, name, &uvcg_frame_type1);
return &h->item;
}
@@ -2215,9 +2251,6 @@ static void uvcg_format_set_indices(struct config_group *fmt)
list_for_each_entry(ci, &fmt->cg_children, ci_entry) {
struct uvcg_frame *frm;
- if (ci->ci_type != &uvcg_frame_type)
- continue;
-
frm = to_uvcg_frame(ci);
frm->frame.b_frame_index = i++;
}
@@ -2678,6 +2711,251 @@ static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = {
};
/* -----------------------------------------------------------------------------
+ * streaming/framebased/<NAME>
+ */
+
+static struct configfs_group_operations uvcg_framebased_group_ops = {
+ .make_item = uvcg_frame_make,
+ .drop_item = uvcg_frame_drop,
+};
+
+#define UVCG_FRAMEBASED_ATTR_RO(cname, aname, bits) \
+static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \
+ char *page) \
+{ \
+ struct uvcg_framebased *u = to_uvcg_framebased(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+UVC_ATTR_RO(uvcg_framebased_, cname, aname)
+
+#define UVCG_FRAMEBASED_ATTR(cname, aname, bits) \
+static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \
+ char *page) \
+{ \
+ struct uvcg_framebased *u = to_uvcg_framebased(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static ssize_t \
+uvcg_framebased_##cname##_store(struct config_item *item, \
+ const char *page, size_t len) \
+{ \
+ struct uvcg_framebased *u = to_uvcg_framebased(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int ret; \
+ u8 num; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ if (u->fmt.linked || opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = kstrtou8(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (num > 255) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ u->desc.aname = num; \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ mutex_unlock(su_mutex); \
+ return ret; \
+} \
+ \
+UVC_ATTR(uvcg_framebased_, cname, aname)
+
+UVCG_FRAMEBASED_ATTR_RO(b_format_index, bFormatIndex, 8);
+UVCG_FRAMEBASED_ATTR_RO(b_bits_per_pixel, bBitsPerPixel, 8);
+UVCG_FRAMEBASED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
+UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
+UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
+UVCG_FRAMEBASED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
+
+#undef UVCG_FRAMEBASED_ATTR
+#undef UVCG_FRAMEBASED_ATTR_RO
+
+static ssize_t uvcg_framebased_guid_format_show(struct config_item *item,
+ char *page)
+{
+ struct uvcg_framebased *ch = to_uvcg_framebased(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat));
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return sizeof(ch->desc.guidFormat);
+}
+
+static ssize_t uvcg_framebased_guid_format_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct uvcg_framebased *ch = to_uvcg_framebased(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
+ int ret;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ if (ch->fmt.linked || opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ memcpy(ch->desc.guidFormat, page,
+ min(sizeof(ch->desc.guidFormat), len));
+ ret = sizeof(ch->desc.guidFormat);
+
+end:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+UVC_ATTR(uvcg_framebased_, guid_format, guidFormat);
+
+static inline ssize_t
+uvcg_framebased_bma_controls_show(struct config_item *item, char *page)
+{
+ struct uvcg_framebased *u = to_uvcg_framebased(item);
+
+ return uvcg_format_bma_controls_show(&u->fmt, page);
+}
+
+static inline ssize_t
+uvcg_framebased_bma_controls_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct uvcg_framebased *u = to_uvcg_framebased(item);
+
+ return uvcg_format_bma_controls_store(&u->fmt, page, len);
+}
+
+UVC_ATTR(uvcg_framebased_, bma_controls, bmaControls);
+
+static struct configfs_attribute *uvcg_framebased_attrs[] = {
+ &uvcg_framebased_attr_b_format_index,
+ &uvcg_framebased_attr_b_default_frame_index,
+ &uvcg_framebased_attr_b_bits_per_pixel,
+ &uvcg_framebased_attr_b_aspect_ratio_x,
+ &uvcg_framebased_attr_b_aspect_ratio_y,
+ &uvcg_framebased_attr_bm_interface_flags,
+ &uvcg_framebased_attr_bma_controls,
+ &uvcg_framebased_attr_guid_format,
+ NULL,
+};
+
+static const struct config_item_type uvcg_framebased_type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_framebased_group_ops,
+ .ct_attrs = uvcg_framebased_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_framebased_make(struct config_group *group,
+ const char *name)
+{
+ static char guid[] = { /*Declear frame based as H264 format*/
+ 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+ };
+ struct uvcg_framebased *h;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->desc.bLength = UVC_DT_FORMAT_FRAMEBASED_SIZE;
+ h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ h->desc.bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED;
+ memcpy(h->desc.guidFormat, guid, sizeof(guid));
+ h->desc.bBitsPerPixel = 0;
+ h->desc.bDefaultFrameIndex = 1;
+ h->desc.bAspectRatioX = 0;
+ h->desc.bAspectRatioY = 0;
+ h->desc.bmInterfaceFlags = 0;
+ h->desc.bCopyProtect = 0;
+ h->desc.bVariableSize = 1;
+
+ INIT_LIST_HEAD(&h->fmt.frames);
+ h->fmt.type = UVCG_FRAMEBASED;
+ config_group_init_type_name(&h->fmt.group, name,
+ &uvcg_framebased_type);
+
+ return &h->fmt.group;
+}
+
+static struct configfs_group_operations uvcg_framebased_grp_ops = {
+ .make_group = uvcg_framebased_make,
+};
+
+static const struct uvcg_config_group_type uvcg_framebased_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_framebased_grp_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "framebased",
+};
+
+/* -----------------------------------------------------------------------------
* streaming/color_matching/default
*/
@@ -2912,6 +3190,7 @@ static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h,
if (ret)
return ret;
grp = &f->fmt->group;
+ j = 0;
list_for_each_entry(item, &grp->cg_children, ci_entry) {
frm = to_uvcg_frame(item);
ret = fun(frm, priv2, priv3, j++, UVCG_FRAME);
@@ -2965,6 +3244,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
container_of(fmt, struct uvcg_mjpeg, fmt);
*size += sizeof(m->desc);
+ } else if (fmt->type == UVCG_FRAMEBASED) {
+ struct uvcg_framebased *f =
+ container_of(fmt, struct uvcg_framebased, fmt);
+
+ *size += sizeof(f->desc);
} else {
return -EINVAL;
}
@@ -2975,6 +3259,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
int sz = sizeof(frm->dw_frame_interval);
*size += sizeof(frm->frame);
+ /*
+ * framebased has duplicate member with uncompressed and
+ * mjpeg, so minus it
+ */
+ *size -= sizeof(u32);
*size += frm->frame.b_frame_interval_type * sz;
}
break;
@@ -2991,6 +3280,27 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
return 0;
}
+static int __uvcg_copy_framebased_desc(void *dest, struct uvcg_frame *frm,
+ int sz)
+{
+ struct uvc_frame_framebased *desc = dest;
+
+ desc->bLength = frm->frame.b_length;
+ desc->bDescriptorType = frm->frame.b_descriptor_type;
+ desc->bDescriptorSubType = frm->frame.b_descriptor_subtype;
+ desc->bFrameIndex = frm->frame.b_frame_index;
+ desc->bmCapabilities = frm->frame.bm_capabilities;
+ desc->wWidth = frm->frame.w_width;
+ desc->wHeight = frm->frame.w_height;
+ desc->dwMinBitRate = frm->frame.dw_min_bit_rate;
+ desc->dwMaxBitRate = frm->frame.dw_max_bit_rate;
+ desc->dwDefaultFrameInterval = frm->frame.dw_default_frame_interval;
+ desc->bFrameIntervalType = frm->frame.b_frame_interval_type;
+ desc->dwBytesPerLine = frm->frame.dw_bytes_perline;
+
+ return 0;
+}
+
/*
* Fill an array of streaming descriptors.
*
@@ -3045,6 +3355,15 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
m->desc.bNumFrameDescriptors = fmt->num_frames;
memcpy(*dest, &m->desc, sizeof(m->desc));
*dest += sizeof(m->desc);
+ } else if (fmt->type == UVCG_FRAMEBASED) {
+ struct uvcg_framebased *f =
+ container_of(fmt, struct uvcg_framebased,
+ fmt);
+
+ f->desc.bFormatIndex = n + 1;
+ f->desc.bNumFrameDescriptors = fmt->num_frames;
+ memcpy(*dest, &f->desc, sizeof(f->desc));
+ *dest += sizeof(f->desc);
} else {
return -EINVAL;
}
@@ -3054,8 +3373,11 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
struct uvcg_frame *frm = priv1;
struct uvc_descriptor_header *h = *dest;
- sz = sizeof(frm->frame);
- memcpy(*dest, &frm->frame, sz);
+ sz = sizeof(frm->frame) - 4;
+ if (frm->fmt_type != UVCG_FRAMEBASED)
+ memcpy(*dest, &frm->frame, sz);
+ else
+ __uvcg_copy_framebased_desc(*dest, frm, sz);
*dest += sz;
sz = frm->frame.b_frame_interval_type *
sizeof(*frm->dw_frame_interval);
@@ -3066,7 +3388,10 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
frm->frame.b_frame_interval_type);
else if (frm->fmt_type == UVCG_MJPEG)
h->bLength = UVC_DT_FRAME_MJPEG_SIZE(
- frm->frame.b_frame_interval_type);
+ frm->frame.b_frame_interval_type);
+ else if (frm->fmt_type == UVCG_FRAMEBASED)
+ h->bLength = UVC_DT_FRAME_FRAMEBASED_SIZE(
+ frm->frame.b_frame_interval_type);
}
break;
case UVCG_COLOR_MATCHING: {
@@ -3285,6 +3610,7 @@ static const struct uvcg_config_group_type uvcg_streaming_grp_type = {
&uvcg_streaming_header_grp_type,
&uvcg_uncompressed_grp_type,
&uvcg_mjpeg_grp_type,
+ &uvcg_framebased_grp_type,
&uvcg_color_matching_grp_type,
&uvcg_streaming_class_grp_type,
NULL,
diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h
index c6a690158138..2f78cd4f396f 100644
--- a/drivers/usb/gadget/function/uvc_configfs.h
+++ b/drivers/usb/gadget/function/uvc_configfs.h
@@ -49,6 +49,7 @@ container_of(group_ptr, struct uvcg_color_matching, group)
enum uvcg_format_type {
UVCG_UNCOMPRESSED = 0,
UVCG_MJPEG,
+ UVCG_FRAMEBASED,
};
struct uvcg_format {
@@ -105,6 +106,7 @@ struct uvcg_frame {
u32 dw_max_video_frame_buffer_size;
u32 dw_default_frame_interval;
u8 b_frame_interval_type;
+ u32 dw_bytes_perline;
} __attribute__((packed)) frame;
u32 *dw_frame_interval;
};
@@ -143,6 +145,20 @@ static inline struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
}
/* -----------------------------------------------------------------------------
+ * streaming/framebased/<NAME>
+ */
+
+struct uvcg_framebased {
+ struct uvcg_format fmt;
+ struct uvc_format_framebased desc;
+};
+
+static inline struct uvcg_framebased *to_uvcg_framebased(struct config_item *item)
+{
+ return container_of(to_uvcg_format(item), struct uvcg_framebased, fmt);
+}
+
+/* -----------------------------------------------------------------------------
* control/extensions/<NAME>
*/
diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c
index 0aa3d7e1f3cc..5eaeae3e2441 100644
--- a/drivers/usb/gadget/function/uvc_queue.c
+++ b/drivers/usb/gadget/function/uvc_queue.c
@@ -21,6 +21,7 @@
#include <media/videobuf2-vmalloc.h>
#include "uvc.h"
+#include "uvc_video.h"
/* ------------------------------------------------------------------------
* Video buffers queue management.
@@ -44,33 +45,23 @@ static int uvc_queue_setup(struct vb2_queue *vq,
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
struct uvc_video *video = container_of(queue, struct uvc_video, queue);
- unsigned int req_size;
- unsigned int nreq;
if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
*nbuffers = UVC_MAX_VIDEO_BUFFERS;
+ if (*nbuffers < UVCG_STREAMING_MIN_BUFFERS)
+ *nbuffers = UVCG_STREAMING_MIN_BUFFERS;
*nplanes = 1;
sizes[0] = video->imagesize;
- req_size = video->ep->maxpacket
- * max_t(unsigned int, video->ep->maxburst, 1)
- * (video->ep->mult);
-
- /* We divide by two, to increase the chance to run
- * into fewer requests for smaller framesizes.
- */
- nreq = DIV_ROUND_UP(DIV_ROUND_UP(sizes[0], 2), req_size);
- nreq = clamp(nreq, 4U, 64U);
- video->uvc_num_requests = nreq;
-
return 0;
}
static int uvc_buffer_prepare(struct vb2_buffer *vb)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_video *video = container_of(queue, struct uvc_video, queue);
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct uvc_buffer *buf = container_of(vbuf, struct uvc_buffer, buf);
@@ -91,10 +82,15 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb)
buf->mem = vb2_plane_vaddr(vb, 0);
}
buf->length = vb2_plane_size(vb, 0);
- if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
buf->bytesused = 0;
- else
+ } else {
buf->bytesused = vb2_get_plane_payload(vb, 0);
+ buf->req_payload_size =
+ DIV_ROUND_UP(buf->bytesused +
+ (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN),
+ video->reqs_per_frame);
+ }
return 0;
}
diff --git a/drivers/usb/gadget/function/uvc_queue.h b/drivers/usb/gadget/function/uvc_queue.h
index 41f87b917f6b..b54becc570a3 100644
--- a/drivers/usb/gadget/function/uvc_queue.h
+++ b/drivers/usb/gadget/function/uvc_queue.h
@@ -39,6 +39,8 @@ struct uvc_buffer {
unsigned int offset;
unsigned int length;
unsigned int bytesused;
+ /* req_payload_size: only used with isoc */
+ unsigned int req_payload_size;
};
#define UVC_QUEUE_DISCONNECTED (1 << 0)
diff --git a/drivers/usb/gadget/function/uvc_trace.c b/drivers/usb/gadget/function/uvc_trace.c
new file mode 100644
index 000000000000..d384f6d8221a
--- /dev/null
+++ b/drivers/usb/gadget/function/uvc_trace.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * trace.c - USB UVC Gadget Trace Support
+ *
+ * Copyright (C) 2024 Pengutronix e.K.
+ *
+ * Author: Michael Grzeschik <m.grzeschik@pengutronix.de>
+ */
+
+#define CREATE_TRACE_POINTS
+#include "uvc_trace.h"
diff --git a/drivers/usb/gadget/function/uvc_trace.h b/drivers/usb/gadget/function/uvc_trace.h
new file mode 100644
index 000000000000..04c33cf43cc2
--- /dev/null
+++ b/drivers/usb/gadget/function/uvc_trace.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * trace.h - USB UVC Gadget Trace Support
+ *
+ * Copyright (C) 2024 Pengutronix e.K.
+ *
+ * Author: Michael Grzeschik <m.grzeschik@pengutronix.de>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM uvcg
+
+#if !defined(__UVCG_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __UVCG_TRACE_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <linux/usb/gadget.h>
+#include <asm/byteorder.h>
+
+DECLARE_EVENT_CLASS(uvcg_video_req,
+ TP_PROTO(struct usb_request *req, u32 queued),
+ TP_ARGS(req, queued),
+ TP_STRUCT__entry(
+ __field(struct usb_request *, req)
+ __field(u32, length)
+ __field(u32, queued)
+ ),
+ TP_fast_assign(
+ __entry->req = req;
+ __entry->length = req->length;
+ __entry->queued = queued;
+ ),
+ TP_printk("req %p length %u queued %u",
+ __entry->req,
+ __entry->length,
+ __entry->queued)
+);
+
+DEFINE_EVENT(uvcg_video_req, uvcg_video_complete,
+ TP_PROTO(struct usb_request *req, u32 queued),
+ TP_ARGS(req, queued)
+);
+
+DEFINE_EVENT(uvcg_video_req, uvcg_video_queue,
+ TP_PROTO(struct usb_request *req, u32 queued),
+ TP_ARGS(req, queued)
+);
+
+#endif /* __UVCG_TRACE_H */
+
+/* this part has to be here */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE uvc_trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index de1736f834e6..fc9a8d31a1e9 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -31,14 +31,23 @@ static const struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat)
{
char guid[16] = UVC_GUID_FORMAT_MJPEG;
const struct uvc_format_desc *format;
- struct uvcg_uncompressed *unc;
if (uformat->type == UVCG_UNCOMPRESSED) {
+ struct uvcg_uncompressed *unc;
+
unc = to_uvcg_uncompressed(&uformat->group.cg_item);
if (!unc)
return ERR_PTR(-EINVAL);
memcpy(guid, unc->desc.guidFormat, sizeof(guid));
+ } else if (uformat->type == UVCG_FRAMEBASED) {
+ struct uvcg_framebased *unc;
+
+ unc = to_uvcg_framebased(&uformat->group.cg_item);
+ if (!unc)
+ return ERR_PTR(-EINVAL);
+
+ memcpy(guid, unc->desc.guidFormat, sizeof(guid));
}
format = uvc_format_by_guid(guid);
@@ -314,6 +323,56 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
return ret;
}
+static int uvc_v4l2_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+ struct uvc_video *video = &uvc->video;
+ struct v4l2_fract timeperframe;
+
+ if (!V4L2_TYPE_IS_OUTPUT(parm->type))
+ return -EINVAL;
+
+ /* Return the actual frame period. */
+ timeperframe.numerator = video->interval;
+ timeperframe.denominator = 10000000;
+ v4l2_simplify_fraction(&timeperframe.numerator,
+ &timeperframe.denominator, 8, 333);
+
+ uvcg_dbg(&uvc->func, "Getting frame interval of %u/%u (%u)\n",
+ timeperframe.numerator, timeperframe.denominator,
+ video->interval);
+
+ parm->parm.output.timeperframe = timeperframe;
+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+
+ return 0;
+}
+
+static int uvc_v4l2_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+ struct uvc_video *video = &uvc->video;
+ struct v4l2_fract timeperframe;
+
+ if (!V4L2_TYPE_IS_OUTPUT(parm->type))
+ return -EINVAL;
+
+ timeperframe = parm->parm.output.timeperframe;
+
+ video->interval = v4l2_fraction_to_interval(timeperframe.numerator,
+ timeperframe.denominator);
+
+ uvcg_dbg(&uvc->func, "Setting frame interval to %u/%u (%u)\n",
+ timeperframe.numerator, timeperframe.denominator,
+ video->interval);
+
+ return 0;
+}
+
static int
uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *fival)
@@ -496,6 +555,9 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
return ret;
+ if (uvc->state != UVC_STATE_STREAMING)
+ return 0;
+
uvc->state = UVC_STATE_CONNECTED;
uvc_function_setup_continue(uvc, 1);
return 0;
@@ -587,6 +649,8 @@ const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
.vidioc_dqbuf = uvc_v4l2_dqbuf,
.vidioc_streamon = uvc_v4l2_streamon,
.vidioc_streamoff = uvc_v4l2_streamoff,
+ .vidioc_s_parm = uvc_v4l2_s_parm,
+ .vidioc_g_parm = uvc_v4l2_g_parm,
.vidioc_subscribe_event = uvc_v4l2_subscribe_event,
.vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event,
.vidioc_default = uvc_v4l2_ioctl_default,
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 57a851151225..79e223713d8b 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -19,6 +19,7 @@
#include "uvc.h"
#include "uvc_queue.h"
#include "uvc_video.h"
+#include "uvc_trace.h"
/* --------------------------------------------------------------------------
* Video codecs
@@ -78,7 +79,7 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
/* Copy video data to the USB buffer. */
mem = buf->mem + queue->buf_used;
- nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
+ nbytes = min_t(unsigned int, len, buf->bytesused - queue->buf_used);
memcpy(data, mem, nbytes);
queue->buf_used += nbytes;
@@ -104,7 +105,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
}
/* Process video data. */
- len = min((int)(video->max_payload_size - video->payload_size), len);
+ len = min_t(int, video->max_payload_size - video->payload_size, len);
ret = uvc_video_encode_data(video, buf, mem, len);
video->payload_size += ret;
@@ -136,7 +137,7 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video,
unsigned int pending = buf->bytesused - video->queue.buf_used;
struct uvc_request *ureq = req->context;
struct scatterlist *sg, *iter;
- unsigned int len = video->req_size;
+ unsigned int len = buf->req_payload_size;
unsigned int sg_left, part = 0;
unsigned int i;
int header_len;
@@ -146,15 +147,15 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video,
/* Init the header. */
header_len = uvc_video_encode_header(video, buf, ureq->header,
- video->req_size);
+ buf->req_payload_size);
sg_set_buf(sg, ureq->header, header_len);
len -= header_len;
if (pending <= len)
len = pending;
- req->length = (len == pending) ?
- len + header_len : video->req_size;
+ req->length = (len == pending) ? len + header_len :
+ buf->req_payload_size;
/* Init the pending sgs with payload */
sg = sg_next(sg);
@@ -202,7 +203,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
{
void *mem = req->buf;
struct uvc_request *ureq = req->context;
- int len = video->req_size;
+ int len = buf->req_payload_size;
int ret;
/* Add the header. */
@@ -214,7 +215,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
ret = uvc_video_encode_data(video, buf, mem, len);
len -= ret;
- req->length = video->req_size - len;
+ req->length = buf->req_payload_size - len;
if (buf->bytesused == video->queue.buf_used ||
video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE) {
@@ -269,6 +270,10 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
}
}
+ atomic_inc(&video->queued);
+
+ trace_uvcg_video_queue(req, atomic_read(&video->queued));
+
return ret;
}
@@ -304,7 +309,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
*/
if (list_empty(&video->req_free) || ureq->last_buf ||
!(video->req_int_count %
- DIV_ROUND_UP(video->uvc_num_requests, 4))) {
+ min(DIV_ROUND_UP(video->uvc_num_requests, 4), UVCG_REQ_MAX_INT_COUNT))) {
video->req_int_count = 0;
req->no_interrupt = 0;
} else {
@@ -322,50 +327,6 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
return 0;
}
-/*
- * Must only be called from uvcg_video_enable - since after that we only want to
- * queue requests to the endpoint from the uvc_video_complete complete handler.
- * This function is needed in order to 'kick start' the flow of requests from
- * gadget driver to the usb controller.
- */
-static void uvc_video_ep_queue_initial_requests(struct uvc_video *video)
-{
- struct usb_request *req = NULL;
- unsigned long flags = 0;
- unsigned int count = 0;
- int ret = 0;
-
- /*
- * We only queue half of the free list since we still want to have
- * some free usb_requests in the free list for the video_pump async_wq
- * thread to encode uvc buffers into. Otherwise we could get into a
- * situation where the free list does not have any usb requests to
- * encode into - we always end up queueing 0 length requests to the
- * end point.
- */
- unsigned int half_list_size = video->uvc_num_requests / 2;
-
- spin_lock_irqsave(&video->req_lock, flags);
- /*
- * Take these requests off the free list and queue them all to the
- * endpoint. Since we queue 0 length requests with the req_lock held,
- * there isn't any 'data' race involved here with the complete handler.
- */
- while (count < half_list_size) {
- req = list_first_entry(&video->req_free, struct usb_request,
- list);
- list_del(&req->list);
- req->length = 0;
- ret = uvcg_video_ep_queue(video, req);
- if (ret < 0) {
- uvcg_queue_cancel(&video->queue, 0);
- break;
- }
- count++;
- }
- spin_unlock_irqrestore(&video->req_lock, flags);
-}
-
static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
{
@@ -373,12 +334,10 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
struct uvc_video *video = ureq->video;
struct uvc_video_queue *queue = &video->queue;
struct uvc_buffer *last_buf;
- struct usb_request *to_queue = req;
unsigned long flags;
- bool is_bulk = video->max_payload_size;
- int ret = 0;
spin_lock_irqsave(&video->req_lock, flags);
+ atomic_dec(&video->queued);
if (!video->is_enabled) {
/*
* When is_enabled is false, uvcg_video_disable() ensures
@@ -438,51 +397,87 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
return;
}
+ list_add_tail(&req->list, &video->req_free);
/*
- * Here we check whether any request is available in the ready
- * list. If it is, queue it to the ep and add the current
- * usb_request to the req_free list - for video_pump to fill in.
- * Otherwise, just use the current usb_request to queue a 0
- * length request to the ep. Since we always add to the req_free
- * list if we dequeue from the ready list, there will never
- * be a situation where the req_free list is completely out of
- * requests and cannot recover.
+ * Queue work to the wq as well since it is possible that a
+ * buffer may not have been completely encoded with the set of
+ * in-flight usb requests for whih the complete callbacks are
+ * firing.
+ * In that case, if we do not queue work to the worker thread,
+ * the buffer will never be marked as complete - and therefore
+ * not be returned to userpsace. As a result,
+ * dequeue -> queue -> dequeue flow of uvc buffers will not
+ * happen. Since there are is a new free request wake up the pump.
*/
- to_queue->length = 0;
- if (!list_empty(&video->req_ready)) {
- to_queue = list_first_entry(&video->req_ready,
- struct usb_request, list);
- list_del(&to_queue->list);
- list_add_tail(&req->list, &video->req_free);
+ queue_work(video->async_wq, &video->pump);
+
+ trace_uvcg_video_complete(req, atomic_read(&video->queued));
+
+ spin_unlock_irqrestore(&video->req_lock, flags);
+
+ kthread_queue_work(video->kworker, &video->hw_submit);
+}
+
+static void uvcg_video_hw_submit(struct kthread_work *work)
+{
+ struct uvc_video *video = container_of(work, struct uvc_video, hw_submit);
+ bool is_bulk = video->max_payload_size;
+ unsigned long flags;
+ struct usb_request *req;
+ int ret = 0;
+
+ while (true) {
+ if (!video->ep->enabled)
+ return;
+ spin_lock_irqsave(&video->req_lock, flags);
/*
- * Queue work to the wq as well since it is possible that a
- * buffer may not have been completely encoded with the set of
- * in-flight usb requests for whih the complete callbacks are
- * firing.
- * In that case, if we do not queue work to the worker thread,
- * the buffer will never be marked as complete - and therefore
- * not be returned to userpsace. As a result,
- * dequeue -> queue -> dequeue flow of uvc buffers will not
- * happen.
+ * Here we check whether any request is available in the ready
+ * list. If it is, queue it to the ep and add the current
+ * usb_request to the req_free list - for video_pump to fill in.
+ * Otherwise, just use the current usb_request to queue a 0
+ * length request to the ep. Since we always add to the req_free
+ * list if we dequeue from the ready list, there will never
+ * be a situation where the req_free list is completely out of
+ * requests and cannot recover.
*/
- queue_work(video->async_wq, &video->pump);
- }
- /*
- * Queue to the endpoint. The actual queueing to ep will
- * only happen on one thread - the async_wq for bulk endpoints
- * and this thread for isoc endpoints.
- */
- ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk);
- if (ret < 0) {
+ if (!list_empty(&video->req_ready)) {
+ req = list_first_entry(&video->req_ready,
+ struct usb_request, list);
+ } else {
+ if (list_empty(&video->req_free) ||
+ (atomic_read(&video->queued) > UVCG_REQ_MAX_ZERO_COUNT)) {
+ spin_unlock_irqrestore(&video->req_lock, flags);
+
+ return;
+ }
+ req = list_first_entry(&video->req_free, struct usb_request,
+ list);
+ req->length = 0;
+ }
+ list_del(&req->list);
+
/*
- * Endpoint error, but the stream is still enabled.
- * Put request back in req_free for it to be cleaned
- * up later.
+ * Queue to the endpoint. The actual queueing to ep will
+ * only happen on one thread - the async_wq for bulk endpoints
+ * and this thread for isoc endpoints.
*/
- list_add_tail(&to_queue->list, &video->req_free);
- }
+ ret = uvcg_video_usb_req_queue(video, req, !is_bulk);
+ if (ret < 0) {
+ /*
+ * Endpoint error, but the stream is still enabled.
+ * Put request back in req_free for it to be cleaned
+ * up later.
+ */
+ list_add_tail(&req->list, &video->req_free);
+ /*
+ * There is a new free request - wake up the pump.
+ */
+ queue_work(video->async_wq, &video->pump);
- spin_unlock_irqrestore(&video->req_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&video->req_lock, flags);
+ }
}
static int
@@ -496,23 +491,71 @@ uvc_video_free_requests(struct uvc_video *video)
INIT_LIST_HEAD(&video->ureqs);
INIT_LIST_HEAD(&video->req_free);
INIT_LIST_HEAD(&video->req_ready);
- video->req_size = 0;
return 0;
}
+static void
+uvc_video_prep_requests(struct uvc_video *video)
+{
+ struct uvc_device *uvc = container_of(video, struct uvc_device, video);
+ struct usb_composite_dev *cdev = uvc->func.config->cdev;
+ unsigned int interval_duration = video->ep->desc->bInterval * 1250;
+ unsigned int max_req_size, req_size, header_size;
+ unsigned int nreq;
+
+ max_req_size = video->ep->maxpacket
+ * max_t(unsigned int, video->ep->maxburst, 1)
+ * (video->ep->mult);
+
+ if (!usb_endpoint_xfer_isoc(video->ep->desc)) {
+ video->req_size = max_req_size;
+ video->reqs_per_frame = video->uvc_num_requests =
+ DIV_ROUND_UP(video->imagesize, max_req_size);
+
+ return;
+ }
+
+ if (cdev->gadget->speed < USB_SPEED_HIGH)
+ interval_duration = video->ep->desc->bInterval * 10000;
+
+ nreq = DIV_ROUND_UP(video->interval, interval_duration);
+
+ header_size = nreq * UVCG_REQUEST_HEADER_LEN;
+
+ req_size = DIV_ROUND_UP(video->imagesize + header_size, nreq);
+
+ if (req_size > max_req_size) {
+ /* The prepared interval length and expected buffer size
+ * is not possible to stream with the currently configured
+ * isoc bandwidth. Fallback to the maximum.
+ */
+ req_size = max_req_size;
+ }
+ video->req_size = req_size;
+
+ /* We need to compensate the amount of requests to be
+ * allocated with the maximum amount of zero length requests.
+ * Since it is possible that hw_submit will initially
+ * enqueue some zero length requests and we then will not be
+ * able to fully encode one frame.
+ */
+ video->uvc_num_requests = nreq + UVCG_REQ_MAX_ZERO_COUNT;
+ video->reqs_per_frame = nreq;
+}
+
static int
uvc_video_alloc_requests(struct uvc_video *video)
{
struct uvc_request *ureq;
- unsigned int req_size;
unsigned int i;
int ret = -ENOMEM;
- BUG_ON(video->req_size);
-
- req_size = video->ep->maxpacket
- * max_t(unsigned int, video->ep->maxburst, 1)
- * (video->ep->mult);
+ /*
+ * calculate in uvc_video_prep_requests
+ * - video->uvc_num_requests
+ * - video->req_size
+ */
+ uvc_video_prep_requests(video);
for (i = 0; i < video->uvc_num_requests; i++) {
ureq = kzalloc(sizeof(struct uvc_request), GFP_KERNEL);
@@ -523,7 +566,7 @@ uvc_video_alloc_requests(struct uvc_video *video)
list_add_tail(&ureq->list, &video->ureqs);
- ureq->req_buffer = kmalloc(req_size, GFP_KERNEL);
+ ureq->req_buffer = kmalloc(video->req_size, GFP_KERNEL);
if (ureq->req_buffer == NULL)
goto error;
@@ -541,12 +584,10 @@ uvc_video_alloc_requests(struct uvc_video *video)
list_add_tail(&ureq->req->list, &video->req_free);
/* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */
sg_alloc_table(&ureq->sgt,
- DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN,
+ DIV_ROUND_UP(video->req_size - UVCG_REQUEST_HEADER_LEN,
PAGE_SIZE) + 2, GFP_KERNEL);
}
- video->req_size = req_size;
-
return 0;
error:
@@ -699,7 +740,6 @@ uvcg_video_disable(struct uvc_video *video)
INIT_LIST_HEAD(&video->ureqs);
INIT_LIST_HEAD(&video->req_free);
INIT_LIST_HEAD(&video->req_ready);
- video->req_size = 0;
spin_unlock_irqrestore(&video->req_lock, flags);
/*
@@ -752,7 +792,9 @@ int uvcg_video_enable(struct uvc_video *video)
video->req_int_count = 0;
- uvc_video_ep_queue_initial_requests(video);
+ atomic_set(&video->queued, 0);
+
+ kthread_queue_work(video->kworker, &video->hw_submit);
queue_work(video->async_wq, &video->pump);
return ret;
@@ -775,12 +817,24 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
if (!video->async_wq)
return -EINVAL;
+ /* Allocate a kthread for asynchronous hw submit handler. */
+ video->kworker = kthread_create_worker(0, "UVCG");
+ if (IS_ERR(video->kworker)) {
+ uvcg_err(&video->uvc->func, "failed to create UVCG kworker\n");
+ return PTR_ERR(video->kworker);
+ }
+
+ kthread_init_work(&video->hw_submit, uvcg_video_hw_submit);
+
+ sched_set_fifo(video->kworker->task);
+
video->uvc = uvc;
video->fcc = V4L2_PIX_FMT_YUYV;
video->bpp = 16;
video->width = 320;
video->height = 240;
video->imagesize = 320 * 240 * 2;
+ video->interval = 666666;
/* Initialize the video buffers queue. */
uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent,
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
index 4ca67b2f8f24..3684546e8801 100644
--- a/drivers/usb/gadget/legacy/hid.c
+++ b/drivers/usb/gadget/legacy/hid.c
@@ -261,7 +261,7 @@ static struct usb_composite_driver hidg_driver = {
};
static struct platform_driver hidg_plat_driver = {
- .remove_new = hidg_plat_driver_remove,
+ .remove = hidg_plat_driver_remove,
.driver = {
.name = "hidg",
},
diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 112fd18d8c99..20165e1582d9 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -782,7 +782,7 @@ static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
if (ret < 0)
goto free;
- length = min(io.length, (unsigned int)ret);
+ length = min_t(unsigned int, io.length, ret);
if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
ret = -EFAULT;
else
@@ -1168,7 +1168,7 @@ static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value)
if (ret < 0)
goto free;
- length = min(io.length, (unsigned int)ret);
+ length = min_t(unsigned int, io.length, ret);
if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
ret = -EFAULT;
else
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c
index f60a019bb173..f2685f89b3e5 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/core.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c
@@ -428,7 +428,7 @@ MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids);
static struct platform_driver ast_vhub_driver = {
.probe = ast_vhub_probe,
- .remove_new = ast_vhub_remove,
+ .remove = ast_vhub_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = ast_vhub_dt_ids,
diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c
index f4781e611aaa..353bfb1ff0a1 100644
--- a/drivers/usb/gadget/udc/aspeed_udc.c
+++ b/drivers/usb/gadget/udc/aspeed_udc.c
@@ -156,7 +156,7 @@
#define AST_EP_DMA_DESC_PID_DATA1 (2 << 14)
#define AST_EP_DMA_DESC_PID_MDATA (3 << 14)
#define EP_DESC1_IN_LEN(x) ((x) & 0x1fff)
-#define AST_EP_DMA_DESC_MAX_LEN (7680) /* Max packet length for trasmit in 1 desc */
+#define AST_EP_DMA_DESC_MAX_LEN (7680) /* Max packet length for transmit in 1 desc */
struct ast_udc_request {
struct usb_request req;
@@ -1590,7 +1590,7 @@ MODULE_DEVICE_TABLE(of, ast_udc_of_dt_ids);
static struct platform_driver ast_udc_driver = {
.probe = ast_udc_probe,
- .remove_new = ast_udc_remove,
+ .remove = ast_udc_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = ast_udc_of_dt_ids,
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index e3bf17a98b38..e3af4ec3794e 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -2002,7 +2002,7 @@ static int at91udc_resume(struct platform_device *pdev)
static struct platform_driver at91_udc_driver = {
.probe = at91udc_probe,
- .remove_new = at91udc_remove,
+ .remove = at91udc_remove,
.shutdown = at91udc_shutdown,
.suspend = at91udc_suspend,
.resume = at91udc_resume,
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 4928eba19327..0c6f2ad81d37 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -2444,7 +2444,7 @@ static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
static struct platform_driver udc_driver = {
.probe = usba_udc_probe,
- .remove_new = usba_udc_remove,
+ .remove = usba_udc_remove,
.driver = {
.name = "atmel_usba_udc",
.pm = &usba_udc_pm_ops,
diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c
index da7011d906e0..502612a5650e 100644
--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
+++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
@@ -2367,7 +2367,7 @@ static void bcm63xx_udc_remove(struct platform_device *pdev)
static struct platform_driver bcm63xx_udc_driver = {
.probe = bcm63xx_udc_probe,
- .remove_new = bcm63xx_udc_remove,
+ .remove = bcm63xx_udc_remove,
.driver = {
.name = DRV_MODULE_NAME,
},
diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
index 5149e2b7f050..5c3d8b64c0e7 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_core.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
@@ -648,7 +648,7 @@ static struct platform_driver bdc_driver = {
.of_match_table = bdc_of_match,
},
.probe = bdc_probe,
- .remove_new = bdc_remove,
+ .remove = bdc_remove,
};
module_platform_driver(bdc_driver);
diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-pci.c b/drivers/usb/gadget/udc/cdns2/cdns2-pci.c
index b1a8f772467c..e589593b4cbf 100644
--- a/drivers/usb/gadget/udc/cdns2/cdns2-pci.c
+++ b/drivers/usb/gadget/udc/cdns2/cdns2-pci.c
@@ -15,7 +15,6 @@
#include "cdns2-gadget.h"
#define PCI_DRIVER_NAME "cdns-pci-usbhs"
-#define PCI_DEVICE_ID_CDNS_USB2 0x0120
#define PCI_BAR_DEV 0
#define PCI_DEV_FN_DEVICE 0
@@ -113,7 +112,7 @@ static const struct dev_pm_ops cdns2_pci_pm_ops = {
};
static const struct pci_device_id cdns2_pci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB2),
+ { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB),
.class = PCI_CLASS_SERIAL_USB_DEVICE },
{ 0, }
};
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 081ac7683c0b..a7e8fa45776b 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -80,7 +80,7 @@ module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC(num, "number of emulated controllers");
/*-------------------------------------------------------------------------*/
-/* gadget side driver data structres */
+/* gadget side driver data structures */
struct dummy_ep {
struct list_head queue;
unsigned long last_io; /* jiffies timestamp */
@@ -1152,7 +1152,7 @@ static int dummy_udc_resume(struct platform_device *pdev)
static struct platform_driver dummy_udc_driver = {
.probe = dummy_udc_probe,
- .remove_new = dummy_udc_remove,
+ .remove = dummy_udc_remove,
.suspend = dummy_udc_suspend,
.resume = dummy_udc_resume,
.driver = {
@@ -2769,7 +2769,7 @@ static int dummy_hcd_resume(struct platform_device *pdev)
static struct platform_driver dummy_hcd_driver = {
.probe = dummy_hcd_probe,
- .remove_new = dummy_hcd_remove,
+ .remove = dummy_hcd_remove,
.suspend = dummy_hcd_suspend,
.resume = dummy_hcd_resume,
.driver = {
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index 4e88681a79b6..aacfde06387c 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -511,7 +511,7 @@ static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num)
out_8(&epparam->tbmr, rtfcr);
tmp = (u16)(ep->ep.maxpacket + USB_CRC_SIZE);
- /* MRBLR must be divisble by 4 */
+ /* MRBLR must be divisible by 4 */
tmp = (u16)(((tmp >> 2) << 2) + 4);
out_be16(&epparam->mrblr, tmp);
@@ -1413,7 +1413,7 @@ static int ep_txframe_handle(struct qe_ep *ep)
return 0;
}
-/* confirm the already trainsmited bd */
+/* confirm the already transmitted bd */
static int qe_ep_txconf(struct qe_ep *ep)
{
struct qe_bd __iomem *bd;
@@ -2196,7 +2196,7 @@ static int tx_irq(struct qe_udc *udc)
}
-/* setup packect's rx is handle in the function too */
+/* setup packet's rx is handle in the function too */
static void rx_irq(struct qe_udc *udc)
{
struct qe_ep *ep;
@@ -2704,7 +2704,7 @@ static struct platform_driver udc_driver = {
.of_match_table = qe_udc_match,
},
.probe = qe_udc_probe,
- .remove_new = qe_udc_remove,
+ .remove = qe_udc_remove,
#ifdef CONFIG_PM
.suspend = qe_udc_suspend,
.resume = qe_udc_resume,
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index 0cabd4eee6ac..8b7f7f961774 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -2685,7 +2685,7 @@ MODULE_DEVICE_TABLE(of, fsl_udc_dt_ids);
static struct platform_driver udc_driver = {
.probe = fsl_udc_probe,
- .remove_new = fsl_udc_remove,
+ .remove = fsl_udc_remove,
.id_table = fsl_udc_devtype,
/* these suspend and resume are not usb suspend and resume */
.suspend = fsl_udc_suspend,
diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c
index 873265634ccc..5e94a99b3e53 100644
--- a/drivers/usb/gadget/udc/fusb300_udc.c
+++ b/drivers/usb/gadget/udc/fusb300_udc.c
@@ -1297,7 +1297,7 @@ static void init_controller(struct fusb300 *fusb300)
reg |= val;
iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR);
- /*set u1 u2 timmer*/
+ /*set u1 u2 timer*/
fusb300_set_u2_timeout(fusb300, 0xff);
fusb300_set_u1_timeout(fusb300, 0xff);
@@ -1507,7 +1507,7 @@ clean_up:
static struct platform_driver fusb300_driver = {
.probe = fusb300_probe,
- .remove_new = fusb300_remove,
+ .remove = fusb300_remove,
.driver = {
.name = udc_name,
},
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index fb901be5dac1..bf5b3c964c18 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -2249,7 +2249,7 @@ static struct platform_driver gr_driver = {
.of_match_table = gr_match,
},
.probe = gr_probe,
- .remove_new = gr_remove,
+ .remove = gr_remove,
};
module_platform_driver(gr_driver);
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 3bfd889ed56a..89d6daf2bda7 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -3249,7 +3249,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match);
static struct platform_driver lpc32xx_udc_driver = {
.probe = lpc32xx_udc_probe,
- .remove_new = lpc32xx_udc_remove,
+ .remove = lpc32xx_udc_remove,
.shutdown = lpc32xx_udc_shutdown,
.suspend = lpc32xx_udc_suspend,
.resume = lpc32xx_udc_resume,
diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c
index bfaa5291e6c8..a938b2af0944 100644
--- a/drivers/usb/gadget/udc/m66592-udc.c
+++ b/drivers/usb/gadget/udc/m66592-udc.c
@@ -1688,7 +1688,7 @@ clean_up:
/*-------------------------------------------------------------------------*/
static struct platform_driver m66592_driver = {
.probe = m66592_probe,
- .remove_new = m66592_remove,
+ .remove = m66592_remove,
.driver = {
.name = udc_name,
},
diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c
index e1dd5cf25d08..062f43e146aa 100644
--- a/drivers/usb/gadget/udc/mv_u3d_core.c
+++ b/drivers/usb/gadget/udc/mv_u3d_core.c
@@ -2047,7 +2047,7 @@ static void mv_u3d_shutdown(struct platform_device *dev)
static struct platform_driver mv_u3d_driver = {
.probe = mv_u3d_probe,
- .remove_new = mv_u3d_remove,
+ .remove = mv_u3d_remove,
.shutdown = mv_u3d_shutdown,
.driver = {
.name = "mv-u3d",
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 71012b282891..ff103e6b3048 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -2409,7 +2409,7 @@ static void mv_udc_shutdown(struct platform_device *pdev)
static struct platform_driver udc_driver = {
.probe = mv_udc_probe,
- .remove_new = mv_udc_remove,
+ .remove = mv_udc_remove,
.shutdown = mv_udc_shutdown,
.driver = {
.name = "mv-udc",
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index 9230db57dab7..7ecddbf5c90d 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -2097,7 +2097,7 @@ static irqreturn_t net2272_irq(int irq, void *_dev)
}
/* check dma interrupts */
#endif
- /* Platform/devcice interrupt handler */
+ /* Platform/device interrupt handler */
#if !defined(PLX_PCI_RDK)
net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1));
net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0));
@@ -2685,7 +2685,7 @@ net2272_plat_remove(struct platform_device *pdev)
static struct platform_driver net2272_plat_driver = {
.probe = net2272_plat_probe,
- .remove_new = net2272_plat_remove,
+ .remove = net2272_plat_remove,
.driver = {
.name = driver_name,
},
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 61a45e4657d5..698463bf697b 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -576,13 +576,13 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
{
- unsigned packets = req->req.length - req->req.actual;
+ unsigned int packets = req->req.length - req->req.actual;
int dma_trigger = 0;
u16 w;
/* set up this DMA transfer, enable the fifo, start */
packets /= ep->ep.maxpacket;
- packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+ packets = min_t(unsigned int, packets, UDC_RXN_TC + 1);
req->dma_bytes = packets * ep->ep.maxpacket;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, packets,
@@ -2980,7 +2980,7 @@ static int omap_udc_resume(struct platform_device *dev)
static struct platform_driver udc_driver = {
.probe = omap_udc_probe,
- .remove_new = omap_udc_remove,
+ .remove = omap_udc_remove,
.suspend = omap_udc_suspend,
.resume = omap_udc_resume,
.driver = {
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index 7c96fc9f680f..1e9998024aaa 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -2474,7 +2474,7 @@ static int pxa25x_udc_resume(struct platform_device *dev)
static struct platform_driver udc_driver = {
.shutdown = pxa25x_udc_shutdown,
.probe = pxa25x_udc_probe,
- .remove_new = pxa25x_udc_remove,
+ .remove = pxa25x_udc_remove,
.suspend = pxa25x_udc_suspend,
.resume = pxa25x_udc_resume,
.driver = {
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index ea79f85f8e0b..f9a55d4f189f 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -2539,7 +2539,7 @@ static struct platform_driver udc_driver = {
.of_match_table = of_match_ptr(udc_pxa_dt_ids),
},
.probe = pxa_udc_probe,
- .remove_new = pxa_udc_remove,
+ .remove = pxa_udc_remove,
.shutdown = pxa_udc_shutdown,
#ifdef CONFIG_PM
.suspend = pxa_udc_suspend,
diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c
index db4a10a979f9..ff6f846b1d41 100644
--- a/drivers/usb/gadget/udc/r8a66597-udc.c
+++ b/drivers/usb/gadget/udc/r8a66597-udc.c
@@ -1965,7 +1965,7 @@ clean_up2:
/*-------------------------------------------------------------------------*/
static struct platform_driver r8a66597_driver = {
.probe = r8a66597_probe,
- .remove_new = r8a66597_remove,
+ .remove = r8a66597_remove,
.driver = {
.name = udc_name,
},
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 3b01734ce1b7..fce5c41d9f29 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -3013,7 +3013,7 @@ static SIMPLE_DEV_PM_OPS(renesas_usb3_pm_ops, renesas_usb3_suspend,
static struct platform_driver renesas_usb3_driver = {
.probe = renesas_usb3_probe,
- .remove_new = renesas_usb3_remove,
+ .remove = renesas_usb3_remove,
.driver = {
.name = udc_name,
.pm = &renesas_usb3_pm_ops,
diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c
index 657f265ac7cc..14f4b2cf05a4 100644
--- a/drivers/usb/gadget/udc/renesas_usbf.c
+++ b/drivers/usb/gadget/udc/renesas_usbf.c
@@ -2482,7 +2482,7 @@ static int usbf_handle_ep0_setup(struct usbf_ep *ep0)
ep0->delayed_status = 0;
if ((crq.ctrlreq.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) {
- /* This is not a USB standard request -> delelate */
+ /* This is not a USB standard request -> delegate */
goto delegate;
}
@@ -3381,7 +3381,7 @@ static struct platform_driver udc_driver = {
.of_match_table = usbf_match,
},
.probe = usbf_probe,
- .remove_new = usbf_remove,
+ .remove = usbf_remove,
};
module_platform_driver(udc_driver);
diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c
index 36f4ff00d22f..4692eae89f44 100644
--- a/drivers/usb/gadget/udc/rzv2m_usb3drd.c
+++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c
@@ -127,7 +127,7 @@ static struct platform_driver rzv2m_usb3drd_driver = {
.of_match_table = rzv2m_usb3drd_of_match,
},
.probe = rzv2m_usb3drd_probe,
- .remove_new = rzv2m_usb3drd_remove,
+ .remove = rzv2m_usb3drd_remove,
};
module_platform_driver(rzv2m_usb3drd_driver);
diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c
index cd89532adec2..1f8a99d2a643 100644
--- a/drivers/usb/gadget/udc/snps_udc_core.c
+++ b/drivers/usb/gadget/udc/snps_udc_core.c
@@ -2707,7 +2707,7 @@ static irqreturn_t udc_control_in_isr(struct udc *dev)
/* write fifo */
udc_txfifo_write(ep, &req->req);
- /* lengh bytes transferred */
+ /* length bytes transferred */
len = req->req.length - req->req.actual;
if (len > ep->ep.maxpacket)
len = ep->ep.maxpacket;
diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c
index ba5a06690507..db842a6de643 100644
--- a/drivers/usb/gadget/udc/snps_udc_plat.c
+++ b/drivers/usb/gadget/udc/snps_udc_plat.c
@@ -309,7 +309,7 @@ MODULE_DEVICE_TABLE(of, of_udc_match);
static struct platform_driver udc_plat_driver = {
.probe = udc_plat_probe,
- .remove_new = udc_plat_remove,
+ .remove = udc_plat_remove,
.driver = {
.name = "snps-udc-plat",
.of_match_table = of_udc_match,
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index 7aa46d426f31..c7fdbc55fb0b 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -4071,7 +4071,7 @@ static const struct dev_pm_ops tegra_xudc_pm_ops = {
static struct platform_driver tegra_xudc_driver = {
.probe = tegra_xudc_probe,
- .remove_new = tegra_xudc_remove,
+ .remove = tegra_xudc_remove,
.driver = {
.name = "tegra-xudc",
.pm = &tegra_xudc_pm_ops,
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index ebc45565c33e..ae2aeb271897 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -2258,7 +2258,7 @@ static struct platform_driver xudc_driver = {
.pm = &xudc_pm_ops,
},
.probe = xudc_probe,
- .remove_new = xudc_remove,
+ .remove = xudc_remove,
};
module_platform_driver(xudc_driver);
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 75f6f99f8173..37a2f1b61cba 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -55,7 +55,7 @@ usb_gadget_get_string (const struct usb_gadget_strings *table, int id, u8 *buf)
return -EINVAL;
/* string descriptors have length, tag, then UTF16-LE text */
- len = min((size_t)USB_MAX_STRING_LEN, strlen(s->s));
+ len = min_t(size_t, USB_MAX_STRING_LEN, strlen(s->s));
len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
(wchar_t *) &buf[2], USB_MAX_STRING_LEN);
if (len < 0)
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index 7558cc4d90cc..519386255886 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/usb/ehci_pdriver.h>
#include <linux/usb/ohci_pdriver.h>
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 6a6e1c510b28..65747270fd88 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -220,7 +220,7 @@ static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
static struct platform_driver ehci_atmel_driver = {
.probe = ehci_atmel_drv_probe,
- .remove_new = ehci_atmel_drv_remove,
+ .remove = ehci_atmel_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "atmel-ehci",
diff --git a/drivers/usb/host/ehci-brcm.c b/drivers/usb/host/ehci-brcm.c
index 68cad0620f1a..888e8f6670d2 100644
--- a/drivers/usb/host/ehci-brcm.c
+++ b/drivers/usb/host/ehci-brcm.c
@@ -250,7 +250,7 @@ MODULE_DEVICE_TABLE(of, brcm_ehci_of_match);
static struct platform_driver ehci_brcm_driver = {
.probe = ehci_brcm_probe,
- .remove_new = ehci_brcm_remove,
+ .remove = ehci_brcm_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ehci-brcm",
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index e3a961d3f5fc..d2a5bedf736a 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, exynos_ehci_match);
static struct platform_driver exynos_ehci_driver = {
.probe = exynos_ehci_probe,
- .remove_new = exynos_ehci_remove,
+ .remove = exynos_ehci_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "exynos-ehci",
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 5b1ce394a417..26f13278d4d6 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -706,7 +706,7 @@ static void fsl_ehci_drv_remove(struct platform_device *pdev)
static struct platform_driver ehci_fsl_driver = {
.probe = fsl_ehci_drv_probe,
- .remove_new = fsl_ehci_drv_remove,
+ .remove = fsl_ehci_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = DRV_NAME,
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index 14150e4d3382..bd9762eaa135 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -168,7 +168,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
static struct platform_driver ehci_grlib_driver = {
.probe = ehci_hcd_grlib_probe,
- .remove_new = ehci_hcd_grlib_remove,
+ .remove = ehci_hcd_grlib_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "grlib-ehci",
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index cbc0b86fcc36..6de79ac5e6a4 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -547,7 +547,7 @@ static int ehci_init(struct usb_hcd *hcd)
* make problems: throughput reduction (!), data errors...
*/
if (park) {
- park = min(park, (unsigned) 3);
+ park = min_t(unsigned int, park, 3);
temp |= CMD_PARK;
temp |= park << 8;
}
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 2f1fc7eb8b72..cbabbe107172 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -279,7 +279,7 @@ static const struct of_device_id ehci_mv_dt_ids[] = {
static struct platform_driver ehci_mv_driver = {
.probe = mv_ehci_probe,
- .remove_new = mv_ehci_remove,
+ .remove = mv_ehci_remove,
.shutdown = mv_ehci_shutdown,
.driver = {
.name = "mv-ehci",
diff --git a/drivers/usb/host/ehci-npcm7xx.c b/drivers/usb/host/ehci-npcm7xx.c
index 3d3317a1a0b3..f1c7034c1e80 100644
--- a/drivers/usb/host/ehci-npcm7xx.c
+++ b/drivers/usb/host/ehci-npcm7xx.c
@@ -122,7 +122,7 @@ MODULE_DEVICE_TABLE(of, npcm7xx_ehci_id_table);
static struct platform_driver npcm7xx_ehci_hcd_driver = {
.probe = npcm7xx_ehci_hcd_drv_probe,
- .remove_new = npcm7xx_ehci_hcd_drv_remove,
+ .remove = npcm7xx_ehci_hcd_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "npcm7xx-ehci",
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index b24f371a46f3..db4a1acb27da 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids);
static struct platform_driver ehci_hcd_omap_driver = {
.probe = ehci_hcd_omap_probe,
- .remove_new = ehci_hcd_omap_remove,
+ .remove = ehci_hcd_omap_remove,
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ehci_hcd_omap_suspend, */
/*.resume = ehci_hcd_omap_resume, */
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index ad145a54ca74..34abff8669f8 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -352,7 +352,7 @@ MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids);
static struct platform_driver ehci_orion_driver = {
.probe = ehci_orion_drv_probe,
- .remove_new = ehci_orion_drv_remove,
+ .remove = ehci_orion_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "orion-ehci",
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 98b073185e1c..cdf41886e8ca 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -508,7 +508,7 @@ static SIMPLE_DEV_PM_OPS(ehci_platform_pm_ops, ehci_platform_suspend,
static struct platform_driver ehci_platform_driver = {
.id_table = ehci_platform_table,
.probe = ehci_platform_probe,
- .remove_new = ehci_platform_remove,
+ .remove = ehci_platform_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ehci-platform",
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 7fd83e806ae4..8063b9d3aebd 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -230,7 +230,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
static struct platform_driver ehci_hcd_ppc_of_driver = {
.probe = ehci_hcd_ppc_of_probe,
- .remove_new = ehci_hcd_ppc_of_remove,
+ .remove = ehci_hcd_ppc_of_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-of-ehci",
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index d31d9506e41a..5d0d972fb7b1 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -169,7 +169,7 @@ static void ehci_hcd_sh_shutdown(struct platform_device *pdev)
static struct platform_driver ehci_hcd_sh_driver = {
.probe = ehci_hcd_sh_probe,
- .remove_new = ehci_hcd_sh_remove,
+ .remove = ehci_hcd_sh_remove,
.shutdown = ehci_hcd_sh_shutdown,
.driver = {
.name = "sh_ehci",
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index d0e94e4c9fe2..e96710192d6b 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -105,7 +105,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
/* registers start at offset 0x0 */
hcd_to_ehci(hcd)->caps = hcd->regs;
- clk_prepare_enable(sehci->clk);
+ retval = clk_prepare_enable(sehci->clk);
+ if (retval)
+ goto err_put_hcd;
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto err_stop_ehci;
@@ -130,8 +132,7 @@ static void spear_ehci_hcd_drv_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
- if (sehci->clk)
- clk_disable_unprepare(sehci->clk);
+ clk_disable_unprepare(sehci->clk);
usb_put_hcd(hcd);
}
@@ -143,7 +144,7 @@ MODULE_DEVICE_TABLE(of, spear_ehci_id_table);
static struct platform_driver spear_ehci_hcd_driver = {
.probe = spear_ehci_hcd_drv_probe,
- .remove_new = spear_ehci_hcd_drv_remove,
+ .remove = spear_ehci_hcd_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "spear-ehci",
diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c
index 2dbb0d86daaa..58867d816af7 100644
--- a/drivers/usb/host/ehci-st.c
+++ b/drivers/usb/host/ehci-st.c
@@ -320,7 +320,7 @@ MODULE_DEVICE_TABLE(of, st_ehci_ids);
static struct platform_driver ehci_platform_driver = {
.probe = st_ehci_platform_probe,
- .remove_new = st_ehci_platform_remove,
+ .remove = st_ehci_platform_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "st-ehci",
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index a2112c28f631..1d16cfefabd7 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -220,7 +220,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match);
static struct platform_driver ehci_hcd_xilinx_of_driver = {
.probe = ehci_hcd_xilinx_of_probe,
- .remove_new = ehci_hcd_xilinx_of_remove,
+ .remove = ehci_hcd_xilinx_of_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "xilinx-of-ehci",
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 9a1b5224f239..22a0942f0bce 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -791,7 +791,7 @@ static struct platform_driver of_fhci_driver = {
.of_match_table = of_fhci_match,
},
.probe = of_fhci_probe,
- .remove_new = of_fhci_remove,
+ .remove = of_fhci_remove,
};
module_platform_driver(of_fhci_driver);
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index a45ede80edfc..c3acd410ce94 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -158,7 +158,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
struct packet *pkt;
u8 *data = NULL;
- /* calcalate data address,len and toggle and then add the transaction */
+ /* calculate data address,len and toggle and then add the transaction */
if (td->toggle == USB_TD_TOGGLE_CARRY)
td->toggle = ed->toggle_carry;
@@ -679,7 +679,7 @@ static void process_done_list(unsigned long data)
DECLARE_TASKLET_OLD(fhci_tasklet, process_done_list);
-/* transfer complted callback */
+/* transfer completed callback */
u32 fhci_transfer_confirm_callback(struct fhci_hcd *fhci)
{
if (!fhci->process_done_task->state)
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 6cdc3d805c32..4e67b9471986 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -362,7 +362,7 @@ static struct platform_driver fsl_usb2_mph_dr_driver = {
.of_match_table = fsl_usb2_mph_dr_of_match,
},
.probe = fsl_usb2_mph_dr_of_probe,
- .remove_new = fsl_usb2_mph_dr_of_remove,
+ .remove = fsl_usb2_mph_dr_of_remove,
};
module_platform_driver(fsl_usb2_mph_dr_driver);
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index a82d8926e922..71c22c4bd163 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1684,7 +1684,7 @@ MODULE_ALIAS("platform:isp116x-hcd");
static struct platform_driver isp116x_driver = {
.probe = isp116x_probe,
- .remove_new = isp116x_remove,
+ .remove = isp116x_remove,
.suspend = isp116x_suspend,
.resume = isp116x_resume,
.driver = {
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 31059c8f94e6..2d3a082cb52f 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2757,7 +2757,7 @@ static int isp1362_resume(struct platform_device *pdev)
static struct platform_driver isp1362_driver = {
.probe = isp1362_probe,
- .remove_new = isp1362_remove,
+ .remove = isp1362_remove,
.suspend = isp1362_suspend,
.resume = isp1362_resume,
diff --git a/drivers/usb/host/octeon-hcd.c b/drivers/usb/host/octeon-hcd.c
index 19d5777f5db2..361d33b0c4d2 100644
--- a/drivers/usb/host/octeon-hcd.c
+++ b/drivers/usb/host/octeon-hcd.c
@@ -3346,7 +3346,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case USB_PORT_FEAT_INDICATOR:
dev_dbg(dev, " INDICATOR\n");
- /* Port inidicator not supported */
+ /* Port indicator not supported */
break;
case USB_PORT_FEAT_C_CONNECTION:
dev_dbg(dev, " C_CONNECTION\n");
@@ -3711,8 +3711,8 @@ static struct platform_driver octeon_usb_driver = {
.name = "octeon-hcd",
.of_match_table = octeon_usb_match,
},
- .probe = octeon_usb_probe,
- .remove_new = octeon_usb_remove,
+ .probe = octeon_usb_probe,
+ .remove = octeon_usb_remove,
};
static int __init octeon_usb_driver_init(void)
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index f691cd98a574..5df793dcb25d 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -685,7 +685,7 @@ static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
- .remove_new = ohci_hcd_at91_drv_remove,
+ .remove = ohci_hcd_at91_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "at91_ohci",
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index d2b67da76762..3c5ca2d7c92e 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -531,7 +531,7 @@ static const struct ohci_driver_overrides da8xx_overrides __initconst = {
*/
static struct platform_driver ohci_hcd_da8xx_driver = {
.probe = ohci_da8xx_probe,
- .remove_new = ohci_da8xx_remove,
+ .remove = ohci_da8xx_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_da8xx_suspend,
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 1379e03644b2..cc5cb0900988 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -262,7 +262,7 @@ MODULE_DEVICE_TABLE(of, exynos_ohci_match);
static struct platform_driver exynos_ohci_driver = {
.probe = exynos_ohci_probe,
- .remove_new = exynos_ohci_remove,
+ .remove = exynos_ohci_remove,
.shutdown = exynos_ohci_shutdown,
.driver = {
.name = "exynos-ohci",
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index 5b775e1ea527..24d5a1dc5056 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -254,7 +254,7 @@ static struct platform_driver ohci_hcd_nxp_driver = {
.of_match_table = of_match_ptr(ohci_hcd_nxp_match),
},
.probe = ohci_hcd_nxp_probe,
- .remove_new = ohci_hcd_nxp_remove,
+ .remove = ohci_hcd_nxp_remove,
};
static int __init ohci_nxp_init(void)
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 21a6f6c55e07..f6e56c4b9914 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -152,7 +152,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd)
rh &= ~RH_A_NOCP;
- /* gpio9 for overcurrent detction */
+ /* gpio9 for overcurrent detection */
omap_cfg_reg(W8_1610_GPIO9);
/* for paranoia's sake: disable USB.PUEN */
@@ -390,7 +390,7 @@ static int ohci_omap_resume(struct platform_device *dev)
*/
static struct platform_driver ohci_hcd_omap_driver = {
.probe = ohci_hcd_omap_probe,
- .remove_new = ohci_hcd_omap_remove,
+ .remove = ohci_hcd_omap_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_omap_suspend,
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 4a75507325dd..f47ae12cde6a 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -344,7 +344,7 @@ static const struct dev_pm_ops ohci_platform_pm_ops = {
static struct platform_driver ohci_platform_driver = {
.id_table = ohci_platform_table,
.probe = ohci_platform_probe,
- .remove_new = ohci_platform_remove,
+ .remove = ohci_platform_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ohci-platform",
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index a6be061f8653..acd0a0e398a4 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -219,7 +219,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
static struct platform_driver ohci_hcd_ppc_of_driver = {
.probe = ohci_hcd_ppc_of_probe,
- .remove_new = ohci_hcd_ppc_of_remove,
+ .remove = ohci_hcd_ppc_of_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-of-ohci",
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3348c25ddb18..45d026e85168 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -569,7 +569,7 @@ static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = {
static struct platform_driver ohci_hcd_pxa27x_driver = {
.probe = ohci_hcd_pxa27x_probe,
- .remove_new = ohci_hcd_pxa27x_remove,
+ .remove = ohci_hcd_pxa27x_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "pxa27x-ohci",
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index c5c9b4cbcb9a..66d970854357 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -457,7 +457,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_s3c2410_dt_ids);
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_probe,
- .remove_new = ohci_hcd_s3c2410_remove,
+ .remove = ohci_hcd_s3c2410_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "s3c2410-ohci",
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 4b39e9d6f33a..843a5378764e 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -252,7 +252,7 @@ static int ohci_sm501_resume(struct platform_device *pdev)
*/
static struct platform_driver ohci_hcd_sm501_driver = {
.probe = ohci_hcd_sm501_drv_probe,
- .remove_new = ohci_hcd_sm501_drv_remove,
+ .remove = ohci_hcd_sm501_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_sm501_suspend,
.resume = ohci_sm501_resume,
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 993f347c5c28..d7131e5a4477 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -157,7 +157,7 @@ MODULE_DEVICE_TABLE(of, spear_ohci_id_table);
/* Driver definition to register with the platform bus */
static struct platform_driver spear_ohci_hcd_driver = {
.probe = spear_ohci_hcd_drv_probe,
- .remove_new = spear_ohci_hcd_drv_remove,
+ .remove = spear_ohci_hcd_drv_remove,
#ifdef CONFIG_PM
.suspend = spear_ohci_hcd_drv_suspend,
.resume = spear_ohci_hcd_drv_resume,
diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c
index 214342013f7e..d1656fce5400 100644
--- a/drivers/usb/host/ohci-st.c
+++ b/drivers/usb/host/ohci-st.c
@@ -298,7 +298,7 @@ MODULE_DEVICE_TABLE(of, st_ohci_platform_ids);
static struct platform_driver ohci_platform_driver = {
.probe = st_ohci_platform_probe,
- .remove_new = st_ohci_platform_remove,
+ .remove = st_ohci_platform_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "st-ohci",
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index ca3859463ba1..a6c20facf945 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -885,7 +885,7 @@ static int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len)
int a_blocks; /* blocks allocated */
int i, j;
- /* Don't allocte bigger than supported */
+ /* Don't allocate bigger than supported */
if (len > BUFFER_SIZE * BUFFER_NUM) {
oxu_err(oxu, "buffer too big (%d)\n", len);
return -ENOMEM;
@@ -902,7 +902,7 @@ static int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len)
/* Find a suitable available data buffer */
for (i = 0; i < BUFFER_NUM;
- i += max(a_blocks, (int)oxu->db_used[i])) {
+ i += max_t(int, a_blocks, oxu->db_used[i])) {
/* Check all the required blocks are available */
for (j = 0; j < a_blocks; j++)
@@ -3040,7 +3040,7 @@ static int oxu_hcd_init(struct usb_hcd *hcd)
* make problems: throughput reduction (!), data errors...
*/
if (park) {
- park = min(park, (unsigned) 3);
+ park = min_t(unsigned int, park, 3);
temp |= CMD_PARK;
temp |= park << 8;
}
@@ -4289,7 +4289,7 @@ static int oxu_drv_resume(struct device *dev)
static struct platform_driver oxu_driver = {
.probe = oxu_drv_probe,
- .remove_new = oxu_drv_remove,
+ .remove = oxu_drv_remove,
.shutdown = oxu_drv_shutdown,
.suspend = oxu_drv_suspend,
.resume = oxu_drv_resume,
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 6576515a29cd..a44992e2561b 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -759,7 +759,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
struct r8a66597_pipe_info *info = &pipe->info;
unsigned short mbw = mbw_value(r8a66597);
- /* pipe dma is only for external controlles */
+ /* pipe dma is only for external controllers */
if (r8a66597->pdata->on_chip)
return;
@@ -1336,7 +1336,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf = (void *)urb->transfer_buffer + urb->actual_length;
urb_len = urb->transfer_buffer_length - urb->actual_length;
}
- bufsize = min(urb_len, (int) td->maxpacket);
+ bufsize = min_t(int, urb_len, td->maxpacket);
if (rcv_len <= bufsize) {
size = rcv_len;
} else {
@@ -2510,7 +2510,7 @@ clean_up:
static struct platform_driver r8a66597_driver = {
.probe = r8a66597_probe,
- .remove_new = r8a66597_remove,
+ .remove = r8a66597_remove,
.driver = {
.name = hcd_name,
.pm = R8A66597_DEV_PM_OPS,
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 92f2d1238448..036f5fd6d159 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1784,7 +1784,7 @@ sl811h_resume(struct platform_device *dev)
/* this driver is exported so sl811_cs can depend on it */
struct platform_driver sl811h_driver = {
.probe = sl811h_probe,
- .remove_new = sl811h_remove,
+ .remove = sl811h_remove,
.suspend = sl811h_suspend,
.resume = sl811h_resume,
diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c
index cfebb833668e..8a1f6d1b5b56 100644
--- a/drivers/usb/host/uhci-grlib.c
+++ b/drivers/usb/host/uhci-grlib.c
@@ -184,7 +184,7 @@ MODULE_DEVICE_TABLE(of, uhci_hcd_grlib_of_match);
static struct platform_driver uhci_grlib_driver = {
.probe = uhci_hcd_grlib_probe,
- .remove_new = uhci_hcd_grlib_remove,
+ .remove = uhci_hcd_grlib_remove,
.shutdown = uhci_hcd_grlib_shutdown,
.driver = {
.name = "grlib-uhci",
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index 3dec5dd3a0d5..a7c934404ebc 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -184,7 +184,7 @@ MODULE_DEVICE_TABLE(of, platform_uhci_ids);
static struct platform_driver uhci_platform_driver = {
.probe = uhci_hcd_platform_probe,
- .remove_new = uhci_hcd_platform_remove,
+ .remove = uhci_hcd_platform_remove,
.shutdown = uhci_hcd_platform_shutdown,
.driver = {
.name = "platform-uhci",
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 241d7aa1fbc2..227e513867dd 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -248,8 +248,9 @@ xhci_dbc_queue_trb(struct xhci_ring *ring, u32 field1,
trb->generic.field[2] = cpu_to_le32(field3);
trb->generic.field[3] = cpu_to_le32(field4);
- trace_xhci_dbc_gadget_ep_queue(ring, &trb->generic);
-
+ trace_xhci_dbc_gadget_ep_queue(ring, &trb->generic,
+ xhci_trb_virt_to_dma(ring->enq_seg,
+ ring->enqueue));
ring->num_trbs_free--;
next = ++(ring->enqueue);
if (TRB_TYPE_LINK_LE32(next->link.control)) {
@@ -471,7 +472,7 @@ xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags)
trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK));
}
INIT_LIST_HEAD(&ring->td_list);
- xhci_initialize_ring_info(ring, 1);
+ xhci_initialize_ring_info(ring);
return ring;
dma_fail:
kfree(seg);
@@ -747,7 +748,7 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event)
return;
}
- trace_xhci_dbc_handle_transfer(ring, &req->trb->generic);
+ trace_xhci_dbc_handle_transfer(ring, &req->trb->generic, req->trb_dma);
switch (comp_code) {
case COMP_SUCCESS:
@@ -898,7 +899,9 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
*/
rmb();
- trace_xhci_dbc_handle_event(dbc->ring_evt, &evt->generic);
+ trace_xhci_dbc_handle_event(dbc->ring_evt, &evt->generic,
+ xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg,
+ dbc->ring_evt->dequeue));
switch (le32_to_cpu(evt->event_cmd.flags) & TRB_TYPE_BITMASK) {
case TRB_TYPE(TRB_PORT_STATUS):
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index f8ba15e7c225..4f0c1b96e208 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -214,14 +214,11 @@ static void xhci_ring_dump_segment(struct seq_file *s,
static int xhci_ring_trb_show(struct seq_file *s, void *unused)
{
- int i;
struct xhci_ring *ring = *(struct xhci_ring **)s->private;
struct xhci_segment *seg = ring->first_seg;
- for (i = 0; i < ring->num_segs; i++) {
+ xhci_for_each_ring_seg(ring->first_seg, seg)
xhci_ring_dump_segment(s, seg);
- seg = seg->next;
- }
return 0;
}
@@ -291,12 +288,13 @@ static int xhci_endpoint_context_show(struct seq_file *s, void *unused)
for (ep_index = 0; ep_index < 31; ep_index++) {
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
dma = dev->out_ctx->dma + (ep_index + 1) * CTX_SIZE(xhci->hcc_params);
- seq_printf(s, "%pad: %s\n", &dma,
+ seq_printf(s, "%pad: %s, virt_state:%#x\n", &dma,
xhci_decode_ep_context(str,
le32_to_cpu(ep_ctx->ep_info),
le32_to_cpu(ep_ctx->ep_info2),
le64_to_cpu(ep_ctx->deq),
- le32_to_cpu(ep_ctx->tx_info)));
+ le32_to_cpu(ep_ctx->tx_info)),
+ dev->eps[ep_index].ep_state);
}
return 0;
diff --git a/drivers/usb/host/xhci-histb.c b/drivers/usb/host/xhci-histb.c
index f9a4a4b0eb57..8a7d46dae62c 100644
--- a/drivers/usb/host/xhci-histb.c
+++ b/drivers/usb/host/xhci-histb.c
@@ -373,7 +373,7 @@ MODULE_DEVICE_TABLE(of, histb_xhci_of_match);
static struct platform_driver histb_xhci_driver = {
.probe = xhci_histb_probe,
- .remove_new = xhci_histb_remove,
+ .remove = xhci_histb_remove,
.driver = {
.name = "xhci-histb",
.pm = DEV_PM_OPS,
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 8d774f19271e..9693464c0520 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -946,9 +946,9 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
}
/* did port event handler already start resume timing? */
if (!port->resume_timestamp) {
- /* If not, maybe we are in a host initated resume? */
+ /* If not, maybe we are in a host initiated resume? */
if (test_bit(wIndex, &bus_state->resuming_ports)) {
- /* Host initated resume doesn't time the resume
+ /* Host initiated resume doesn't time the resume
* signalling using resume_done[].
* It manually sets RESUME state, sleeps 20ms
* and sets U0 state. This should probably be
@@ -1924,7 +1924,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
/* resume already initiated */
break;
default:
- /* not in a resumeable state, ignore it */
+ /* not in a resumable state, ignore it */
clear_bit(port_index,
&bus_state->bus_suspended);
break;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index d2900197a49e..15db90c54a45 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -27,14 +27,12 @@
* "All components of all Command and Transfer TRBs shall be initialized to '0'"
*/
static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
- unsigned int cycle_state,
unsigned int max_packet,
unsigned int num,
gfp_t flags)
{
struct xhci_segment *seg;
dma_addr_t dma;
- int i;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
seg = kzalloc_node(sizeof(*seg), flags, dev_to_node(dev));
@@ -56,11 +54,6 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
return NULL;
}
}
- /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
- if (cycle_state == 0) {
- for (i = 0; i < TRBS_PER_SEGMENT; i++)
- seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE);
- }
seg->num = num;
seg->dma = dma;
seg->next = NULL;
@@ -78,82 +71,104 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
kfree(seg);
}
-static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
- struct xhci_segment *first)
+static void xhci_ring_segments_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
- struct xhci_segment *seg;
+ struct xhci_segment *seg, *next;
+
+ ring->last_seg->next = NULL;
+ seg = ring->first_seg;
- seg = first->next;
- while (seg && seg != first) {
- struct xhci_segment *next = seg->next;
+ while (seg) {
+ next = seg->next;
xhci_segment_free(xhci, seg);
seg = next;
}
- xhci_segment_free(xhci, first);
}
/*
- * Make the prev segment point to the next segment.
+ * Only for transfer and command rings where driver is the producer, not for
+ * event rings.
*
- * Change the last TRB in the prev segment to be a Link TRB which points to the
+ * Change the last TRB in the segment to be a Link TRB which points to the
* DMA address of the next segment. The caller needs to set any Link TRB
* related flags, such as End TRB, Toggle Cycle, and no snoop.
*/
-static void xhci_link_segments(struct xhci_segment *prev,
- struct xhci_segment *next,
- enum xhci_ring_type type, bool chain_links)
+static void xhci_set_link_trb(struct xhci_segment *seg, bool chain_links)
{
+ union xhci_trb *trb;
u32 val;
- if (!prev || !next)
+ if (!seg || !seg->next)
return;
- prev->next = next;
- if (type != TYPE_EVENT) {
- prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
- cpu_to_le64(next->dma);
- /* Set the last TRB in the segment to have a TRB type ID of Link TRB */
- val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
- val &= ~TRB_TYPE_BITMASK;
- val |= TRB_TYPE(TRB_LINK);
- if (chain_links)
- val |= TRB_CHAIN;
- prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
- }
+ trb = &seg->trbs[TRBS_PER_SEGMENT - 1];
+
+ /* Set the last TRB in the segment to have a TRB type ID of Link TRB */
+ val = le32_to_cpu(trb->link.control);
+ val &= ~TRB_TYPE_BITMASK;
+ val |= TRB_TYPE(TRB_LINK);
+ if (chain_links)
+ val |= TRB_CHAIN;
+ trb->link.control = cpu_to_le32(val);
+ trb->link.segment_ptr = cpu_to_le64(seg->next->dma);
+}
+
+static void xhci_initialize_ring_segments(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+ struct xhci_segment *seg;
+ bool chain_links;
+
+ if (ring->type == TYPE_EVENT)
+ return;
+
+ chain_links = xhci_link_chain_quirk(xhci, ring->type);
+ xhci_for_each_ring_seg(ring->first_seg, seg)
+ xhci_set_link_trb(seg, chain_links);
+
+ /* See section 4.9.2.1 and 6.4.4.1 */
+ ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= cpu_to_le32(LINK_TOGGLE);
}
/*
- * Link the ring to the new segments.
+ * Link the src ring segments to the dst ring.
* Set Toggle Cycle for the new ring if needed.
*/
-static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
- struct xhci_segment *first, struct xhci_segment *last,
- unsigned int num_segs)
+static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *src, struct xhci_ring *dst)
{
- struct xhci_segment *next, *seg;
+ struct xhci_segment *seg;
bool chain_links;
- if (!ring || !first || !last)
+ if (!src || !dst)
return;
- chain_links = xhci_link_chain_quirk(xhci, ring->type);
+ /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
+ if (dst->cycle_state == 0) {
+ xhci_for_each_ring_seg(src->first_seg, seg) {
+ for (int i = 0; i < TRBS_PER_SEGMENT; i++)
+ seg->trbs[i].link.control |= cpu_to_le32(TRB_CYCLE);
+ }
+ }
- next = ring->enq_seg->next;
- xhci_link_segments(ring->enq_seg, first, ring->type, chain_links);
- xhci_link_segments(last, next, ring->type, chain_links);
- ring->num_segs += num_segs;
+ src->last_seg->next = dst->enq_seg->next;
+ dst->enq_seg->next = src->first_seg;
+ if (dst->type != TYPE_EVENT) {
+ chain_links = xhci_link_chain_quirk(xhci, dst->type);
+ xhci_set_link_trb(dst->enq_seg, chain_links);
+ xhci_set_link_trb(src->last_seg, chain_links);
+ }
+ dst->num_segs += src->num_segs;
- if (ring->enq_seg == ring->last_seg) {
- if (ring->type != TYPE_EVENT) {
- ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control
+ if (dst->enq_seg == dst->last_seg) {
+ if (dst->type != TYPE_EVENT)
+ dst->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control
&= ~cpu_to_le32(LINK_TOGGLE);
- last->trbs[TRBS_PER_SEGMENT-1].link.control
- |= cpu_to_le32(LINK_TOGGLE);
- }
- ring->last_seg = last;
+
+ dst->last_seg = src->last_seg;
+ } else if (dst->type != TYPE_EVENT) {
+ src->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control &= ~cpu_to_le32(LINK_TOGGLE);
}
- for (seg = ring->enq_seg; seg != ring->last_seg; seg = seg->next)
+ for (seg = dst->enq_seg; seg != dst->last_seg; seg = seg->next)
seg->next->num = seg->num + 1;
}
@@ -224,7 +239,6 @@ static int xhci_update_stream_segment_mapping(
struct radix_tree_root *trb_address_map,
struct xhci_ring *ring,
struct xhci_segment *first_seg,
- struct xhci_segment *last_seg,
gfp_t mem_flags)
{
struct xhci_segment *seg;
@@ -234,28 +248,22 @@ static int xhci_update_stream_segment_mapping(
if (WARN_ON_ONCE(trb_address_map == NULL))
return 0;
- seg = first_seg;
- do {
+ xhci_for_each_ring_seg(first_seg, seg) {
ret = xhci_insert_segment_mapping(trb_address_map,
ring, seg, mem_flags);
if (ret)
goto remove_streams;
- if (seg == last_seg)
- return 0;
- seg = seg->next;
- } while (seg != first_seg);
+ }
return 0;
remove_streams:
failed_seg = seg;
- seg = first_seg;
- do {
+ xhci_for_each_ring_seg(first_seg, seg) {
xhci_remove_segment_mapping(trb_address_map, seg);
if (seg == failed_seg)
return ret;
- seg = seg->next;
- } while (seg != first_seg);
+ }
return ret;
}
@@ -267,17 +275,14 @@ static void xhci_remove_stream_mapping(struct xhci_ring *ring)
if (WARN_ON_ONCE(ring->trb_address_map == NULL))
return;
- seg = ring->first_seg;
- do {
+ xhci_for_each_ring_seg(ring->first_seg, seg)
xhci_remove_segment_mapping(ring->trb_address_map, seg);
- seg = seg->next;
- } while (seg != ring->first_seg);
}
static int xhci_update_stream_mapping(struct xhci_ring *ring, gfp_t mem_flags)
{
return xhci_update_stream_segment_mapping(ring->trb_address_map, ring,
- ring->first_seg, ring->last_seg, mem_flags);
+ ring->first_seg, mem_flags);
}
/* XXX: Do we need the hcd structure in all these functions? */
@@ -291,14 +296,13 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
if (ring->first_seg) {
if (ring->type == TYPE_STREAM)
xhci_remove_stream_mapping(ring);
- xhci_free_segments_for_ring(xhci, ring->first_seg);
+ xhci_ring_segments_free(xhci, ring);
}
kfree(ring);
}
-void xhci_initialize_ring_info(struct xhci_ring *ring,
- unsigned int cycle_state)
+void xhci_initialize_ring_info(struct xhci_ring *ring)
{
/* The ring is empty, so the enqueue pointer == dequeue pointer */
ring->enqueue = ring->first_seg->trbs;
@@ -312,7 +316,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring,
* New rings are initialized with cycle state equal to 1; if we are
* handling ring expansion, set the cycle state equal to the old ring.
*/
- ring->cycle_state = cycle_state;
+ ring->cycle_state = 1;
/*
* Each segment has a link TRB, and leave an extra TRB for SW
@@ -323,46 +327,36 @@ void xhci_initialize_ring_info(struct xhci_ring *ring,
EXPORT_SYMBOL_GPL(xhci_initialize_ring_info);
/* Allocate segments and link them for a ring */
-static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
- struct xhci_segment **first,
- struct xhci_segment **last,
- unsigned int num_segs,
- unsigned int cycle_state,
- enum xhci_ring_type type,
- unsigned int max_packet,
- gfp_t flags)
+static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, gfp_t flags)
{
struct xhci_segment *prev;
unsigned int num = 0;
- bool chain_links;
-
- chain_links = xhci_link_chain_quirk(xhci, type);
- prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags);
+ prev = xhci_segment_alloc(xhci, ring->bounce_buf_len, num, flags);
if (!prev)
return -ENOMEM;
num++;
- *first = prev;
- while (num < num_segs) {
+ ring->first_seg = prev;
+ while (num < ring->num_segs) {
struct xhci_segment *next;
- next = xhci_segment_alloc(xhci, cycle_state, max_packet, num,
- flags);
+ next = xhci_segment_alloc(xhci, ring->bounce_buf_len, num, flags);
if (!next)
goto free_segments;
- xhci_link_segments(prev, next, type, chain_links);
+ prev->next = next;
prev = next;
num++;
}
- xhci_link_segments(prev, *first, type, chain_links);
- *last = prev;
+ ring->last_seg = prev;
+ ring->last_seg->next = ring->first_seg;
return 0;
free_segments:
- xhci_free_segments_for_ring(xhci, *first);
+ ring->last_seg = prev;
+ xhci_ring_segments_free(xhci, ring);
return -ENOMEM;
}
@@ -373,9 +367,8 @@ free_segments:
* Set the end flag and the cycle toggle bit on the last segment.
* See section 4.9.1 and figures 15 and 16.
*/
-struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
- unsigned int num_segs, unsigned int cycle_state,
- enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
+struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, unsigned int num_segs,
+ enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
{
struct xhci_ring *ring;
int ret;
@@ -392,18 +385,12 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
if (num_segs == 0)
return ring;
- ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, &ring->last_seg, num_segs,
- cycle_state, type, max_packet, flags);
+ ret = xhci_alloc_segments_for_ring(xhci, ring, flags);
if (ret)
goto fail;
- /* Only event ring does not use link TRB */
- if (type != TYPE_EVENT) {
- /* See section 4.9.2.1 and 6.4.4.1 */
- ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |=
- cpu_to_le32(LINK_TOGGLE);
- }
- xhci_initialize_ring_info(ring, cycle_state);
+ xhci_initialize_ring_segments(xhci, ring);
+ xhci_initialize_ring_info(ring);
trace_xhci_ring_alloc(ring);
return ring;
@@ -427,23 +414,29 @@ void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_new_segs, gfp_t flags)
{
- struct xhci_segment *first;
- struct xhci_segment *last;
- int ret;
+ struct xhci_ring new_ring;
+ int ret;
+
+ if (num_new_segs == 0)
+ return 0;
- ret = xhci_alloc_segments_for_ring(xhci, &first, &last, num_new_segs, ring->cycle_state,
- ring->type, ring->bounce_buf_len, flags);
+ new_ring.num_segs = num_new_segs;
+ new_ring.bounce_buf_len = ring->bounce_buf_len;
+ new_ring.type = ring->type;
+ ret = xhci_alloc_segments_for_ring(xhci, &new_ring, flags);
if (ret)
return -ENOMEM;
+ xhci_initialize_ring_segments(xhci, &new_ring);
+
if (ring->type == TYPE_STREAM) {
- ret = xhci_update_stream_segment_mapping(ring->trb_address_map,
- ring, first, last, flags);
+ ret = xhci_update_stream_segment_mapping(ring->trb_address_map, ring,
+ new_ring.first_seg, flags);
if (ret)
goto free_segments;
}
- xhci_link_rings(xhci, ring, first, last, num_new_segs);
+ xhci_link_rings(xhci, ring, &new_ring);
trace_xhci_ring_expansion(ring);
xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
"ring expansion succeed, now has %d segments",
@@ -452,7 +445,7 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
return 0;
free_segments:
- xhci_free_segments_for_ring(xhci, first);
+ xhci_ring_segments_free(xhci, &new_ring);
return ret;
}
@@ -642,8 +635,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
stream_info->stream_rings[cur_stream] =
- xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, max_packet,
- mem_flags);
+ xhci_ring_alloc(xhci, 2, TYPE_STREAM, max_packet, mem_flags);
cur_ring = stream_info->stream_rings[cur_stream];
if (!cur_ring)
goto cleanup_rings;
@@ -658,6 +650,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, addr);
ret = xhci_update_stream_mapping(cur_ring, mem_flags);
+
+ trace_xhci_alloc_stream_info_ctx(stream_info, cur_stream);
if (ret) {
xhci_ring_free(xhci, cur_ring);
stream_info->stream_rings[cur_stream] = NULL;
@@ -984,7 +978,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
}
/* Allocate endpoint 0 ring */
- dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, 0, flags);
+ dev->eps[0].ring = xhci_ring_alloc(xhci, 2, TYPE_CTRL, 0, flags);
if (!dev->eps[0].ring)
goto fail;
@@ -1461,7 +1455,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
/* Set up the endpoint ring */
virt_dev->eps[ep_index].new_ring =
- xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
+ xhci_ring_alloc(xhci, 2, ring_type, max_packet, mem_flags);
if (!virt_dev->eps[ep_index].new_ring)
return -ENOMEM;
@@ -2271,7 +2265,7 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags)
if (!ir)
return NULL;
- ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags);
+ ir->event_ring = xhci_ring_alloc(xhci, segs, TYPE_EVENT, 0, flags);
if (!ir->event_ring) {
xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
kfree(ir);
@@ -2473,7 +2467,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
goto fail;
/* Set up the command ring to have one segments for now. */
- xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, 0, flags);
+ xhci->cmd_ring = xhci_ring_alloc(xhci, 1, TYPE_COMMAND, 0, flags);
if (!xhci->cmd_ring)
goto fail;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@@ -2518,11 +2512,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
ir->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
- /*
- * XXX: Might need to set the Interrupter Moderation Register to
- * something other than the default (~1ms minimum between interrupts).
- * See section 5.5.1.2.
- */
for (i = 0; i < MAX_HC_SLOTS; i++)
xhci->devs[i] = NULL;
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 3252e3d2d79c..904831344440 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -853,7 +853,7 @@ MODULE_DEVICE_TABLE(of, mtk_xhci_of_match);
static struct platform_driver mtk_xhci_driver = {
.probe = xhci_mtk_probe,
- .remove_new = xhci_mtk_remove,
+ .remove = xhci_mtk_remove,
.driver = {
.name = "xhci-mtk",
.pm = DEV_PM_OPS,
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index cb07cee9ed0c..b21474e81482 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -28,18 +28,18 @@
#define SPARSE_CNTL_ENABLE 0xC12C
/* Device for a quirk */
-#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
-#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
+#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
+#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1009 0x1009
#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 0x1100
#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400
-#define PCI_VENDOR_ID_ETRON 0x1b6f
-#define PCI_DEVICE_ID_EJ168 0x7023
-#define PCI_DEVICE_ID_EJ188 0x7052
+#define PCI_VENDOR_ID_ETRON 0x1b6f
+#define PCI_DEVICE_ID_ETRON_EJ168 0x7023
+#define PCI_DEVICE_ID_ETRON_EJ188 0x7052
-#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
-#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1
#define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f
@@ -82,9 +82,6 @@
#define PCI_DEVICE_ID_ASMEDIA_3042_XHCI 0x3042
#define PCI_DEVICE_ID_ASMEDIA_3242_XHCI 0x3242
-#define PCI_DEVICE_ID_CADENCE 0x17CD
-#define PCI_DEVICE_ID_CADENCE_SSP 0x0200
-
static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -150,14 +147,11 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
hcd->irq = 0;
/*
- * calculate number of MSI-X vectors supported.
- * - HCS_MAX_INTRS: the max number of interrupts the host can handle,
- * with max number of interrupters based on the xhci HCSPARAMS1.
- * - num_online_cpus: maximum MSI-X vectors per CPUs core.
- * Add additional 1 vector to ensure always available interrupt.
+ * Calculate number of MSI/MSI-X vectors supported.
+ * - max_interrupters: the max number of interrupts requested, capped to xhci HCSPARAMS1.
+ * - num_online_cpus: one vector per CPUs core, with at least one overall.
*/
- xhci->nvecs = min(num_online_cpus() + 1,
- HCS_MAX_INTRS(xhci->hcs_params1));
+ xhci->nvecs = min(num_online_cpus() + 1, xhci->max_interrupters);
/* TODO: Check with MSI Soc for sysdev */
xhci->nvecs = pci_alloc_irq_vectors(pdev, 1, xhci->nvecs,
@@ -395,14 +389,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
- pdev->device == PCI_DEVICE_ID_EJ168) {
- xhci->quirks |= XHCI_RESET_ON_RESUME;
- xhci->quirks |= XHCI_BROKEN_STREAMS;
- }
- if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
- pdev->device == PCI_DEVICE_ID_EJ188) {
+ (pdev->device == PCI_DEVICE_ID_ETRON_EJ168 ||
+ pdev->device == PCI_DEVICE_ID_ETRON_EJ188)) {
+ xhci->quirks |= XHCI_ETRON_HOST;
xhci->quirks |= XHCI_RESET_ON_RESUME;
xhci->quirks |= XHCI_BROKEN_STREAMS;
+ xhci->quirks |= XHCI_NO_SOFT_RETRY;
}
if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
@@ -482,8 +474,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
}
- if (pdev->vendor == PCI_DEVICE_ID_CADENCE &&
- pdev->device == PCI_DEVICE_ID_CADENCE_SSP)
+ if (pdev->vendor == PCI_VENDOR_ID_CDNS &&
+ pdev->device == PCI_DEVICE_ID_CDNS_USBSSP)
xhci->quirks |= XHCI_CDNS_SCTX_QUIRK;
/* xHC spec requires PCI devices to support D3hot and D3cold */
@@ -646,6 +638,9 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id)
dma_set_max_seg_size(&dev->dev, UINT_MAX);
+ if (device_property_read_bool(&dev->dev, "ti,pwron-active-high"))
+ pci_clear_and_set_config_dword(dev, 0xE0, 0, 1 << 22);
+
return 0;
put_usb3_hcd:
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index ecaa75718e59..e6c9006bd568 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -573,7 +573,7 @@ MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match);
static struct platform_driver usb_generic_xhci_driver = {
.probe = xhci_generic_plat_probe,
- .remove_new = xhci_plat_remove,
+ .remove = xhci_plat_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "xhci-hcd",
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index 8b357647728c..1cc082a3b793 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -274,7 +274,7 @@ static int xhci_renesas_probe(struct platform_device *pdev)
static struct platform_driver usb_xhci_renesas_driver = {
.probe = xhci_renesas_probe,
- .remove_new = xhci_plat_remove,
+ .remove = xhci_plat_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "xhci-renesas-hcd",
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 928b93ad1ee8..4cf5363875c7 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -52,6 +52,7 @@
* endpoint rings; it generates events on the event ring for these.
*/
+#include <linux/jiffies.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
@@ -145,10 +146,8 @@ static void trb_to_noop(union xhci_trb *trb, u32 noop_type)
* TRB is in a new segment. This does not skip over link TRBs, and it does not
* effect the ring dequeue or enqueue pointers.
*/
-static void next_trb(struct xhci_hcd *xhci,
- struct xhci_ring *ring,
- struct xhci_segment **seg,
- union xhci_trb **trb)
+static void next_trb(struct xhci_segment **seg,
+ union xhci_trb **trb)
{
if (trb_is_link(*trb) || last_trb_on_seg(*seg, *trb)) {
*seg = (*seg)->next;
@@ -169,13 +168,16 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
if (ring->type == TYPE_EVENT) {
if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
ring->dequeue++;
- goto out;
+ return;
}
if (last_trb_on_ring(ring, ring->deq_seg, ring->dequeue))
ring->cycle_state ^= 1;
ring->deq_seg = ring->deq_seg->next;
ring->dequeue = ring->deq_seg->trbs;
- goto out;
+
+ trace_xhci_inc_deq(ring);
+
+ return;
}
/* All other rings have link trbs */
@@ -190,14 +192,13 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
ring->deq_seg = ring->deq_seg->next;
ring->dequeue = ring->deq_seg->trbs;
+ trace_xhci_inc_deq(ring);
+
if (link_trb_count++ > ring->num_segs) {
xhci_warn(xhci, "Ring is an endless link TRB loop\n");
break;
}
}
-out:
- trace_xhci_inc_deq(ring);
-
return;
}
@@ -266,13 +267,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
ring->enqueue = ring->enq_seg->trbs;
next = ring->enqueue;
+ trace_xhci_inc_enq(ring);
+
if (link_trb_count++ > ring->num_segs) {
xhci_warn(xhci, "%s: Ring link TRB loop\n", __func__);
break;
}
}
-
- trace_xhci_inc_enq(ring);
}
/*
@@ -426,7 +427,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
}
}
-/* Must be called with xhci->lock held, releases and aquires lock back */
+/* Must be called with xhci->lock held, releases and acquires lock back */
static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
{
struct xhci_segment *new_seg = xhci->cmd_ring->deq_seg;
@@ -446,9 +447,9 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
* avoiding corrupting the command ring pointer in case the command ring
* is stopped by the time the upper dword is written.
*/
- next_trb(xhci, NULL, &new_seg, &new_deq);
+ next_trb(&new_seg, &new_deq);
if (trb_is_link(new_deq))
- next_trb(xhci, NULL, &new_seg, &new_deq);
+ next_trb(&new_seg, &new_deq);
crcr = xhci_trb_virt_to_dma(new_seg, new_deq);
xhci_write_64(xhci, crcr | CMD_RING_ABORT, &xhci->op_regs->cmd_ring);
@@ -660,8 +661,8 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
/*
* We want to find the pointer, segment and cycle state of the new trb
- * (the one after current TD's last_trb). We know the cycle state at
- * hw_dequeue, so walk the ring until both hw_dequeue and last_trb are
+ * (the one after current TD's end_trb). We know the cycle state at
+ * hw_dequeue, so walk the ring until both hw_dequeue and end_trb are
* found.
*/
do {
@@ -671,14 +672,14 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
if (td_last_trb_found)
break;
}
- if (new_deq == td->last_trb)
+ if (new_deq == td->end_trb)
td_last_trb_found = true;
if (cycle_found && trb_is_link(new_deq) &&
link_trb_toggles_cycle(new_deq))
new_cycle ^= 0x1;
- next_trb(xhci, ep_ring, &new_seg, &new_deq);
+ next_trb(&new_seg, &new_deq);
/* Search wrapped around, bail out */
if (new_deq == ep->ring->dequeue) {
@@ -740,23 +741,22 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
* (The last TRB actually points to the ring enqueue pointer, which is not part
* of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
*/
-static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
- struct xhci_td *td, bool flip_cycle)
+static void td_to_noop(struct xhci_td *td, bool flip_cycle)
{
struct xhci_segment *seg = td->start_seg;
- union xhci_trb *trb = td->first_trb;
+ union xhci_trb *trb = td->start_trb;
while (1) {
trb_to_noop(trb, TRB_TR_NOOP);
/* flip cycle if asked to */
- if (flip_cycle && trb != td->first_trb && trb != td->last_trb)
+ if (flip_cycle && trb != td->start_trb && trb != td->end_trb)
trb->generic.field[3] ^= cpu_to_le32(TRB_CYCLE);
- if (trb == td->last_trb)
+ if (trb == td->end_trb)
break;
- next_trb(xhci, ep_ring, &seg, &trb);
+ next_trb(&seg, &trb);
}
}
@@ -799,7 +799,7 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
DMA_FROM_DEVICE);
- /* for in tranfers we need to copy the data from bounce to sg */
+ /* for in transfers we need to copy the data from bounce to sg */
if (urb->num_sgs) {
len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
seg->bounce_len, seg->bounce_offs);
@@ -814,8 +814,8 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
seg->bounce_offs = 0;
}
-static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
- struct xhci_ring *ep_ring, int status)
+static void xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
+ struct xhci_ring *ep_ring, int status)
{
struct urb *urb = NULL;
@@ -858,10 +858,18 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
status = 0;
xhci_giveback_urb_in_irq(xhci, td, status);
}
-
- return 0;
}
+/* Give back previous TD and move on to the next TD. */
+static void xhci_dequeue_td(struct xhci_hcd *xhci, struct xhci_td *td, struct xhci_ring *ring,
+ u32 status)
+{
+ ring->dequeue = td->end_trb;
+ ring->deq_seg = td->end_seg;
+ inc_deq(xhci, ring);
+
+ xhci_td_cleanup(xhci, td, ring, status);
+}
/* Complete the cancelled URBs we unlinked from td_list. */
static void xhci_giveback_invalidated_tds(struct xhci_virt_ep *ep)
@@ -972,13 +980,20 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
unsigned int slot_id = ep->vdev->slot_id;
int err;
+ /*
+ * This is not going to work if the hardware is changing its dequeue
+ * pointers as we look at them. Completion handler will call us later.
+ */
+ if (ep->ep_state & SET_DEQ_PENDING)
+ return 0;
+
xhci = ep->xhci;
list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, cancelled_td_list) {
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"Removing canceled TD starting at 0x%llx (dma) in stream %u URB %p",
(unsigned long long)xhci_trb_virt_to_dma(
- td->start_seg, td->first_trb),
+ td->start_seg, td->start_trb),
td->urb->stream_id, td->urb);
list_del_init(&td->td_list);
ring = xhci_urb_to_transfer_ring(xhci, td->urb);
@@ -1020,16 +1035,16 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
"Found multiple active URBs %p and %p in stream %u?\n",
td->urb, cached_td->urb,
td->urb->stream_id);
- td_to_noop(xhci, ring, cached_td, false);
+ td_to_noop(cached_td, false);
cached_td->cancel_status = TD_CLEARED;
}
- td_to_noop(xhci, ring, td, false);
+ td_to_noop(td, false);
td->cancel_status = TD_CLEARING_CACHE;
cached_td = td;
break;
}
} else {
- td_to_noop(xhci, ring, td, false);
+ td_to_noop(td, false);
td->cancel_status = TD_CLEARED;
}
}
@@ -1054,7 +1069,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
continue;
xhci_warn(xhci, "Failed to clear cancelled cached URB %p, mark clear anyway\n",
td->urb);
- td_to_noop(xhci, ring, td, false);
+ td_to_noop(td, false);
td->cancel_status = TD_CLEARED;
}
}
@@ -1062,6 +1077,19 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
}
/*
+ * Erase queued TDs from transfer ring(s) and give back those the xHC didn't
+ * stop on. If necessary, queue commands to move the xHC off cancelled TDs it
+ * stopped on. Those will be given back later when the commands complete.
+ *
+ * Call under xhci->lock on a stopped endpoint.
+ */
+void xhci_process_cancelled_tds(struct xhci_virt_ep *ep)
+{
+ xhci_invalidate_cancelled_tds(ep);
+ xhci_giveback_invalidated_tds(ep);
+}
+
+/*
* Returns the TD the endpoint ring halted on.
* Only call for non-running rings without streams.
*/
@@ -1151,16 +1179,35 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
return;
case EP_STATE_STOPPED:
/*
- * NEC uPD720200 sometimes sets this state and fails with
- * Context Error while continuing to process TRBs.
- * Be conservative and trust EP_CTX_STATE on other chips.
+ * Per xHCI 4.6.9, Stop Endpoint command on a Stopped
+ * EP is a Context State Error, and EP stays Stopped.
+ *
+ * But maybe it failed on Halted, and somebody ran Reset
+ * Endpoint later. EP state is now Stopped and EP_HALTED
+ * still set because Reset EP handler will run after us.
+ */
+ if (ep->ep_state & EP_HALTED)
+ break;
+ /*
+ * On some HCs EP state remains Stopped for some tens of
+ * us to a few ms or more after a doorbell ring, and any
+ * new Stop Endpoint fails without aborting the restart.
+ * This handler may run quickly enough to still see this
+ * Stopped state, but it will soon change to Running.
+ *
+ * Assume this bug on unexpected Stop Endpoint failures.
+ * Keep retrying until the EP starts and stops again, on
+ * chips where this is known to help. Wait for 100ms.
*/
if (!(xhci->quirks & XHCI_NEC_HOST))
break;
+ if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100)))
+ break;
fallthrough;
case EP_STATE_RUNNING:
/* Race, HW handled stop ep cmd before ep was running */
- xhci_dbg(xhci, "Stop ep completion ctx error, ep is running\n");
+ xhci_dbg(xhci, "Stop ep completion ctx error, ctx_state %d\n",
+ GET_EP_CTX_STATE(ep_ctx));
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command) {
@@ -1338,8 +1385,8 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
struct xhci_virt_ep *ep;
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
+ struct xhci_stream_ctx *stream_ctx;
struct xhci_td *td, *tmp_td;
- bool deferred = false;
ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));
stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2]));
@@ -1360,6 +1407,11 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
trace_xhci_handle_cmd_set_deq(slot_ctx);
trace_xhci_handle_cmd_set_deq_ep(ep_ctx);
+ if (ep->ep_state & EP_HAS_STREAMS) {
+ stream_ctx = &ep->stream_info->stream_ctx_array[stream_id];
+ trace_xhci_handle_cmd_set_deq_stream(ep->stream_info, stream_id);
+ }
+
if (cmd_comp_code != COMP_SUCCESS) {
unsigned int ep_state;
unsigned int slot_state;
@@ -1396,9 +1448,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
u64 deq;
/* 4.6.10 deq ptr is written to the stream ctx for streams */
if (ep->ep_state & EP_HAS_STREAMS) {
- struct xhci_stream_ctx *ctx =
- &ep->stream_info->stream_ctx_array[stream_id];
- deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK;
+ deq = le64_to_cpu(stream_ctx->stream_ring) & SCTX_DEQ_MASK;
/*
* Cadence xHCI controllers store some endpoint state
@@ -1410,8 +1460,8 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
* To fix this issue driver must clear Rsvd0 field.
*/
if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) {
- ctx->reserved[0] = 0;
- ctx->reserved[1] = 0;
+ stream_ctx->reserved[0] = 0;
+ stream_ctx->reserved[1] = 0;
}
} else {
deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
@@ -1440,8 +1490,6 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
xhci_dbg(ep->xhci, "%s: Giveback cancelled URB %p TD\n",
__func__, td->urb);
xhci_td_cleanup(ep->xhci, td, ep_ring, td->status);
- } else if (td->cancel_status == TD_CLEARING_CACHE_DEFERRED) {
- deferred = true;
} else {
xhci_dbg(ep->xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n",
__func__, td->urb, td->cancel_status);
@@ -1452,11 +1500,15 @@ cleanup:
ep->queued_deq_seg = NULL;
ep->queued_deq_ptr = NULL;
- if (deferred) {
- /* We have more streams to clear */
+ /* Check for deferred or newly cancelled TDs */
+ if (!list_empty(&ep->cancelled_td_list)) {
xhci_dbg(ep->xhci, "%s: Pending TDs to clear, continuing with invalidation\n",
__func__);
xhci_invalidate_cancelled_tds(ep);
+ /* Try to restart the endpoint if all is done */
+ ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+ /* Start giving back any TDs invalidated above */
+ xhci_giveback_invalidated_tds(ep);
} else {
/* Restart any rings with pending URBs */
xhci_dbg(ep->xhci, "%s: All TDs cleared, ring doorbell\n", __func__);
@@ -1716,7 +1768,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
cmd_dma = le64_to_cpu(event->cmd_trb);
cmd_trb = xhci->cmd_ring->dequeue;
- trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic);
+ trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic, cmd_dma);
cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
@@ -2074,7 +2126,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_ad
dma_addr_t end_trb_dma;
struct xhci_segment *cur_seg;
- start_dma = xhci_trb_virt_to_dma(td->start_seg, td->first_trb);
+ start_dma = xhci_trb_virt_to_dma(td->start_seg, td->start_trb);
cur_seg = td->start_seg;
do {
@@ -2084,7 +2136,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_ad
end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
&cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
/* If the end TRB isn't in this segment, this is set to 0 */
- end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->last_trb);
+ end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->end_trb);
if (debug)
xhci_warn(xhci,
@@ -2184,9 +2236,9 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
return 0;
}
-static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
- struct xhci_ring *ep_ring, struct xhci_td *td,
- u32 trb_comp_code)
+static void finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ struct xhci_ring *ep_ring, struct xhci_td *td,
+ u32 trb_comp_code)
{
struct xhci_ep_ctx *ep_ctx;
@@ -2201,7 +2253,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
* stopped TDs. A stopped TD may be restarted, so don't update
* the ring dequeue pointer or take this TD off any lists yet.
*/
- return 0;
+ return;
case COMP_USB_TRANSACTION_ERROR:
case COMP_BABBLE_DETECTED_ERROR:
case COMP_SPLIT_TRANSACTION_ERROR:
@@ -2226,8 +2278,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
!list_empty(&td->cancelled_td_list)) {
xhci_dbg(xhci, "Already resolving halted ep for 0x%llx\n",
(unsigned long long)xhci_trb_virt_to_dma(
- td->start_seg, td->first_trb));
- return 0;
+ td->start_seg, td->start_trb));
+ return;
}
/* endpoint not halted, don't reset it */
break;
@@ -2235,7 +2287,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
/* Almost same procedure as for STALL_ERROR below */
xhci_clear_hub_tt_buffer(xhci, td, ep);
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
- return 0;
+ return;
case COMP_STALL_ERROR:
/*
* xhci internal endpoint state will go to a "halt" state for
@@ -2252,28 +2304,22 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
- return 0; /* xhci_handle_halted_endpoint marked td cancelled */
+ return; /* xhci_handle_halted_endpoint marked td cancelled */
default:
break;
}
- /* Update ring dequeue pointer */
- ep_ring->dequeue = td->last_trb;
- ep_ring->deq_seg = td->last_trb_seg;
- inc_deq(xhci, ep_ring);
-
- return xhci_td_cleanup(xhci, td, ep_ring, td->status);
+ xhci_dequeue_td(xhci, td, ep_ring, td->status);
}
-/* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */
-static int sum_trb_lengths(struct xhci_hcd *xhci, struct xhci_ring *ring,
- union xhci_trb *stop_trb)
+/* sum trb lengths from the first trb up to stop_trb, _excluding_ stop_trb */
+static u32 sum_trb_lengths(struct xhci_td *td, union xhci_trb *stop_trb)
{
u32 sum;
- union xhci_trb *trb = ring->dequeue;
- struct xhci_segment *seg = ring->deq_seg;
+ union xhci_trb *trb = td->start_trb;
+ struct xhci_segment *seg = td->start_seg;
- for (sum = 0; trb != stop_trb; next_trb(xhci, ring, &seg, &trb)) {
+ for (sum = 0; trb != stop_trb; next_trb(&seg, &trb)) {
if (!trb_is_noop(trb) && !trb_is_link(trb))
sum += TRB_LEN(le32_to_cpu(trb->generic.field[2]));
}
@@ -2283,9 +2329,9 @@ static int sum_trb_lengths(struct xhci_hcd *xhci, struct xhci_ring *ring,
/*
* Process control tds, update urb status and actual_length.
*/
-static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
- struct xhci_ring *ep_ring, struct xhci_td *td,
- union xhci_trb *ep_trb, struct xhci_transfer_event *event)
+static void process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ struct xhci_ring *ep_ring, struct xhci_td *td,
+ union xhci_trb *ep_trb, struct xhci_transfer_event *event)
{
struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code;
@@ -2364,7 +2410,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
td->urb_length_set = true;
td->urb->actual_length = requested - remaining;
xhci_dbg(xhci, "Waiting for status stage event\n");
- return 0;
+ return;
}
/* at status stage */
@@ -2372,15 +2418,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
td->urb->actual_length = requested;
finish_td:
- return finish_td(xhci, ep, ep_ring, td, trb_comp_code);
+ finish_td(xhci, ep, ep_ring, td, trb_comp_code);
}
/*
* Process isochronous tds, update urb packet status and actual_length.
*/
-static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
- struct xhci_ring *ep_ring, struct xhci_td *td,
- union xhci_trb *ep_trb, struct xhci_transfer_event *event)
+static void process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ struct xhci_ring *ep_ring, struct xhci_td *td,
+ union xhci_trb *ep_trb, struct xhci_transfer_event *event)
{
struct urb_priv *urb_priv;
int idx;
@@ -2425,7 +2471,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
fallthrough;
case COMP_ISOCH_BUFFER_OVERRUN:
frame->status = -EOVERFLOW;
- if (ep_trb != td->last_trb)
+ if (ep_trb != td->end_trb)
td->error_mid_td = true;
break;
case COMP_INCOMPATIBLE_DEVICE_ERROR:
@@ -2435,14 +2481,14 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
case COMP_USB_TRANSACTION_ERROR:
frame->status = -EPROTO;
sum_trbs_for_length = true;
- if (ep_trb != td->last_trb)
+ if (ep_trb != td->end_trb)
td->error_mid_td = true;
break;
case COMP_STOPPED:
sum_trbs_for_length = true;
break;
case COMP_STOPPED_SHORT_PACKET:
- /* field normally containing residue now contains tranferred */
+ /* field normally containing residue now contains transferred */
frame->status = short_framestatus;
requested = remaining;
break;
@@ -2462,7 +2508,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
goto finish_td;
if (sum_trbs_for_length)
- frame->actual_length = sum_trb_lengths(xhci, ep->ring, ep_trb) +
+ frame->actual_length = sum_trb_lengths(td, ep_trb) +
ep_trb_len - remaining;
else
frame->actual_length = requested;
@@ -2471,17 +2517,16 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
finish_td:
/* Don't give back TD yet if we encountered an error mid TD */
- if (td->error_mid_td && ep_trb != td->last_trb) {
+ if (td->error_mid_td && ep_trb != td->end_trb) {
xhci_dbg(xhci, "Error mid isoc TD, wait for final completion event\n");
td->urb_length_set = true;
- return 0;
+ return;
}
-
- return finish_td(xhci, ep, ep_ring, td, trb_comp_code);
+ finish_td(xhci, ep, ep_ring, td, trb_comp_code);
}
-static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
- struct xhci_virt_ep *ep, int status)
+static void skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
+ struct xhci_virt_ep *ep, int status)
{
struct urb_priv *urb_priv;
struct usb_iso_packet_descriptor *frame;
@@ -2497,20 +2542,15 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* calc actual length */
frame->actual_length = 0;
- /* Update ring dequeue pointer */
- ep->ring->dequeue = td->last_trb;
- ep->ring->deq_seg = td->last_trb_seg;
- inc_deq(xhci, ep->ring);
-
- return xhci_td_cleanup(xhci, td, ep->ring, status);
+ xhci_dequeue_td(xhci, td, ep->ring, status);
}
/*
* Process bulk and interrupt tds, update urb status and actual_length.
*/
-static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
- struct xhci_ring *ep_ring, struct xhci_td *td,
- union xhci_trb *ep_trb, struct xhci_transfer_event *event)
+static void process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ struct xhci_ring *ep_ring, struct xhci_td *td,
+ union xhci_trb *ep_trb, struct xhci_transfer_event *event)
{
struct xhci_slot_ctx *slot_ctx;
u32 trb_comp_code;
@@ -2526,7 +2566,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
case COMP_SUCCESS:
ep->err_count = 0;
/* handle success with untransferred data as short packet */
- if (ep_trb != td->last_trb || remaining) {
+ if (ep_trb != td->end_trb || remaining) {
xhci_warn(xhci, "WARN Successful completion on short TX\n");
xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n",
td->urb->ep->desc.bEndpointAddress,
@@ -2542,7 +2582,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
goto finish_td;
case COMP_STOPPED_LENGTH_INVALID:
/* stopped on ep trb with invalid length, exclude it */
- td->urb->actual_length = sum_trb_lengths(xhci, ep_ring, ep_trb);
+ td->urb->actual_length = sum_trb_lengths(td, ep_trb);
goto finish_td;
case COMP_USB_TRANSACTION_ERROR:
if (xhci->quirks & XHCI_NO_SOFT_RETRY ||
@@ -2553,17 +2593,17 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
td->status = 0;
xhci_handle_halted_endpoint(xhci, ep, td, EP_SOFT_RESET);
- return 0;
+ return;
default:
/* do nothing */
break;
}
- if (ep_trb == td->last_trb)
+ if (ep_trb == td->end_trb)
td->urb->actual_length = requested - remaining;
else
td->urb->actual_length =
- sum_trb_lengths(xhci, ep_ring, ep_trb) +
+ sum_trb_lengths(td, ep_trb) +
ep_trb_len - remaining;
finish_td:
if (remaining > requested) {
@@ -2572,7 +2612,7 @@ finish_td:
td->urb->actual_length = 0;
}
- return finish_td(xhci, ep, ep_ring, td, trb_comp_code);
+ finish_td(xhci, ep, ep_ring, td, trb_comp_code);
}
/* Transfer events which don't point to a transfer TRB, see xhci 4.17.4 */
@@ -2792,10 +2832,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (td && td->error_mid_td && !trb_in_td(xhci, td, ep_trb_dma, false)) {
xhci_dbg(xhci, "Missing TD completion event after mid TD error\n");
- ep_ring->dequeue = td->last_trb;
- ep_ring->deq_seg = td->last_trb_seg;
- inc_deq(xhci, ep_ring);
- xhci_td_cleanup(xhci, td, ep_ring, td->status);
+ xhci_dequeue_td(xhci, td, ep_ring, td->status);
}
if (list_empty(&ep_ring->td_list)) {
@@ -2889,7 +2926,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep_ring->last_td_was_short = false;
ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
- trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb);
+ trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma);
/*
* No-op TRB could trigger interrupts in a case where a URB was killed
@@ -2939,7 +2976,9 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter
{
u32 trb_type;
- trace_xhci_handle_event(ir->event_ring, &event->generic);
+ trace_xhci_handle_event(ir->event_ring, &event->generic,
+ xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
+ ir->event_ring->dequeue));
/*
* Barrier between reading the TRB_CYCLE (valid) flag before, and any
@@ -3162,7 +3201,8 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
wmb();
trb->field[3] = cpu_to_le32(field4);
- trace_xhci_queue_trb(ring, trb);
+ trace_xhci_queue_trb(ring, trb,
+ xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue));
inc_enq(xhci, ring, more_trbs_coming);
}
@@ -3302,7 +3342,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
/* Add this TD to the tail of the endpoint ring's TD list */
list_add_tail(&td->td_list, &ep_ring->td_list);
td->start_seg = ep_ring->enq_seg;
- td->first_trb = ep_ring->enqueue;
+ td->start_trb = ep_ring->enqueue;
return 0;
}
@@ -3641,8 +3681,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field &= ~TRB_CHAIN;
field |= TRB_IOC;
more_trbs_coming = false;
- td->last_trb = ring->enqueue;
- td->last_trb_seg = ring->enq_seg;
+ td->end_trb = ring->enqueue;
+ td->end_seg = ring->enq_seg;
if (xhci_urb_suitable_for_idt(urb)) {
memcpy(&send_addr, urb->transfer_buffer,
trb_buff_len);
@@ -3690,8 +3730,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
1, urb, 1, mem_flags);
- urb_priv->td[1].last_trb = ring->enqueue;
- urb_priv->td[1].last_trb_seg = ring->enq_seg;
+ urb_priv->td[1].end_trb = ring->enqueue;
+ urb_priv->td[1].end_seg = ring->enq_seg;
field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC;
queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field);
}
@@ -3727,6 +3767,20 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (!urb->setup_packet)
return -EINVAL;
+ if ((xhci->quirks & XHCI_ETRON_HOST) &&
+ urb->dev->speed >= USB_SPEED_SUPER) {
+ /*
+ * If next available TRB is the Link TRB in the ring segment then
+ * enqueue a No Op TRB, this can prevent the Setup and Data Stage
+ * TRB to be breaked by the Link TRB.
+ */
+ if (trb_is_link(ep_ring->enqueue + 1)) {
+ field = TRB_TYPE(TRB_TR_NOOP) | ep_ring->cycle_state;
+ queue_trb(xhci, ep_ring, false, 0, 0,
+ TRB_INTR_TARGET(0), field);
+ }
+ }
+
/* 1 TRB for setup, 1 for status */
num_trbs = 2;
/*
@@ -3815,8 +3869,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
}
/* Save the DMA address of the last TRB in the TD */
- td->last_trb = ep_ring->enqueue;
- td->last_trb_seg = ep_ring->enq_seg;
+ td->end_trb = ep_ring->enqueue;
+ td->end_seg = ep_ring->enq_seg;
/* Queue status TRB - see Table 7 and sections 4.11.2.2 and 6.4.1.2.3 */
/* If the device sent data, the status stage is an OUT transfer */
@@ -4101,8 +4155,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field |= TRB_CHAIN;
} else {
more_trbs_coming = false;
- td->last_trb = ep_ring->enqueue;
- td->last_trb_seg = ep_ring->enq_seg;
+ td->end_trb = ep_ring->enqueue;
+ td->end_seg = ep_ring->enq_seg;
field |= TRB_IOC;
if (trb_block_event_intr(xhci, num_tds, i, ir))
field |= TRB_BEI;
@@ -4168,14 +4222,14 @@ cleanup:
/* Use the first TD as a temporary variable to turn the TDs we've queued
* into No-ops with a software-owned cycle bit. That way the hardware
* won't accidentally start executing bogus TDs when we partially
- * overwrite them. td->first_trb and td->start_seg are already set.
+ * overwrite them. td->start_trb and td->start_seg are already set.
*/
- urb_priv->td[0].last_trb = ep_ring->enqueue;
+ urb_priv->td[0].end_trb = ep_ring->enqueue;
/* Every TRB except the first & last will have its cycle bit flipped. */
- td_to_noop(xhci, ep_ring, &urb_priv->td[0], true);
+ td_to_noop(&urb_priv->td[0], true);
/* Reset the ring enqueue back to the first TRB and its cycle bit. */
- ep_ring->enqueue = urb_priv->td[0].first_trb;
+ ep_ring->enqueue = urb_priv->td[0].start_trb;
ep_ring->enq_seg = urb_priv->td[0].start_seg;
ep_ring->cycle_state = start_cycle;
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 76f228e7443c..06ae193ec874 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -2664,7 +2664,7 @@ MODULE_DEVICE_TABLE(of, tegra_xusb_of_match);
static struct platform_driver tegra_xusb_driver = {
.probe = tegra_xusb_probe,
- .remove_new = tegra_xusb_remove,
+ .remove = tegra_xusb_remove,
.shutdown = tegra_xusb_shutdown,
.driver = {
.name = "tegra-xusb",
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
index 24405315ffe6..bfb5c5c17012 100644
--- a/drivers/usb/host/xhci-trace.h
+++ b/drivers/usb/host/xhci-trace.h
@@ -108,9 +108,10 @@ DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx,
);
DECLARE_EVENT_CLASS(xhci_log_trb,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb),
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma),
TP_STRUCT__entry(
+ __field(dma_addr_t, dma)
__field(u32, type)
__field(u32, field0)
__field(u32, field1)
@@ -118,51 +119,54 @@ DECLARE_EVENT_CLASS(xhci_log_trb,
__field(u32, field3)
),
TP_fast_assign(
+ __entry->dma = dma;
__entry->type = ring->type;
__entry->field0 = le32_to_cpu(trb->field[0]);
__entry->field1 = le32_to_cpu(trb->field[1]);
__entry->field2 = le32_to_cpu(trb->field[2]);
__entry->field3 = le32_to_cpu(trb->field[3]);
),
- TP_printk("%s: %s", xhci_ring_type_string(__entry->type),
+ TP_printk("%s: @%pad %s",
+ xhci_ring_type_string(__entry->type), &__entry->dma,
xhci_decode_trb(__get_buf(XHCI_MSG_MAX), XHCI_MSG_MAX, __entry->field0,
__entry->field1, __entry->field2, __entry->field3)
)
);
DEFINE_EVENT(xhci_log_trb, xhci_handle_event,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb)
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma)
);
DEFINE_EVENT(xhci_log_trb, xhci_handle_command,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb)
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma)
);
DEFINE_EVENT(xhci_log_trb, xhci_handle_transfer,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb)
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma)
);
DEFINE_EVENT(xhci_log_trb, xhci_queue_trb,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb)
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma)
+
);
DEFINE_EVENT(xhci_log_trb, xhci_dbc_handle_event,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb)
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma)
);
DEFINE_EVENT(xhci_log_trb, xhci_dbc_handle_transfer,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb)
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma)
);
DEFINE_EVENT(xhci_log_trb, xhci_dbc_gadget_ep_queue,
- TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb),
- TP_ARGS(ring, trb)
+ TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma),
+ TP_ARGS(ring, trb, dma)
);
DECLARE_EVENT_CLASS(xhci_log_free_virt_dev,
@@ -310,6 +314,37 @@ DEFINE_EVENT(xhci_log_urb, xhci_urb_dequeue,
TP_ARGS(urb)
);
+DECLARE_EVENT_CLASS(xhci_log_stream_ctx,
+ TP_PROTO(struct xhci_stream_info *info, unsigned int stream_id),
+ TP_ARGS(info, stream_id),
+ TP_STRUCT__entry(
+ __field(unsigned int, stream_id)
+ __field(u64, stream_ring)
+ __field(dma_addr_t, ctx_array_dma)
+
+ ),
+ TP_fast_assign(
+ __entry->stream_id = stream_id;
+ __entry->stream_ring = le64_to_cpu(info->stream_ctx_array[stream_id].stream_ring);
+ __entry->ctx_array_dma = info->ctx_array_dma + stream_id * 16;
+
+ ),
+ TP_printk("stream %u ctx @%pad: SCT %llu deq %llx", __entry->stream_id,
+ &__entry->ctx_array_dma, CTX_TO_SCT(__entry->stream_ring),
+ __entry->stream_ring
+ )
+);
+
+DEFINE_EVENT(xhci_log_stream_ctx, xhci_alloc_stream_info_ctx,
+ TP_PROTO(struct xhci_stream_info *info, unsigned int stream_id),
+ TP_ARGS(info, stream_id)
+);
+
+DEFINE_EVENT(xhci_log_stream_ctx, xhci_handle_cmd_set_deq_stream,
+ TP_PROTO(struct xhci_stream_info *info, unsigned int stream_id),
+ TP_ARGS(info, stream_id)
+);
+
DECLARE_EVENT_CLASS(xhci_log_ep_ctx,
TP_PROTO(struct xhci_ep_ctx *ctx),
TP_ARGS(ctx),
@@ -454,8 +489,6 @@ DECLARE_EVENT_CLASS(xhci_log_ring,
__field(void *, ring)
__field(dma_addr_t, enq)
__field(dma_addr_t, deq)
- __field(dma_addr_t, enq_seg)
- __field(dma_addr_t, deq_seg)
__field(unsigned int, num_segs)
__field(unsigned int, stream_id)
__field(unsigned int, cycle_state)
@@ -466,17 +499,15 @@ DECLARE_EVENT_CLASS(xhci_log_ring,
__entry->type = ring->type;
__entry->num_segs = ring->num_segs;
__entry->stream_id = ring->stream_id;
- __entry->enq_seg = ring->enq_seg->dma;
- __entry->deq_seg = ring->deq_seg->dma;
__entry->cycle_state = ring->cycle_state;
__entry->bounce_buf_len = ring->bounce_buf_len;
__entry->enq = xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
__entry->deq = xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
),
- TP_printk("%s %p: enq %pad(%pad) deq %pad(%pad) segs %d stream %d bounce %d cycle %d",
+ TP_printk("%s %p: enq %pad deq %pad segs %d stream %d bounce %d cycle %d",
xhci_ring_type_string(__entry->type), __entry->ring,
- &__entry->enq, &__entry->enq_seg,
- &__entry->deq, &__entry->deq_seg,
+ &__entry->enq,
+ &__entry->deq,
__entry->num_segs,
__entry->stream_id,
__entry->bounce_buf_len,
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 899c0effb5d3..5ebde8cae4fc 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -8,6 +8,7 @@
* Some code borrowed from the Linux EHCI driver.
*/
+#include <linux/jiffies.h>
#include <linux/pci.h>
#include <linux/iommu.h>
#include <linux/iopoll.h>
@@ -40,15 +41,15 @@ MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
{
- struct xhci_segment *seg = ring->first_seg;
+ struct xhci_segment *seg;
if (!td || !td->start_seg)
return false;
- do {
+
+ xhci_for_each_ring_seg(ring->first_seg, seg) {
if (seg == td->start_seg)
return true;
- seg = seg->next;
- } while (seg && seg != ring->first_seg);
+ }
return false;
}
@@ -473,14 +474,7 @@ static int xhci_init(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init");
spin_lock_init(&xhci->lock);
- if (xhci->hci_version == 0x95 && link_quirk) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
- "QUIRK: Not clearing Link TRB chain bits.");
- xhci->quirks |= XHCI_LINK_TRB_QUIRK;
- } else {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "xHCI doesn't need link TRB QUIRK");
- }
+
retval = xhci_mem_init(xhci, GFP_KERNEL);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init");
@@ -785,16 +779,10 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
struct xhci_segment *seg;
ring = xhci->cmd_ring;
- seg = ring->deq_seg;
- do {
- memset(seg->trbs, 0,
- sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1));
- seg->trbs[TRBS_PER_SEGMENT - 1].link.control &=
- cpu_to_le32(~TRB_CYCLE);
- seg = seg->next;
- } while (seg != ring->deq_seg);
-
- xhci_initialize_ring_info(ring, 1);
+ xhci_for_each_ring_seg(ring->first_seg, seg)
+ memset(seg->trbs, 0, sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1));
+
+ xhci_initialize_ring_info(ring);
/*
* Reset the hardware dequeue pointer.
* Yes, this will need to be re-written after resume, but we're paranoid
@@ -1756,7 +1744,7 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
urb->ep->desc.bEndpointAddress,
(unsigned long long) xhci_trb_virt_to_dma(
urb_priv->td[i].start_seg,
- urb_priv->td[i].first_trb));
+ urb_priv->td[i].start_trb));
for (; i < urb_priv->num_tds; i++) {
td = &urb_priv->td[i];
@@ -1768,15 +1756,27 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
}
}
- /* Queue a stop endpoint command, but only if this is
- * the first cancellation to be handled.
- */
- if (!(ep->ep_state & EP_STOP_CMD_PENDING)) {
+ /* These completion handlers will sort out cancelled TDs for us */
+ if (ep->ep_state & (EP_STOP_CMD_PENDING | EP_HALTED | SET_DEQ_PENDING)) {
+ xhci_dbg(xhci, "Not queuing Stop Endpoint on slot %d ep %d in state 0x%x\n",
+ urb->dev->slot_id, ep_index, ep->ep_state);
+ goto done;
+ }
+
+ /* In this case no commands are pending but the endpoint is stopped */
+ if (ep->ep_state & EP_CLEARING_TT) {
+ /* and cancelled TDs can be given back right away */
+ xhci_dbg(xhci, "Invalidating TDs instantly on slot %d ep %d in state 0x%x\n",
+ urb->dev->slot_id, ep_index, ep->ep_state);
+ xhci_process_cancelled_tds(ep);
+ } else {
+ /* Otherwise, queue a new Stop Endpoint command */
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command) {
ret = -ENOMEM;
goto done;
}
+ ep->stop_time = jiffies;
ep->ep_state |= EP_STOP_CMD_PENDING;
xhci_queue_stop_endpoint(xhci, command, urb->dev->slot_id,
ep_index, 0);
@@ -2794,6 +2794,51 @@ static int xhci_reserve_bandwidth(struct xhci_hcd *xhci,
return -ENOMEM;
}
+/*
+ * Synchronous XHCI stop endpoint helper. Issues the stop endpoint command and
+ * waits for the command completion before returning. This does not call
+ * xhci_handle_cmd_stop_ep(), which has additional handling for 'context error'
+ * cases, along with transfer ring cleanup.
+ *
+ * xhci_stop_endpoint_sync() is intended to be utilized by clients that manage
+ * their own transfer ring, such as offload situations.
+ */
+int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int suspend,
+ gfp_t gfp_flags)
+{
+ struct xhci_command *command;
+ unsigned long flags;
+ int ret;
+
+ command = xhci_alloc_command(xhci, true, gfp_flags);
+ if (!command)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ ret = xhci_queue_stop_endpoint(xhci, command, ep->vdev->slot_id,
+ ep->ep_index, suspend);
+ if (ret < 0) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ goto out;
+ }
+
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ wait_for_completion(command->completion);
+
+ /* No handling for COMP_CONTEXT_STATE_ERROR done at command completion*/
+ if (command->status == COMP_COMMAND_ABORTED ||
+ command->status == COMP_COMMAND_RING_STOPPED) {
+ xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
+ ret = -ETIME;
+ }
+out:
+ xhci_free_command(xhci, command);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xhci_stop_endpoint_sync);
/* Issue a configure endpoint command or evaluate context command
* and wait for it to finish.
@@ -3692,6 +3737,8 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
xhci->num_active_eps);
}
+static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
+
/*
* This submits a Reset Device Command, which will set the device state to 0,
* set the device address to 0, and disable all the endpoints except the default
@@ -3762,6 +3809,23 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
SLOT_STATE_DISABLED)
return 0;
+ if (xhci->quirks & XHCI_ETRON_HOST) {
+ /*
+ * Obtaining a new device slot to inform the xHCI host that
+ * the USB device has been reset.
+ */
+ ret = xhci_disable_slot(xhci, udev->slot_id);
+ xhci_free_virt_device(xhci, udev->slot_id);
+ if (!ret) {
+ ret = xhci_alloc_dev(hcd, udev);
+ if (ret == 1)
+ ret = 0;
+ else
+ ret = -EINVAL;
+ }
+ return ret;
+ }
+
trace_xhci_discover_or_reset_device(slot_ctx);
xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
@@ -5251,6 +5315,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (xhci->hci_version > 0x96)
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+ if (xhci->hci_version == 0x95 && link_quirk) {
+ xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits");
+ xhci->quirks |= XHCI_LINK_TRB_QUIRK;
+ }
+
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
if (retval)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index f0fb696d5619..4914f0a10cff 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -554,6 +554,7 @@ struct xhci_stream_ctx {
/* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */
#define SCT_FOR_CTX(p) (((p) & 0x7) << 1)
+#define CTX_TO_SCT(p) (((p) >> 1) & 0x7)
/* Secondary stream array type, dequeue pointer is to a transfer ring */
#define SCT_SEC_TR 0
/* Primary stream array type, dequeue pointer is to a transfer ring */
@@ -690,6 +691,7 @@ struct xhci_virt_ep {
/* Bandwidth checking storage */
struct xhci_bw_info bw_info;
struct list_head bw_endpoint_list;
+ unsigned long stop_time;
/* Isoch Frame ID checking storage */
int next_frame_id;
/* Use new Isoch TRB layout needed for extended TBC support */
@@ -1023,9 +1025,6 @@ enum xhci_setup_dev {
/* Interrupter Target - which MSI-X vector to target the completion event at */
#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
-/* Total burst count field, Rsvdz on xhci 1.1 with Extended TBC enabled (ETE) */
-#define TRB_TBC(p) (((p) & 0x3) << 7)
-#define TRB_TLBPC(p) (((p) & 0xf) << 16)
/* Cycle bit - indicates TRB ownership by HC or HCD */
#define TRB_CYCLE (1<<0)
@@ -1059,6 +1058,12 @@ enum xhci_setup_dev {
/* Isochronous TRB specific fields */
#define TRB_SIA (1<<31)
#define TRB_FRAME_ID(p) (((p) & 0x7ff) << 20)
+#define GET_FRAME_ID(p) (((p) >> 20) & 0x7ff)
+/* Total burst count field, Rsvdz on xhci 1.1 with Extended TBC enabled (ETE) */
+#define TRB_TBC(p) (((p) & 0x3) << 7)
+#define GET_TBC(p) (((p) >> 7) & 0x3)
+#define TRB_TLBPC(p) (((p) & 0xf) << 16)
+#define GET_TLBPC(p) (((p) >> 16) & 0xf)
/* TRB cache size for xHC with TRB cache */
#define TRB_CACHE_SIZE_HS 8
@@ -1259,6 +1264,9 @@ static inline const char *xhci_trb_type_string(u8 type)
#define AVOID_BEI_INTERVAL_MIN 8
#define AVOID_BEI_INTERVAL_MAX 32
+#define xhci_for_each_ring_seg(head, seg) \
+ for (seg = head; seg != NULL; seg = (seg->next != head ? seg->next : NULL))
+
struct xhci_segment {
union xhci_trb *trbs;
/* private to HCD */
@@ -1287,9 +1295,9 @@ struct xhci_td {
enum xhci_cancelled_td_status cancel_status;
struct urb *urb;
struct xhci_segment *start_seg;
- union xhci_trb *first_trb;
- union xhci_trb *last_trb;
- struct xhci_segment *last_trb_seg;
+ union xhci_trb *start_trb;
+ struct xhci_segment *end_seg;
+ union xhci_trb *end_trb;
struct xhci_segment *bounce_seg;
/* actual_length of the URB has already been set */
bool urb_length_set;
@@ -1624,6 +1632,7 @@ struct xhci_hcd {
#define XHCI_ZHAOXIN_HOST BIT_ULL(46)
#define XHCI_WRITE_64_HI_LO BIT_ULL(47)
#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
+#define XHCI_ETRON_HOST BIT_ULL(49)
unsigned int num_active_eps;
unsigned int limit_active_eps;
@@ -1788,14 +1797,12 @@ void xhci_slot_copy(struct xhci_hcd *xhci,
int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
struct usb_device *udev, struct usb_host_endpoint *ep,
gfp_t mem_flags);
-struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
- unsigned int num_segs, unsigned int cycle_state,
+struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, unsigned int num_segs,
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags);
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs, gfp_t flags);
-void xhci_initialize_ring_info(struct xhci_ring *ring,
- unsigned int cycle_state);
+void xhci_initialize_ring_info(struct xhci_ring *ring);
void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
unsigned int ep_index);
@@ -1913,6 +1920,9 @@ void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
unsigned int count_trbs(u64 addr, u64 len);
+int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ int suspend, gfp_t gfp_flags);
+void xhci_process_cancelled_tds(struct xhci_virt_ep *ep);
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
@@ -2070,7 +2080,6 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_NORMAL:
- case TRB_ISOC:
case TRB_EVENT_DATA:
case TRB_TR_NOOP:
snprintf(str, size,
@@ -2087,7 +2096,25 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
field3 & TRB_ENT ? 'E' : 'e',
field3 & TRB_CYCLE ? 'C' : 'c');
break;
-
+ case TRB_ISOC:
+ snprintf(str, size,
+ "Buffer %08x%08x length %d TD size/TBC %d intr %d type '%s' TBC %u TLBPC %u frame_id %u flags %c:%c:%c:%c:%c:%c:%c:%c:%c",
+ field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ xhci_trb_type_string(type),
+ GET_TBC(field3),
+ GET_TLBPC(field3),
+ GET_FRAME_ID(field3),
+ field3 & TRB_SIA ? 'S' : 's',
+ field3 & TRB_BEI ? 'B' : 'b',
+ field3 & TRB_IDT ? 'I' : 'i',
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_NO_SNOOP ? 'S' : 's',
+ field3 & TRB_ISP ? 'I' : 'i',
+ field3 & TRB_ENT ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
case TRB_CMD_NOOP:
case TRB_ENABLE_SLOT:
snprintf(str, size,
diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
index fe1e3985419a..a64190addba6 100644
--- a/drivers/usb/isp1760/isp1760-if.c
+++ b/drivers/usb/isp1760/isp1760-if.c
@@ -263,7 +263,7 @@ MODULE_DEVICE_TABLE(of, isp1760_of_match);
static struct platform_driver isp1760_plat_driver = {
.probe = isp1760_plat_probe,
- .remove_new = isp1760_plat_remove,
+ .remove = isp1760_plat_remove,
.driver = {
.name = "isp1760",
.of_match_table = of_match_ptr(isp1760_of_match),
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index 6fb5140e29b9..225863321dc4 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -27,6 +27,8 @@ static struct usb_class_driver chaoskey_class;
static int chaoskey_rng_read(struct hwrng *rng, void *data,
size_t max, bool wait);
+static DEFINE_MUTEX(chaoskey_list_lock);
+
#define usb_dbg(usb_if, format, arg...) \
dev_dbg(&(usb_if)->dev, format, ## arg)
@@ -233,6 +235,7 @@ static void chaoskey_disconnect(struct usb_interface *interface)
usb_deregister_dev(interface, &chaoskey_class);
usb_set_intfdata(interface, NULL);
+ mutex_lock(&chaoskey_list_lock);
mutex_lock(&dev->lock);
dev->present = false;
@@ -244,6 +247,7 @@ static void chaoskey_disconnect(struct usb_interface *interface)
} else
mutex_unlock(&dev->lock);
+ mutex_unlock(&chaoskey_list_lock);
usb_dbg(interface, "disconnect done");
}
@@ -251,6 +255,7 @@ static int chaoskey_open(struct inode *inode, struct file *file)
{
struct chaoskey *dev;
struct usb_interface *interface;
+ int rv = 0;
/* get the interface from minor number and driver information */
interface = usb_find_interface(&chaoskey_driver, iminor(inode));
@@ -266,18 +271,23 @@ static int chaoskey_open(struct inode *inode, struct file *file)
}
file->private_data = dev;
+ mutex_lock(&chaoskey_list_lock);
mutex_lock(&dev->lock);
- ++dev->open;
+ if (dev->present)
+ ++dev->open;
+ else
+ rv = -ENODEV;
mutex_unlock(&dev->lock);
+ mutex_unlock(&chaoskey_list_lock);
- usb_dbg(interface, "open success");
- return 0;
+ return rv;
}
static int chaoskey_release(struct inode *inode, struct file *file)
{
struct chaoskey *dev = file->private_data;
struct usb_interface *interface;
+ int rv = 0;
if (dev == NULL)
return -ENODEV;
@@ -286,14 +296,15 @@ static int chaoskey_release(struct inode *inode, struct file *file)
usb_dbg(interface, "release");
+ mutex_lock(&chaoskey_list_lock);
mutex_lock(&dev->lock);
usb_dbg(interface, "open count at release is %d", dev->open);
if (dev->open <= 0) {
usb_dbg(interface, "invalid open count (%d)", dev->open);
- mutex_unlock(&dev->lock);
- return -ENODEV;
+ rv = -ENODEV;
+ goto bail;
}
--dev->open;
@@ -302,13 +313,15 @@ static int chaoskey_release(struct inode *inode, struct file *file)
if (dev->open == 0) {
mutex_unlock(&dev->lock);
chaoskey_free(dev);
- } else
- mutex_unlock(&dev->lock);
- } else
- mutex_unlock(&dev->lock);
-
+ goto destruction;
+ }
+ }
+bail:
+ mutex_unlock(&dev->lock);
+destruction:
+ mutex_unlock(&chaoskey_list_lock);
usb_dbg(interface, "release success");
- return 0;
+ return rv;
}
static void chaos_read_callback(struct urb *urb)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 6d28467ce352..365c10069345 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -277,28 +277,45 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,
struct iowarrior *dev;
int read_idx;
int offset;
+ int retval;
dev = file->private_data;
+ if (file->f_flags & O_NONBLOCK) {
+ retval = mutex_trylock(&dev->mutex);
+ if (!retval)
+ return -EAGAIN;
+ } else {
+ retval = mutex_lock_interruptible(&dev->mutex);
+ if (retval)
+ return -ERESTARTSYS;
+ }
+
/* verify that the device wasn't unplugged */
- if (!dev || !dev->present)
- return -ENODEV;
+ if (!dev->present) {
+ retval = -ENODEV;
+ goto exit;
+ }
dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n",
dev->minor, count);
/* read count must be packet size (+ time stamp) */
if ((count != dev->report_size)
- && (count != (dev->report_size + 1)))
- return -EINVAL;
+ && (count != (dev->report_size + 1))) {
+ retval = -EINVAL;
+ goto exit;
+ }
/* repeat until no buffer overrun in callback handler occur */
do {
atomic_set(&dev->overflow_flag, 0);
if ((read_idx = read_index(dev)) == -1) {
/* queue empty */
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto exit;
+ }
else {
//next line will return when there is either new data, or the device is unplugged
int r = wait_event_interruptible(dev->read_wait,
@@ -309,28 +326,37 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,
-1));
if (r) {
//we were interrupted by a signal
- return -ERESTART;
+ retval = -ERESTART;
+ goto exit;
}
if (!dev->present) {
//The device was unplugged
- return -ENODEV;
+ retval = -ENODEV;
+ goto exit;
}
if (read_idx == -1) {
// Can this happen ???
- return 0;
+ retval = 0;
+ goto exit;
}
}
}
offset = read_idx * (dev->report_size + 1);
if (copy_to_user(buffer, dev->read_queue + offset, count)) {
- return -EFAULT;
+ retval = -EFAULT;
+ goto exit;
}
} while (atomic_read(&dev->overflow_flag));
read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;
atomic_set(&dev->read_idx, read_idx);
+ mutex_unlock(&dev->mutex);
return count;
+
+exit:
+ mutex_unlock(&dev->mutex);
+ return retval;
}
/*
@@ -885,7 +911,6 @@ error:
static void iowarrior_disconnect(struct usb_interface *interface)
{
struct iowarrior *dev = usb_get_intfdata(interface);
- int minor = dev->minor;
usb_deregister_dev(interface, &iowarrior_class);
@@ -909,9 +934,6 @@ static void iowarrior_disconnect(struct usb_interface *interface)
mutex_unlock(&dev->mutex);
iowarrior_delete(dev);
}
-
- dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
- minor - IOWARRIOR_MINOR_BASE);
}
/* usb specific object needed to register this driver with the usb subsystem */
diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c
index 75dfdca04ff1..36b11127280f 100644
--- a/drivers/usb/misc/onboard_usb_dev.c
+++ b/drivers/usb/misc/onboard_usb_dev.c
@@ -473,7 +473,7 @@ static const struct dev_pm_ops __maybe_unused onboard_dev_pm_ops = {
static struct platform_driver onboard_dev_driver = {
.probe = onboard_dev_probe,
- .remove_new = onboard_dev_remove,
+ .remove = onboard_dev_remove,
.driver = {
.name = "onboard-usb-dev",
diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c
index 19906301a4eb..83079c414b4f 100644
--- a/drivers/usb/misc/qcom_eud.c
+++ b/drivers/usb/misc/qcom_eud.c
@@ -239,7 +239,7 @@ MODULE_DEVICE_TABLE(of, eud_dt_match);
static struct platform_driver eud_driver = {
.probe = eud_probe,
- .remove_new = eud_remove,
+ .remove = eud_remove,
.driver = {
.name = "qcom_eud",
.dev_groups = eud_groups,
diff --git a/drivers/usb/misc/usb-ljca.c b/drivers/usb/misc/usb-ljca.c
index 01ceafc4ab78..d9c21f783055 100644
--- a/drivers/usb/misc/usb-ljca.c
+++ b/drivers/usb/misc/usb-ljca.c
@@ -332,14 +332,11 @@ static int ljca_send(struct ljca_adapter *adap, u8 type, u8 cmd,
ret = usb_bulk_msg(adap->usb_dev, adap->tx_pipe, header,
msg_len, &transferred, LJCA_WRITE_TIMEOUT_MS);
-
- usb_autopm_put_interface(adap->intf);
-
if (ret < 0)
- goto out;
+ goto out_put;
if (transferred != msg_len) {
ret = -EIO;
- goto out;
+ goto out_put;
}
if (ack) {
@@ -347,11 +344,14 @@ static int ljca_send(struct ljca_adapter *adap, u8 type, u8 cmd,
timeout);
if (!ret) {
ret = -ETIMEDOUT;
- goto out;
+ goto out_put;
}
}
ret = adap->actual_length;
+out_put:
+ usb_autopm_put_interface(adap->intf);
+
out:
spin_lock_irqsave(&adap->lock, flags);
adap->ex_buf = NULL;
@@ -811,6 +811,14 @@ static int ljca_probe(struct usb_interface *interface,
if (ret)
goto err_free;
+ /*
+ * This works around problems with ov2740 initialization on some
+ * Lenovo platforms. The autosuspend delay, has to be smaller than
+ * the delay after setting the reset_gpio line in ov2740_resume().
+ * Otherwise the sensor randomly fails to initialize.
+ */
+ pm_runtime_set_autosuspend_delay(&usb_dev->dev, 10);
+
usb_enable_autosuspend(usb_dev);
return 0;
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index 3b33e4878c60..322e59381b78 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -423,7 +423,7 @@ static struct platform_driver usb3503_platform_driver = {
.pm = pm_ptr(&usb3503_platform_pm_ops),
},
.probe = usb3503_platform_probe,
- .remove_new = usb3503_platform_remove,
+ .remove = usb3503_platform_remove,
};
static int __init usb3503_init(void)
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index caf65f8294db..8d379ae835bc 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -2021,7 +2021,8 @@ static struct urb *iso_alloc_urb(
for (i = 0; i < packets; i++) {
/* here, only the last packet will be short */
- urb->iso_frame_desc[i].length = min((unsigned) bytes, maxp);
+ urb->iso_frame_desc[i].length = min_t(unsigned int,
+ bytes, maxp);
bytes -= urb->iso_frame_desc[i].length;
urb->iso_frame_desc[i].offset = maxp * i;
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 6aebc736a80c..70dff0db5354 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -441,7 +441,10 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
if (count == 0)
goto error;
- mutex_lock(&dev->io_mutex);
+ retval = mutex_lock_interruptible(&dev->io_mutex);
+ if (retval < 0)
+ return -EINTR;
+
if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex);
retval = -ENODEV;
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index afb71c18415d..c93b43f5bc46 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -823,7 +823,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf,
ep = MON_OFF2HDR(rp, rp->b_out);
if (rp->b_read < hdrbytes) {
- step_len = min(nbytes, (size_t)(hdrbytes - rp->b_read));
+ step_len = min_t(size_t, nbytes, hdrbytes - rp->b_read);
ptr = ((char *)ep) + rp->b_read;
if (step_len && copy_to_user(buf, ptr, step_len)) {
mutex_unlock(&rp->fetch_lock);
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index 6858ed9fc3b2..7b5a431acb56 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -307,7 +307,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
if (otg_sx->role_sw_used || otg_sx->manual_drd_enabled)
goto out;
- if (of_property_read_bool(node, "extcon")) {
+ if (of_property_present(node, "extcon")) {
otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
if (IS_ERR(otg_sx->edev)) {
return dev_err_probe(dev, PTR_ERR(otg_sx->edev),
@@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, mtu3_of_match);
static struct platform_driver mtu3_driver = {
.probe = mtu3_probe,
- .remove_new = mtu3_remove,
+ .remove = mtu3_remove,
.driver = {
.name = MTU3_DRIVER_NAME,
.pm = DEV_PM_OPS,
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 953094c1930c..f772aa272bea 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -633,7 +633,7 @@ MODULE_DEVICE_TABLE(of, da8xx_id_table);
static struct platform_driver da8xx_driver = {
.probe = da8xx_probe,
- .remove_new = da8xx_remove,
+ .remove = da8xx_remove,
.driver = {
.name = "musb-da8xx",
.pm = &da8xx_pm_ops,
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index b38df9226278..acdeb1117cd3 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -325,7 +325,7 @@ MODULE_DEVICE_TABLE(of, jz4740_musb_of_match);
static struct platform_driver jz4740_driver = {
.probe = jz4740_probe,
- .remove_new = jz4740_remove,
+ .remove = jz4740_remove,
.driver = {
.name = "musb-jz4740",
.of_match_table = jz4740_musb_of_match,
diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c
index 63c86c046b98..aa988d74b58d 100644
--- a/drivers/usb/musb/mediatek.c
+++ b/drivers/usb/musb/mediatek.c
@@ -523,7 +523,7 @@ MODULE_DEVICE_TABLE(of, mtk_musb_match);
static struct platform_driver mtk_musb_driver = {
.probe = mtk_musb_probe,
- .remove_new = mtk_musb_remove,
+ .remove = mtk_musb_remove,
.driver = {
.name = "musb-mtk",
.of_match_table = of_match_ptr(mtk_musb_match),
diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c
index 00e13214aa76..7edc8429b274 100644
--- a/drivers/usb/musb/mpfs.c
+++ b/drivers/usb/musb/mpfs.c
@@ -369,7 +369,7 @@ MODULE_DEVICE_TABLE(of, mpfs_id_table);
static struct platform_driver mpfs_musb_driver = {
.probe = mpfs_probe,
- .remove_new = mpfs_remove,
+ .remove = mpfs_remove,
.driver = {
.name = "mpfs-musb",
.of_match_table = of_match_ptr(mpfs_id_table)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index b24adb5b399f..03b1154a6014 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1387,7 +1387,7 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
/* expect hw_ep has already been zero-initialized */
- size = ffs(max(maxpacket, (u16) 8)) - 1;
+ size = ffs(max_t(u16, maxpacket, 8)) - 1;
maxpacket = 1 << size;
c_size = size - 3;
@@ -2953,7 +2953,7 @@ static struct platform_driver musb_driver = {
.dev_groups = musb_groups,
},
.probe = musb_probe,
- .remove_new = musb_remove,
+ .remove = musb_remove,
};
module_platform_driver(musb_driver);
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 9c7a8bbc0542..2542239ec64e 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -1032,7 +1032,7 @@ static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
static struct platform_driver dsps_usbss_driver = {
.probe = dsps_probe,
- .remove_new = dsps_remove,
+ .remove = dsps_remove,
.driver = {
.name = "musb-dsps",
.pm = &dsps_pm_ops,
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index bdf13911a1e5..c6076df0d50c 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1161,12 +1161,19 @@ void musb_free_request(struct usb_ep *ep, struct usb_request *req)
*/
void musb_ep_restart(struct musb *musb, struct musb_request *req)
{
+ u16 csr;
+ void __iomem *epio = req->ep->hw_ep->regs;
+
trace_musb_req_start(req);
musb_ep_select(musb->mregs, req->epnum);
- if (req->tx)
+ if (req->tx) {
txstate(musb, req);
- else
- rxstate(musb, req);
+ } else {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
}
static int musb_ep_restart_resume_work(struct musb *musb, void *data)
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 6d7336727388..f0786f8fbb25 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -533,7 +533,7 @@ static void ep0_txstate(struct musb *musb)
/* load the data */
fifo_src = (u8 *) request->buf + request->actual;
- fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE,
+ fifo_count = min_t(unsigned, MUSB_EP0_FIFOSIZE,
request->length - request->actual);
musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src);
request->actual += fifo_count;
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index bc4507781167..732ba981e607 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -798,10 +798,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
}
if (can_bulk_split(musb, qh->type))
- load_count = min((u32) hw_ep->max_packet_sz_tx,
- len);
+ load_count = min_t(u32, hw_ep->max_packet_sz_tx, len);
else
- load_count = min((u32) packet_sz, len);
+ load_count = min_t(u32, packet_sz, len);
if (dma_channel && musb_tx_dma_program(dma_controller,
hw_ep, qh, urb, offset, len))
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index b4a4c1df4e0d..2970967a4fd2 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -608,7 +608,7 @@ MODULE_DEVICE_TABLE(of, omap2430_id_table);
static struct platform_driver omap2430_driver = {
.probe = omap2430_probe,
- .remove_new = omap2430_remove,
+ .remove = omap2430_remove,
.driver = {
.name = "musb-omap2430",
.pm = DEV_PM_OPS,
diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c
index 05b6e7e52e02..eac1cde86be3 100644
--- a/drivers/usb/musb/sunxi.c
+++ b/drivers/usb/musb/sunxi.c
@@ -857,7 +857,7 @@ MODULE_DEVICE_TABLE(of, sunxi_musb_match);
static struct platform_driver sunxi_musb_driver = {
.probe = sunxi_musb_probe,
- .remove_new = sunxi_musb_remove,
+ .remove = sunxi_musb_remove,
.driver = {
.name = "musb-sunxi",
.of_match_table = sunxi_musb_match,
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 461587629bf2..90b760a95e4e 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1290,7 +1290,7 @@ static void tusb_remove(struct platform_device *pdev)
static struct platform_driver tusb_driver = {
.probe = tusb_probe,
- .remove_new = tusb_remove,
+ .remove = tusb_remove,
.driver = {
.name = "musb-tusb",
},
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index c8d9d2a1d2f0..8c2a43d992f5 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -355,7 +355,7 @@ MODULE_DEVICE_TABLE(of, ux500_match);
static struct platform_driver ux500_driver = {
.probe = ux500_probe,
- .remove_new = ux500_remove,
+ .remove = ux500_remove,
.driver = {
.name = "musb-ux500",
.pm = &ux500_pm_ops,
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
index 408f47e39025..6a98aeeeae31 100644
--- a/drivers/usb/phy/phy-ab8500-usb.c
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -987,7 +987,7 @@ MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype);
static struct platform_driver ab8500_usb_driver = {
.probe = ab8500_usb_probe,
- .remove_new = ab8500_usb_remove,
+ .remove = ab8500_usb_remove,
.id_table = ab8500_usb_devtype,
.driver = {
.name = "abx5x0-usb",
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
index 6db88e00f127..ca9353dad71a 100644
--- a/drivers/usb/phy/phy-am335x.c
+++ b/drivers/usb/phy/phy-am335x.c
@@ -133,7 +133,7 @@ MODULE_DEVICE_TABLE(of, am335x_phy_ids);
static struct platform_driver am335x_phy_driver = {
.probe = am335x_phy_probe,
- .remove_new = am335x_phy_remove,
+ .remove = am335x_phy_remove,
.driver = {
.name = "am335x-phy-driver",
.pm = &am335x_pm_ops,
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index c5c6b818998e..42c42e193232 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -1002,7 +1002,7 @@ static void fsl_otg_remove(struct platform_device *pdev)
struct platform_driver fsl_otg_driver = {
.probe = fsl_otg_probe,
- .remove_new = fsl_otg_remove,
+ .remove = fsl_otg_remove,
.driver = {
.name = driver_name,
},
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index e7d50e0a1612..6c3ececf9137 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -345,7 +345,7 @@ MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
static struct platform_driver usb_phy_generic_driver = {
.probe = usb_phy_generic_probe,
- .remove_new = usb_phy_generic_remove,
+ .remove = usb_phy_generic_remove,
.driver = {
.name = "usb_phy_generic",
.of_match_table = nop_xceiv_dt_ids,
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index 5428b2b67de1..ce09e789afd8 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -385,7 +385,7 @@ static struct platform_driver gpio_vbus_driver = {
.of_match_table = gpio_vbus_of_match,
},
.probe = gpio_vbus_probe,
- .remove_new = gpio_vbus_remove,
+ .remove = gpio_vbus_remove,
};
module_platform_driver(gpio_vbus_driver);
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
index 993d7525a102..f9b5c411aee4 100644
--- a/drivers/usb/phy/phy-isp1301.c
+++ b/drivers/usb/phy/phy-isp1301.c
@@ -25,7 +25,7 @@ struct isp1301 {
#define phy_to_isp(p) (container_of((p), struct isp1301, phy))
static const struct i2c_device_id isp1301_id[] = {
- { "isp1301", 0 },
+ { "isp1301" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isp1301_id);
diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c
index bd9a98ad1b30..51155c5513d3 100644
--- a/drivers/usb/phy/phy-keystone.c
+++ b/drivers/usb/phy/phy-keystone.c
@@ -103,7 +103,7 @@ MODULE_DEVICE_TABLE(of, keystone_usbphy_ids);
static struct platform_driver keystone_usbphy_driver = {
.probe = keystone_usbphy_probe,
- .remove_new = keystone_usbphy_remove,
+ .remove = keystone_usbphy_remove,
.driver = {
.name = "keystone-usbphy",
.of_match_table = keystone_usbphy_ids,
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
index df7c27474a75..a7a102f2e163 100644
--- a/drivers/usb/phy/phy-mv-usb.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -867,7 +867,7 @@ static int mv_otg_resume(struct platform_device *pdev)
static struct platform_driver mv_otg_driver = {
.probe = mv_otg_probe,
- .remove_new = mv_otg_remove,
+ .remove = mv_otg_remove,
.driver = {
.name = driver_name,
.dev_groups = mv_otg_groups,
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index cc4156c1b148..7490f1798b46 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -952,7 +952,7 @@ static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend,
static struct platform_driver mxs_phy_driver = {
.probe = mxs_phy_probe,
- .remove_new = mxs_phy_remove,
+ .remove = mxs_phy_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxs_phy_dt_ids,
diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c
index 5cac31c6029b..ae7bf3ff89ee 100644
--- a/drivers/usb/phy/phy-tahvo.c
+++ b/drivers/usb/phy/phy-tahvo.c
@@ -424,7 +424,7 @@ static void tahvo_usb_remove(struct platform_device *pdev)
static struct platform_driver tahvo_usb_driver = {
.probe = tahvo_usb_probe,
- .remove_new = tahvo_usb_remove,
+ .remove = tahvo_usb_remove,
.driver = {
.name = "tahvo-usb",
.dev_groups = tahvo_groups,
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index 4ea47e6f835b..bee222967f6b 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -1495,7 +1495,7 @@ static void tegra_usb_phy_remove(struct platform_device *pdev)
static struct platform_driver tegra_usb_phy_driver = {
.probe = tegra_usb_phy_probe,
- .remove_new = tegra_usb_phy_remove,
+ .remove = tegra_usb_phy_remove,
.driver = {
.name = "tegra-phy",
.of_match_table = tegra_usb_phy_id_table,
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index da09cff55abc..49d79c1257f3 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -432,7 +432,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
static struct platform_driver twl6030_usb_driver = {
.probe = twl6030_usb_probe,
- .remove_new = twl6030_usb_remove,
+ .remove = twl6030_usb_remove,
.driver = {
.name = "twl6030_usb",
.of_match_table = of_match_ptr(twl6030_usb_id_table),
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index 06f789097989..1ce134505cee 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -365,7 +365,7 @@ static int usb_add_extcon(struct usb_phy *x)
{
int ret;
- if (of_property_read_bool(x->dev->of_node, "extcon")) {
+ if (of_property_present(x->dev->of_node, "extcon")) {
x->edev = extcon_get_edev_by_phandle(x->dev, 0);
if (IS_ERR(x->edev))
return PTR_ERR(x->edev);
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index edc43f169d49..935fc496fe94 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -632,7 +632,7 @@ static int usbhs_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- if (of_property_read_bool(dev_of_node(dev), "extcon")) {
+ if (of_property_present(dev_of_node(dev), "extcon")) {
priv->edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(priv->edev))
return PTR_ERR(priv->edev);
@@ -835,7 +835,7 @@ static struct platform_driver renesas_usbhs_driver = {
.of_match_table = usbhs_of_match,
},
.probe = usbhs_probe,
- .remove_new = usbhs_remove,
+ .remove = usbhs_remove,
};
module_platform_driver(renesas_usbhs_driver);
diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c b/drivers/usb/roles/intel-xhci-usb-role-switch.c
index e5c6c413a075..cd2e026dcb22 100644
--- a/drivers/usb/roles/intel-xhci-usb-role-switch.c
+++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c
@@ -217,7 +217,7 @@ static struct platform_driver intel_xhci_usb_driver = {
},
.id_table = intel_xhci_usb_table,
.probe = intel_xhci_usb_probe,
- .remove_new = intel_xhci_usb_remove,
+ .remove = intel_xhci_usb_remove,
};
module_platform_driver(intel_xhci_usb_driver);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index d200e2c29a8f..2fea1b1db4a2 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -136,12 +136,11 @@ static void free_dynids(struct usb_serial_driver *drv)
{
struct usb_dynid *dynid, *n;
- spin_lock(&drv->dynids.lock);
+ guard(mutex)(&usb_dynids_lock);
list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
- spin_unlock(&drv->dynids.lock);
}
const struct bus_type usb_serial_bus_type = {
@@ -157,7 +156,6 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
int retval;
driver->driver.bus = &usb_serial_bus_type;
- spin_lock_init(&driver->dynids.lock);
INIT_LIST_HEAD(&driver->dynids.list);
retval = driver_register(&driver->driver);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c6f17d732b95..e07c5e3eb18c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1443,9 +1443,11 @@ static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
+ mutex_lock(&priv->cfg_lock);
ss->flags = priv->flags;
ss->baud_base = priv->baud_base;
ss->custom_divisor = priv->custom_divisor;
+ mutex_unlock(&priv->cfg_lock);
}
static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 28c71d99e857..1fffda7647f9 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1129,7 +1129,7 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
spin_lock_irqsave(&edge_port->ep_lock, flags);
/* calculate number of bytes to put in fifo */
- copySize = min((unsigned int)count,
+ copySize = min_t(unsigned int, count,
(edge_port->txCredits - fifo->count));
dev_dbg(&port->dev, "%s of %d byte(s) Fifo room %d -- will copy %d bytes\n",
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index ad41363e3cea..010688dd9e49 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -31,6 +31,7 @@
#define PL2303_QUIRK_UART_STATE_IDX0 BIT(0)
#define PL2303_QUIRK_LEGACY BIT(1)
#define PL2303_QUIRK_ENDPOINT_HACK BIT(2)
+#define PL2303_QUIRK_NO_BREAK_GETLINE BIT(3)
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID),
@@ -467,6 +468,25 @@ static int pl2303_detect_type(struct usb_serial *serial)
return -ENODEV;
}
+static bool pl2303_is_hxd_clone(struct usb_serial *serial)
+{
+ struct usb_device *udev = serial->dev;
+ unsigned char *buf;
+ int ret;
+
+ buf = kmalloc(7, GFP_KERNEL);
+ if (!buf)
+ return false;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+
+ kfree(buf);
+
+ return ret == -EPIPE;
+}
+
static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_serial_private *spriv;
@@ -489,6 +509,9 @@ static int pl2303_startup(struct usb_serial *serial)
spriv->quirks = (unsigned long)usb_get_serial_data(serial);
spriv->quirks |= spriv->type->quirks;
+ if (type == TYPE_HXD && pl2303_is_hxd_clone(serial))
+ spriv->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE;
+
usb_set_serial_data(serial, spriv);
if (type != TYPE_HXN) {
@@ -725,9 +748,18 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty,
static int pl2303_get_line_request(struct usb_serial_port *port,
unsigned char buf[7])
{
- struct usb_device *udev = port->serial->dev;
+ struct usb_serial *serial = port->serial;
+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
+ struct usb_device *udev = serial->dev;
int ret;
+ if (spriv->quirks & PL2303_QUIRK_NO_BREAK_GETLINE) {
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+
+ memcpy(buf, priv->line_settings, 7);
+ return 0;
+ }
+
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
@@ -1064,9 +1096,13 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)
static int pl2303_set_break(struct usb_serial_port *port, bool enable)
{
struct usb_serial *serial = port->serial;
+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
u16 state;
int result;
+ if (spriv->quirks & PL2303_QUIRK_NO_BREAK_GETLINE)
+ return -ENOTTY;
+
if (enable)
state = BREAK_ON;
else
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 64a2e0bb5723..741e68e46139 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -421,7 +421,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
unsigned long flags;
unsigned char *buffer;
struct urb *urb;
- size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER);
+ size_t writesize = min_t(size_t, count, MAX_TRANSFER);
int retval = 0;
/* verify that we actually have some data to write */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index df6a2ae0bf42..7266558d823a 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -706,14 +706,12 @@ static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
{
struct usb_dynid *dynid;
- spin_lock(&drv->dynids.lock);
+ guard(mutex)(&usb_dynids_lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (usb_match_one_id(intf, &dynid->id)) {
- spin_unlock(&drv->dynids.lock);
return &dynid->id;
}
}
- spin_unlock(&drv->dynids.lock);
return NULL;
}
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index a4bfbecbf16c..fd46e81388d2 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -737,7 +737,7 @@ static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
- bcb->Flags = 0x00;
+ bcb->Flags = US_BULK_FLAG_OUT;
bcb->CDB[0] = 0xF0;
bcb->CDB[5] = (unsigned char)(bnByte);
bcb->CDB[4] = (unsigned char)(bnByte>>8);
@@ -1163,7 +1163,7 @@ static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200*len;
- bcb->Flags = 0x00;
+ bcb->Flags = US_BULK_FLAG_OUT;
bcb->CDB[0] = 0xF0;
bcb->CDB[1] = 0x08;
bcb->CDB[4] = (unsigned char)(oldphy);
@@ -1759,7 +1759,7 @@ static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
- bcb->Flags = 0x00;
+ bcb->Flags = US_BULK_FLAG_OUT;
bcb->CDB[0] = 0xF0;
bcb->CDB[1] = 0x04;
bcb->CDB[5] = (unsigned char)(bn);
@@ -1931,7 +1931,7 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = sd_fw->size;
- bcb->Flags = 0x00;
+ bcb->Flags = US_BULK_FLAG_OUT;
bcb->CDB[0] = 0xEF;
result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index 0c423916d7bf..54ffff86c6fa 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -212,7 +212,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(buf_len);
- bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : US_BULK_FLAG_OUT;
bcb->Tag = ++us->tag;
bcb->Lun = lun;
bcb->Length = cmd_len;
@@ -301,7 +301,7 @@ static int rts51x_bulk_transport_special(struct us_data *us, u8 lun,
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(buf_len);
- bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : US_BULK_FLAG_OUT;
bcb->Tag = ++us->tag;
bcb->Lun = lun;
bcb->Length = cmd_len;
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 03d1b9c69ea1..30ee76cfef05 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -752,7 +752,7 @@ sddr09_read_data(struct us_data *us,
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
- len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
+ len = min_t(unsigned int, sectors, info->blocksize) * info->pagesize;
buffer = kmalloc(len, GFP_NOIO);
if (!buffer)
return -ENOMEM;
@@ -997,7 +997,7 @@ sddr09_write_data(struct us_data *us,
* at a time between the bounce buffer and the actual transfer buffer.
*/
- len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
+ len = min_t(unsigned int, sectors, info->blocksize) * info->pagesize;
buffer = kmalloc(len, GFP_NOIO);
if (!buffer) {
kfree(blockbuffer);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index b8227478a7ad..a37fc505c57f 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -206,7 +206,7 @@ static int sddr55_read_data(struct us_data *us,
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
- len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
+ len = min_t(unsigned int, sectors, info->blocksize >>
info->smallpageshift) * PAGESIZE;
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
@@ -224,7 +224,7 @@ static int sddr55_read_data(struct us_data *us,
// Read as many sectors as possible in this block
- pages = min((unsigned int) sectors << info->smallpageshift,
+ pages = min_t(unsigned int, sectors << info->smallpageshift,
info->blocksize - page);
len = pages << info->pageshift;
@@ -333,7 +333,7 @@ static int sddr55_write_data(struct us_data *us,
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
- len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
+ len = min_t(unsigned int, sectors, info->blocksize >>
info->smallpageshift) * PAGESIZE;
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
@@ -351,7 +351,7 @@ static int sddr55_write_data(struct us_data *us,
// Write as many sectors as possible in this block
- pages = min((unsigned int) sectors << info->smallpageshift,
+ pages = min_t(unsigned int, sectors << info->smallpageshift,
info->blocksize - page);
len = pages << info->pageshift;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 7449e379077a..9d767f6bf722 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1133,7 +1133,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(transfer_length);
bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ?
- US_BULK_FLAG_IN : 0;
+ US_BULK_FLAG_IN : US_BULK_FLAG_OUT;
bcb->Tag = ++us->tag;
bcb->Lun = srb->device->lun;
if (us->fflags & US_FL_SCM_MULT_TARG)
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
index 92cc1b136120..2f03190a9873 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -729,7 +729,7 @@ int dp_altmode_probe(struct typec_altmode *alt)
/* FIXME: Port can only be DFP_U. */
- /* Make sure we have compatiple pin configurations */
+ /* Make sure we have compatible pin configurations */
if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) &
DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) &&
!(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) &
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 58f40156de56..4b3047e055a3 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -219,6 +219,13 @@ static ssize_t usb_power_delivery_revision_show(struct device *dev,
char *buf);
static DEVICE_ATTR_RO(usb_power_delivery_revision);
+static const char * const usb_modes[] = {
+ [USB_MODE_NONE] = "none",
+ [USB_MODE_USB2] = "usb2",
+ [USB_MODE_USB3] = "usb3",
+ [USB_MODE_USB4] = "usb4"
+};
+
/* ------------------------------------------------------------------------- */
/* Alternate Modes */
@@ -614,6 +621,75 @@ EXPORT_SYMBOL_GPL(typec_unregister_altmode);
/* ------------------------------------------------------------------------- */
/* Type-C Partners */
+/**
+ * typec_partner_set_usb_mode - Assign active USB Mode for the partner
+ * @partner: USB Type-C partner
+ * @mode: USB Mode (USB2, USB3 or USB4)
+ *
+ * The port drivers can use this function to assign the active USB Mode to
+ * @partner. The USB Mode can change for example due to Data Reset.
+ */
+void typec_partner_set_usb_mode(struct typec_partner *partner, enum usb_mode mode)
+{
+ if (!partner || partner->usb_mode == mode)
+ return;
+
+ partner->usb_capability |= BIT(mode - 1);
+ partner->usb_mode = mode;
+ sysfs_notify(&partner->dev.kobj, NULL, "usb_mode");
+}
+EXPORT_SYMBOL_GPL(typec_partner_set_usb_mode);
+
+static ssize_t
+usb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct typec_partner *partner = to_typec_partner(dev);
+ int len = 0;
+ int i;
+
+ for (i = USB_MODE_USB2; i < USB_MODE_USB4 + 1; i++) {
+ if (!(BIT(i - 1) & partner->usb_capability))
+ continue;
+
+ if (i == partner->usb_mode)
+ len += sysfs_emit_at(buf, len, "[%s] ", usb_modes[i]);
+ else
+ len += sysfs_emit_at(buf, len, "%s ", usb_modes[i]);
+ }
+
+ sysfs_emit_at(buf, len - 1, "\n");
+
+ return len;
+}
+
+static ssize_t usb_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_partner *partner = to_typec_partner(dev);
+ struct typec_port *port = to_typec_port(dev->parent);
+ int mode;
+ int ret;
+
+ if (!port->ops || !port->ops->enter_usb_mode)
+ return -EOPNOTSUPP;
+
+ mode = sysfs_match_string(usb_modes, buf);
+ if (mode < 0)
+ return mode;
+
+ if (mode == partner->usb_mode)
+ return size;
+
+ ret = port->ops->enter_usb_mode(port, mode);
+ if (ret)
+ return ret;
+
+ typec_partner_set_usb_mode(partner, mode);
+
+ return size;
+}
+static DEVICE_ATTR_RW(usb_mode);
+
static ssize_t accessory_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -660,6 +736,7 @@ static struct attribute *typec_partner_attrs[] = {
&dev_attr_supports_usb_power_delivery.attr,
&dev_attr_number_of_alternate_modes.attr,
&dev_attr_type.attr,
+ &dev_attr_usb_mode.attr,
&dev_attr_usb_power_delivery_revision.attr,
NULL
};
@@ -667,6 +744,14 @@ static struct attribute *typec_partner_attrs[] = {
static umode_t typec_partner_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
{
struct typec_partner *partner = to_typec_partner(kobj_to_dev(kobj));
+ struct typec_port *port = to_typec_port(partner->dev.parent);
+
+ if (attr == &dev_attr_usb_mode.attr) {
+ if (!partner->usb_capability)
+ return 0;
+ if (!port->ops || !port->ops->enter_usb_mode)
+ return 0444;
+ }
if (attr == &dev_attr_number_of_alternate_modes.attr) {
if (partner->num_altmodes < 0)
@@ -740,10 +825,33 @@ static void typec_partner_unlink_device(struct typec_partner *partner, struct de
*/
int typec_partner_set_identity(struct typec_partner *partner)
{
- if (!partner->identity)
+ u8 usb_capability = partner->usb_capability;
+ struct device *dev = &partner->dev;
+ struct usb_pd_identity *id;
+
+ id = get_pd_identity(dev);
+ if (!id)
return -EINVAL;
- typec_report_identity(&partner->dev);
+ if (to_typec_port(dev->parent)->data_role == TYPEC_HOST) {
+ u32 devcap = PD_VDO_UFP_DEVCAP(id->vdo[0]);
+
+ if (devcap & (DEV_USB2_CAPABLE | DEV_USB2_BILLBOARD))
+ usb_capability |= USB_CAPABILITY_USB2;
+ if (devcap & DEV_USB3_CAPABLE)
+ usb_capability |= USB_CAPABILITY_USB3;
+ if (devcap & DEV_USB4_CAPABLE)
+ usb_capability |= USB_CAPABILITY_USB4;
+ } else {
+ usb_capability = PD_VDO_DFP_HOSTCAP(id->vdo[0]);
+ }
+
+ if (partner->usb_capability != usb_capability) {
+ partner->usb_capability = usb_capability;
+ sysfs_notify(&dev->kobj, NULL, "usb_mode");
+ }
+
+ typec_report_identity(dev);
return 0;
}
EXPORT_SYMBOL_GPL(typec_partner_set_identity);
@@ -913,6 +1021,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
partner->usb_pd = desc->usb_pd;
partner->accessory = desc->accessory;
partner->num_altmodes = -1;
+ partner->usb_capability = desc->usb_capability;
partner->pd_revision = desc->pd_revision;
partner->svdm_version = port->cap->svdm_version;
partner->attach = desc->attach;
@@ -932,6 +1041,15 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
partner->dev.type = &typec_partner_dev_type;
dev_set_name(&partner->dev, "%s-partner", dev_name(&port->dev));
+ if (port->usb2_dev) {
+ partner->usb_capability |= USB_CAPABILITY_USB2;
+ partner->usb_mode = USB_MODE_USB2;
+ }
+ if (port->usb3_dev) {
+ partner->usb_capability |= USB_CAPABILITY_USB2 | USB_CAPABILITY_USB3;
+ partner->usb_mode = USB_MODE_USB3;
+ }
+
ret = device_register(&partner->dev);
if (ret) {
dev_err(&port->dev, "failed to register partner (%d)\n", ret);
@@ -1293,6 +1411,67 @@ EXPORT_SYMBOL_GPL(typec_unregister_cable);
/* USB Type-C ports */
/**
+ * typec_port_set_usb_mode - Set the operational USB mode for the port
+ * @port: USB Type-C port
+ * @mode: USB Mode (USB2, USB3 or USB4)
+ *
+ * @mode will be used with the next Enter_USB message. Existing connections are
+ * not affected.
+ */
+void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode)
+{
+ port->usb_mode = mode;
+}
+EXPORT_SYMBOL_GPL(typec_port_set_usb_mode);
+
+static ssize_t
+usb_capability_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+ int len = 0;
+ int i;
+
+ for (i = USB_MODE_USB2; i < USB_MODE_USB4 + 1; i++) {
+ if (!(BIT(i - 1) & port->cap->usb_capability))
+ continue;
+
+ if (i == port->usb_mode)
+ len += sysfs_emit_at(buf, len, "[%s] ", usb_modes[i]);
+ else
+ len += sysfs_emit_at(buf, len, "%s ", usb_modes[i]);
+ }
+
+ sysfs_emit_at(buf, len - 1, "\n");
+
+ return len;
+}
+
+static ssize_t
+usb_capability_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_port *port = to_typec_port(dev);
+ int ret = 0;
+ int mode;
+
+ if (!port->ops || !port->ops->default_usb_mode_set)
+ return -EOPNOTSUPP;
+
+ mode = sysfs_match_string(usb_modes, buf);
+ if (mode < 0)
+ return mode;
+
+ ret = port->ops->default_usb_mode_set(port, mode);
+ if (ret)
+ return ret;
+
+ port->usb_mode = mode;
+
+ return size;
+}
+static DEVICE_ATTR_RW(usb_capability);
+
+/**
* typec_port_set_usb_power_delivery - Assign USB PD for port.
* @port: USB Type-C port.
* @pd: USB PD instance.
@@ -1760,6 +1939,7 @@ static struct attribute *typec_attrs[] = {
&dev_attr_vconn_source.attr,
&dev_attr_port_type.attr,
&dev_attr_orientation.attr,
+ &dev_attr_usb_capability.attr,
NULL,
};
@@ -1793,6 +1973,11 @@ static umode_t typec_attr_is_visible(struct kobject *kobj,
if (port->cap->orientation_aware)
return 0444;
return 0;
+ } else if (attr == &dev_attr_usb_capability.attr) {
+ if (!port->cap->usb_capability)
+ return 0;
+ if (!port->ops || !port->ops->default_usb_mode_set)
+ return 0444;
}
return attr->mode;
@@ -1864,13 +2049,18 @@ static void typec_partner_attach(struct typec_connector *con, struct device *dev
struct typec_port *port = container_of(con, struct typec_port, con);
struct typec_partner *partner = typec_get_partner(port);
struct usb_device *udev = to_usb_device(dev);
+ enum usb_mode usb_mode;
- if (udev->speed < USB_SPEED_SUPER)
+ if (udev->speed < USB_SPEED_SUPER) {
+ usb_mode = USB_MODE_USB2;
port->usb2_dev = dev;
- else
+ } else {
+ usb_mode = USB_MODE_USB3;
port->usb3_dev = dev;
+ }
if (partner) {
+ typec_partner_set_usb_mode(partner, usb_mode);
typec_partner_link_device(partner, dev);
put_device(&partner->dev);
}
@@ -2433,6 +2623,13 @@ struct typec_port *typec_register_port(struct device *parent,
port->con.attach = typec_partner_attach;
port->con.deattach = typec_partner_deattach;
+ if (cap->usb_capability & USB_CAPABILITY_USB4)
+ port->usb_mode = USB_MODE_USB4;
+ else if (cap->usb_capability & USB_CAPABILITY_USB3)
+ port->usb_mode = USB_MODE_USB3;
+ else if (cap->usb_capability & USB_CAPABILITY_USB2)
+ port->usb_mode = USB_MODE_USB2;
+
device_initialize(&port->dev);
port->dev.class = &typec_class;
port->dev.parent = parent;
diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
index 7485cdb9dd20..b3076a24ad2e 100644
--- a/drivers/usb/typec/class.h
+++ b/drivers/usb/typec/class.h
@@ -35,6 +35,8 @@ struct typec_partner {
int num_altmodes;
u16 pd_revision; /* 0300H = "3.0" */
enum usb_pd_svdm_ver svdm_version;
+ enum usb_mode usb_mode;
+ u8 usb_capability;
struct usb_power_delivery *pd;
@@ -55,6 +57,7 @@ struct typec_port {
enum typec_role vconn_role;
enum typec_pwr_opmode pwr_opmode;
enum typec_port_type port_type;
+ enum usb_mode usb_mode;
struct mutex port_type_lock;
enum typec_orientation orientation;
diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig
index ce7db6ad3057..67381b4ef4f6 100644
--- a/drivers/usb/typec/mux/Kconfig
+++ b/drivers/usb/typec/mux/Kconfig
@@ -66,6 +66,15 @@ config TYPEC_MUX_PTN36502
Say Y or M if your system has a NXP PTN36502 Type-C redriver chip
found on some devices with a Type-C port.
+config TYPEC_MUX_TUSB1046
+ tristate "TI TUSB1046 Type-C crosspoint switch driver"
+ depends on I2C
+ help
+ Driver for the Texas Instruments TUSB1046-DCI crosspoint switch.
+ Supports flipping USB-C SuperSpeed lanes to adapt to orientation
+ changes, as well as muxing DisplayPort and sideband signals to a
+ common Type-C connector.
+
config TYPEC_MUX_WCD939X_USBSS
tristate "Qualcomm WCD939x USBSS Analog Audio Switch driver"
depends on I2C
diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile
index bb96f30267af..60879446da93 100644
--- a/drivers/usb/typec/mux/Makefile
+++ b/drivers/usb/typec/mux/Makefile
@@ -7,4 +7,5 @@ obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o
obj-$(CONFIG_TYPEC_MUX_IT5205) += it5205.o
obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M) += nb7vpq904m.o
obj-$(CONFIG_TYPEC_MUX_PTN36502) += ptn36502.o
+obj-$(CONFIG_TYPEC_MUX_TUSB1046) += tusb1046.o
obj-$(CONFIG_TYPEC_MUX_WCD939X_USBSS) += wcd939x-usbss.o
diff --git a/drivers/usb/typec/mux/gpio-sbu-mux.c b/drivers/usb/typec/mux/gpio-sbu-mux.c
index 8902102c05a8..1834f1a2dd9d 100644
--- a/drivers/usb/typec/mux/gpio-sbu-mux.c
+++ b/drivers/usb/typec/mux/gpio-sbu-mux.c
@@ -159,7 +159,7 @@ MODULE_DEVICE_TABLE(of, gpio_sbu_mux_match);
static struct platform_driver gpio_sbu_mux_driver = {
.probe = gpio_sbu_mux_probe,
- .remove_new = gpio_sbu_mux_remove,
+ .remove = gpio_sbu_mux_remove,
.driver = {
.name = "gpio_sbu_mux",
.of_match_table = gpio_sbu_mux_match,
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
index 46b4c5c3a6be..5dfe95754394 100644
--- a/drivers/usb/typec/mux/intel_pmc_mux.c
+++ b/drivers/usb/typec/mux/intel_pmc_mux.c
@@ -828,7 +828,7 @@ static struct platform_driver pmc_usb_driver = {
.acpi_match_table = ACPI_PTR(pmc_usb_acpi_ids),
},
.probe = pmc_usb_probe,
- .remove_new = pmc_usb_remove,
+ .remove = pmc_usb_remove,
};
static int __init pmc_usb_init(void)
diff --git a/drivers/usb/typec/mux/tusb1046.c b/drivers/usb/typec/mux/tusb1046.c
new file mode 100644
index 000000000000..b4f45c217b59
--- /dev/null
+++ b/drivers/usb/typec/mux/tusb1046.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the TUSB1046-DCI USB Type-C crosspoint switch
+ *
+ * Copyright (C) 2024 Bootlin
+ */
+
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/err.h>
+#include <linux/of_device.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+
+#define TUSB1046_REG_GENERAL 0xa
+
+/* General register bits */
+#define TUSB1046_GENERAL_FLIPSEL BIT(2)
+#define TUSB1046_GENERAL_CTLSEL GENMASK(1, 0)
+
+/* Mux modes */
+#define TUSB1046_CTLSEL_DISABLED 0x0
+#define TUSB1046_CTLSEL_USB3 0x1
+#define TUSB1046_CTLSEL_4LANE_DP 0x2
+#define TUSB1046_CTLSEL_USB3_AND_2LANE_DP 0x3
+
+struct tusb1046_priv {
+ struct i2c_client *client;
+ struct typec_switch_dev *sw;
+ struct typec_mux_dev *mux;
+
+ /* Lock General register during accesses */
+ struct mutex general_reg_lock;
+};
+
+static int tusb1046_mux_set(struct typec_mux_dev *mux,
+ struct typec_mux_state *state)
+{
+ struct tusb1046_priv *priv = typec_mux_get_drvdata(mux);
+ struct i2c_client *client = priv->client;
+ struct device *dev = &client->dev;
+ int mode, val, ret = 0;
+
+ if (state->mode >= TYPEC_STATE_MODAL &&
+ state->alt->svid != USB_TYPEC_DP_SID)
+ return -EINVAL;
+
+ dev_dbg(dev, "mux mode requested: %lu\n", state->mode);
+
+ mutex_lock(&priv->general_reg_lock);
+
+ val = i2c_smbus_read_byte_data(client, TUSB1046_REG_GENERAL);
+ if (val < 0) {
+ dev_err(dev, "failed to read ctlsel status, err %d\n", val);
+ ret = val;
+ goto out_unlock;
+ }
+
+ switch (state->mode) {
+ case TYPEC_STATE_USB:
+ mode = TUSB1046_CTLSEL_USB3;
+ break;
+ case TYPEC_DP_STATE_C:
+ case TYPEC_DP_STATE_E:
+ mode = TUSB1046_CTLSEL_4LANE_DP;
+ break;
+ case TYPEC_DP_STATE_D:
+ mode = TUSB1046_CTLSEL_USB3_AND_2LANE_DP;
+ break;
+ case TYPEC_STATE_SAFE:
+ default:
+ mode = TUSB1046_CTLSEL_DISABLED;
+ break;
+ }
+
+ val &= ~TUSB1046_GENERAL_CTLSEL;
+ val |= mode;
+
+ ret = i2c_smbus_write_byte_data(client, TUSB1046_REG_GENERAL, val);
+
+out_unlock:
+ mutex_unlock(&priv->general_reg_lock);
+ return ret;
+}
+
+static int tusb1046_switch_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct tusb1046_priv *priv = typec_switch_get_drvdata(sw);
+ struct i2c_client *client = priv->client;
+ struct device *dev = &client->dev;
+ int val, ret = 0;
+
+ dev_dbg(dev, "setting USB3.0 lane flip for orientation %d\n", orientation);
+
+ mutex_lock(&priv->general_reg_lock);
+
+ val = i2c_smbus_read_byte_data(client, TUSB1046_REG_GENERAL);
+ if (val < 0) {
+ dev_err(dev, "failed to read flipsel status, err %d\n", val);
+ ret = val;
+ goto out_unlock;
+ }
+
+ if (orientation == TYPEC_ORIENTATION_REVERSE)
+ val |= TUSB1046_GENERAL_FLIPSEL;
+ else
+ val &= ~TUSB1046_GENERAL_FLIPSEL;
+
+ ret = i2c_smbus_write_byte_data(client, TUSB1046_REG_GENERAL, val);
+
+out_unlock:
+ mutex_unlock(&priv->general_reg_lock);
+ return ret;
+}
+
+static int tusb1046_i2c_probe(struct i2c_client *client)
+{
+ struct typec_switch_desc sw_desc = { };
+ struct typec_mux_desc mux_desc = { };
+ struct device *dev = &client->dev;
+ struct tusb1046_priv *priv;
+ int ret = 0;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return dev_err_probe(dev, -ENOMEM, "failed to allocate driver data\n");
+
+ priv->client = client;
+
+ mutex_init(&priv->general_reg_lock);
+
+ sw_desc.drvdata = priv;
+ sw_desc.fwnode = dev_fwnode(dev);
+ sw_desc.set = tusb1046_switch_set;
+
+ priv->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(priv->sw)) {
+ ret = dev_err_probe(dev, PTR_ERR(priv->sw), "failed to register type-c switch\n");
+ goto err_destroy_mutex;
+ }
+
+ mux_desc.drvdata = priv;
+ mux_desc.fwnode = dev_fwnode(dev);
+ mux_desc.set = tusb1046_mux_set;
+
+ priv->mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(priv->mux)) {
+ ret = dev_err_probe(dev, PTR_ERR(priv->mux), "failed to register type-c mux\n");
+ goto err_unregister_switch;
+ }
+
+ i2c_set_clientdata(client, priv);
+
+ return 0;
+
+err_unregister_switch:
+ typec_switch_unregister(priv->sw);
+err_destroy_mutex:
+ mutex_destroy(&priv->general_reg_lock);
+ return ret;
+}
+
+static void tusb1046_i2c_remove(struct i2c_client *client)
+{
+ struct tusb1046_priv *priv = i2c_get_clientdata(client);
+
+ typec_switch_unregister(priv->sw);
+ typec_mux_unregister(priv->mux);
+ mutex_destroy(&priv->general_reg_lock);
+}
+
+static const struct of_device_id tusb1046_match_table[] = {
+ {.compatible = "ti,tusb1046"},
+ {},
+};
+
+static struct i2c_driver tusb1046_driver = {
+ .driver = {
+ .name = "tusb1046",
+ .of_match_table = tusb1046_match_table,
+ },
+ .probe = tusb1046_i2c_probe,
+ .remove = tusb1046_i2c_remove,
+};
+
+module_i2c_driver(tusb1046_driver);
+
+MODULE_DESCRIPTION("TUSB1046 USB Type-C switch driver");
+MODULE_AUTHOR("Romain Gantois <romain.gantois@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c
index f3140fc04c12..6d85b25b40bc 100644
--- a/drivers/usb/typec/stusb160x.c
+++ b/drivers/usb/typec/stusb160x.c
@@ -633,9 +633,8 @@ MODULE_DEVICE_TABLE(of, stusb160x_of_match);
static int stusb160x_probe(struct i2c_client *client)
{
+ const struct regmap_config *regmap_config;
struct stusb160x *chip;
- const struct of_device_id *match;
- struct regmap_config *regmap_config;
struct fwnode_handle *fwnode;
int ret;
@@ -645,8 +644,8 @@ static int stusb160x_probe(struct i2c_client *client)
i2c_set_clientdata(client, chip);
- match = i2c_of_match_device(stusb160x_of_match, client);
- regmap_config = (struct regmap_config *)match->data;
+ regmap_config = i2c_get_match_data(client);
+
chip->regmap = devm_regmap_init_i2c(client, regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
index b80eb2d78d88..3766790c1548 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
@@ -163,7 +163,7 @@ static struct platform_driver qcom_pmic_typec_driver = {
.of_match_table = qcom_pmic_typec_table,
},
.probe = qcom_pmic_typec_probe,
- .remove_new = qcom_pmic_typec_remove,
+ .remove = qcom_pmic_typec_remove,
};
module_platform_driver(qcom_pmic_typec_driver);
diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c
index 02b7fd302265..881ffacbfd77 100644
--- a/drivers/usb/typec/tcpm/tcpci_mt6360.c
+++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c
@@ -221,7 +221,7 @@ static struct platform_driver mt6360_tcpc_driver = {
.of_match_table = mt6360_tcpc_of_id,
},
.probe = mt6360_tcpc_probe,
- .remove_new = mt6360_tcpc_remove,
+ .remove = mt6360_tcpc_remove,
};
module_platform_driver(mt6360_tcpc_driver);
diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
index 9cda1005ef01..1479f961772d 100644
--- a/drivers/usb/typec/tcpm/tcpci_mt6370.c
+++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
@@ -196,7 +196,7 @@ static struct platform_driver mt6370_tcpc_driver = {
.of_match_table = mt6370_tcpc_devid_table,
},
.probe = mt6370_tcpc_probe,
- .remove_new = mt6370_tcpc_remove,
+ .remove = mt6370_tcpc_remove,
};
module_platform_driver(mt6370_tcpc_driver);
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 7ae341a40342..6021eeb903fe 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -310,6 +310,18 @@ struct pd_data {
unsigned int operating_snk_mw;
};
+/*
+ * @sink_wait_cap_time: Deadline (in ms) for tTypeCSinkWaitCap timer
+ * @ps_src_wait_off_time: Deadline (in ms) for tPSSourceOff timer
+ * @cc_debounce_time: Deadline (in ms) for tCCDebounce timer
+ */
+struct pd_timings {
+ u32 sink_wait_cap_time;
+ u32 ps_src_off_time;
+ u32 cc_debounce_time;
+ u32 snk_bc12_cmpletion_time;
+};
+
struct tcpm_port {
struct device *dev;
@@ -552,6 +564,9 @@ struct tcpm_port {
*/
unsigned int message_id_prime;
unsigned int rx_msgid_prime;
+
+ /* Timer deadline values configured at runtime */
+ struct pd_timings timings;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
struct mutex logbuffer_lock; /* log buffer access lock */
@@ -4640,15 +4655,15 @@ static void run_state_machine(struct tcpm_port *port)
case SRC_ATTACH_WAIT:
if (tcpm_port_is_debug(port))
tcpm_set_state(port, DEBUG_ACC_ATTACHED,
- PD_T_CC_DEBOUNCE);
+ port->timings.cc_debounce_time);
else if (tcpm_port_is_audio(port))
tcpm_set_state(port, AUDIO_ACC_ATTACHED,
- PD_T_CC_DEBOUNCE);
+ port->timings.cc_debounce_time);
else if (tcpm_port_is_source(port) && port->vbus_vsafe0v)
tcpm_set_state(port,
tcpm_try_snk(port) ? SNK_TRY
: SRC_ATTACHED,
- PD_T_CC_DEBOUNCE);
+ port->timings.cc_debounce_time);
break;
case SNK_TRY:
@@ -4699,7 +4714,7 @@ static void run_state_machine(struct tcpm_port *port)
}
break;
case SRC_TRYWAIT_DEBOUNCE:
- tcpm_set_state(port, SRC_ATTACHED, PD_T_CC_DEBOUNCE);
+ tcpm_set_state(port, SRC_ATTACHED, port->timings.cc_debounce_time);
break;
case SRC_TRYWAIT_UNATTACHED:
tcpm_set_state(port, SNK_UNATTACHED, 0);
@@ -4902,7 +4917,7 @@ static void run_state_machine(struct tcpm_port *port)
(port->cc1 != TYPEC_CC_OPEN &&
port->cc2 == TYPEC_CC_OPEN))
tcpm_set_state(port, SNK_DEBOUNCED,
- PD_T_CC_DEBOUNCE);
+ port->timings.cc_debounce_time);
else if (tcpm_port_is_disconnected(port))
tcpm_set_state(port, SNK_UNATTACHED,
PD_T_PD_DEBOUNCE);
@@ -4942,7 +4957,7 @@ static void run_state_machine(struct tcpm_port *port)
break;
case SNK_TRYWAIT:
tcpm_set_cc(port, TYPEC_CC_RD);
- tcpm_set_state(port, SNK_TRYWAIT_VBUS, PD_T_CC_DEBOUNCE);
+ tcpm_set_state(port, SNK_TRYWAIT_VBUS, port->timings.cc_debounce_time);
break;
case SNK_TRYWAIT_VBUS:
/*
@@ -4965,7 +4980,16 @@ static void run_state_machine(struct tcpm_port *port)
if (ret < 0)
tcpm_set_state(port, SNK_UNATTACHED, 0);
else
- tcpm_set_state(port, SNK_STARTUP, 0);
+ /*
+ * For Type C port controllers that use Battery Charging
+ * Detection (based on BCv1.2 spec) to detect USB
+ * charger type, add a delay of "snk_bc12_cmpletion_time"
+ * before transitioning to SNK_STARTUP to allow BC1.2
+ * detection to complete before PD is eventually enabled
+ * in later states.
+ */
+ tcpm_set_state(port, SNK_STARTUP,
+ port->timings.snk_bc12_cmpletion_time);
break;
case SNK_STARTUP:
opmode = tcpm_get_pwr_opmode(port->polarity ?
@@ -5015,7 +5039,7 @@ static void run_state_machine(struct tcpm_port *port)
break;
case SNK_DISCOVERY_DEBOUNCE:
tcpm_set_state(port, SNK_DISCOVERY_DEBOUNCE_DONE,
- PD_T_CC_DEBOUNCE);
+ port->timings.cc_debounce_time);
break;
case SNK_DISCOVERY_DEBOUNCE_DONE:
if (!tcpm_port_is_disconnected(port) &&
@@ -5042,13 +5066,14 @@ static void run_state_machine(struct tcpm_port *port)
if (port->vbus_never_low) {
port->vbus_never_low = false;
tcpm_set_state(port, SNK_SOFT_RESET,
- PD_T_SINK_WAIT_CAP);
+ port->timings.sink_wait_cap_time);
} else {
if (!port->self_powered)
upcoming_state = SNK_WAIT_CAPABILITIES_TIMEOUT;
else
upcoming_state = hard_reset_state(port);
- tcpm_set_state(port, upcoming_state, PD_T_SINK_WAIT_CAP);
+ tcpm_set_state(port, SNK_WAIT_CAPABILITIES_TIMEOUT,
+ port->timings.sink_wait_cap_time);
}
break;
case SNK_WAIT_CAPABILITIES_TIMEOUT:
@@ -5070,7 +5095,8 @@ static void run_state_machine(struct tcpm_port *port)
if (tcpm_pd_send_control(port, PD_CTRL_GET_SOURCE_CAP, TCPC_TX_SOP))
tcpm_set_state_cond(port, hard_reset_state(port), 0);
else
- tcpm_set_state(port, hard_reset_state(port), PD_T_SINK_WAIT_CAP);
+ tcpm_set_state(port, hard_reset_state(port),
+ port->timings.sink_wait_cap_time);
break;
case SNK_NEGOTIATE_CAPABILITIES:
port->pd_capable = true;
@@ -5207,7 +5233,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ACC_UNATTACHED, 0);
break;
case AUDIO_ACC_DEBOUNCE:
- tcpm_set_state(port, ACC_UNATTACHED, PD_T_CC_DEBOUNCE);
+ tcpm_set_state(port, ACC_UNATTACHED, port->timings.cc_debounce_time);
break;
/* Hard_Reset states */
@@ -5274,7 +5300,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, SRC_UNATTACHED, PD_T_PS_SOURCE_ON);
break;
case SNK_HARD_RESET_SINK_OFF:
- /* Do not discharge/disconnect during hard reseet */
+ /* Do not discharge/disconnect during hard reset */
tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0);
memset(&port->pps_data, 0, sizeof(port->pps_data));
tcpm_set_vconn(port, false);
@@ -5424,7 +5450,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ERROR_RECOVERY, 0);
break;
case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF:
- tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_OFF);
+ tcpm_set_state(port, ERROR_RECOVERY, port->timings.ps_src_off_time);
break;
case FR_SWAP_SNK_SRC_NEW_SINK_READY:
if (port->vbus_source)
@@ -5479,7 +5505,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_cc(port, TYPEC_CC_RD);
/* allow CC debounce */
tcpm_set_state(port, PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED,
- PD_T_CC_DEBOUNCE);
+ port->timings.cc_debounce_time);
break;
case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED:
/*
@@ -5514,7 +5540,7 @@ static void run_state_machine(struct tcpm_port *port)
port->pps_data.active, 0);
tcpm_set_charge(port, false);
tcpm_set_state(port, hard_reset_state(port),
- PD_T_PS_SOURCE_OFF);
+ port->timings.ps_src_off_time);
break;
case PR_SWAP_SNK_SRC_SOURCE_ON:
tcpm_enable_auto_vbus_discharge(port, true);
@@ -5670,7 +5696,7 @@ static void run_state_machine(struct tcpm_port *port)
case PORT_RESET_WAIT_OFF:
tcpm_set_state(port,
tcpm_default_state(port),
- port->vbus_present ? PD_T_PS_SOURCE_OFF : 0);
+ port->vbus_present ? port->timings.ps_src_off_time : 0);
break;
/* AMS intermediate state */
@@ -6070,7 +6096,7 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
break;
case SNK_ATTACH_WAIT:
case SNK_DEBOUNCED:
- /* Do nothing, as TCPM is still waiting for vbus to reaach VSAFE5V to connect */
+ /* Do nothing, as TCPM is still waiting for vbus to reach VSAFE5V to connect */
break;
case SNK_NEGOTIATE_CAPABILITIES:
@@ -6161,7 +6187,7 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
case SRC_ATTACH_WAIT:
if (tcpm_port_is_source(port))
tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED,
- PD_T_CC_DEBOUNCE);
+ port->timings.cc_debounce_time);
break;
case SRC_STARTUP:
case SRC_SEND_CAPABILITIES:
@@ -7057,6 +7083,34 @@ err_unregister:
return ret;
}
+static void tcpm_fw_get_timings(struct tcpm_port *port, struct fwnode_handle *fwnode)
+{
+ int ret;
+ u32 val;
+
+ ret = fwnode_property_read_u32(fwnode, "sink-wait-cap-time-ms", &val);
+ if (!ret)
+ port->timings.sink_wait_cap_time = val;
+ else
+ port->timings.sink_wait_cap_time = PD_T_SINK_WAIT_CAP;
+
+ ret = fwnode_property_read_u32(fwnode, "ps-source-off-time-ms", &val);
+ if (!ret)
+ port->timings.ps_src_off_time = val;
+ else
+ port->timings.ps_src_off_time = PD_T_PS_SOURCE_OFF;
+
+ ret = fwnode_property_read_u32(fwnode, "cc-debounce-time-ms", &val);
+ if (!ret)
+ port->timings.cc_debounce_time = val;
+ else
+ port->timings.cc_debounce_time = PD_T_CC_DEBOUNCE;
+
+ ret = fwnode_property_read_u32(fwnode, "sink-bc12-completion-time-ms", &val);
+ if (!ret)
+ port->timings.snk_bc12_cmpletion_time = val;
+}
+
static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode)
{
struct fwnode_handle *capabilities, *child, *caps = NULL;
@@ -7371,7 +7425,7 @@ static int tcpm_psy_get_input_power_limit(struct tcpm_port *port,
src_mv = pdo_fixed_voltage(pdo);
src_ma = pdo_max_current(pdo);
tmp = src_mv * src_ma;
- max_src_uw = tmp > max_src_uw ? tmp : max_src_uw;
+ max_src_uw = max(tmp, max_src_uw);
}
}
@@ -7614,6 +7668,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
if (err < 0)
goto out_destroy_wq;
+ tcpm_fw_get_timings(port, tcpc->fwnode);
+
port->try_role = port->typec_caps.prefer_role;
port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */
diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c
index 60b2766a69bf..759c982bb16a 100644
--- a/drivers/usb/typec/tcpm/wcove.c
+++ b/drivers/usb/typec/tcpm/wcove.c
@@ -687,7 +687,7 @@ static struct platform_driver wcove_typec_driver = {
.name = "bxt_wcove_usbc",
},
.probe = wcove_typec_probe,
- .remove_new = wcove_typec_remove,
+ .remove = wcove_typec_remove,
};
module_platform_driver(wcove_typec_driver);
diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c
index f67733cecfdf..83ff23086d79 100644
--- a/drivers/usb/typec/ucsi/debugfs.c
+++ b/drivers/usb/typec/ucsi/debugfs.c
@@ -32,6 +32,7 @@ static int ucsi_cmd(void *data, u64 val)
case UCSI_SET_UOR:
case UCSI_SET_PDR:
case UCSI_CONNECTOR_RESET:
+ case UCSI_SET_SINK_PATH:
ret = ucsi_send_command(ucsi, val, NULL, 0);
break;
case UCSI_GET_CAPABILITY:
diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c
index 1c631c7855a9..62ac69730405 100644
--- a/drivers/usb/typec/ucsi/psy.c
+++ b/drivers/usb/typec/ucsi/psy.c
@@ -55,8 +55,8 @@ static int ucsi_psy_get_online(struct ucsi_connector *con,
union power_supply_propval *val)
{
val->intval = UCSI_PSY_OFFLINE;
- if (con->status.flags & UCSI_CONSTAT_CONNECTED &&
- (con->status.flags & UCSI_CONSTAT_PWR_DIR) == TYPEC_SINK)
+ if (UCSI_CONSTAT(con, CONNECTED) &&
+ (UCSI_CONSTAT(con, PWR_DIR) == TYPEC_SINK))
val->intval = UCSI_PSY_FIXED_ONLINE;
return 0;
}
@@ -66,7 +66,7 @@ static int ucsi_psy_get_voltage_min(struct ucsi_connector *con,
{
u32 pdo;
- switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
pdo = con->src_pdos[0];
val->intval = pdo_fixed_voltage(pdo) * 1000;
@@ -89,7 +89,7 @@ static int ucsi_psy_get_voltage_max(struct ucsi_connector *con,
{
u32 pdo;
- switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
if (con->num_pdos > 0) {
pdo = con->src_pdos[con->num_pdos - 1];
@@ -117,7 +117,7 @@ static int ucsi_psy_get_voltage_now(struct ucsi_connector *con,
int index;
u32 pdo;
- switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
index = rdo_index(con->rdo);
if (index > 0) {
@@ -145,7 +145,7 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con,
{
u32 pdo;
- switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
if (con->num_pdos > 0) {
pdo = con->src_pdos[con->num_pdos - 1];
@@ -173,9 +173,7 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con,
static int ucsi_psy_get_current_now(struct ucsi_connector *con,
union power_supply_propval *val)
{
- u16 flags = con->status.flags;
-
- if (UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD)
+ if (UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD)
val->intval = rdo_op_current(con->rdo) * 1000;
else
val->intval = 0;
@@ -185,11 +183,9 @@ static int ucsi_psy_get_current_now(struct ucsi_connector *con,
static int ucsi_psy_get_usb_type(struct ucsi_connector *con,
union power_supply_propval *val)
{
- u16 flags = con->status.flags;
-
val->intval = POWER_SUPPLY_USB_TYPE_C;
- if (flags & UCSI_CONSTAT_CONNECTED &&
- UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD)
+ if (UCSI_CONSTAT(con, CONNECTED) &&
+ UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD)
val->intval = POWER_SUPPLY_USB_TYPE_PD;
return 0;
@@ -197,18 +193,18 @@ static int ucsi_psy_get_usb_type(struct ucsi_connector *con,
static int ucsi_psy_get_charge_type(struct ucsi_connector *con, union power_supply_propval *val)
{
- if (!(con->status.flags & UCSI_CONSTAT_CONNECTED)) {
+ if (!(UCSI_CONSTAT(con, CONNECTED))) {
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
return 0;
}
/* The Battery Charging Cabability Status field is only valid in sink role. */
- if ((con->status.flags & UCSI_CONSTAT_PWR_DIR) != TYPEC_SINK) {
+ if (UCSI_CONSTAT(con, PWR_DIR) != TYPEC_SINK) {
val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
return 0;
}
- switch (UCSI_CONSTAT_BC_STATUS(con->status.pwr_status)) {
+ switch (UCSI_CONSTAT(con, BC_STATUS)) {
case UCSI_CONSTAT_BC_NOMINAL_CHARGING:
val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
break;
diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h
index a0d3a934d3d9..41701dee7056 100644
--- a/drivers/usb/typec/ucsi/trace.h
+++ b/drivers/usb/typec/ucsi/trace.h
@@ -40,8 +40,8 @@ DEFINE_EVENT(ucsi_log_command, ucsi_reset_ppm,
);
DECLARE_EVENT_CLASS(ucsi_log_connector_status,
- TP_PROTO(int port, struct ucsi_connector_status *status),
- TP_ARGS(port, status),
+ TP_PROTO(int port, struct ucsi_connector *con),
+ TP_ARGS(port, con),
TP_STRUCT__entry(
__field(int, port)
__field(u16, change)
@@ -55,14 +55,14 @@ DECLARE_EVENT_CLASS(ucsi_log_connector_status,
),
TP_fast_assign(
__entry->port = port - 1;
- __entry->change = status->change;
- __entry->opmode = UCSI_CONSTAT_PWR_OPMODE(status->flags);
- __entry->connected = !!(status->flags & UCSI_CONSTAT_CONNECTED);
- __entry->pwr_dir = !!(status->flags & UCSI_CONSTAT_PWR_DIR);
- __entry->partner_flags = UCSI_CONSTAT_PARTNER_FLAGS(status->flags);
- __entry->partner_type = UCSI_CONSTAT_PARTNER_TYPE(status->flags);
- __entry->request_data_obj = status->request_data_obj;
- __entry->bc_status = UCSI_CONSTAT_BC_STATUS(status->pwr_status);
+ __entry->change = UCSI_CONSTAT(con, CHANGE);
+ __entry->opmode = UCSI_CONSTAT(con, PWR_OPMODE);
+ __entry->connected = UCSI_CONSTAT(con, CONNECTED);
+ __entry->pwr_dir = UCSI_CONSTAT(con, PWR_DIR);
+ __entry->partner_flags = UCSI_CONSTAT(con, PARTNER_FLAGS);
+ __entry->partner_type = UCSI_CONSTAT(con, PARTNER_TYPE);
+ __entry->request_data_obj = UCSI_CONSTAT(con, RDO);
+ __entry->bc_status = UCSI_CONSTAT(con, BC_STATUS);
),
TP_printk("port%d status: change=%04x, opmode=%x, connected=%d, "
"sourcing=%d, partner_flags=%x, partner_type=%x, "
@@ -73,13 +73,13 @@ DECLARE_EVENT_CLASS(ucsi_log_connector_status,
);
DEFINE_EVENT(ucsi_log_connector_status, ucsi_connector_change,
- TP_PROTO(int port, struct ucsi_connector_status *status),
- TP_ARGS(port, status)
+ TP_PROTO(int port, struct ucsi_connector *con),
+ TP_ARGS(port, con)
);
DEFINE_EVENT(ucsi_log_connector_status, ucsi_register_port,
- TP_PROTO(int port, struct ucsi_connector_status *status),
- TP_ARGS(port, status)
+ TP_PROTO(int port, struct ucsi_connector *con),
+ TP_ARGS(port, con)
);
DECLARE_EVENT_CLASS(ucsi_log_register_altmode,
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index e0f3925e401b..c435c0835744 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -648,6 +648,17 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient)
}
}
+static int ucsi_get_connector_status(struct ucsi_connector *con, bool conn_ack)
+{
+ u64 command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+ size_t size = min(UCSI_GET_CONNECTOR_STATUS_SIZE, UCSI_MAX_DATA_LENGTH(con->ucsi));
+ int ret;
+
+ ret = ucsi_send_command_common(con->ucsi, command, &con->status, size, conn_ack);
+
+ return ret < 0 ? ret : 0;
+}
+
static int ucsi_read_pdos(struct ucsi_connector *con,
enum typec_role role, int is_partner,
u32 *pdos, int offset, int num_pdos)
@@ -658,8 +669,7 @@ static int ucsi_read_pdos(struct ucsi_connector *con,
if (is_partner &&
ucsi->quirks & UCSI_NO_PARTNER_PDOS &&
- ((con->status.flags & UCSI_CONSTAT_PWR_DIR) ||
- !is_source(role)))
+ (UCSI_CONSTAT(con, PWR_DIR) || !is_source(role)))
return 0;
command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num);
@@ -973,6 +983,7 @@ static void ucsi_unregister_cable(struct ucsi_connector *con)
static int ucsi_check_connector_capability(struct ucsi_connector *con)
{
+ u64 pd_revision;
u64 command;
int ret;
@@ -986,17 +997,17 @@ static int ucsi_check_connector_capability(struct ucsi_connector *con)
return ret;
}
- typec_partner_set_pd_revision(con->partner,
- UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags));
+ pd_revision = UCSI_CONCAP(con, PARTNER_PD_REVISION_V2_1);
+ typec_partner_set_pd_revision(con->partner, UCSI_SPEC_REVISION_TO_BCD(pd_revision));
return ret;
}
static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
{
- switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
- con->rdo = con->status.request_data_obj;
+ con->rdo = UCSI_CONSTAT(con, RDO);
typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD);
ucsi_partner_task(con, ucsi_get_src_pdos, 30, 0);
ucsi_partner_task(con, ucsi_check_altmodes, 30, HZ);
@@ -1020,7 +1031,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
static int ucsi_register_partner(struct ucsi_connector *con)
{
- u8 pwr_opmode = UCSI_CONSTAT_PWR_OPMODE(con->status.flags);
+ u8 pwr_opmode = UCSI_CONSTAT(con, PWR_OPMODE);
struct typec_partner_desc desc;
struct typec_partner *partner;
@@ -1029,7 +1040,7 @@ static int ucsi_register_partner(struct ucsi_connector *con)
memset(&desc, 0, sizeof(desc));
- switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PARTNER_TYPE)) {
case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
desc.accessory = TYPEC_ACCESSORY_DEBUG;
break;
@@ -1047,6 +1058,11 @@ static int ucsi_register_partner(struct ucsi_connector *con)
desc.identity = &con->partner_identity;
desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD;
+ if (con->ucsi->version >= UCSI_VERSION_2_1) {
+ u64 pd_revision = UCSI_CONCAP(con, PARTNER_PD_REVISION_V2_1);
+ desc.pd_revision = UCSI_SPEC_REVISION_TO_BCD(pd_revision);
+ }
+
partner = typec_register_partner(con->port, &desc);
if (IS_ERR(partner)) {
dev_err(con->ucsi->dev,
@@ -1057,6 +1073,13 @@ static int ucsi_register_partner(struct ucsi_connector *con)
con->partner = partner;
+ if (con->ucsi->version >= UCSI_VERSION_3_0 &&
+ UCSI_CONSTAT(con, PARTNER_FLAG_USB4_GEN4))
+ typec_partner_set_usb_mode(partner, USB_MODE_USB4);
+ else if (con->ucsi->version >= UCSI_VERSION_2_0 &&
+ UCSI_CONSTAT(con, PARTNER_FLAG_USB4_GEN3))
+ typec_partner_set_usb_mode(partner, USB_MODE_USB4);
+
return 0;
}
@@ -1081,7 +1104,7 @@ static void ucsi_partner_change(struct ucsi_connector *con)
enum usb_role u_role = USB_ROLE_NONE;
int ret;
- switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PARTNER_TYPE)) {
case UCSI_CONSTAT_PARTNER_TYPE_UFP:
case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP:
u_role = USB_ROLE_HOST;
@@ -1097,8 +1120,8 @@ static void ucsi_partner_change(struct ucsi_connector *con)
break;
}
- if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
- switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
+ if (UCSI_CONSTAT(con, CONNECTED)) {
+ switch (UCSI_CONSTAT(con, PARTNER_TYPE)) {
case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
typec_set_mode(con->port, TYPEC_MODE_DEBUG);
break;
@@ -1106,14 +1129,13 @@ static void ucsi_partner_change(struct ucsi_connector *con)
typec_set_mode(con->port, TYPEC_MODE_AUDIO);
break;
default:
- if (UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) ==
- UCSI_CONSTAT_PARTNER_FLAG_USB)
+ if (UCSI_CONSTAT(con, PARTNER_FLAG_USB))
typec_set_mode(con->port, TYPEC_STATE_USB);
}
}
/* Only notify USB controller if partner supports USB data */
- if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB))
+ if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB)))
u_role = USB_ROLE_NONE;
ret = usb_role_switch_set_role(con->usb_role_sw, u_role);
@@ -1124,21 +1146,18 @@ static void ucsi_partner_change(struct ucsi_connector *con)
static int ucsi_check_connection(struct ucsi_connector *con)
{
- u8 prev_flags = con->status.flags;
- u64 command;
+ u8 prev_state = UCSI_CONSTAT(con, CONNECTED);
int ret;
- command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
- ret = ucsi_send_command(con->ucsi, command, &con->status, sizeof(con->status));
- if (ret < 0) {
+ ret = ucsi_get_connector_status(con, false);
+ if (ret) {
dev_err(con->ucsi->dev, "GET_CONNECTOR_STATUS failed (%d)\n", ret);
return ret;
}
- if (con->status.flags == prev_flags)
- return 0;
-
- if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
+ if (UCSI_CONSTAT(con, CONNECTED)) {
+ if (prev_state)
+ return 0;
ucsi_register_partner(con);
ucsi_pwr_opmode_change(con);
ucsi_partner_change(con);
@@ -1194,7 +1213,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
work);
struct ucsi *ucsi = con->ucsi;
enum typec_role role;
- u64 command;
+ u16 change;
int ret;
mutex_lock(&con->lock);
@@ -1203,25 +1222,23 @@ static void ucsi_handle_connector_change(struct work_struct *work)
dev_err_once(ucsi->dev, "%s entered without EVENT_PENDING\n",
__func__);
- command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
-
- ret = ucsi_send_command_common(ucsi, command, &con->status,
- sizeof(con->status), true);
- if (ret < 0) {
+ ret = ucsi_get_connector_status(con, true);
+ if (ret) {
dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
__func__, ret);
clear_bit(EVENT_PENDING, &con->ucsi->flags);
goto out_unlock;
}
- trace_ucsi_connector_change(con->num, &con->status);
+ trace_ucsi_connector_change(con->num, con);
if (ucsi->ops->connector_status)
ucsi->ops->connector_status(con);
- role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR);
+ change = UCSI_CONSTAT(con, CHANGE);
+ role = UCSI_CONSTAT(con, PWR_DIR);
- if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) {
+ if (change & UCSI_CONSTAT_POWER_DIR_CHANGE) {
typec_set_pwr_role(con->port, role);
/* Complete pending power role swap */
@@ -1229,12 +1246,12 @@ static void ucsi_handle_connector_change(struct work_struct *work)
complete(&con->complete);
}
- if (con->status.change & UCSI_CONSTAT_CONNECT_CHANGE) {
+ if (change & UCSI_CONSTAT_CONNECT_CHANGE) {
typec_set_pwr_role(con->port, role);
ucsi_port_psy_changed(con);
ucsi_partner_change(con);
- if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
+ if (UCSI_CONSTAT(con, CONNECTED)) {
ucsi_register_partner(con);
ucsi_partner_task(con, ucsi_check_connection, 1, HZ);
if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE)
@@ -1242,8 +1259,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS)
ucsi_partner_task(con, ucsi_check_cable, 1, HZ);
- if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) ==
- UCSI_CONSTAT_PWR_OPMODE_PD) {
+ if (UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) {
ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ);
ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ);
}
@@ -1252,11 +1268,10 @@ static void ucsi_handle_connector_change(struct work_struct *work)
}
}
- if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE ||
- con->status.change & UCSI_CONSTAT_POWER_LEVEL_CHANGE)
+ if (change & (UCSI_CONSTAT_POWER_OPMODE_CHANGE | UCSI_CONSTAT_POWER_LEVEL_CHANGE))
ucsi_pwr_opmode_change(con);
- if (con->partner && con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) {
+ if (con->partner && (change & UCSI_CONSTAT_PARTNER_CHANGE)) {
ucsi_partner_change(con);
/* Complete pending data role swap */
@@ -1264,10 +1279,10 @@ static void ucsi_handle_connector_change(struct work_struct *work)
complete(&con->complete);
}
- if (con->status.change & UCSI_CONSTAT_CAM_CHANGE)
+ if (change & UCSI_CONSTAT_CAM_CHANGE)
ucsi_partner_task(con, ucsi_check_altmodes, 1, HZ);
- if (con->status.change & UCSI_CONSTAT_BC_CHANGE)
+ if (change & UCSI_CONSTAT_BC_CHANGE)
ucsi_port_psy_changed(con);
out_unlock:
@@ -1427,7 +1442,7 @@ static int ucsi_dr_swap(struct typec_port *port, enum typec_data_role role)
goto out_unlock;
}
- partner_type = UCSI_CONSTAT_PARTNER_TYPE(con->status.flags);
+ partner_type = UCSI_CONSTAT(con, PARTNER_TYPE);
if ((partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP &&
role == TYPEC_DEVICE) ||
(partner_type == UCSI_CONSTAT_PARTNER_TYPE_UFP &&
@@ -1471,7 +1486,7 @@ static int ucsi_pr_swap(struct typec_port *port, enum typec_role role)
goto out_unlock;
}
- cur_role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR);
+ cur_role = UCSI_CONSTAT(con, PWR_DIR);
if (cur_role == role)
goto out_unlock;
@@ -1494,8 +1509,7 @@ static int ucsi_pr_swap(struct typec_port *port, enum typec_role role)
mutex_lock(&con->lock);
/* Something has gone wrong while swapping the role */
- if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) !=
- UCSI_CONSTAT_PWR_OPMODE_PD) {
+ if (UCSI_CONSTAT(con, PWR_OPMODE) != UCSI_CONSTAT_PWR_OPMODE_PD) {
ucsi_reset_connector(con, true);
ret = -EPROTO;
}
@@ -1563,19 +1577,18 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
if (ret < 0)
goto out_unlock;
- if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP)
+ if (UCSI_CONCAP(con, OPMODE_DRP))
cap->data = TYPEC_PORT_DRD;
- else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DFP)
+ else if (UCSI_CONCAP(con, OPMODE_DFP))
cap->data = TYPEC_PORT_DFP;
- else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_UFP)
+ else if (UCSI_CONCAP(con, OPMODE_UFP))
cap->data = TYPEC_PORT_UFP;
- if ((con->cap.flags & UCSI_CONCAP_FLAG_PROVIDER) &&
- (con->cap.flags & UCSI_CONCAP_FLAG_CONSUMER))
+ if (UCSI_CONCAP(con, PROVIDER) && UCSI_CONCAP(con, CONSUMER))
cap->type = TYPEC_PORT_DRP;
- else if (con->cap.flags & UCSI_CONCAP_FLAG_PROVIDER)
+ else if (UCSI_CONCAP(con, PROVIDER))
cap->type = TYPEC_PORT_SRC;
- else if (con->cap.flags & UCSI_CONCAP_FLAG_CONSUMER)
+ else if (UCSI_CONCAP(con, CONSUMER))
cap->type = TYPEC_PORT_SNK;
cap->revision = ucsi->cap.typec_version;
@@ -1583,11 +1596,18 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
cap->svdm_version = SVDM_VER_2_0;
cap->prefer_role = TYPEC_NO_PREFERRED_ROLE;
- if (con->cap.op_mode & UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY)
+ if (UCSI_CONCAP(con, OPMODE_AUDIO_ACCESSORY))
*accessory++ = TYPEC_ACCESSORY_AUDIO;
- if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY)
+ if (UCSI_CONCAP(con, OPMODE_DEBUG_ACCESSORY))
*accessory = TYPEC_ACCESSORY_DEBUG;
+ if (UCSI_CONCAP_USB2_SUPPORT(con))
+ cap->usb_capability |= USB_CAPABILITY_USB2;
+ if (UCSI_CONCAP_USB3_SUPPORT(con))
+ cap->usb_capability |= USB_CAPABILITY_USB3;
+ if (UCSI_CONCAP_USB4_SUPPORT(con))
+ cap->usb_capability |= USB_CAPABILITY_USB4;
+
cap->driver_data = con;
cap->ops = &ucsi_ops;
@@ -1617,19 +1637,16 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
}
/* Get the status */
- command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
- ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status));
- if (ret < 0) {
+ ret = ucsi_get_connector_status(con, false);
+ if (ret) {
dev_err(ucsi->dev, "con%d: failed to get status\n", con->num);
- ret = 0;
goto out;
}
- ret = 0; /* ucsi_send_command() returns length on success */
if (ucsi->ops->connector_status)
ucsi->ops->connector_status(con);
- switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
+ switch (UCSI_CONSTAT(con, PARTNER_TYPE)) {
case UCSI_CONSTAT_PARTNER_TYPE_UFP:
case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP:
u_role = USB_ROLE_HOST;
@@ -1646,9 +1663,8 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
}
/* Check if there is already something connected */
- if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
- typec_set_pwr_role(con->port,
- !!(con->status.flags & UCSI_CONSTAT_PWR_DIR));
+ if (UCSI_CONSTAT(con, CONNECTED)) {
+ typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR));
ucsi_register_partner(con);
ucsi_pwr_opmode_change(con);
ucsi_port_psy_changed(con);
@@ -1659,7 +1675,7 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
}
/* Only notify USB controller if partner supports USB data */
- if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB))
+ if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB)))
u_role = USB_ROLE_NONE;
ret = usb_role_switch_set_role(con->usb_role_sw, u_role);
@@ -1669,16 +1685,14 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
ret = 0;
}
- if (con->partner &&
- UCSI_CONSTAT_PWR_OPMODE(con->status.flags) ==
- UCSI_CONSTAT_PWR_OPMODE_PD) {
+ if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) {
ucsi_register_device_pdos(con);
ucsi_get_src_pdos(con);
ucsi_check_altmodes(con);
ucsi_check_connector_capability(con);
}
- trace_ucsi_register_port(con->num, &con->status);
+ trace_ucsi_register_port(con->num, con);
out:
fwnode_handle_put(cap->fwnode);
@@ -1761,7 +1775,8 @@ static int ucsi_init(struct ucsi *ucsi)
/* Get PPM capabilities */
command = UCSI_GET_CAPABILITY;
- ret = ucsi_send_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap));
+ ret = ucsi_send_command(ucsi, command, &ucsi->cap,
+ BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE));
if (ret < 0)
goto err_reset;
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 1cf5aad4c23a..5ff369c24a2f 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -4,6 +4,7 @@
#define __DRIVER_USB_TYPEC_UCSI_H
#include <linux/bitops.h>
+#include <linux/bitmap.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/power_supply.h>
@@ -95,26 +96,31 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
/* -------------------------------------------------------------------------- */
/* Commands */
-#define UCSI_PPM_RESET 0x01
-#define UCSI_CANCEL 0x02
-#define UCSI_CONNECTOR_RESET 0x03
-#define UCSI_ACK_CC_CI 0x04
-#define UCSI_SET_NOTIFICATION_ENABLE 0x05
-#define UCSI_GET_CAPABILITY 0x06
-#define UCSI_GET_CONNECTOR_CAPABILITY 0x07
-#define UCSI_SET_UOM 0x08
-#define UCSI_SET_UOR 0x09
-#define UCSI_SET_PDM 0x0a
-#define UCSI_SET_PDR 0x0b
-#define UCSI_GET_ALTERNATE_MODES 0x0c
-#define UCSI_GET_CAM_SUPPORTED 0x0d
-#define UCSI_GET_CURRENT_CAM 0x0e
-#define UCSI_SET_NEW_CAM 0x0f
-#define UCSI_GET_PDOS 0x10
-#define UCSI_GET_CABLE_PROPERTY 0x11
-#define UCSI_GET_CONNECTOR_STATUS 0x12
-#define UCSI_GET_ERROR_STATUS 0x13
-#define UCSI_GET_PD_MESSAGE 0x15
+#define UCSI_PPM_RESET 0x01
+#define UCSI_CANCEL 0x02
+#define UCSI_CONNECTOR_RESET 0x03
+#define UCSI_ACK_CC_CI 0x04
+#define UCSI_SET_NOTIFICATION_ENABLE 0x05
+#define UCSI_GET_CAPABILITY 0x06
+#define UCSI_GET_CAPABILITY_SIZE 128
+#define UCSI_GET_CONNECTOR_CAPABILITY 0x07
+#define UCSI_GET_CONNECTOR_CAPABILITY_SIZE 32
+#define UCSI_SET_UOM 0x08
+#define UCSI_SET_UOR 0x09
+#define UCSI_SET_PDM 0x0a
+#define UCSI_SET_PDR 0x0b
+#define UCSI_GET_ALTERNATE_MODES 0x0c
+#define UCSI_GET_CAM_SUPPORTED 0x0d
+#define UCSI_GET_CURRENT_CAM 0x0e
+#define UCSI_SET_NEW_CAM 0x0f
+#define UCSI_GET_PDOS 0x10
+#define UCSI_GET_CABLE_PROPERTY 0x11
+#define UCSI_GET_CABLE_PROPERTY_SIZE 64
+#define UCSI_GET_CONNECTOR_STATUS 0x12
+#define UCSI_GET_CONNECTOR_STATUS_SIZE 152
+#define UCSI_GET_ERROR_STATUS 0x13
+#define UCSI_GET_PD_MESSAGE 0x15
+#define UCSI_SET_SINK_PATH 0x1c
#define UCSI_CONNECTOR_NUMBER(_num_) ((u64)(_num_) << 16)
#define UCSI_COMMAND(_cmd_) ((_cmd_) & 0xff)
@@ -126,7 +132,6 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
#define UCSI_CONNECTOR_RESET_HARD_VER_1_0 BIT(23) /* Deprecated in v1.1 */
#define UCSI_CONNECTOR_RESET_DATA_VER_2_0 BIT(23) /* Redefined in v2.0 */
-
/* ACK_CC_CI bits */
#define UCSI_ACK_CONNECTOR_CHANGE BIT(16)
#define UCSI_ACK_COMMAND_COMPLETE BIT(17)
@@ -250,42 +255,6 @@ struct ucsi_capability {
u16 typec_version;
} __packed;
-/* Data structure filled by PPM in response to GET_CONNECTOR_CAPABILITY cmd. */
-struct ucsi_connector_capability {
- u8 op_mode;
-#define UCSI_CONCAP_OPMODE_DFP BIT(0)
-#define UCSI_CONCAP_OPMODE_UFP BIT(1)
-#define UCSI_CONCAP_OPMODE_DRP BIT(2)
-#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY BIT(3)
-#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY BIT(4)
-#define UCSI_CONCAP_OPMODE_USB2 BIT(5)
-#define UCSI_CONCAP_OPMODE_USB3 BIT(6)
-#define UCSI_CONCAP_OPMODE_ALT_MODE BIT(7)
- u32 flags;
-#define UCSI_CONCAP_FLAG_PROVIDER BIT(0)
-#define UCSI_CONCAP_FLAG_CONSUMER BIT(1)
-#define UCSI_CONCAP_FLAG_SWAP_TO_DFP BIT(2)
-#define UCSI_CONCAP_FLAG_SWAP_TO_UFP BIT(3)
-#define UCSI_CONCAP_FLAG_SWAP_TO_SRC BIT(4)
-#define UCSI_CONCAP_FLAG_SWAP_TO_SINK BIT(5)
-#define UCSI_CONCAP_FLAG_EX_OP_MODE(_f_) \
- (((_f_) & GENMASK(13, 6)) >> 6)
-#define UCSI_CONCAP_EX_OP_MODE_USB4_GEN2 BIT(0)
-#define UCSI_CONCAP_EX_OP_MODE_EPR_SRC BIT(1)
-#define UCSI_CONCAP_EX_OP_MODE_EPR_SINK BIT(2)
-#define UCSI_CONCAP_EX_OP_MODE_USB4_GEN3 BIT(3)
-#define UCSI_CONCAP_EX_OP_MODE_USB4_GEN4 BIT(4)
-#define UCSI_CONCAP_FLAG_MISC_CAPS(_f_) \
- (((_f_) & GENMASK(17, 14)) >> 14)
-#define UCSI_CONCAP_MISC_CAP_FW_UPDATE BIT(0)
-#define UCSI_CONCAP_MISC_CAP_SECURITY BIT(1)
-#define UCSI_CONCAP_FLAG_REV_CURR_PROT_SUPPORT BIT(18)
-#define UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV(_f_) \
- (((_f_) & GENMASK(20, 19)) >> 19)
-#define UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(_f_) \
- UCSI_SPEC_REVISION_TO_BCD(UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV(_f_))
-} __packed;
-
struct ucsi_altmode {
u16 svid;
u32 mid;
@@ -311,49 +280,143 @@ struct ucsi_cable_property {
u8 latency;
} __packed;
-/* Data structure filled by PPM in response to GET_CONNECTOR_STATUS command. */
-struct ucsi_connector_status {
- u16 change;
-#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1)
-#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2)
-#define UCSI_CONSTAT_PDOS_CHANGE BIT(5)
-#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6)
-#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7)
-#define UCSI_CONSTAT_CAM_CHANGE BIT(8)
-#define UCSI_CONSTAT_BC_CHANGE BIT(9)
-#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11)
-#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12)
-#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14)
-#define UCSI_CONSTAT_ERROR BIT(15)
- u16 flags;
-#define UCSI_CONSTAT_PWR_OPMODE(_f_) ((_f_) & GENMASK(2, 0))
+/* Get Connector Capability Fields. */
+#define UCSI_CONCAP_OPMODE UCSI_DECLARE_BITFIELD(0, 0, 8)
+#define UCSI_CONCAP_OPMODE_DFP UCSI_DECLARE_BITFIELD(0, 0, 1)
+#define UCSI_CONCAP_OPMODE_UFP UCSI_DECLARE_BITFIELD(0, 1, 1)
+#define UCSI_CONCAP_OPMODE_DRP UCSI_DECLARE_BITFIELD(0, 2, 1)
+#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY UCSI_DECLARE_BITFIELD(0, 3, 1)
+#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY UCSI_DECLARE_BITFIELD(0, 4, 1)
+#define UCSI_CONCAP_OPMODE_USB2 UCSI_DECLARE_BITFIELD(0, 5, 1)
+#define UCSI_CONCAP_OPMODE_USB3 UCSI_DECLARE_BITFIELD(0, 6, 1)
+#define UCSI_CONCAP_OPMODE_ALT_MODE UCSI_DECLARE_BITFIELD(0, 7, 1)
+#define UCSI_CONCAP_PROVIDER UCSI_DECLARE_BITFIELD(0, 8, 1)
+#define UCSI_CONCAP_CONSUMER UCSI_DECLARE_BITFIELD(0, 9, 1)
+#define UCSI_CONCAP_SWAP_TO_DFP_V1_1 UCSI_DECLARE_BITFIELD_V1_1(10, 1)
+#define UCSI_CONCAP_SWAP_TO_UFP_V1_1 UCSI_DECLARE_BITFIELD_V1_1(11, 1)
+#define UCSI_CONCAP_SWAP_TO_SRC_V1_1 UCSI_DECLARE_BITFIELD_V1_1(12, 1)
+#define UCSI_CONCAP_SWAP_TO_SNK_V1_1 UCSI_DECLARE_BITFIELD_V1_1(13, 1)
+#define UCSI_CONCAP_EXT_OPMODE_V2_0 UCSI_DECLARE_BITFIELD_V2_0(14, 8)
+#define UCSI_CONCAP_EXT_OPMODE_USB4_GEN2_V2_0 UCSI_DECLARE_BITFIELD_V2_0(14, 1)
+#define UCSI_CONCAP_EXT_OPMODE_EPR_SRC_V2_0 UCSI_DECLARE_BITFIELD_V2_0(15, 1)
+#define UCSI_CONCAP_EXT_OPMODE_EPR_SINK_V2_0 UCSI_DECLARE_BITFIELD_V2_0(16, 1)
+#define UCSI_CONCAP_EXT_OPMODE_USB4_GEN3_V2_0 UCSI_DECLARE_BITFIELD_V2_0(17, 1)
+#define UCSI_CONCAP_EXT_OPMODE_USB4_GEN4_V2_0 UCSI_DECLARE_BITFIELD_V2_0(18, 1)
+#define UCSI_CONCAP_MISC_V2_0 UCSI_DECLARE_BITFIELD_V2_0(22, 4)
+#define UCSI_CONCAP_MISC_FW_UPDATE_V2_0 UCSI_DECLARE_BITFIELD_V2_0(22, 1)
+#define UCSI_CONCAP_MISC_SECURITY_V2_0 UCSI_DECLARE_BITFIELD_V2_0(23, 1)
+#define UCSI_CONCAP_REV_CURR_PROT_SUPPORT_V2_0 UCSI_DECLARE_BITFIELD_V2_0(26, 1)
+#define UCSI_CONCAP_PARTNER_PD_REVISION_V2_1 UCSI_DECLARE_BITFIELD_V2_1(27, 2)
+
+/* Helpers for USB capability checks. */
+#define UCSI_CONCAP_USB2_SUPPORT(_con_) UCSI_CONCAP((_con_), OPMODE_USB2)
+#define UCSI_CONCAP_USB3_SUPPORT(_con_) UCSI_CONCAP((_con_), OPMODE_USB3)
+#define UCSI_CONCAP_USB4_SUPPORT(_con_) \
+ ((_con_)->ucsi->version >= UCSI_VERSION_2_0 && \
+ (UCSI_CONCAP((_con_), EXT_OPMODE_USB4_GEN2_V2_0) | \
+ UCSI_CONCAP((_con_), EXT_OPMODE_USB4_GEN3_V2_0) | \
+ UCSI_CONCAP((_con_), EXT_OPMODE_USB4_GEN4_V2_0)))
+
+/* Get Connector Status Fields. */
+#define UCSI_CONSTAT_CHANGE UCSI_DECLARE_BITFIELD(0, 0, 16)
+#define UCSI_CONSTAT_PWR_OPMODE UCSI_DECLARE_BITFIELD(0, 16, 3)
#define UCSI_CONSTAT_PWR_OPMODE_NONE 0
#define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1
#define UCSI_CONSTAT_PWR_OPMODE_BC 2
#define UCSI_CONSTAT_PWR_OPMODE_PD 3
#define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5 4
#define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5
-#define UCSI_CONSTAT_CONNECTED BIT(3)
-#define UCSI_CONSTAT_PWR_DIR BIT(4)
-#define UCSI_CONSTAT_PARTNER_FLAGS(_f_) (((_f_) & GENMASK(12, 5)) >> 5)
-#define UCSI_CONSTAT_PARTNER_FLAG_USB 1
-#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE 2
-#define UCSI_CONSTAT_PARTNER_TYPE(_f_) (((_f_) & GENMASK(15, 13)) >> 13)
+#define UCSI_CONSTAT_CONNECTED UCSI_DECLARE_BITFIELD(0, 19, 1)
+#define UCSI_CONSTAT_PWR_DIR UCSI_DECLARE_BITFIELD(0, 20, 1)
+#define UCSI_CONSTAT_PARTNER_FLAGS UCSI_DECLARE_BITFIELD(0, 21, 8)
+#define UCSI_CONSTAT_PARTNER_FLAG_USB UCSI_DECLARE_BITFIELD(0, 21, 1)
+#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE UCSI_DECLARE_BITFIELD(0, 22, 1)
+#define UCSI_CONSTAT_PARTNER_FLAG_USB4_GEN3 UCSI_DECLARE_BITFIELD(0, 23, 1)
+#define UCSI_CONSTAT_PARTNER_FLAG_USB4_GEN4 UCSI_DECLARE_BITFIELD(0, 24, 1)
+#define UCSI_CONSTAT_PARTNER_TYPE UCSI_DECLARE_BITFIELD(0, 29, 3)
#define UCSI_CONSTAT_PARTNER_TYPE_DFP 1
#define UCSI_CONSTAT_PARTNER_TYPE_UFP 2
-#define UCSI_CONSTAT_PARTNER_TYPE_CABLE 3 /* Powered Cable */
-#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */
+#define UCSI_CONSTAT_PARTNER_TYPE_CABLE 3 /* Powered Cable */
+#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */
#define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5
#define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6
- u32 request_data_obj;
-
- u8 pwr_status;
-#define UCSI_CONSTAT_BC_STATUS(_p_) ((_p_) & GENMASK(1, 0))
+#define UCSI_CONSTAT_RDO UCSI_DECLARE_BITFIELD(0, 32, 32)
+#define UCSI_CONSTAT_BC_STATUS UCSI_DECLARE_BITFIELD(0, 64, 2)
#define UCSI_CONSTAT_BC_NOT_CHARGING 0
#define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1
#define UCSI_CONSTAT_BC_SLOW_CHARGING 2
#define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3
-} __packed;
+#define UCSI_CONSTAT_PD_VERSION_V1_2 UCSI_DECLARE_BITFIELD_V1_2(70, 16)
+
+/* Connector Status Change Bits. */
+#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1)
+#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2)
+#define UCSI_CONSTAT_PDOS_CHANGE BIT(5)
+#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6)
+#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7)
+#define UCSI_CONSTAT_CAM_CHANGE BIT(8)
+#define UCSI_CONSTAT_BC_CHANGE BIT(9)
+#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11)
+#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12)
+#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14)
+#define UCSI_CONSTAT_ERROR BIT(15)
+
+#define UCSI_DECLARE_BITFIELD_V1_1(_offset_, _size_) \
+ UCSI_DECLARE_BITFIELD(UCSI_VERSION_1_1, (_offset_), (_size_))
+#define UCSI_DECLARE_BITFIELD_V1_2(_offset_, _size_) \
+ UCSI_DECLARE_BITFIELD(UCSI_VERSION_1_2, (_offset_), (_size_))
+#define UCSI_DECLARE_BITFIELD_V2_0(_offset_, _size_) \
+ UCSI_DECLARE_BITFIELD(UCSI_VERSION_2_0, (_offset_), (_size_))
+#define UCSI_DECLARE_BITFIELD_V2_1(_offset_, _size_) \
+ UCSI_DECLARE_BITFIELD(UCSI_VERSION_2_1, (_offset_), (_size_))
+#define UCSI_DECLARE_BITFIELD_V3_0(_offset_, _size_) \
+ UCSI_DECLARE_BITFIELD(UCSI_VERSION_3_0, (_offset_), (_size_))
+
+#define UCSI_DECLARE_BITFIELD(_ver_, _offset_, _size_) \
+(struct ucsi_bitfield) { \
+ .version = _ver_, \
+ .offset = _offset_, \
+ .size = _size_, \
+}
+
+struct ucsi_bitfield {
+ const u16 version;
+ const u8 offset;
+ const u8 size;
+};
+
+/**
+ * ucsi_bitfield_read - Read a field from UCSI command response
+ * @_map_: UCSI command response
+ * @_field_: The field offset in the response data structure
+ * @_ver_: UCSI version where the field was introduced
+ *
+ * Reads the fields in the command responses by first checking that the field is
+ * valid with the UCSI interface version that is used in the system.
+ * @_ver_ is the minimum UCSI version for the @_field_. If the UCSI interface is
+ * older than @_ver_, a warning is generated.
+ *
+ * Caveats:
+ * - Removed fields are not checked - @_ver_ is just the minimum UCSI version.
+ *
+ * Returns the value of @_field_, or 0 when the UCSI interface is older than
+ * @_ver_.
+ */
+#define ucsi_bitfield_read(_map_, _field_, _ver_) \
+({ \
+ struct ucsi_bitfield f = (_field_); \
+ WARN((_ver_) < f.version, \
+ "Access to unsupported field at offset 0x%x (need version %04x)", \
+ f.offset, f.version) ? 0 : \
+ bitmap_read((_map_), f.offset, f.size); \
+})
+
+/* Helpers to access cached command responses. */
+#define UCSI_CONCAP(_con_, _field_) \
+ ucsi_bitfield_read((_con_)->cap, UCSI_CONCAP_##_field_, (_con_)->ucsi->version)
+
+#define UCSI_CONSTAT(_con_, _field_) \
+ ucsi_bitfield_read((_con_)->status, UCSI_CONSTAT_##_field_, (_con_)->ucsi->version)
/* -------------------------------------------------------------------------- */
@@ -433,8 +496,10 @@ struct ucsi_connector {
struct typec_capability typec_cap;
- struct ucsi_connector_status status;
- struct ucsi_connector_capability cap;
+ /* Cached command responses. */
+ DECLARE_BITMAP(cap, UCSI_GET_CONNECTOR_CAPABILITY_SIZE);
+ DECLARE_BITMAP(status, UCSI_GET_CONNECTOR_STATUS_SIZE);
+
struct power_supply *psy;
struct power_supply_desc psy_desc;
u32 rdo;
diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
index 7a5dff8d9cc6..5c5515551963 100644
--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
@@ -61,9 +61,11 @@ static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci)
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
int ret;
- ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
- if (ret)
- return ret;
+ if (UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
+ ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
+ if (ret)
+ return ret;
+ }
memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci));
@@ -73,11 +75,6 @@ static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci)
static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
{
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
- int ret;
-
- ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
- if (ret)
- return ret;
memcpy(val, ua->base + UCSI_MESSAGE_IN, val_len);
@@ -102,48 +99,11 @@ static const struct ucsi_operations ucsi_acpi_ops = {
.async_control = ucsi_acpi_async_control
};
-static int
-ucsi_zenbook_read_cci(struct ucsi *ucsi, u32 *cci)
-{
- struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
- int ret;
-
- if (UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
- ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
- if (ret)
- return ret;
- }
-
- memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci));
-
- return 0;
-}
-
-static int
-ucsi_zenbook_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
-{
- struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
-
- /* UCSI_MESSAGE_IN is never read for PPM_RESET, return stored data */
- memcpy(val, ua->base + UCSI_MESSAGE_IN, val_len);
-
- return 0;
-}
-
-static const struct ucsi_operations ucsi_zenbook_ops = {
- .read_version = ucsi_acpi_read_version,
- .read_cci = ucsi_zenbook_read_cci,
- .read_message_in = ucsi_zenbook_read_message_in,
- .sync_control = ucsi_sync_control_common,
- .async_control = ucsi_acpi_async_control
-};
-
static int ucsi_gram_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
{
u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE |
UCSI_CONSTAT_PDOS_CHANGE;
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
- struct ucsi_connector_status *status;
int ret;
ret = ucsi_acpi_read_message_in(ucsi, val, val_len);
@@ -152,11 +112,9 @@ static int ucsi_gram_read_message_in(struct ucsi *ucsi, void *val, size_t val_le
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS &&
ua->check_bogus_event) {
- status = (struct ucsi_connector_status *)val;
-
/* Clear the bogus change */
- if (status->change == bogus_change)
- status->change = 0;
+ if (*(u16 *)val == bogus_change)
+ *(u16 *)val = 0;
ua->check_bogus_event = false;
}
@@ -192,13 +150,6 @@ static const struct ucsi_operations ucsi_gram_ops = {
static const struct dmi_system_id ucsi_acpi_quirks[] = {
{
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
- },
- .driver_data = (void *)&ucsi_zenbook_ops,
- },
- {
- .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
DMI_MATCH(DMI_PRODUCT_FAMILY, "LG gram PC"),
DMI_MATCH(DMI_PRODUCT_NAME, "90Q"),
@@ -320,7 +271,7 @@ static struct platform_driver ucsi_acpi_platform_driver = {
.acpi_match_table = ACPI_PTR(ucsi_acpi_match),
},
.probe = ucsi_acpi_probe,
- .remove_new = ucsi_acpi_remove,
+ .remove = ucsi_acpi_remove,
};
module_platform_driver(ucsi_acpi_platform_driver);
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
index bccfc03b5986..fcb8e61136cf 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -644,6 +644,10 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command)
uc->has_multiple_dp) {
con_index = (uc->last_cmd_sent >> 16) &
UCSI_CMD_CONNECTOR_MASK;
+ if (con_index == 0) {
+ ret = -EINVAL;
+ goto unlock;
+ }
con = &uc->ucsi->connector[con_index - 1];
ucsi_ccg_update_set_new_cam_cmd(uc, con, &command);
}
@@ -651,6 +655,7 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command)
ret = ucsi_sync_control_common(ucsi, command);
pm_runtime_put_sync(uc->dev);
+unlock:
mutex_unlock(&uc->lock);
return ret;
diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c
index 03c0fa8edc8d..90948cd6d297 100644
--- a/drivers/usb/typec/ucsi/ucsi_glink.c
+++ b/drivers/usb/typec/ucsi/ucsi_glink.c
@@ -172,12 +172,12 @@ static int pmic_glink_ucsi_async_control(struct ucsi *__ucsi, u64 command)
static void pmic_glink_ucsi_update_connector(struct ucsi_connector *con)
{
struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi);
- int i;
- for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) {
- if (ucsi->port_orientation[i])
- con->typec_cap.orientation_aware = true;
- }
+ if (con->num > PMIC_GLINK_MAX_PORTS ||
+ !ucsi->port_orientation[con->num - 1])
+ return;
+
+ con->typec_cap.orientation_aware = true;
}
static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con)
@@ -185,7 +185,7 @@ static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con)
struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi);
int orientation;
- if (con->num >= PMIC_GLINK_MAX_PORTS ||
+ if (con->num > PMIC_GLINK_MAX_PORTS ||
!ucsi->port_orientation[con->num - 1])
return;
@@ -322,7 +322,6 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
struct pmic_glink_ucsi *ucsi;
struct device *dev = &adev->dev;
const struct of_device_id *match;
- struct fwnode_handle *fwnode;
int ret;
ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL);
@@ -354,14 +353,13 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
ucsi_set_drvdata(ucsi->ucsi, ucsi);
- device_for_each_child_node(dev, fwnode) {
+ device_for_each_child_node_scoped(dev, fwnode) {
struct gpio_desc *desc;
u32 port;
ret = fwnode_property_read_u32(fwnode, "reg", &port);
if (ret < 0) {
dev_err(dev, "missing reg property of %pOFn\n", fwnode);
- fwnode_handle_put(fwnode);
return ret;
}
@@ -376,11 +374,10 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
if (!desc)
continue;
- if (IS_ERR(desc)) {
- fwnode_handle_put(fwnode);
+ if (IS_ERR(desc))
return dev_err_probe(dev, PTR_ERR(desc),
"unable to acquire orientation gpio\n");
- }
+
ucsi->port_orientation[port] = desc;
}
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 8dac1edc74d4..b03e5021c25b 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -1487,7 +1487,7 @@ static int vhci_hcd_resume(struct platform_device *pdev)
static struct platform_driver vhci_driver = {
.probe = vhci_hcd_probe,
- .remove_new = vhci_hcd_remove,
+ .remove = vhci_hcd_remove,
.suspend = vhci_hcd_suspend,
.resume = vhci_hcd_resume,
.driver = {
diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c
index 8bee553e4894..993e721cb840 100644
--- a/drivers/usb/usbip/vudc_main.c
+++ b/drivers/usb/usbip/vudc_main.c
@@ -19,7 +19,7 @@ MODULE_PARM_DESC(num, "number of emulated controllers");
static struct platform_driver vudc_driver = {
.probe = vudc_probe,
- .remove_new = vudc_remove,
+ .remove = vudc_remove,
.driver = {
.name = GADGET_NAME,
.dev_groups = vudc_groups,
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index e4bddb927795..d2402bf4aea2 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -121,6 +121,7 @@
#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310
#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320
#define PCI_CLASS_SERIAL_USB_XHCI 0x0c0330
+#define PCI_CLASS_SERIAL_USB_CDNS 0x0c0380
#define PCI_CLASS_SERIAL_USB_DEVICE 0x0c03fe
#define PCI_CLASS_SERIAL_FIBER 0x0c04
#define PCI_CLASS_SERIAL_SMBUS 0x0c05
@@ -2421,6 +2422,9 @@
#define PCI_VENDOR_ID_QCOM 0x17cb
#define PCI_VENDOR_ID_CDNS 0x17cd
+#define PCI_DEVICE_ID_CDNS_USBSS 0x0100
+#define PCI_DEVICE_ID_CDNS_USB 0x0120
+#define PCI_DEVICE_ID_CDNS_USBSSP 0x0200
#define PCI_VENDOR_ID_ARECA 0x17d3
#define PCI_DEVICE_ID_ARECA_1110 0x1110
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 672d8fc2abdb..cfa8005e24f9 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1129,8 +1129,8 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
/* ----------------------------------------------------------------------- */
/* Stuff for dynamic usb ids */
+extern struct mutex usb_dynids_lock;
struct usb_dynids {
- spinlock_t lock;
struct list_head list;
};
@@ -1243,7 +1243,7 @@ struct usb_driver {
unsigned int disable_hub_initiated_lpm:1;
unsigned int soft_unbind:1;
};
-#define to_usb_driver(d) container_of(d, struct usb_driver, driver)
+#define to_usb_driver(d) container_of_const(d, struct usb_driver, driver)
/**
* struct usb_device_driver - identifies USB device driver to usbcore
@@ -1294,8 +1294,7 @@ struct usb_device_driver {
unsigned int supports_autosuspend:1;
unsigned int generic_subclass:1;
};
-#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \
- driver)
+#define to_usb_device_driver(d) container_of_const(d, struct usb_device_driver, driver)
/**
* struct usb_class_driver - identifies a USB driver that wants to use the USB major number
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index 5a7f96684ea2..ebdfef124b2b 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -65,6 +65,7 @@ struct ci_hdrc_platform_data {
#define CI_HDRC_PHY_VBUS_CONTROL BIT(16)
#define CI_HDRC_HAS_PORTSC_PEC_MISSED BIT(17)
#define CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS BIT(18)
+#define CI_HDRC_HAS_SHORT_PKT_LIMIT BIT(19)
enum usb_dr_mode dr_mode;
#define CI_HDRC_CONTROLLER_RESET_EVENT 0
#define CI_HDRC_CONTROLLER_STOPPED_EVENT 1
diff --git a/include/linux/usb/storage.h b/include/linux/usb/storage.h
index 2827ce72e502..8539956bc2be 100644
--- a/include/linux/usb/storage.h
+++ b/include/linux/usb/storage.h
@@ -53,7 +53,7 @@ struct bulk_cb_wrap {
__le32 Signature; /* contains 'USBC' */
__u32 Tag; /* unique per command id */
__le32 DataTransferLength; /* size of data */
- __u8 Flags; /* direction in bit 0 */
+ __u8 Flags; /* direction in bit 7 */
__u8 Lun; /* LUN normally 0 */
__u8 Length; /* length of the CDB */
__u8 CDB[16]; /* max command */
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index 549275f8ac1b..d616b8807000 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -87,6 +87,17 @@ enum typec_orientation {
TYPEC_ORIENTATION_REVERSE,
};
+enum usb_mode {
+ USB_MODE_NONE,
+ USB_MODE_USB2,
+ USB_MODE_USB3,
+ USB_MODE_USB4
+};
+
+#define USB_CAPABILITY_USB2 BIT(0)
+#define USB_CAPABILITY_USB3 BIT(1)
+#define USB_CAPABILITY_USB4 BIT(2)
+
/*
* struct enter_usb_data - Enter_USB Message details
* @eudo: Enter_USB Data Object
@@ -209,6 +220,7 @@ struct typec_cable_desc {
* @accessory: Audio, Debug or none.
* @identity: Discover Identity command data
* @pd_revision: USB Power Delivery Specification Revision if supported
+ * @usb_capability: Supported USB Modes
* @attach: Notification about attached USB device
* @deattach: Notification about removed USB device
*
@@ -226,6 +238,7 @@ struct typec_partner_desc {
enum typec_accessory accessory;
struct usb_pd_identity *identity;
u16 pd_revision; /* 0300H = "3.0" */
+ u8 usb_capability;
void (*attach)(struct typec_partner *partner, struct device *dev);
void (*deattach)(struct typec_partner *partner, struct device *dev);
@@ -240,6 +253,8 @@ struct typec_partner_desc {
* @port_type_set: Set port type
* @pd_get: Get available USB Power Delivery Capabilities.
* @pd_set: Set USB Power Delivery Capabilities.
+ * @default_usb_mode_set: USB Mode to be used by default with Enter_USB Message
+ * @enter_usb_mode: Change the active USB Mode
*/
struct typec_operations {
int (*try_role)(struct typec_port *port, int role);
@@ -250,6 +265,8 @@ struct typec_operations {
enum typec_port_type type);
struct usb_power_delivery **(*pd_get)(struct typec_port *port);
int (*pd_set)(struct typec_port *port, struct usb_power_delivery *pd);
+ int (*default_usb_mode_set)(struct typec_port *port, enum usb_mode mode);
+ int (*enter_usb_mode)(struct typec_port *port, enum usb_mode mode);
};
enum usb_pd_svdm_ver {
@@ -267,6 +284,7 @@ enum usb_pd_svdm_ver {
* @svdm_version: USB PD Structured VDM version if supported
* @prefer_role: Initial role preference (DRP ports).
* @accessory: Supported Accessory Modes
+ * @usb_capability: Supported USB Modes
* @fwnode: Optional fwnode of the port
* @driver_data: Private pointer for driver specific info
* @pd: Optional USB Power Delivery Support
@@ -283,6 +301,7 @@ struct typec_capability {
int prefer_role;
enum typec_accessory accessory[TYPEC_MAX_ACCESSORY];
unsigned int orientation_aware:1;
+ u8 usb_capability;
struct fwnode_handle *fwnode;
void *driver_data;
@@ -350,6 +369,9 @@ int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_
int typec_partner_set_usb_power_delivery(struct typec_partner *partner,
struct usb_power_delivery *pd);
+void typec_partner_set_usb_mode(struct typec_partner *partner, enum usb_mode usb_mode);
+void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode);
+
/**
* struct typec_connector - Representation of Type-C port for external drivers
* @attach: notification about device removal
diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
index 2ff0e8a3a683..526b5155e23c 100644
--- a/include/uapi/linux/usb/video.h
+++ b/include/uapi/linux/usb/video.h
@@ -597,5 +597,63 @@ struct UVC_FRAME_MJPEG(n) { \
__le32 dwFrameInterval[n]; \
} __attribute__ ((packed))
+/* Frame Based Payload - 3.1.1. Frame Based Video Format Descriptor */
+struct uvc_format_framebased {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bFormatIndex;
+ __u8 bNumFrameDescriptors;
+ __u8 guidFormat[16];
+ __u8 bBitsPerPixel;
+ __u8 bDefaultFrameIndex;
+ __u8 bAspectRatioX;
+ __u8 bAspectRatioY;
+ __u8 bmInterfaceFlags;
+ __u8 bCopyProtect;
+ __u8 bVariableSize;
+} __attribute__((__packed__));
+
+#define UVC_DT_FORMAT_FRAMEBASED_SIZE 28
+
+/* Frame Based Payload - 3.1.2. Frame Based Video Frame Descriptor */
+struct uvc_frame_framebased {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bFrameIndex;
+ __u8 bmCapabilities;
+ __u16 wWidth;
+ __u16 wHeight;
+ __u32 dwMinBitRate;
+ __u32 dwMaxBitRate;
+ __u32 dwDefaultFrameInterval;
+ __u8 bFrameIntervalType;
+ __u32 dwBytesPerLine;
+ __u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_DT_FRAME_FRAMEBASED_SIZE(n) (26+4*(n))
+
+#define UVC_FRAME_FRAMEBASED(n) \
+ uvc_frame_framebased_##n
+
+#define DECLARE_UVC_FRAME_FRAMEBASED(n) \
+struct UVC_FRAME_FRAMEBASED(n) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u8 bFrameIndex; \
+ __u8 bmCapabilities; \
+ __u16 wWidth; \
+ __u16 wHeight; \
+ __u32 dwMinBitRate; \
+ __u32 dwMaxBitRate; \
+ __u32 dwDefaultFrameInterval; \
+ __u8 bFrameIntervalType; \
+ __u32 dwBytesPerLine; \
+ __u32 dwFrameInterval[n]; \
+} __attribute__ ((packed))
+
#endif /* __LINUX_USB_VIDEO_H */