From e1edf95e0f4274f4d68aa00387a03a92b51cbbe3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Feb 2023 17:53:22 -0600 Subject: usb: host: xhci-tegra: Drop using of_irq_parse_one() Drivers generally shouldn't be using of_irq_parse_one() directly as it is a low-level interrupt parsing API. The exceptions are cases that need the values from the 'interrupts' property. This is not the case for Tegra XHCI driver as it just uses of_irq_parse_one() to test for 'interrupts' being absent or invalid. Instead, just make the interrupt optional on any error other than deferred probe. The exact reason for failing to get the interrupt is not that important. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230228235322.13289-1-robh@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 1ff22f675930..b9349b8c8ff1 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1535,7 +1535,6 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra) static int tegra_xusb_probe(struct platform_device *pdev) { - struct of_phandle_args args; struct tegra_xusb *tegra; struct device_node *np; struct resource *regs; @@ -1594,15 +1593,13 @@ static int tegra_xusb_probe(struct platform_device *pdev) goto put_padctl; } - /* Older device-trees don't have padctrl interrupt */ - err = of_irq_parse_one(np, 0, &args); - if (!err) { - tegra->padctl_irq = of_irq_get(np, 0); - if (tegra->padctl_irq <= 0) { - err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq; - goto put_padctl; - } - } else { + tegra->padctl_irq = of_irq_get(np, 0); + if (tegra->padctl_irq == -EPROBE_DEFER) { + err = tegra->padctl_irq; + goto put_padctl; + } else if (tegra->padctl_irq <= 0) { + /* Older device-trees don't have padctrl interrupt */ + tegra->padctl_irq = 0; dev_dbg(&pdev->dev, "%pOF is missing an interrupt, disabling PM support\n", np); } -- cgit v1.2.3 From 1d8ce4d889643dd0e8dd196c8ff959d7cc2698c6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 23 Feb 2023 21:44:28 -0600 Subject: usb: host: oxu210hp-hcd: Replace fake flex-array with flexible-array member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zero-length arrays as fake flexible arrays are deprecated and we are moving towards adopting C99 flexible-array members instead. Transform zero-length array into flexible-array member in struct ehci_regs. Address the following warnings found with GCC-13 and -fstrict-flex-arrays=3 enabled: drivers/usb/host/oxu210hp-hcd.c:3983:30: warning: array subscript i is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:3986:38: warning: array subscript i is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:3971:30: warning: array subscript i is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:3978:30: warning: array subscript i is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:3523:30: warning: array subscript i is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:2774:39: warning: array subscript port is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:3569:35: warning: array subscript is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:3888:36: warning: array subscript port is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] drivers/usb/host/oxu210hp-hcd.c:2911:45: warning: array subscript i is outside array bounds of ‘u32[0]’ {aka ‘unsigned int[]’} [-Warray-bounds=] This helps with the ongoing efforts to tighten the FORTIFY_SOURCE routines on memcpy() and help us make progress towards globally enabling -fstrict-flex-arrays=3 [1]. Link: https://github.com/KSPP/linux/issues/21 Link: https://github.com/KSPP/linux/issues/259 Link: https://gcc.gnu.org/pipermail/gcc-patches/2022-October/602902.html [1] Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/Y/gynI9Wv8RZTD8M@work Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/oxu210hp-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 3a441310c713..f998d3f1a78a 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -169,7 +169,7 @@ struct ehci_regs { #define FLAG_CF (1<<0) /* true: we'll support "high speed" */ /* PORTSC: offset 0x44 */ - u32 port_status[0]; /* up to N_PORTS */ + u32 port_status[]; /* up to N_PORTS */ /* 31:23 reserved */ #define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ #define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ -- cgit v1.2.3 From 5d67f4861884762ebc2bddb5d667444e45f25782 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 7 Mar 2023 17:30:37 +0100 Subject: usb: host: xhci-rcar: remove leftover quirk handling Loading V3 firmware does not need a quirk anymore, remove the leftover code. Fixes: ed8603e11124 ("usb: host: xhci-rcar: Simplify getting the firmware name for R-Car Gen3") Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20230307163041.3815-10-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-rcar.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 7f18509a1d39..567b096a24e9 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -80,7 +80,6 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); /* For soc_device_attribute */ #define RCAR_XHCI_FIRMWARE_V2 BIT(0) /* FIRMWARE V2 */ -#define RCAR_XHCI_FIRMWARE_V3 BIT(1) /* FIRMWARE V3 */ static const struct soc_device_attribute rcar_quirks_match[] = { { @@ -152,8 +151,6 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) if (quirks & RCAR_XHCI_FIRMWARE_V2) firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2; - else if (quirks & RCAR_XHCI_FIRMWARE_V3) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3; else firmware_name = priv->firmware_name; -- cgit v1.2.3 From 87b383f82e4ea8f7fb8e6d6c4d42d0e4a213dd7b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 7 Mar 2023 17:30:38 +0100 Subject: usb: host: xhci-rcar: remove R-Car H3 ES1.* handling R-Car H3 ES1.* was only available to an internal development group and needed a lot of quirks and workarounds. These become a maintenance burden now, so our development group decided to remove upstream support and disable booting for this SoC. Public users only have ES2 onwards. Reviewed-by: Laurent Pinchart Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20230307163041.3815-11-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-rcar.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 567b096a24e9..c4925f8d6b06 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -12,26 +12,22 @@ #include #include #include -#include #include "xhci.h" #include "xhci-plat.h" #include "xhci-rzv2m.h" #define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem" -#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem" #define XHCI_RCAR_FIRMWARE_NAME_V3 "r8a779x_usb3_v3.dlmem" /* -* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x) -* - The V2 firmware is for r8a7795 ES1.x. +* - The V3 firmware is for all R-Car Gen3 * - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes * performance degradation. So, this driver continues to use the V1 if R-Car * Gen2. * - The V1 firmware is impossible to use on R-Car Gen3. */ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1); -MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2); MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); /*** Register Offset ***/ @@ -78,17 +74,6 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); #define RCAR_USB3_RX_POL_VAL BIT(21) #define RCAR_USB3_TX_POL_VAL BIT(4) -/* For soc_device_attribute */ -#define RCAR_XHCI_FIRMWARE_V2 BIT(0) /* FIRMWARE V2 */ - -static const struct soc_device_attribute rcar_quirks_match[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = (void *)RCAR_XHCI_FIRMWARE_V2, - }, - { /* sentinel */ } -}; - static void xhci_rcar_start_gen2(struct usb_hcd *hcd) { /* LCLK Select */ @@ -134,9 +119,6 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) const struct firmware *fw; int retval, index, j; u32 data, val, temp; - u32 quirks = 0; - const struct soc_device_attribute *attr; - const char *firmware_name; /* * According to the datasheet, "Upon the completion of FW Download, @@ -145,17 +127,8 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) if (readl(regs + RCAR_USB3_DL_CTRL) & RCAR_USB3_DL_CTRL_FW_SUCCESS) return 0; - attr = soc_device_match(rcar_quirks_match); - if (attr) - quirks = (uintptr_t)attr->data; - - if (quirks & RCAR_XHCI_FIRMWARE_V2) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2; - else - firmware_name = priv->firmware_name; - /* request R-Car USB3.0 firmware */ - retval = request_firmware(&fw, firmware_name, dev); + retval = request_firmware(&fw, priv->firmware_name, dev); if (retval) return retval; -- cgit v1.2.3 From f3323cd03e5852e2a2f725d67f1b01777341c706 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 7 Mar 2023 17:30:39 +0100 Subject: usb: gadget: udc: renesas_usb3: remove R-Car H3 ES1.* handling R-Car H3 ES1.* was only available to an internal development group and needed a lot of quirks and workarounds. These become a maintenance burden now, so our development group decided to remove upstream support and disable booting for this SoC. Public users only have ES2 onwards. Reviewed-by: Laurent Pinchart Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20230307163041.3815-12-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/renesas_usb3.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index bee6bceafc4f..f2ac6447b748 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -2781,13 +2780,6 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev, } } -static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = { - .ramsize_per_ramif = SZ_16K, - .num_ramif = 2, - .ramsize_per_pipe = SZ_4K, - .workaround_for_vbus = true, -}; - static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { .ramsize_per_ramif = SZ_16K, .num_ramif = 4, @@ -2829,14 +2821,6 @@ static const struct of_device_id usb3_of_match[] = { }; MODULE_DEVICE_TABLE(of, usb3_of_match); -static const struct soc_device_attribute renesas_usb3_quirks_match[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = &renesas_usb3_priv_r8a7795_es1, - }, - { /* sentinel */ } -}; - static const unsigned int renesas_usb3_cable[] = { EXTCON_USB, EXTCON_USB_HOST, @@ -2854,13 +2838,8 @@ static int renesas_usb3_probe(struct platform_device *pdev) struct renesas_usb3 *usb3; int irq, ret; const struct renesas_usb3_priv *priv; - const struct soc_device_attribute *attr; - attr = soc_device_match(renesas_usb3_quirks_match); - if (attr) - priv = attr->data; - else - priv = of_device_get_match_data(&pdev->dev); + priv = of_device_get_match_data(&pdev->dev); irq = platform_get_irq(pdev, 0); if (irq < 0) -- cgit v1.2.3 From 2da1b848e366bd8881137b5bdfc2bfaf4bee8b2d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 4 Mar 2023 14:03:02 +0100 Subject: dt-bindings: usb: snps,dwc3: document extcon property The DWC3 USB Linux driver and several DTS use extcon property, so document it, even though it is deprecated, to fix warnings like: sm6125-sony-xperia-seine-pdx201.dtb: usb@4ef8800: usb@4e00000: Unevaluated properties are not allowed ('extcon' was unexpected) Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230304130302.51497-1-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/snps,dwc3.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index be36956af53b..cad2efd5f8c9 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -70,6 +70,10 @@ properties: dma-coherent: true + extcon: + maxItems: 1 + deprecated: true + iommus: maxItems: 1 -- cgit v1.2.3 From f81a8591db7330a4caa0d430f50e54369a8520ca Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Tue, 28 Feb 2023 19:29:09 +0100 Subject: dt-bindings: usb: usb-device: make "compatible" optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This binding was originally meant to describe hard-wired USB devices but in some situations we need to describe USB ports. That is needed e.g. if USB port is meant to be used as a trigger source but it can have any device plugged. It's a common case for home routers which have USB ports (with no hard-wired devices) and USB LEDs to indicate ports state. There is no point (and no easy way) to add separate binding covering just USB ports. Adjust existing devices binding to allow describing ports. This fixes: arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@21000: port@1: 'compatible' is a required property From schema: Documentation/devicetree/bindings/usb/generic-ehci.yaml arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@21000: port@2: 'compatible' is a required property From schema: Documentation/devicetree/bindings/usb/generic-ehci.yaml arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@21000: Unevaluated properties are not allowed ('#address-cells', '#size-cells', 'port@1', 'port@2' were unexpected) From schema: Documentation/devicetree/bindings/usb/generic-ehci.yaml arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@22000: port@1: 'compatible' is a required property From schema: Documentation/devicetree/bindings/usb/generic-ohci.yaml arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@22000: port@2: 'compatible' is a required property From schema: Documentation/devicetree/bindings/usb/generic-ohci.yaml arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@22000: Unevaluated properties are not allowed ('#address-cells', '#size-cells', 'port@1', 'port@2' were unexpected) From schema: Documentation/devicetree/bindings/usb/generic-ohci.yaml arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@23000: port@1: 'compatible' is a required property From schema: Documentation/devicetree/bindings/usb/generic-xhci.yaml arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dtb: usb@23000: Unevaluated properties are not allowed ('#address-cells', '#size-cells', 'phy-names', 'phys', 'port@1' were unexpected) From schema: Documentation/devicetree/bindings/usb/generic-xhci.yaml Signed-off-by: Rafał Miłecki Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230228182909.1011-1-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-device.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml index 7a771125ec76..da890ee60ce6 100644 --- a/Documentation/devicetree/bindings/usb/usb-device.yaml +++ b/Documentation/devicetree/bindings/usb/usb-device.yaml @@ -76,7 +76,6 @@ patternProperties: maxItems: 1 required: - - compatible - reg additionalProperties: true -- cgit v1.2.3 From aa78a736a94f1e2771d5400d4286d907624f5f8d Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Tue, 28 Feb 2023 16:21:05 +0100 Subject: dt-bindings: usb: allow evaluated properties in OHCI controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This binding uses usb-hcd.yaml so replace additionalProperties with unevaluatedProperties to allow generic USB HCD properties. It's how EHCI and XHCI bindings work too. Signed-off-by: Rafał Miłecki Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230228152105.25358-1-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/generic-ohci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml index a9ba7257b884..d06d1e7d8876 100644 --- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml @@ -148,7 +148,7 @@ allOf: properties: transceiver: false -additionalProperties: false +unevaluatedProperties: false examples: - | -- cgit v1.2.3 From 487e6f420b7a3eed775118635d310ffa024ff7ef Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Wed, 15 Feb 2023 15:01:45 +0530 Subject: dt-bindings: usb: dwc3: Add snps,ulpi-ext-vbus-drv quirk Some ULPI USB PHYs do not support an internal vBus supply, to drive the CPEN pin properly, it requires configuration of the ULPI DRVVBUSEXTERNAL bit of the USB ULPI PHY OTG_CTRL register. Added 'snps,ulpi-ext-vbus-drv' DT property to configure the USB2 PHY to drives VBUS with an external supply. When the ULPIEXTVBUSDRV bit is set to '1' in the Global USB2 PHY Configuration registers, PHY drive vBus with an external 5V supply source. Signed-off-by: Piyush Mehta Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230215093146.5812-2-piyush.mehta@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/snps,dwc3.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index cad2efd5f8c9..c167fd577cae 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -260,6 +260,14 @@ properties: of resume. This option is to support certain legacy ULPI PHYs. type: boolean + snps,ulpi-ext-vbus-drv: + description: + Some ULPI USB PHY does not support internal VBUS supply, and driving + the CPEN pin, requires the configuration of the ulpi DRVVBUSEXTERNAL + bit. When set, the xhci host will configure the USB2 PHY drives VBUS + with an external supply. + type: boolean + snps,is-utmi-l1-suspend: description: True when DWC3 asserts output signal utmi_l1_suspend_n, false when -- cgit v1.2.3 From b84ba26c922a99c7541d53ab1971f070b65264fe Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Wed, 15 Feb 2023 15:01:46 +0530 Subject: usb: dwc3: core: add external vBus supply support for ulpi phy Some ULPI USB PHY does not support internal VBUS supply, to drive the CPEN pin, which requires the configuration of the ULPI DRVVBUSEXTERNAL bit of OTG_CTRL register. Added 'snps,ulpi-ext-vbus-drv' a DT property to configure the USB2 PHY to drive VBUS with an external supply, by setting the USB2 PHY ULPIEXTVBUSDRV bit[:17] of the GUSB2PHYCFG register to drive VBUS with an external supply. Signed-off-by: Piyush Mehta Link: https://lore.kernel.org/r/20230215093146.5812-3-piyush.mehta@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 12 ++++++++++++ drivers/usb/dwc3/core.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 476b63618511..ed0ab90d3fac 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -800,6 +800,16 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; + /* + * Some ULPI USB PHY does not support internal VBUS supply, to drive + * the CPEN pin requires the configuration of the ULPI DRVVBUSEXTERNAL + * bit of OTG_CTRL register. Controller configures the USB2 PHY + * ULPIEXTVBUSDRV bit[17] of the GUSB2PHYCFG register to drive vBus + * with an external supply. + */ + if (dwc->ulpi_ext_vbus_drv) + reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); return 0; @@ -1553,6 +1563,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis-tx-ipgap-linecheck-quirk"); dwc->resume_hs_terminations = device_property_read_bool(dev, "snps,resume-hs-terminations"); + dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev, + "snps,ulpi-ext-vbus-drv"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, "snps,parkmode-disable-ss-quirk"); dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev, diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 582ebd9cf9c2..b1bd63188f52 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -280,6 +280,7 @@ /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) #define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30) +#define DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV BIT(17) #define DWC3_GUSB2PHYCFG_SUSPHY BIT(6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4) #define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8) @@ -1100,6 +1101,8 @@ struct dwc3_scratchpad_array { * check during HS transmit. * @resume-hs-terminations: Set if we enable quirk for fixing improper crc * generation after resume from suspend. + * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin + * VBUS with an external supply. * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed * instances in park mode. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk @@ -1317,6 +1320,7 @@ struct dwc3 { unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1; unsigned resume_hs_terminations:1; + unsigned ulpi_ext_vbus_drv:1; unsigned parkmode_disable_ss_quirk:1; unsigned gfladj_refclk_lpm_sel:1; -- cgit v1.2.3 From 4decf4060ecfee1f7a710999fcd421645ac0c419 Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Fri, 24 Feb 2023 11:16:58 +0530 Subject: usb: dwc3: gadget: Change condition for processing suspend event Currently we process the suspend interrupt event only if the device is in configured state. Consider a case where device is not configured and got suspend interrupt, in that case our gadget will still use 100mA as composite_suspend didn't happen. But battery charging specification (BC1.2) expects a downstream device to draw less than 2.5mA when unconnected OR suspended. Fix this by removing the condition for processing suspend event, and thus composite_resume would set vbus draw to 2. Fixes: 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler") Signed-off-by: Prashanth K Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/1677217619-10261-2-git-send-email-quic_prashk@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3c63fa97a680..07989c645a94 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4239,15 +4239,8 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, break; case DWC3_DEVICE_EVENT_SUSPEND: /* It changed to be suspend event for version 2.30a and above */ - if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) { - /* - * Ignore suspend event until the gadget enters into - * USB_STATE_CONFIGURED state. - */ - if (dwc->gadget->state >= USB_STATE_CONFIGURED) - dwc3_gadget_suspend_interrupt(dwc, - event->event_info); - } + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) + dwc3_gadget_suspend_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_SOF: case DWC3_DEVICE_EVENT_ERRATIC_ERROR: -- cgit v1.2.3 From 2ae4e0dea3b0c7b380821bac05e03a71da1f452f Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Fri, 24 Feb 2023 11:16:59 +0530 Subject: usb: gadget: composite: Draw 100mA current if not configured Currently we don't change the current value if device isn't in configured state. But in battery charging specification (section 1.2 and 1.4.13), it is mentioned that the device can draw up to 100mA of current if it's in unconfigured state. Hence add vbus draw work in composite_resume to draw 100mA if the device isn't configured. Signed-off-by: Prashanth K Link: https://lore.kernel.org/r/1677217619-10261-3-git-send-email-quic_prashk@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index fa7dd6cf014d..36add1879ed2 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2531,6 +2531,10 @@ void composite_resume(struct usb_gadget *gadget) usb_gadget_clear_selfpowered(gadget); usb_gadget_vbus_draw(gadget, maxpower); + } else { + maxpower = CONFIG_USB_GADGET_VBUS_DRAW; + maxpower = min(maxpower, 100U); + usb_gadget_vbus_draw(gadget, maxpower); } cdev->suspended = 0; -- cgit v1.2.3 From 5aacc9d540cea790fe4419b61bfa8a1218a4474a Mon Sep 17 00:00:00 2001 From: Kang Chen Date: Sat, 25 Feb 2023 12:11:48 +0800 Subject: usb: gadget: udc: add return value check of kzalloc in mv_udc_probe Even an 8-byte kzalloc will fail when we don't have enough memory, so we need a nullptr check and do the cleanup when it fails. Reported-by: eriri <1527030098@qq.com> Link: https://bugzilla.kernel.org/show_bug.cgi?id=217081 Signed-off-by: Kang Chen Link: https://lore.kernel.org/r/20230225041149.136-1-void0red@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/mv_udc_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index b397f3a848cf..6dd6d52de3af 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2230,6 +2230,10 @@ static int mv_udc_probe(struct platform_device *pdev) /* allocate a small amount of memory to get valid address */ udc->status_req->req.buf = kzalloc(8, GFP_KERNEL); + if (!udc->status_req->req.buf) { + retval = -ENOMEM; + goto err_destroy_dma; + } udc->status_req->req.dma = DMA_ADDR_INVALID; udc->resume_state = USB_STATE_NOTATTACHED; -- cgit v1.2.3 From 514c7ff5fe56164b769d2d105f0a382ca98c0851 Mon Sep 17 00:00:00 2001 From: Kang Chen Date: Sat, 25 Feb 2023 12:11:49 +0800 Subject: usb: gadget: udc: replace kzalloc with devm_kzalloc in mv_udc_probe This driver uses the unified memory management api, so replace kzalloc with devm_kzalloc to avoid a memory leak. Reported-by: Dongliang Mu Link: https://lore.kernel.org/all/CAD-N9QX5i5toj8cs7DxBjYWtRGf3ZRnfTAf809sFW6iX0Ktfmw@mail.gmail.com Signed-off-by: Kang Chen Link: https://lore.kernel.org/r/20230225041149.136-2-void0red@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/mv_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 6dd6d52de3af..08474c08d874 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2229,7 +2229,7 @@ static int mv_udc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&udc->status_req->queue); /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = kzalloc(8, GFP_KERNEL); + udc->status_req->req.buf = devm_kzalloc(&pdev->dev, 8, GFP_KERNEL); if (!udc->status_req->req.buf) { retval = -ENOMEM; goto err_destroy_dma; -- cgit v1.2.3 From 180bb831b232b43bbd658dcdb20a49020059c1b8 Mon Sep 17 00:00:00 2001 From: Yuta Hayama Date: Tue, 28 Feb 2023 17:56:37 +0900 Subject: usb: gadget: f_fs: Fix incorrect version checking of OS descs Currently, the USB gadget framework supports only version 1.0 of the MS OS descriptor. OS desc has a field bcdVersion indicating its version, with v1.0 represented by the value 0x100. However, __ffs_do_os_desc_header() was expecting the incorrect value 0x1, so allow the correct value 0x100. The bcdVersion field of the descriptor that is actually sent to the host is set by composite_setup() (in composite.c) to the fixed value 0x100. Therefore, it can be understood that __ffs_do_os_desc_header() is only performing a format check of the OS desc passed to functionfs. If a value other than 0x100 is accepted, there is no effect on communication over the USB bus. Indeed, until now __ffs_do_os_desc_header() has only accepted the incorrect value 0x1, but there was no problem with the communication over the USB bus. However, this can be confusing for functionfs userspace drivers. Since bcdVersion=0x100 is used in actual communication, functionfs should accept the value 0x100. Note that the correct value for bcdVersion in OS desc v1.0 is 0x100, but to avoid breaking old userspace drivers, the value 0x1 is also accepted as an exception. At this time, a message is output to notify the user to fix the userspace driver. Signed-off-by: Yuta Hayama Reviewed-by: Andrzej Pietrasiewicz Link: https://lore.kernel.org/r/290f96db-1877-5137-373a-318e7b4f2dde@lineo.co.jp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index ddfc537c7526..a277c70aac84 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2292,8 +2292,11 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, u16 bcd_version = le16_to_cpu(desc->bcdVersion); u16 w_index = le16_to_cpu(desc->wIndex); - if (bcd_version != 1) { - pr_vdebug("unsupported os descriptors version: %d", + if (bcd_version == 0x1) { + pr_warn("bcdVersion must be 0x0100, stored in Little Endian order. " + "Userspace driver should be fixed, accepting 0x0001 for compatibility.\n"); + } else if (bcd_version != 0x100) { + pr_vdebug("unsupported os descriptors version: 0x%x\n", bcd_version); return -EINVAL; } -- cgit v1.2.3 From 195a58cb3617d46f274a8cb47ee151d74d39ce0e Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Mon, 27 Feb 2023 10:44:07 +0800 Subject: usb: cdns3: change trace event cdns3_ring() operation the original design seem have several problems, first during trace event output stage, cdns3_dbg_ring() still refer to priv_ep->trb_pool which data content may changed during runtime, second when ring number is greater than TRBS_PER_SEGMENT, it has no change to show "too big" message, third in cdns3_log_ring event class definition, it allocate too much trace event buffer. change cdns3_dbg_ring() to be called at trace event fast assign time, and change trace buffer real dynamic according ring numbers. Signed-off-by: Linyu Yuan Link: https://lore.kernel.org/r/1677465850-1396-2-git-send-email-quic_linyyuan@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-debug.h | 8 ++------ drivers/usb/cdns3/cdns3-trace.h | 16 +++++----------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/usb/cdns3/cdns3-debug.h b/drivers/usb/cdns3/cdns3-debug.h index a5c6a29e1340..4618cfe85a4f 100644 --- a/drivers/usb/cdns3/cdns3-debug.h +++ b/drivers/usb/cdns3/cdns3-debug.h @@ -107,8 +107,7 @@ static inline char *cdns3_decode_ep0_irq(char *str, * Prints out all TRBs in the endpoint ring, even those after the Link TRB. *. */ -static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, - struct cdns3_trb *ring, char *str) +static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, char *str) { dma_addr_t addr = priv_ep->trb_pool_dma; struct cdns3_trb *trb; @@ -136,9 +135,6 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs); - if (trb_per_sector > TRBS_PER_SEGMENT) - trb_per_sector = TRBS_PER_SEGMENT; - if (trb_per_sector > TRBS_PER_SEGMENT) { sprintf(str + ret, "\t\tTransfer ring %d too big\n", trb_per_sector); @@ -146,7 +142,7 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, } for (i = 0; i < trb_per_sector; ++i) { - trb = &ring[i]; + trb = &priv_ep->trb_pool[i]; ret += sprintf(str + ret, "\t\t@%pad %08x %08x %08x\n", &addr, le32_to_cpu(trb->buffer), diff --git a/drivers/usb/cdns3/cdns3-trace.h b/drivers/usb/cdns3/cdns3-trace.h index 7574b4a62813..99057186393b 100644 --- a/drivers/usb/cdns3/cdns3-trace.h +++ b/drivers/usb/cdns3/cdns3-trace.h @@ -438,22 +438,16 @@ DECLARE_EVENT_CLASS(cdns3_log_ring, TP_PROTO(struct cdns3_endpoint *priv_ep), TP_ARGS(priv_ep), TP_STRUCT__entry( - __dynamic_array(u8, ring, TRB_RING_SIZE) - __dynamic_array(u8, priv_ep, sizeof(struct cdns3_endpoint)) __dynamic_array(char, buffer, - (TRBS_PER_SEGMENT * 65) + CDNS3_MSG_MAX) + GET_TRBS_PER_SEGMENT(priv_ep->type) > TRBS_PER_SEGMENT ? + CDNS3_MSG_MAX : + (GET_TRBS_PER_SEGMENT(priv_ep->type) * 65) + CDNS3_MSG_MAX) ), TP_fast_assign( - memcpy(__get_dynamic_array(priv_ep), priv_ep, - sizeof(struct cdns3_endpoint)); - memcpy(__get_dynamic_array(ring), priv_ep->trb_pool, - TRB_RING_SIZE); + cdns3_dbg_ring(priv_ep, __get_str(buffer)); ), - TP_printk("%s", - cdns3_dbg_ring((struct cdns3_endpoint *)__get_str(priv_ep), - (struct cdns3_trb *)__get_str(ring), - __get_str(buffer))) + TP_printk("%s", __get_str(buffer)) ); DEFINE_EVENT(cdns3_log_ring, cdns3_ring, -- cgit v1.2.3 From 47ebfd604f9b48e44d2f88caf527180463a2fb2c Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Mon, 27 Feb 2023 10:44:08 +0800 Subject: usb: cdns3: change some trace event __dynamic_array() to __get_buf() some __dynamic_array() buffer will only used at trace event output time, change to __get_buf() which will allocate tempary trace seq buffer for output purpose. Signed-off-by: Linyu Yuan Link: https://lore.kernel.org/r/1677465850-1396-3-git-send-email-quic_linyyuan@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-trace.h | 12 ++++-------- drivers/usb/cdns3/cdnsp-trace.h | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/usb/cdns3/cdns3-trace.h b/drivers/usb/cdns3/cdns3-trace.h index 99057186393b..40db89e3333c 100644 --- a/drivers/usb/cdns3/cdns3-trace.h +++ b/drivers/usb/cdns3/cdns3-trace.h @@ -100,13 +100,12 @@ DECLARE_EVENT_CLASS(cdns3_log_usb_irq, TP_STRUCT__entry( __field(enum usb_device_speed, speed) __field(u32, usb_ists) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->speed = cdns3_get_speed(priv_dev); __entry->usb_ists = usb_ists; ), - TP_printk("%s", cdns3_decode_usb_irq(__get_str(str), __entry->speed, + TP_printk("%s", cdns3_decode_usb_irq(__get_buf(CDNS3_MSG_MAX), __entry->speed, __entry->usb_ists)) ); @@ -124,7 +123,6 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq, __field(u32, ep_traddr) __field(u32, ep_last_sid) __field(u32, use_streams) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __assign_str(ep_name, priv_ep->name); @@ -134,7 +132,7 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq, __entry->use_streams = priv_ep->use_streams; ), TP_printk("%s, ep_traddr: %08x ep_last_sid: %08x use_streams: %d", - cdns3_decode_epx_irq(__get_str(str), + cdns3_decode_epx_irq(__get_buf(CDNS3_MSG_MAX), __get_str(ep_name), __entry->ep_sts), __entry->ep_traddr, @@ -153,13 +151,12 @@ DECLARE_EVENT_CLASS(cdns3_log_ep0_irq, TP_STRUCT__entry( __field(int, ep_dir) __field(u32, ep_sts) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->ep_dir = priv_dev->selected_ep; __entry->ep_sts = ep_sts; ), - TP_printk("%s", cdns3_decode_ep0_irq(__get_str(str), + TP_printk("%s", cdns3_decode_ep0_irq(__get_buf(CDNS3_MSG_MAX), __entry->ep_dir, __entry->ep_sts)) ); @@ -178,7 +175,6 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl, __field(u16, wValue) __field(u16, wIndex) __field(u16, wLength) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -187,7 +183,7 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNS3_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(CDNS3_MSG_MAX), CDNS3_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) diff --git a/drivers/usb/cdns3/cdnsp-trace.h b/drivers/usb/cdns3/cdnsp-trace.h index 5983dfb99653..4b51011eb00b 100644 --- a/drivers/usb/cdns3/cdnsp-trace.h +++ b/drivers/usb/cdns3/cdnsp-trace.h @@ -271,7 +271,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl, __field(u16, wValue) __field(u16, wIndex) __field(u16, wLength) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -280,7 +279,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNSP_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) @@ -345,7 +344,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb, __field(u32, field3) __field(union cdnsp_trb *, trb) __field(dma_addr_t, trb_dma) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->type = ring->type; @@ -359,7 +357,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb, ), TP_printk("%s: %s trb: %p(%pad)", cdnsp_ring_type_string(__entry->type), - cdnsp_decode_trb(__get_str(str), CDNSP_MSG_MAX, + cdnsp_decode_trb(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->field0, __entry->field1, __entry->field2, __entry->field3), __entry->trb, &__entry->trb_dma @@ -544,7 +542,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx, __field(u32, info2) __field(u64, deq) __field(u32, tx_info) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->ep_info); @@ -552,7 +549,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx, __entry->deq = le64_to_cpu(ctx->deq); __entry->tx_info = le32_to_cpu(ctx->tx_info); ), - TP_printk("%s", cdnsp_decode_ep_context(__get_str(str), CDNSP_MSG_MAX, + TP_printk("%s", cdnsp_decode_ep_context(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->info, __entry->info2, __entry->deq, __entry->tx_info) ) @@ -777,7 +774,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc, TP_STRUCT__entry( __field(u32, portnum) __field(u32, portsc) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->portnum = portnum; @@ -785,7 +781,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc, ), TP_printk("port-%d: %s", __entry->portnum, - cdnsp_decode_portsc(__get_str(str), CDNSP_MSG_MAX, + cdnsp_decode_portsc(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->portsc) ) ); -- cgit v1.2.3 From f09d24aa463c51672ff37462fed17eff824b8b18 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Mon, 27 Feb 2023 10:44:09 +0800 Subject: usb: dwc3: change some trace event __dynamic_array() to __get_buf() some __dynamic_array() buffer will only used at trace event output time, change to __get_buf() which will allocate tempary trace seq buffer for output purpose. Signed-off-by: Linyu Yuan Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/1677465850-1396-4-git-send-email-quic_linyyuan@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/trace.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 1975aec8d36d..d2997d17cfbe 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -54,14 +54,13 @@ DECLARE_EVENT_CLASS(dwc3_log_event, TP_STRUCT__entry( __field(u32, event) __field(u32, ep0state) - __dynamic_array(char, str, DWC3_MSG_MAX) ), TP_fast_assign( __entry->event = event; __entry->ep0state = dwc->ep0state; ), TP_printk("event (%08x): %s", __entry->event, - dwc3_decode_event(__get_str(str), DWC3_MSG_MAX, + dwc3_decode_event(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX, __entry->event, __entry->ep0state)) ); @@ -79,7 +78,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __field(__u16, wValue) __field(__u16, wIndex) __field(__u16, wLength) - __dynamic_array(char, str, DWC3_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -88,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), DWC3_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) -- cgit v1.2.3 From 7d1a898f52288f068f163aa970f029872c21c031 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Mon, 27 Feb 2023 10:44:10 +0800 Subject: usb: xhci: change some trace event __dynamic_array() to __get_buf() some __dynamic_array() buffer will only used at trace event output time, change to __get_buf() which will allocate tempary trace seq buffer for output purpose. Signed-off-by: Linyu Yuan Link: https://lore.kernel.org/r/1677465850-1396-5-git-send-email-quic_linyyuan@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-trace.h | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 61e93a3540a7..4286dba5b157 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -120,7 +120,6 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __field(u32, field1) __field(u32, field2) __field(u32, field3) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->type = ring->type; @@ -130,8 +129,8 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __entry->field3 = le32_to_cpu(trb->field[3]); ), TP_printk("%s: %s", xhci_ring_type_string(__entry->type), - xhci_decode_trb(__get_str(str), XHCI_MSG_MAX, __entry->field0, __entry->field1, - __entry->field2, __entry->field3) + xhci_decode_trb(__get_buf(XHCI_MSG_MAX), XHCI_MSG_MAX, __entry->field0, + __entry->field1, __entry->field2, __entry->field3) ) ); @@ -322,7 +321,6 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __field(u32, info2) __field(u64, deq) __field(u32, tx_info) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->ep_info); @@ -330,7 +328,7 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __entry->deq = le64_to_cpu(ctx->deq); __entry->tx_info = le32_to_cpu(ctx->tx_info); ), - TP_printk("%s", xhci_decode_ep_context(__get_str(str), + TP_printk("%s", xhci_decode_ep_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->deq, __entry->tx_info) ) ); @@ -368,7 +366,6 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __field(u32, info2) __field(u32, tt_info) __field(u32, state) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->dev_info); @@ -376,7 +373,7 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __entry->tt_info = le64_to_cpu(ctx->tt_info); __entry->state = le32_to_cpu(ctx->dev_state); ), - TP_printk("%s", xhci_decode_slot_context(__get_str(str), + TP_printk("%s", xhci_decode_slot_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->tt_info, __entry->state) ) @@ -433,13 +430,12 @@ DECLARE_EVENT_CLASS(xhci_log_ctrl_ctx, TP_STRUCT__entry( __field(u32, drop) __field(u32, add) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->drop = le32_to_cpu(ctrl_ctx->drop_flags); __entry->add = le32_to_cpu(ctrl_ctx->add_flags); ), - TP_printk("%s", xhci_decode_ctrl_ctx(__get_str(str), __entry->drop, __entry->add) + TP_printk("%s", xhci_decode_ctrl_ctx(__get_buf(XHCI_MSG_MAX), __entry->drop, __entry->add) ) ); @@ -525,7 +521,6 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, TP_STRUCT__entry( __field(u32, portnum) __field(u32, portsc) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->portnum = portnum; @@ -533,7 +528,7 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, ), TP_printk("port-%d: %s", __entry->portnum, - xhci_decode_portsc(__get_str(str), __entry->portsc) + xhci_decode_portsc(__get_buf(XHCI_MSG_MAX), __entry->portsc) ) ); @@ -558,14 +553,13 @@ DECLARE_EVENT_CLASS(xhci_log_doorbell, TP_STRUCT__entry( __field(u32, slot) __field(u32, doorbell) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->slot = slot; __entry->doorbell = doorbell; ), TP_printk("Ring doorbell for %s", - xhci_decode_doorbell(__get_str(str), __entry->slot, __entry->doorbell) + xhci_decode_doorbell(__get_buf(XHCI_MSG_MAX), __entry->slot, __entry->doorbell) ) ); -- cgit v1.2.3 From 3754c41c76867e41fe720555dc186ba4b3cccad9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 3 Feb 2023 09:45:26 +0800 Subject: dt-bindings: usb: snps,dwc3: support i.MX8MQ i.MX8MQ use Synopsys DesignWare USB3 Controller IP, so add the compatible. Signed-off-by: Peng Fan Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230203014526.1461386-1-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/snps,dwc3.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index c167fd577cae..16c7d06c9172 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -30,11 +30,13 @@ allOf: properties: compatible: - contains: - oneOf: - - const: snps,dwc3 - - const: synopsys,dwc3 - deprecated: true + oneOf: + - items: + - const: fsl,imx8mq-dwc3 + - const: snps,dwc3 + - const: snps,dwc3 + - const: synopsys,dwc3 + deprecated: true reg: maxItems: 1 -- cgit v1.2.3 From c8325b3227508459fab42f4f48fb232bc687f1ba Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 23 Feb 2023 15:07:42 -0600 Subject: thunderbolt: use `tb_eeprom_get_drom_offset` to discover DROM offset The static function `tb_eeprom_get_drom_offset` has more safety guards for the DROM offset fetching. Use this instead of just `tb_sw_read` No intended functional changes. Signed-off-by: Mario Limonciello Signed-off-by: Mika Westerberg --- drivers/thunderbolt/eeprom.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index c90d22f56d4e..3b96a55295a0 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -471,14 +471,13 @@ err: static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size) { - u32 drom_offset; + u16 drom_offset; int ret; if (!sw->dma_port) return -ENODEV; - ret = tb_sw_read(sw, &drom_offset, TB_CFG_SWITCH, - sw->cap_plug_events + 12, 1); + ret = tb_eeprom_get_drom_offset(sw, &drom_offset); if (ret) return ret; -- cgit v1.2.3 From ebde5ba27c640e08e92c83fe30be0d9fa224eea9 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 23 Feb 2023 15:07:43 -0600 Subject: thunderbolt: Refactor DROM reading The NVM reading code has a series of gotos that potentially introduce unexpected behaviors with retries if something unexpected has failed to parse. Refactor the code to remove the gotos and drop the retry logic. Signed-off-by: Mario Limonciello [mw: renamed root switch to host router, split device handling too] Signed-off-by: Mika Westerberg --- drivers/thunderbolt/eeprom.c | 199 +++++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 94 deletions(-) diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index 3b96a55295a0..0f6099c18a94 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -416,7 +416,7 @@ static int tb_drom_parse_entries(struct tb_switch *sw, size_t header_size) if (pos + 1 == drom_size || pos + entry->len > drom_size || !entry->len) { tb_sw_warn(sw, "DROM buffer overrun\n"); - return -EILSEQ; + return -EIO; } switch (entry->type) { @@ -512,7 +512,7 @@ err_free: return ret; } -static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size) +static int usb4_copy_drom(struct tb_switch *sw, u16 *size) { int ret; @@ -535,15 +535,40 @@ static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size) return ret; } -static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val, - size_t count) +static int tb_drom_bit_bang(struct tb_switch *sw, u16 *size) { - if (tb_switch_is_usb4(sw)) - return usb4_switch_drom_read(sw, offset, val, count); - return tb_eeprom_read_n(sw, offset, val, count); + int ret; + + ret = tb_eeprom_read_n(sw, 14, (u8 *)size, 2); + if (ret) + return ret; + + *size &= 0x3ff; + *size += TB_DROM_DATA_START; + + tb_sw_dbg(sw, "reading DROM (length: %#x)\n", *size); + if (*size < sizeof(struct tb_drom_header)) { + tb_sw_warn(sw, "DROM too small, aborting\n"); + return -EIO; + } + + sw->drom = kzalloc(*size, GFP_KERNEL); + if (!sw->drom) + return -ENOMEM; + + ret = tb_eeprom_read_n(sw, 0, sw->drom, *size); + if (ret) + goto err; + + return 0; + +err: + kfree(sw->drom); + sw->drom = NULL; + return ret; } -static int tb_drom_parse(struct tb_switch *sw) +static int tb_drom_parse_v1(struct tb_switch *sw) { const struct tb_drom_header *header = (const struct tb_drom_header *)sw->drom; @@ -554,7 +579,7 @@ static int tb_drom_parse(struct tb_switch *sw) tb_sw_warn(sw, "DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n", header->uid_crc8, crc); - return -EILSEQ; + return -EIO; } if (!sw->uid) sw->uid = header->uid; @@ -588,85 +613,14 @@ static int usb4_drom_parse(struct tb_switch *sw) return tb_drom_parse_entries(sw, USB4_DROM_HEADER_SIZE); } -/** - * tb_drom_read() - Copy DROM to sw->drom and parse it - * @sw: Router whose DROM to read and parse - * - * This function reads router DROM and if successful parses the entries and - * populates the fields in @sw accordingly. Can be called for any router - * generation. - * - * Returns %0 in case of success and negative errno otherwise. - */ -int tb_drom_read(struct tb_switch *sw) +static int tb_drom_parse(struct tb_switch *sw, u16 size) { - u16 size; - struct tb_drom_header *header; - int res, retries = 1; - - if (sw->drom) - return 0; - - if (tb_route(sw) == 0) { - /* - * Apple's NHI EFI driver supplies a DROM for the root switch - * in a device property. Use it if available. - */ - if (tb_drom_copy_efi(sw, &size) == 0) - goto parse; - - /* Non-Apple hardware has the DROM as part of NVM */ - if (tb_drom_copy_nvm(sw, &size) == 0) - goto parse; - - /* - * USB4 hosts may support reading DROM through router - * operations. - */ - if (tb_switch_is_usb4(sw)) { - usb4_switch_read_uid(sw, &sw->uid); - if (!usb4_copy_host_drom(sw, &size)) - goto parse; - } else { - /* - * The root switch contains only a dummy drom - * (header only, no entries). Hardcode the - * configuration here. - */ - tb_drom_read_uid_only(sw, &sw->uid); - } - - return 0; - } - - res = tb_drom_read_n(sw, 14, (u8 *) &size, 2); - if (res) - return res; - size &= 0x3ff; - size += TB_DROM_DATA_START; - tb_sw_dbg(sw, "reading drom (length: %#x)\n", size); - if (size < sizeof(*header)) { - tb_sw_warn(sw, "drom too small, aborting\n"); - return -EIO; - } - - sw->drom = kzalloc(size, GFP_KERNEL); - if (!sw->drom) - return -ENOMEM; -read: - res = tb_drom_read_n(sw, 0, sw->drom, size); - if (res) - goto err; - -parse: - header = (void *) sw->drom; + const struct tb_drom_header *header = (const void *)sw->drom; + int ret; if (header->data_len + TB_DROM_DATA_START != size) { - tb_sw_warn(sw, "drom size mismatch\n"); - if (retries--) { - msleep(100); - goto read; - } + tb_sw_warn(sw, "DROM size mismatch\n"); + ret = -EIO; goto err; } @@ -674,29 +628,86 @@ parse: switch (header->device_rom_revision) { case 3: - res = usb4_drom_parse(sw); + ret = usb4_drom_parse(sw); break; default: tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n", header->device_rom_revision); fallthrough; case 1: - res = tb_drom_parse(sw); + ret = tb_drom_parse_v1(sw); break; } - /* If the DROM parsing fails, wait a moment and retry once */ - if (res == -EILSEQ && retries--) { + if (ret) { tb_sw_warn(sw, "parsing DROM failed\n"); - msleep(100); - goto read; + goto err; } - if (!res) - return 0; + return 0; err: kfree(sw->drom); sw->drom = NULL; - return -EIO; + + return ret; +} + +static int tb_drom_host_read(struct tb_switch *sw) +{ + u16 size; + + if (tb_switch_is_usb4(sw)) { + usb4_switch_read_uid(sw, &sw->uid); + if (!usb4_copy_drom(sw, &size)) + return tb_drom_parse(sw, size); + } else { + if (!tb_drom_copy_efi(sw, &size)) + return tb_drom_parse(sw, size); + + if (!tb_drom_copy_nvm(sw, &size)) + return tb_drom_parse(sw, size); + + tb_drom_read_uid_only(sw, &sw->uid); + } + + return 0; +} + +static int tb_drom_device_read(struct tb_switch *sw) +{ + u16 size; + int ret; + + if (tb_switch_is_usb4(sw)) { + usb4_switch_read_uid(sw, &sw->uid); + ret = usb4_copy_drom(sw, &size); + } else { + ret = tb_drom_bit_bang(sw, &size); + } + + if (ret) + return ret; + + return tb_drom_parse(sw, size); +} + +/** + * tb_drom_read() - Copy DROM to sw->drom and parse it + * @sw: Router whose DROM to read and parse + * + * This function reads router DROM and if successful parses the entries and + * populates the fields in @sw accordingly. Can be called for any router + * generation. + * + * Returns %0 in case of success and negative errno otherwise. + */ +int tb_drom_read(struct tb_switch *sw) +{ + if (sw->drom) + return 0; + + if (!tb_route(sw)) + return tb_drom_host_read(sw); + return tb_drom_device_read(sw); } -- cgit v1.2.3 From 4fa1387261e725a418066f8f46ea87a6ba0e5be1 Mon Sep 17 00:00:00 2001 From: Yalong Zou Date: Thu, 9 Mar 2023 23:08:15 +0800 Subject: usb: remove dead code in dwc3_gadget_get_irq platform_get_irq() only return non-zero irq number on success, or negative error number on failure. There is no need to check the return value of platform_get_irq() to determine the return value of dwc3_gadget_get_irq(), removing them to solve this problem. Signed-off-by: Yalong Zou Signed-off-by: Dongliang Mu Link: https://lore.kernel.org/r/20230309150815.1884260-1-yalongz@hust.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 07989c645a94..a1ebb30c15fa 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4402,11 +4402,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc) goto out; irq = platform_get_irq(dwc3_pdev, 0); - if (irq > 0) - goto out; - - if (!irq) - irq = -EINVAL; out: return irq; -- cgit v1.2.3 From a20bf02aaa6c026e81b2b15d5878c08f683517bb Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Thu, 9 Mar 2023 20:44:52 +0000 Subject: usb: musb: mpfs: convert SOC_MICROCHIP_POLARFIRE to ARCH_MICROCHIP_POLARFIRE As part of converting RISC-V SOC_FOO symbols to ARCH_FOO to match the use of such symbols on other architectures, convert the Microchip FPGA usb glue layer driver to use the new symbol. Signed-off-by: Conor Dooley Link: https://lore.kernel.org/r/20230309204452.969574-6-conor@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 3a1f4bcea80c..9a8cf3de0617 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -113,7 +113,7 @@ config USB_MUSB_MEDIATEK config USB_MUSB_POLARFIRE_SOC tristate "Microchip PolarFire SoC platforms" - depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST depends on NOP_USB_XCEIV select USB_MUSB_DUAL_ROLE help -- cgit v1.2.3 From a3927e1a9f1c3b7d71d9c8215905397e55da4da3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Mar 2023 08:47:27 -0600 Subject: usb: Use of_property_present() for testing DT property presence It is preferred to use typed property access functions (i.e. of_property_read_ functions) rather than low-level of_get_property/of_find_property functions for reading properties. As part of this, convert of_get_property/of_find_property calls to the recently added of_property_present() helper when we just want to test for presence of a property and nothing more. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230310144728.1545786-1-robh@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/snps_udc_plat.c | 2 +- drivers/usb/host/fsl-mph-dr-of.c | 4 ++-- drivers/usb/musb/omap2430.c | 2 +- drivers/usb/phy/phy-mxs-usb.c | 2 +- drivers/usb/phy/phy-tegra-usb.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c index 8bbb89c80348..0d3e705655b9 100644 --- a/drivers/usb/gadget/udc/snps_udc_plat.c +++ b/drivers/usb/gadget/udc/snps_udc_plat.c @@ -158,7 +158,7 @@ static int udc_plat_probe(struct platform_device *pdev) } /* Register for extcon if supported */ - if (of_get_property(dev->of_node, "extcon", NULL)) { + if (of_property_present(dev->of_node, "extcon")) { udc->edev = extcon_get_edev_by_phandle(dev, 0); if (IS_ERR(udc->edev)) { if (PTR_ERR(udc->edev) == -EPROBE_DEFER) diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 46c6a152b865..cdf71b716c2b 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -200,10 +200,10 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) dev_data = get_dr_mode_data(np); if (of_device_is_compatible(np, "fsl-usb2-mph")) { - if (of_get_property(np, "port0", NULL)) + if (of_property_present(np, "port0")) pdata->port_enables |= FSL_USB2_PORT0_ENABLED; - if (of_get_property(np, "port1", NULL)) + if (of_property_present(np, "port1")) pdata->port_enables |= FSL_USB2_PORT1_ENABLED; pdata->operating_mode = FSL_USB2_MPH_HOST; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 44a21ec865fb..7f305b352591 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -334,7 +334,7 @@ static int omap2430_probe(struct platform_device *pdev) * Legacy SoCs using omap_device get confused if node is moved * because of interconnect properties mixed into the node. */ - if (of_get_property(np, "ti,hwmods", NULL)) { + if (of_property_present(np, "ti,hwmods")) { dev_warn(&pdev->dev, "please update to probe with ti-sysc\n"); populate_irqs = true; } else { diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index d2836ef5d15c..0a8e3fd699ca 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -733,7 +733,7 @@ static int mxs_phy_probe(struct platform_device *pdev) return -ENOMEM; /* Some SoCs don't have anatop registers */ - if (of_get_property(np, "fsl,anatop", NULL)) { + if (of_property_present(np, "fsl,anatop")) { mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle (np, "fsl,anatop"); if (IS_ERR(mxs_phy->regmap_anatop)) { diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index f0240107edb1..4d207ce3ddf2 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -1375,7 +1375,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->is_legacy_phy = of_property_read_bool(np, "nvidia,has-legacy-mode"); - if (of_find_property(np, "dr_mode", NULL)) + if (of_property_present(np, "dr_mode")) tegra_phy->mode = usb_get_dr_mode(&pdev->dev); else tegra_phy->mode = USB_DR_MODE_HOST; -- cgit v1.2.3 From f977caea50381e9ca38319037a2b23fe3209d647 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Mar 2023 08:47:28 -0600 Subject: usb: Use of_property_read_bool() for boolean properties It is preferred to use typed property access functions (i.e. of_property_read_ functions) rather than low-level of_get_property/of_find_property functions for reading properties. Convert reading boolean properties to to of_property_read_bool(). Signed-off-by: Rob Herring Reviewed-by: Richard Leitner Link: https://lore.kernel.org/r/20230310144729.1545857-1-robh@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 6 +++--- drivers/usb/chipidea/core.c | 2 +- drivers/usb/dwc2/params.c | 3 +-- drivers/usb/host/ehci-ppc-of.c | 6 +++--- drivers/usb/host/fsl-mph-dr-of.c | 7 ++----- drivers/usb/misc/usb251xb.c | 33 +++++++++++++++------------------ 6 files changed, 25 insertions(+), 32 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 2eeccf4ec9d6..2855ac303001 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -152,12 +152,12 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) * Check the various over current related properties. If over current * detection is disabled we're not interested in the polarity. */ - if (of_find_property(np, "disable-over-current", NULL)) { + if (of_property_read_bool(np, "disable-over-current")) { data->disable_oc = 1; - } else if (of_find_property(np, "over-current-active-high", NULL)) { + } else if (of_property_read_bool(np, "over-current-active-high")) { data->oc_pol_active_low = 0; data->oc_pol_configured = 1; - } else if (of_find_property(np, "over-current-active-low", NULL)) { + } else if (of_property_read_bool(np, "over-current-active-low")) { data->oc_pol_active_low = 1; data->oc_pol_configured = 1; } else { diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 27c601296130..7ccb223ed53c 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -753,7 +753,7 @@ static int ci_get_platdata(struct device *dev, return ret; } - if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL)) + if (of_property_read_bool(dev->of_node, "non-zero-ttctrl-ttha")) platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA; ext_id = ERR_PTR(-ENODEV); diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 9ed9fd956940..21d16533bd2f 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -508,8 +508,7 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) of_usb_update_otg_caps(hsotg->dev->of_node, &p->otg_caps); } - if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL)) - p->oc_disable = true; + p->oc_disable = of_property_read_bool(hsotg->dev->of_node, "disable-over-current"); } static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 62a0a193798c..b3aa464e9d2c 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -151,13 +151,13 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op) of_node_put(np); } - if (of_get_property(dn, "big-endian", NULL)) { + if (of_property_read_bool(dn, "big-endian")) { ehci->big_endian_mmio = 1; ehci->big_endian_desc = 1; } - if (of_get_property(dn, "big-endian-regs", NULL)) + if (of_property_read_bool(dn, "big-endian-regs")) ehci->big_endian_mmio = 1; - if (of_get_property(dn, "big-endian-desc", NULL)) + if (of_property_read_bool(dn, "big-endian-desc")) ehci->big_endian_desc = 1; ehci->caps = hcd->regs; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index cdf71b716c2b..9db909d12354 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -208,11 +208,8 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->operating_mode = FSL_USB2_MPH_HOST; } else { - if (of_get_property(np, "fsl,invert-drvvbus", NULL)) - pdata->invert_drvvbus = 1; - - if (of_get_property(np, "fsl,invert-pwr-fault", NULL)) - pdata->invert_pwr_fault = 1; + pdata->invert_drvvbus = of_property_read_bool(np, "fsl,invert-drvvbus"); + pdata->invert_pwr_fault = of_property_read_bool(np, "fsl,invert-pwr-fault"); /* setup mode selected in the device tree */ pdata->operating_mode = dev_data->op_mode; diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index e3abe67a155d..96f25c1ec113 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -410,10 +410,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, return -ENODEV; } - if (of_get_property(np, "skip-config", NULL)) - hub->skip_config = 1; - else - hub->skip_config = 0; + hub->skip_config = of_property_read_bool(np, "skip-config"); hub->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hub->gpio_reset)) @@ -431,40 +428,40 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->device_id = USB251XB_DEF_DEVICE_ID; hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1; - if (of_get_property(np, "self-powered", NULL)) { + if (of_property_read_bool(np, "self-powered")) { hub->conf_data1 |= BIT(7); /* Configure Over-Current sens when self-powered */ hub->conf_data1 &= ~BIT(2); - if (of_get_property(np, "ganged-sensing", NULL)) + if (of_property_read_bool(np, "ganged-sensing")) hub->conf_data1 &= ~BIT(1); - else if (of_get_property(np, "individual-sensing", NULL)) + else if (of_property_read_bool(np, "individual-sensing")) hub->conf_data1 |= BIT(1); - } else if (of_get_property(np, "bus-powered", NULL)) { + } else if (of_property_read_bool(np, "bus-powered")) { hub->conf_data1 &= ~BIT(7); /* Disable Over-Current sense when bus-powered */ hub->conf_data1 |= BIT(2); } - if (of_get_property(np, "disable-hi-speed", NULL)) + if (of_property_read_bool(np, "disable-hi-speed")) hub->conf_data1 |= BIT(5); - if (of_get_property(np, "multi-tt", NULL)) + if (of_property_read_bool(np, "multi-tt")) hub->conf_data1 |= BIT(4); - else if (of_get_property(np, "single-tt", NULL)) + else if (of_property_read_bool(np, "single-tt")) hub->conf_data1 &= ~BIT(4); - if (of_get_property(np, "disable-eop", NULL)) + if (of_property_read_bool(np, "disable-eop")) hub->conf_data1 |= BIT(3); - if (of_get_property(np, "individual-port-switching", NULL)) + if (of_property_read_bool(np, "individual-port-switching")) hub->conf_data1 |= BIT(0); - else if (of_get_property(np, "ganged-port-switching", NULL)) + else if (of_property_read_bool(np, "ganged-port-switching")) hub->conf_data1 &= ~BIT(0); hub->conf_data2 = USB251XB_DEF_CONFIG_DATA_2; - if (of_get_property(np, "dynamic-power-switching", NULL)) + if (of_property_read_bool(np, "dynamic-power-switching")) hub->conf_data2 |= BIT(7); if (!of_property_read_u32(np, "oc-delay-us", &property_u32)) { @@ -487,17 +484,17 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, } } - if (of_get_property(np, "compound-device", NULL)) + if (of_property_read_bool(np, "compound-device")) hub->conf_data2 |= BIT(3); hub->conf_data3 = USB251XB_DEF_CONFIG_DATA_3; - if (of_get_property(np, "port-mapping-mode", NULL)) + if (of_property_read_bool(np, "port-mapping-mode")) hub->conf_data3 |= BIT(3); if (data->led_support && of_get_property(np, "led-usb-mode", NULL)) hub->conf_data3 &= ~BIT(1); - if (of_get_property(np, "string-support", NULL)) + if (of_property_read_bool(np, "string-support")) hub->conf_data3 |= BIT(0); hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; -- cgit v1.2.3 From e13a7333067e47d01f8bfcc36e300e26ab4f8bea Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Mar 2023 18:41:29 +0200 Subject: usb: acpi: Switch to use acpi_evaluate_dsm_typed() The acpi_evaluate_dsm_typed() provides a way to check the type of the object evaluated by _DSM call. Use it instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230310164129.21937-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb-acpi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 533baa85083c..a34b22537d7c 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -81,15 +81,11 @@ int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index) return -ENODEV; } - obj = acpi_evaluate_dsm(port_handle, &guid, 0, - USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL); - - if (!obj) - return -ENODEV; - - if (obj->type != ACPI_TYPE_INTEGER) { + obj = acpi_evaluate_dsm_typed(port_handle, &guid, 0, + USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL, + ACPI_TYPE_INTEGER); + if (!obj) { dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1); - ACPI_FREE(obj); return -EINVAL; } -- cgit v1.2.3 From d6cfb252107d36fdddb66891c16d34a346882c36 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Mar 2023 18:36:18 +0100 Subject: usb: host: xhci-rcar: drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). drivers/usb/host/xhci-rcar.c:269:34: error: ‘usb_xhci_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230311173624.263189-1-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-rcar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index c4925f8d6b06..ad966b797b89 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -282,7 +282,7 @@ static struct platform_driver usb_xhci_renesas_driver = { .driver = { .name = "xhci-renesas-hcd", .pm = &xhci_plat_pm_ops, - .of_match_table = of_match_ptr(usb_xhci_of_match), + .of_match_table = usb_xhci_of_match, }, }; module_platform_driver(usb_xhci_renesas_driver); -- cgit v1.2.3 From 658e467b76eb41005ef0c257d0b7accf73dcd32a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Mar 2023 18:36:19 +0100 Subject: usb: host: max3421-hcd: drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). drivers/usb/host/max3421-hcd.c:1943:34: error: ‘max3421_of_match_table’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230311173624.263189-2-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 28d1524ee2fa..d152d72de126 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1951,7 +1951,7 @@ static struct spi_driver max3421_driver = { .remove = max3421_remove, .driver = { .name = "max3421-hcd", - .of_match_table = of_match_ptr(max3421_of_match_table), + .of_match_table = max3421_of_match_table, }, }; -- cgit v1.2.3 From 94d1957fc361bb7efa76c25f3c78296c3c9f867f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Mar 2023 18:36:20 +0100 Subject: usb: renesas_usbhs: drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). drivers/usb/renesas_usbhs/common.c:535:34: error: ‘usbhs_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230311173624.263189-3-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 96f3939a65e2..fa34efabcccf 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -823,7 +823,7 @@ static struct platform_driver renesas_usbhs_driver = { .driver = { .name = "renesas_usbhs", .pm = &usbhsc_pm_ops, - .of_match_table = of_match_ptr(usbhs_of_match), + .of_match_table = usbhs_of_match, }, .probe = usbhs_probe, .remove = usbhs_remove, -- cgit v1.2.3 From 2df6349323f627cc1f8e076fa4a7b715f6a05e5a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Mar 2023 18:36:21 +0100 Subject: usb: gadget: rzv2m_usb3drd: drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). drivers/usb/gadget/udc/rzv2m_usb3drd.c:120:34: error: ‘rzv2m_usb3drd_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230311173624.263189-4-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/rzv2m_usb3drd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c index 3c8bbf843038..8855d8e8d793 100644 --- a/drivers/usb/gadget/udc/rzv2m_usb3drd.c +++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c @@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_usb3drd_of_match); static struct platform_driver rzv2m_usb3drd_driver = { .driver = { .name = "rzv2m-usb3drd", - .of_match_table = of_match_ptr(rzv2m_usb3drd_of_match), + .of_match_table = rzv2m_usb3drd_of_match, }, .probe = rzv2m_usb3drd_probe, .remove = rzv2m_usb3drd_remove, -- cgit v1.2.3 From 4997cacd6ecb588b32c5c43bf6bbe87d311dfb1e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Mar 2023 18:36:22 +0100 Subject: usb: gadget: renesas_usb3: drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). drivers/usb/gadget/udc/renesas_usb3.c:2811:34: error: ‘usb3_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230311173624.263189-5-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/renesas_usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index f2ac6447b748..17e765d2e093 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -3018,7 +3018,7 @@ static struct platform_driver renesas_usb3_driver = { .driver = { .name = udc_name, .pm = &renesas_usb3_pm_ops, - .of_match_table = of_match_ptr(usb3_of_match), + .of_match_table = usb3_of_match, }, }; module_platform_driver(renesas_usb3_driver); -- cgit v1.2.3 From f80391ddb7793dca03c0fb548acf39ee562982f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Mar 2023 18:36:23 +0100 Subject: usb: gadget: max3420_udc: drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). drivers/usb/gadget/udc/max3420_udc.c:1312:34: error: ‘max3420_udc_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230311173624.263189-6-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/max3420_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c index ddf0ed3eb4f2..12c519f32bf7 100644 --- a/drivers/usb/gadget/udc/max3420_udc.c +++ b/drivers/usb/gadget/udc/max3420_udc.c @@ -1319,7 +1319,7 @@ MODULE_DEVICE_TABLE(of, max3420_udc_of_match); static struct spi_driver max3420_driver = { .driver = { .name = "max3420-udc", - .of_match_table = of_match_ptr(max3420_udc_of_match), + .of_match_table = max3420_udc_of_match, }, .probe = max3420_probe, .remove = max3420_remove, -- cgit v1.2.3 From 2665eb8e20539a16d113725fdbcc2fb63fd627a5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 11 Mar 2023 18:36:24 +0100 Subject: usb: misc: usb251xb: drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver will match mostly by DT table (even thought there is regular ID table) so there is little benefit in of_match_ptr (this also allows ACPI matching via PRP0001, even though it might not be relevant here). drivers/usb/misc/usb251xb.c:223:35: error: ‘usb2517i_data’ defined but not used [-Werror=unused-const-variable=] drivers/usb/misc/usb251xb.c:215:35: error: ‘usb2517_data’ defined but not used [-Werror=unused-const-variable=] drivers/usb/misc/usb251xb.c:207:35: error: ‘usb2514bi_data’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Acked-by: Richard Leitner Link: https://lore.kernel.org/r/20230311173624.263189-7-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb251xb.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 96f25c1ec113..ce1da80d3365 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -377,7 +377,6 @@ out_err: return err; } -#ifdef CONFIG_OF static void usb251xb_get_ports_field(struct usb251xb *hub, const char *prop_name, u8 port_cnt, bool ds_only, u8 *fld) @@ -623,13 +622,6 @@ static const struct of_device_id usb251xb_of_match[] = { } }; MODULE_DEVICE_TABLE(of, usb251xb_of_match); -#else /* CONFIG_OF */ -static int usb251xb_get_ofdata(struct usb251xb *hub, - const struct usb251xb_data *data) -{ - return 0; -} -#endif /* CONFIG_OF */ static void usb251xb_regulator_disable_action(void *data) { @@ -751,7 +743,7 @@ MODULE_DEVICE_TABLE(i2c, usb251xb_id); static struct i2c_driver usb251xb_i2c_driver = { .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(usb251xb_of_match), + .of_match_table = usb251xb_of_match, .pm = &usb251xb_pm_ops, }, .probe_new = usb251xb_i2c_probe, -- cgit v1.2.3 From 45e7c9e448e345f27c4329d0395946f4a9cfd8c3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Mar 2023 23:29:36 +0100 Subject: usb: typec: hd3ss3220: Drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it is not relevant here). drivers/usb/typec/hd3ss3220.c:284:34: error: ‘dev_ids’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Reviewed-by: Heikki Krogerus Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230310222937.315773-1-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/hd3ss3220.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c index 746ef3a75b76..8bbeb9b1e439 100644 --- a/drivers/usb/typec/hd3ss3220.c +++ b/drivers/usb/typec/hd3ss3220.c @@ -290,7 +290,7 @@ MODULE_DEVICE_TABLE(of, dev_ids); static struct i2c_driver hd3ss3220_driver = { .driver = { .name = "hd3ss3220", - .of_match_table = of_match_ptr(dev_ids), + .of_match_table = dev_ids, }, .probe_new = hd3ss3220_probe, .remove = hd3ss3220_remove, -- cgit v1.2.3 From b16de6a5c70b53bee495a42ebe74ccca076a3e26 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Mar 2023 23:29:37 +0100 Subject: usb: typec: fusb302: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: drivers/usb/typec/tcpm/fusb302.c:1816:34: error: ‘fusb302_dt_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Reviewed-by: Heikki Krogerus Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230310222937.315773-2-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/fusb302.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 1ffce00d94b4..592b0aec782f 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -1813,7 +1813,7 @@ static int fusb302_pm_resume(struct device *dev) return 0; } -static const struct of_device_id fusb302_dt_match[] = { +static const struct of_device_id fusb302_dt_match[] __maybe_unused = { {.compatible = "fcs,fusb302"}, {}, }; -- cgit v1.2.3 From 34427557747cad5f599d65be894e846b31714602 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 13 Mar 2023 17:53:10 +0200 Subject: usb: gadget: aspeed: Rectify a bit a random header inclusion It looks like the driver copied'n'pasted almost random set of headers for its code. Rectify it a bit by removing of_gpio.h that is not only unused, but also will be removed in the future completely. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230313155310.80022-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed-vhub/core.c | 1 - drivers/usb/gadget/udc/aspeed-vhub/dev.c | 1 - drivers/usb/gadget/udc/aspeed-vhub/ep0.c | 1 - drivers/usb/gadget/udc/aspeed-vhub/epn.c | 1 - drivers/usb/gadget/udc/aspeed-vhub/hub.c | 1 - 5 files changed, 5 deletions(-) diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index ac3ca24f8b04..86398a04a012 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 4f3bc27c1c62..573109ca5b79 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index b4cf46249fea..e9aa74231760 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 56e55472daa1..148d7ec3ebf4 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index e2207d014620..a63e4af60a56 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 1239e8124714ca94dd4c882266ee4bcad3f46e73 Mon Sep 17 00:00:00 2001 From: Emanuele Ghidoli Date: Mon, 13 Mar 2023 17:50:37 +0100 Subject: dt-bindings: usb: smsc,usb3503: Add usb3803 Add support for usb3803, compared to usb3503 it uses a regular USB connection to upstream instead of HSIC, it has an additional low power mode (bypass) and an additional control signal (BYPASS_N). In bypass mode the downstream port 3 is connected to the upstream port with low switch resistance R_on. Signed-off-by: Emanuele Ghidoli Signed-off-by: Francesco Dolcini Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230313165039.255579-2-francesco@dolcini.it Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/smsc,usb3503.yaml | 54 +++++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml index a09f4528aea3..6156dc26e65c 100644 --- a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml +++ b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml @@ -14,6 +14,7 @@ properties: enum: - smsc,usb3503 - smsc,usb3503a + - smsc,usb3803 reg: maxItems: 1 @@ -33,6 +34,12 @@ properties: description: > GPIO for reset + bypass-gpios: + maxItems: 1 + description: > + GPIO for bypass. + Control signal to select between HUB MODE and BYPASS MODE. + disabled-ports: $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 @@ -46,9 +53,10 @@ properties: initial-mode: $ref: /schemas/types.yaml#/definitions/uint32 - enum: [1, 2] description: > - Specifies initial mode. 1 for Hub mode, 2 for standby mode. + Specifies initial mode. 1 for Hub mode, 2 for standby mode and 3 for bypass mode. + In bypass mode the downstream port 3 is connected to the upstream port with low + switch resistance R_on. clocks: maxItems: 1 @@ -71,6 +79,29 @@ properties: required: - compatible +allOf: + - if: + not: + properties: + compatible: + enum: + - smsc,usb3803 + then: + properties: + bypass-gpios: false + + - if: + required: + - bypass-gpios + then: + properties: + initial-mode: + enum: [1, 2, 3] + else: + properties: + initial-mode: + enum: [1, 2] + additionalProperties: false examples: @@ -92,6 +123,25 @@ examples: }; }; + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + usb-hub@8 { + compatible = "smsc,usb3803"; + reg = <0x08>; + connect-gpios = <&gpx3 0 1>; + disabled-ports = <2 3>; + intn-gpios = <&gpx3 4 1>; + reset-gpios = <&gpx3 5 1>; + bypass-gpios = <&gpx3 6 1>; + initial-mode = <3>; + clocks = <&clks 80>; + clock-names = "refclk"; + }; + }; + - | #include -- cgit v1.2.3 From b04b32cd67304bdda9f19fc52fc5abd95f8502ab Mon Sep 17 00:00:00 2001 From: Emanuele Ghidoli Date: Mon, 13 Mar 2023 17:50:38 +0100 Subject: usb: misc: usb3503: refactor code to prepare for usb3803 addition Refactor code to simplify adding support for USB3803 and bypass mode. Remove static usb3503_reset() and move it to usb3503_switch_mode(), with the addition of the bypass mode we need to drive the various control signals to the expected configuration, not just to assert/release the reset. In addition to that the usb3503_connect() needs to be called only for HUB mode. No functional changes expected nor intended because of this change. Signed-off-by: Emanuele Ghidoli Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20230313165039.255579-3-francesco@dolcini.it Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb3503.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index bd47c4437ca4..3044db9fd8aa 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -52,28 +52,11 @@ struct usb3503 { bool secondary_ref_clk; }; -static int usb3503_reset(struct usb3503 *hub, int state) -{ - if (!state && hub->connect) - gpiod_set_value_cansleep(hub->connect, 0); - - if (hub->reset) - gpiod_set_value_cansleep(hub->reset, !state); - - /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ - if (state) - usleep_range(4000, 10000); - - return 0; -} - static int usb3503_connect(struct usb3503 *hub) { struct device *dev = hub->dev; int err; - usb3503_reset(hub, 1); - if (hub->regmap) { /* SP_ILOCK: set connect_n, config_n for config */ err = regmap_write(hub->regmap, USB3503_SP_ILOCK, @@ -126,25 +109,36 @@ static int usb3503_connect(struct usb3503 *hub) static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) { struct device *dev = hub->dev; - int err = 0; + int rst, conn; switch (mode) { case USB3503_MODE_HUB: - err = usb3503_connect(hub); + conn = 1; + rst = 0; break; - case USB3503_MODE_STANDBY: - usb3503_reset(hub, 0); + conn = 0; + rst = 1; dev_info(dev, "switched to STANDBY mode\n"); break; - default: dev_err(dev, "unknown mode is requested\n"); - err = -EINVAL; - break; + return -EINVAL; } - return err; + if (!conn && hub->connect) + gpiod_set_value_cansleep(hub->connect, 0); + + if (hub->reset) + gpiod_set_value_cansleep(hub->reset, rst); + + if (conn) { + /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ + usleep_range(4000, 10000); + return usb3503_connect(hub); + } + + return 0; } static const struct regmap_config usb3503_regmap_config = { -- cgit v1.2.3 From b91e6107119f62be8b51b9955294be52c0b4fc80 Mon Sep 17 00:00:00 2001 From: Emanuele Ghidoli Date: Mon, 13 Mar 2023 17:50:39 +0100 Subject: usb: misc: usb3503: support usb3803 and bypass mode Add support for USB3803 and bypass mode, with this change is also possible to move the component out of bypass mode. In bypass mode the downstream port 3 is connected to the upstream port with low switch resistance R_on. Controlling mode of operations: | RESET_N | BYPASS_N | Mode | -------------------------------- | 0 | 0 | standby | | 1 | 0 | bypass | | 1 | 1 | hub | Datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/UNG/ProductDocuments/DataSheets/00001691D.pdf Signed-off-by: Emanuele Ghidoli Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20230313165039.255579-4-francesco@dolcini.it Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb3503.c | 22 +++++++++++++++++++++- include/linux/platform_data/usb3503.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 3044db9fd8aa..c6cfd1edaf76 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -46,6 +46,7 @@ struct usb3503 { struct device *dev; struct clk *clk; u8 port_off_mask; + struct gpio_desc *bypass; struct gpio_desc *intn; struct gpio_desc *reset; struct gpio_desc *connect; @@ -109,18 +110,25 @@ static int usb3503_connect(struct usb3503 *hub) static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) { struct device *dev = hub->dev; - int rst, conn; + int rst, bypass, conn; switch (mode) { case USB3503_MODE_HUB: conn = 1; rst = 0; + bypass = 0; break; case USB3503_MODE_STANDBY: conn = 0; rst = 1; + bypass = 1; dev_info(dev, "switched to STANDBY mode\n"); break; + case USB3503_MODE_BYPASS: + conn = 0; + rst = 0; + bypass = 1; + break; default: dev_err(dev, "unknown mode is requested\n"); return -EINVAL; @@ -132,6 +140,9 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) if (hub->reset) gpiod_set_value_cansleep(hub->reset, rst); + if (hub->bypass) + gpiod_set_value_cansleep(hub->bypass, bypass); + if (conn) { /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ usleep_range(4000, 10000); @@ -247,6 +258,14 @@ static int usb3503_probe(struct usb3503 *hub) if (hub->connect) gpiod_set_consumer_name(hub->connect, "usb3503 connect"); + hub->bypass = devm_gpiod_get_optional(dev, "bypass", GPIOD_OUT_HIGH); + if (IS_ERR(hub->bypass)) { + err = PTR_ERR(hub->bypass); + goto err_clk; + } + if (hub->bypass) + gpiod_set_consumer_name(hub->bypass, "usb3503 bypass"); + hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hub->reset)) { err = PTR_ERR(hub->reset); @@ -382,6 +401,7 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id); static const struct of_device_id usb3503_of_match[] = { { .compatible = "smsc,usb3503", }, { .compatible = "smsc,usb3503a", }, + { .compatible = "smsc,usb3803", }, {}, }; MODULE_DEVICE_TABLE(of, usb3503_of_match); diff --git a/include/linux/platform_data/usb3503.h b/include/linux/platform_data/usb3503.h index d01ef97ddf36..f3c942f396f8 100644 --- a/include/linux/platform_data/usb3503.h +++ b/include/linux/platform_data/usb3503.h @@ -12,6 +12,7 @@ enum usb3503_mode { USB3503_MODE_UNKNOWN, USB3503_MODE_HUB, USB3503_MODE_STANDBY, + USB3503_MODE_BYPASS, }; struct usb3503_platform_data { -- cgit v1.2.3 From 55b7fa634d9f5d88f008f8b785448db40a2d5229 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 14 Mar 2023 13:53:00 +0100 Subject: dt-bindings: usb: dwc3: Add QCM2290 compatible Document the QCM2290 DWC3 controller. Signed-off-by: Konrad Dybcio Reviewed-by: Bhupesh Sharma Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230314-topic-2290_compats-v1-5-47e26c3c0365@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/qcom,dwc3.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 4875c5b7d5b5..a2aabdac4105 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -21,6 +21,7 @@ properties: - qcom,msm8994-dwc3 - qcom,msm8996-dwc3 - qcom,msm8998-dwc3 + - qcom,qcm2290-dwc3 - qcom,qcs404-dwc3 - qcom,sc7180-dwc3 - qcom,sc7280-dwc3 @@ -300,6 +301,7 @@ allOf: compatible: contains: enum: + - qcom,qcm2290-dwc3 - qcom,sm6115-dwc3 - qcom,sm6125-dwc3 - qcom,sm8150-dwc3 -- cgit v1.2.3 From 9e67955322838b93e37f3902cabde0ee712dd2ef Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Mar 2023 11:19:10 +0100 Subject: usb: host: u132-hcd: Various style improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Don't break strings over two (or more) lines - Put the , separating function args at the end of line - Replace if (cond) {} else { ... } by if (!cond) { ... } - Consistently use curly braces in all blocks belonging to the same if if at least one block needs them. - Don't start a new line just for ); There are no semantic changes. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230321101911.342538-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 398 +++++++++++++++++++++++--------------------- 1 file changed, 208 insertions(+), 190 deletions(-) diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 95240c9c45bd..f5433993c76e 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -71,8 +71,8 @@ INT_MODULE_PARM(testing, 0); /* Some boards misreport power switching/overcurrent*/ static bool distrust_firmware = true; module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent" - "t setup"); +MODULE_PARM_DESC(distrust_firmware, + "true to distrust firmware power/overcurrentt setup"); static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); /* * u132_module_lock exists to protect access to global variables @@ -254,8 +254,9 @@ static void u132_hcd_delete(struct kref *kref) mutex_lock(&u132_module_lock); u132_instances -= 1; mutex_unlock(&u132_module_lock); - dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" - "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); + dev_warn(&u132->platform_dev->dev, + "FREEING the hcd=%p and thus the u132=%p going=%d pdev=%p\n", + hcd, u132, u132->going, pdev); usb_put_hcd(hcd); } @@ -346,8 +347,9 @@ static void u132_endp_delete(struct kref *kref) ring->curr_endp = next_endp; list_del(head); } - } else + } else { list_del(head); + } if (endp->input) { udev->endp_number_in[usb_endp] = 0; u132_udev_put_kref(u132, udev); @@ -419,35 +421,32 @@ static int read_roothub_info(struct u132 *u132) { u32 revision; int retval; + struct device *dev = &u132->platform_dev->dev; + retval = u132_read_pcimem(u132, revision, &revision); if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); + dev_err(dev, "error %d accessing device control\n", retval); return retval; } else if ((revision & 0xFF) == 0x10) { } else if ((revision & 0xFF) == 0x11) { } else { - dev_err(&u132->platform_dev->dev, "device revision is not valid" - " %08X\n", revision); + dev_err(dev, "device revision is not valid %08X\n", revision); return -ENODEV; } retval = u132_read_pcimem(u132, control, &u132->hc_control); if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); + dev_err(dev, "error %d accessing device control\n", retval); return retval; } retval = u132_read_pcimem(u132, roothub.status, &u132->hc_roothub_status); if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.status\n", retval); + dev_err(dev, "error %d accessing device reg roothub.status\n", retval); return retval; } retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.a\n", retval); + dev_err(dev, "error %d accessing device reg roothub.a\n", retval); return retval; } { @@ -457,12 +456,12 @@ static int read_roothub_info(struct u132 *u132) retval = u132_read_pcimem(u132, roothub.portstatus[i], &u132->hc_roothub_portstatus[i]); if (retval) { - dev_err(&u132->platform_dev->dev, "error %d acc" - "essing device roothub.portstatus[%d]\n" - , retval, i); + dev_err(dev, "error %d accessing device roothub.portstatus[%d]\n", + retval, i); return retval; - } else + } else { i += 1; + } } } return 0; @@ -472,8 +471,8 @@ static void u132_hcd_monitor_work(struct work_struct *work) { struct u132 *u132 = container_of(work, struct u132, monitor.work); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "device has been removed %d\n", + u132->going); u132_monitor_put_kref(u132); return; } else if (u132->going > 0) { @@ -622,8 +621,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, struct u132_udev *udev = &u132->udev[address]; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "device has been removed %d\n", + u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -633,8 +632,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -694,9 +693,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, endp->toggle_bits = 0x2; usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p givin" - "g back INTERRUPT %s\n", urb, - cc_to_text[condition_code]); + dev_err(&u132->platform_dev->dev, "urb=%p giving back INTERRUPT %s\n", + urb, cc_to_text[condition_code]); } mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, @@ -704,8 +702,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -721,8 +719,8 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, u8 address = u132->addr[endp->usb_addr].address; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "device has been removed %d\n", + u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -732,8 +730,8 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -755,8 +753,8 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -773,8 +771,8 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, struct u132_udev *udev = &u132->udev[address]; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -784,8 +782,8 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -833,9 +831,9 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, endp->toggle_bits = toggle_bits; usb_settoggle(udev->usb_device, endp->usb_endp, 0, 1 & toggle_bits); - dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK" - ") giving back BULK IN %s\n", urb, - cc_to_text[condition_code]); + dev_warn(&u132->platform_dev->dev, + "urb=%p(SHORT NOT OK) giving back BULK IN %s\n", + urb, cc_to_text[condition_code]); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -849,17 +847,18 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, } else { endp->toggle_bits = 0x2; usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p giving back B" - "ULK IN code=%d %s\n", urb, condition_code, - cc_to_text[condition_code]); + dev_err(&u132->platform_dev->dev, + "urb=%p giving back BULK IN code=%d %s\n", + urb, condition_code, cc_to_text[condition_code]); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, cc_to_error[condition_code]); return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -874,8 +873,8 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, struct u132 *u132 = endp->u132; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -885,8 +884,8 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -895,8 +894,9 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -912,8 +912,8 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, u8 address = u132->addr[endp->usb_addr].address; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -923,8 +923,8 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -952,23 +952,24 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, return; } else if (condition_code == TD_CC_STALL) { mutex_unlock(&u132->scheduler_lock); - dev_warn(&u132->platform_dev->dev, "giving back SETUP I" - "NPUT STALL urb %p\n", urb); + dev_warn(&u132->platform_dev->dev, + "giving back SETUP INPUT STALL urb %p\n", urb); u132_hcd_giveback_urb(u132, endp, urb, cc_to_error[condition_code]); return; } else { mutex_unlock(&u132->scheduler_lock); - dev_err(&u132->platform_dev->dev, "giving back SETUP IN" - "PUT %s urb %p\n", cc_to_text[condition_code], - urb); + dev_err(&u132->platform_dev->dev, + "giving back SETUP INPUT %s urb %p\n", + cc_to_text[condition_code], urb); u132_hcd_giveback_urb(u132, endp, urb, cc_to_error[condition_code]); return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -983,8 +984,8 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, struct u132 *u132 = endp->u132; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "device has been removed %d\n", + u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -994,8 +995,8 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -1004,8 +1005,9 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -1021,8 +1023,8 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, u8 address = u132->addr[endp->usb_addr].address; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, "device has been removed %d\n", + u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -1032,8 +1034,8 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -1062,8 +1064,9 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -1080,8 +1083,8 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, struct u132_udev *udev = &u132->udev[address]; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -1091,8 +1094,8 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -1103,8 +1106,9 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -1119,8 +1123,8 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, struct u132 *u132 = endp->u132; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -1130,8 +1134,7 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -1146,8 +1149,9 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -1162,8 +1166,8 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, struct u132 *u132 = endp->u132; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -1173,8 +1177,8 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -1183,8 +1187,9 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -1200,8 +1205,8 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u8 address = u132->addr[endp->usb_addr].address; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -1211,8 +1216,8 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -1235,8 +1240,9 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -1252,8 +1258,8 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u8 address = u132->addr[endp->usb_addr].address; mutex_lock(&u132->scheduler_lock); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); mutex_unlock(&u132->scheduler_lock); u132_hcd_forget_urb(u132, endp, urb, -ENODEV); return; @@ -1263,8 +1269,8 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; @@ -1279,8 +1285,9 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); + dev_err(&u132->platform_dev->dev, + "CALLBACK called urb=%p unlinked=%d\n", + urb, urb->unlinked); mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; @@ -1462,8 +1469,7 @@ static void u132_hcd_endp_work_scheduler(struct work_struct *work) retval = edset_input(u132, ring, endp, urb, address, endp->toggle_bits, u132_hcd_bulk_input_recv); - if (retval == 0) { - } else + if (retval != 0) u132_hcd_giveback_urb(u132, endp, urb, retval); return; @@ -1485,8 +1491,7 @@ static void u132_hcd_endp_work_scheduler(struct work_struct *work) retval = edset_output(u132, ring, endp, urb, address, endp->toggle_bits, u132_hcd_bulk_output_sent); - if (retval == 0) { - } else + if (retval != 0) u132_hcd_giveback_urb(u132, endp, urb, retval); return; @@ -1608,8 +1613,9 @@ static int u132_run(struct u132 *u132) retval = u132_read_pcimem(u132, control, &u132->hc_control); if (retval) return retval; - dev_info(&u132->platform_dev->dev, "resetting from state '%s', control " - "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), + dev_info(&u132->platform_dev->dev, + "resetting from state '%s', control = %08X\n", + hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), u132->hc_control); switch (u132->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_OPER: @@ -1662,8 +1668,8 @@ extra: { return retval; if (0 != (status & OHCI_HCR)) { if (--reset_timeout == 0) { - dev_err(&u132->platform_dev->dev, "USB HC reset" - " timed out!\n"); + dev_err(&u132->platform_dev->dev, + "USB HC reset timed out!\n"); return -ENODEV; } else { msleep(5); @@ -1701,9 +1707,11 @@ extra: { if (!(u132->flags & OHCI_QUIRK_INITRESET)) { u132->flags |= OHCI_QUIRK_INITRESET; goto retry; - } else - dev_err(&u132->platform_dev->dev, "init err(%08x %04x)" - "\n", fminterval, periodicstart); + } else { + dev_err(&u132->platform_dev->dev, + "init err(%08x %04x)\n", + fminterval, periodicstart); + } } /* start controller operations */ u132->hc_control &= OHCI_CTRL_RWC; u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; @@ -1767,11 +1775,12 @@ static void u132_hcd_stop(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b" - "een removed %d\n", u132, hcd, u132->going); + dev_err(&u132->platform_dev->dev, + "u132 device %p(hcd=%p) has been removed %d\n", + u132, hcd, u132->going); } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); + dev_err(&u132->platform_dev->dev, + "device hcd=%p is being removed\n", hcd); } else { mutex_lock(&u132->sw_lock); msleep(100); @@ -1784,8 +1793,8 @@ static int u132_hcd_start(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); @@ -1803,8 +1812,8 @@ static int u132_hcd_start(struct usb_hcd *hcd) if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { u132->flags = OHCI_QUIRK_AMD756; } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { - dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar" - "ounds unavailable\n"); + dev_err(&u132->platform_dev->dev, + "WARNING: OPTi workarounds unavailable\n"); } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) u132->flags |= OHCI_QUIRK_ZFMICRO; retval = u132_run(u132); @@ -1825,8 +1834,8 @@ static int u132_hcd_reset(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); @@ -2181,8 +2190,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132, } } if (I == 0) { - dev_err(&u132->platform_dev->dev, "run out of d" - "evice space\n"); + dev_err(&u132->platform_dev->dev, + "run out of device space\n"); return -EINVAL; } urb->hcpriv = u132; @@ -2239,12 +2248,12 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, } } if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); + dev_err(&u132->platform_dev->dev, + "device is being removed urb=%p\n", urb); return -ESHUTDOWN; } else { u8 usb_addr = usb_pipedevice(urb->pipe); @@ -2289,8 +2298,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, usb_endp, address, mem_flags); } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - dev_err(&u132->platform_dev->dev, "the hardware does no" - "t support PIPE_ISOCHRONOUS\n"); + dev_err(&u132->platform_dev->dev, + "the hardware does not support PIPE_ISOCHRONOUS\n"); return -EINVAL; } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { u8 address = u132->addr[usb_addr].address; @@ -2323,10 +2332,11 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, } } else if (u132->num_endpoints == MAX_U132_ENDPS) { return -EINVAL; - } else + } else { return create_endpoint_and_queue_bulk(u132, udev, urb, usb_dev, usb_addr, usb_endp, address, mem_flags); + } } else { struct u132_endp *endp = urb->ep->hcpriv; u16 urb_size = 8; @@ -2343,8 +2353,9 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int w = sprintf(d, " %02X", *b++); d += w; l += w; - } else + } else { d += sprintf(d, " .."); + } } if (endp) { unsigned long irqs; @@ -2371,10 +2382,11 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, } } else if (u132->num_endpoints == MAX_U132_ENDPS) { return -EINVAL; - } else + } else { return create_endpoint_and_queue_control(u132, urb, usb_dev, usb_addr, usb_endp, mem_flags); + } } } } @@ -2394,9 +2406,9 @@ static int dequeue_from_overflow_chain(struct u132 *u132, return 0; } } - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring" - "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X" - "\n", urb, endp->endp_number, endp, endp->ring->number, + dev_err(&u132->platform_dev->dev, + "urb=%p not found in endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X\n", + urb, endp->endp_number, endp, endp->ring->number, endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', endp->usb_endp, endp->usb_addr, endp->queue_size, endp->queue_next, endp->queue_last); @@ -2416,9 +2428,9 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, return rc; } if (endp->queue_size == 0) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" - "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, - endp->endp_number, endp, endp->ring->number, + dev_err(&u132->platform_dev->dev, + "urb=%p not found in endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", + urb, endp->endp_number, endp, endp->ring->number, endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', endp->usb_endp, endp->usb_addr); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); @@ -2477,10 +2489,9 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in " - "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr" - "=%d size=%d next=%04X last=%04X\n", urb, - endp->endp_number, endp, endp->ring->number, + dev_err(&u132->platform_dev->dev, + "urb=%p not found in endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X\n", + urb, endp->endp_number, endp, endp->ring->number, endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', endp->usb_endp, endp->usb_addr, endp->queue_size, @@ -2503,8 +2514,8 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else { u8 usb_addr = usb_pipedevice(urb->pipe); @@ -2528,9 +2539,9 @@ static void u132_endpoint_disable(struct usb_hcd *hcd, { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p" - ") has been removed %d\n", u132, hcd, hep, - u132->going); + dev_err(&u132->platform_dev->dev, + "u132 device %p(hcd=%p hep=%p) has been removed %d\n", + u132, hcd, hep, u132->going); } else { struct u132_endp *endp = hep->hcpriv; if (endp) @@ -2542,8 +2553,8 @@ static int u132_get_frame(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); @@ -2590,8 +2601,9 @@ static int u132_roothub_descriptor(struct u132 *u132, if (u132->num_ports > 7) { desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; desc->u.hs.DeviceRemovable[2] = 0xff; - } else + } else { desc->u.hs.DeviceRemovable[1] = 0xff; + } return 0; } @@ -2614,8 +2626,8 @@ static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) roothub.portstatus[port], &rh_portstatus); *desc = cpu_to_le32(rh_portstatus); if (*(u16 *) (desc + 2)) { - dev_info(&u132->platform_dev->dev, "Port %d Status Chan" - "ge = %08X\n", port, *desc); + dev_info(&u132->platform_dev->dev, + "Port %d Status Change = %08X\n", port, *desc); } return ret_portstatus; } @@ -2660,9 +2672,10 @@ static int u132_roothub_portreset(struct u132 *u132, int port_index) if (retval) return retval; } - } else + } else { break; /* start the next reset, sleep till it's probably done */ + } retval = u132_write_pcimem(u132, roothub.portstatus[port_index], RH_PS_PRS); if (retval) @@ -2721,8 +2734,8 @@ static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, temp = RH_PS_POCI; if ((u132->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { - dev_err(&u132->platform_dev->dev, "TODO resume_" - "root_hub\n"); + dev_err(&u132->platform_dev->dev, + "TODO resume_root_hub\n"); } break; case USB_PORT_FEAT_C_SUSPEND: @@ -2754,19 +2767,20 @@ static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov" - "ed %d\n", hcd, u132->going); + dev_err(&u132->platform_dev->dev, + "device hcd=%p has been removed %d\n", + hcd, u132->going); return -ENODEV; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); + dev_err(&u132->platform_dev->dev, + "device hcd=%p is being removed\n", hcd); return -ESHUTDOWN; } else { int i, changed = 0, length = 1; if (u132->flags & OHCI_QUIRK_AMD756) { if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { - dev_err(&u132->platform_dev->dev, "bogus NDP, r" - "ereads as NDP=%d\n", + dev_err(&u132->platform_dev->dev, + "bogus NDP, rereads as NDP=%d\n", u132->hc_roothub_a & RH_A_NDP); goto done; } @@ -2806,8 +2820,8 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); @@ -2888,14 +2902,15 @@ static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); return -ESHUTDOWN; - } else + } else { return 0; + } } @@ -2904,28 +2919,30 @@ static int u132_bus_suspend(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); return -ESHUTDOWN; - } else + } else { return 0; + } } static int u132_bus_resume(struct usb_hcd *hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); return -ESHUTDOWN; - } else + } else { return 0; + } } #else @@ -2963,14 +2980,15 @@ static int u132_remove(struct platform_device *pdev) if (hcd) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going++ > 1) { - dev_err(&u132->platform_dev->dev, "already being remove" - "d\n"); + dev_err(&u132->platform_dev->dev, + "already being removed\n"); return -ENODEV; } else { int rings = MAX_U132_RINGS; int endps = MAX_U132_ENDPS; - dev_err(&u132->platform_dev->dev, "removing device u132" - ".%d\n", u132->sequence_num); + dev_err(&u132->platform_dev->dev, + "removing device u132.%d\n", + u132->sequence_num); msleep(100); mutex_lock(&u132->sw_lock); u132_monitor_cancel_work(u132); @@ -2991,8 +3009,9 @@ static int u132_remove(struct platform_device *pdev) u132_u132_put_kref(u132); return 0; } - } else + } else { return 0; + } } static void u132_initialise(struct u132 *u132, struct platform_device *pdev) @@ -3075,8 +3094,7 @@ static int u132_probe(struct platform_device *pdev) hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { - printk(KERN_ERR "failed to create the usb hcd struct for U132\n" - ); + printk(KERN_ERR "failed to create the usb hcd struct for U132\n"); ftdi_elan_gone_away(pdev); return -ENOMEM; } else { @@ -3114,8 +3132,8 @@ static int u132_suspend(struct platform_device *pdev, pm_message_t state) struct usb_hcd *hcd = platform_get_drvdata(pdev); struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); @@ -3144,8 +3162,8 @@ static int u132_resume(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); + dev_err(&u132->platform_dev->dev, + "device has been removed %d\n", u132->going); return -ENODEV; } else if (u132->going > 0) { dev_err(&u132->platform_dev->dev, "device is being removed\n"); -- cgit v1.2.3 From ee2f38b3c6f2c68a0e6f5945aae91d607bc9a7c6 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Mar 2023 11:19:11 +0100 Subject: usb: host: u132-hcd: Drop if with an always true condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A platform device's .remove() callback is only ever called after .probe() successfully completed. After such a successful call, platform_get_drvdata() doesn't return NULL. Simplify accordingly. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230321101911.342538-3-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 66 +++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index f5433993c76e..45244c791bcb 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2977,39 +2977,36 @@ static const struct hc_driver u132_hc_driver = { static int u132_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - if (hcd) { - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going++ > 1) { - dev_err(&u132->platform_dev->dev, - "already being removed\n"); - return -ENODEV; - } else { - int rings = MAX_U132_RINGS; - int endps = MAX_U132_ENDPS; - dev_err(&u132->platform_dev->dev, - "removing device u132.%d\n", - u132->sequence_num); - msleep(100); - mutex_lock(&u132->sw_lock); - u132_monitor_cancel_work(u132); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - u132_ring_cancel_work(u132, ring); - } - while (endps-- > 0) { - struct u132_endp *endp = u132->endp[endps]; - if (endp) - u132_endp_cancel_work(u132, endp); - } - u132->going += 1; - printk(KERN_INFO "removing device u132.%d\n", - u132->sequence_num); - mutex_unlock(&u132->sw_lock); - usb_remove_hcd(hcd); - u132_u132_put_kref(u132); - return 0; - } + struct u132 *u132 = hcd_to_u132(hcd); + + if (u132->going++ > 1) { + dev_err(&u132->platform_dev->dev, + "already being removed\n"); + return -ENODEV; } else { + int rings = MAX_U132_RINGS; + int endps = MAX_U132_ENDPS; + dev_err(&u132->platform_dev->dev, + "removing device u132.%d\n", + u132->sequence_num); + msleep(100); + mutex_lock(&u132->sw_lock); + u132_monitor_cancel_work(u132); + while (rings-- > 0) { + struct u132_ring *ring = &u132->ring[rings]; + u132_ring_cancel_work(u132, ring); + } + while (endps-- > 0) { + struct u132_endp *endp = u132->endp[endps]; + if (endp) + u132_endp_cancel_work(u132, endp); + } + u132->going += 1; + printk(KERN_INFO "removing device u132.%d\n", + u132->sequence_num); + mutex_unlock(&u132->sw_lock); + usb_remove_hcd(hcd); + u132_u132_put_kref(u132); return 0; } } @@ -3092,6 +3089,11 @@ static int u132_probe(struct platform_device *pdev) if (retval) return retval; + /* + * Note that after a successful call of usb_create_hcd(), + * dev_set_drvdata() was called such that platform_get_drvdata(pdev) + * returns hcd later on. + */ hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { printk(KERN_ERR "failed to create the usb hcd struct for U132\n"); -- cgit v1.2.3 From 653b131a897e67c65a0fb2ddbfba29b6daec76e2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Mar 2023 18:39:02 -0500 Subject: dt-bindings: usb: Drop unneeded quotes Cleanup bindings dropping unneeded quotes. Once all these are fixed, checking for this can be enabled in yamllint. Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230320233904.2920197-1-robh@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml | 4 ++-- Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml | 2 +- Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml | 4 ++-- Documentation/devicetree/bindings/usb/generic-ehci.yaml | 2 +- Documentation/devicetree/bindings/usb/generic-xhci.yaml | 2 +- Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml | 4 ++-- Documentation/devicetree/bindings/usb/maxim,max33359.yaml | 4 ++-- Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml | 4 ++-- Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml | 4 ++-- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 2 +- Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml | 8 ++++---- Documentation/devicetree/bindings/usb/mediatek,musb.yaml | 4 ++-- Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml | 4 ++-- Documentation/devicetree/bindings/usb/realtek,rts5411.yaml | 2 +- Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml | 4 ++-- Documentation/devicetree/bindings/usb/richtek,rt1719.yaml | 4 ++-- Documentation/devicetree/bindings/usb/st,stusb160x.yaml | 4 ++-- Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml | 4 ++-- Documentation/devicetree/bindings/usb/ti,tps6598x.yaml | 4 ++-- Documentation/devicetree/bindings/usb/usb-xhci.yaml | 2 +- 20 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml index f38a2be07eda..da757c1155d4 100644 --- a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml +++ b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson G12A DWC3 USB SoC Controller Glue diff --git a/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml index ad075407d85e..1536cbec6334 100644 --- a/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Broadcom STB USB EHCI Controller allOf: - - $ref: "usb-hcd.yaml" + - $ref: usb-hcd.yaml maintainers: - Al Cooper diff --git a/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml b/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml index 51120fe90322..f6e7a5c1ff0b 100644 --- a/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml +++ b/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/fcs,fsa4480.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: ON Semiconductor Analog Audio Switch diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml index 050cfd5acdaa..9445764bd8de 100644 --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml @@ -10,7 +10,7 @@ maintainers: - Greg Kroah-Hartman allOf: - - $ref: "usb-hcd.yaml" + - $ref: usb-hcd.yaml - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/usb/generic-xhci.yaml b/Documentation/devicetree/bindings/usb/generic-xhci.yaml index db841589fc33..594ebb3ee432 100644 --- a/Documentation/devicetree/bindings/usb/generic-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-xhci.yaml @@ -10,7 +10,7 @@ maintainers: - Mathias Nyman allOf: - - $ref: "usb-xhci.yaml#" + - $ref: usb-xhci.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml b/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml index bf4b1d016e1f..f196beb826d8 100644 --- a/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml +++ b/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: GPIO-based SBU mux diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml index 8e513a6af378..beccbd1d4d0e 100644 --- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml +++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/maxim,max33359.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/maxim,max33359.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim TCPCI Type-C PD controller diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml index c72257c19220..4f6018aadc8c 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Mediatek MT6360 Type-C Port Switch and Power Delivery controller diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml index 72f56cc88457..747d0f16d9b6 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index c119caa9ad16..556bedb96165 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -11,7 +11,7 @@ maintainers: - Chunfeng Yun allOf: - - $ref: "usb-xhci.yaml" + - $ref: usb-xhci.yaml description: | There are two scenarios: diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml index d2655173e108..5b908c457e3d 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml @@ -11,7 +11,7 @@ maintainers: - Chunfeng Yun allOf: - - $ref: "usb-drd.yaml" + - $ref: usb-drd.yaml description: | The DRD controller has a glue layer IPPC (IP Port Control), and its host is @@ -204,9 +204,9 @@ patternProperties: example if the host mode is enabled. dependencies: - connector: [ 'usb-role-switch' ] - port: [ 'usb-role-switch' ] - role-switch-default-mode: [ 'usb-role-switch' ] + connector: [ usb-role-switch ] + port: [ usb-role-switch ] + role-switch-default-mode: [ usb-role-switch ] wakeup-source: [ 'mediatek,syscon-wakeup' ] required: diff --git a/Documentation/devicetree/bindings/usb/mediatek,musb.yaml b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml index f16ab30a95d2..a39d38db7714 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,musb.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml @@ -68,8 +68,8 @@ properties: type: object dependencies: - usb-role-switch: [ 'connector' ] - connector: [ 'usb-role-switch' ] + usb-role-switch: [ connector ] + connector: [ usb-role-switch ] required: - compatible diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml index e638f77658fc..e2270ce0c56b 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: NVIDIA Tegra XUSB device mode controller (XUDC) diff --git a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml index 623d04a88a81..9309f003cd07 100644 --- a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml +++ b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml @@ -26,7 +26,7 @@ properties: phandle to the regulator that provides power to the hub. peer-hub: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle to the peer hub on the controller. diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml index 1999f614c89b..3bec824ec446 100644 --- a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml +++ b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/richtek,rt1711h.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Richtek RT1711H Type-C Port Switch and Power Delivery controller diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml index e3e87e4d3292..43562041b646 100644 --- a/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml +++ b/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/richtek,rt1719.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/richtek,rt1719.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Richtek RT1719 sink-only Type-C PD controller diff --git a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml index ffcd9897ea38..edfebb813f77 100644 --- a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml +++ b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/st,stusb160x.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/st,stusb160x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: STMicroelectronics STUSB160x Type-C controller diff --git a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml index f81ba3e90297..fd36dd02fe74 100644 --- a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml +++ b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/ti,j721e-usb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TI wrapper module for the Cadence USBSS-DRD controller diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml index 348a715d61f4..7d9c5e786e42 100644 --- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml +++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/ti,tps6598x.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/ti,tps6598x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.yaml b/Documentation/devicetree/bindings/usb/usb-xhci.yaml index f2139a9f35fb..180a261c3e8f 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/usb-xhci.yaml @@ -10,7 +10,7 @@ maintainers: - Mathias Nyman allOf: - - $ref: "usb-hcd.yaml#" + - $ref: usb-hcd.yaml# properties: usb2-lpm-disable: -- cgit v1.2.3 From 213acadd21a080fc8cda8eebe6d14cc2d4ad1332 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Mar 2023 11:36:38 +0100 Subject: usb: host: u132-hcd: Delete driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver got its last actual change in 2006 and is probably unused as nowbody should use a cardbus to USB adapter any more. If it were still used, the driver was in urgent need for maintainer love. (Explicit kref handling, underdocumented locking, .remove() can return errors ...) Also the link in the (now removed) help text doesn't look actively maintained. According to archive.org it forwarded to http://www.copenhagen-hotel.net/ already back in 2018. So don't waste more time on this driver and just delete it. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230321103638.343886-1-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- arch/mips/configs/mtx1_defconfig | 1 - arch/powerpc/configs/ppc6xx_defconfig | 1 - drivers/usb/Makefile | 1 - drivers/usb/host/Kconfig | 27 - drivers/usb/host/Makefile | 1 - drivers/usb/host/u132-hcd.c | 3239 --------------------------------- drivers/usb/misc/Kconfig | 2 - 7 files changed, 3272 deletions(-) delete mode 100644 drivers/usb/host/u132-hcd.c diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 89a1511d2ee4..7b6a2a9daa10 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -497,7 +497,6 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_HCD_PLATFORM=m CONFIG_USB_UHCI_HCD=m -CONFIG_USB_U132_HCD=m CONFIG_USB_SL811_HCD=m CONFIG_USB_SL811_CS=m CONFIG_USB_ACM=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 110258277959..fd5cc93c4a99 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -845,7 +845,6 @@ CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_OHCI_HCD_PPC_OF_LE=y CONFIG_USB_UHCI_HCD=m -CONFIG_USB_U132_HCD=m CONFIG_USB_SL811_HCD=m CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a81e6ef293af..3a9a0dd4be70 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_USB_FHCI_HCD) += host/ obj-$(CONFIG_USB_XHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_ISP1362_HCD) += host/ -obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_FSL_USB2) += host/ obj-$(CONFIG_USB_FOTG210_HCD) += host/ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index eacb603ad1b2..c170672f847e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -622,33 +622,6 @@ config FHCI_DEBUG Say "y" to see some FHCI debug information and statistics through debugfs. -config USB_U132_HCD - tristate "Elan U132 Adapter Host Controller" - depends on USB_FTDI_ELAN - help - The U132 adapter is a USB to CardBus adapter specifically designed - for PC cards that contain an OHCI host controller. Typical PC cards - are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 - adapter will *NOT* work with PC cards that do not contain an OHCI - controller. - - For those PC cards that contain multiple OHCI controllers only the - first one is used. - - The driver consists of two modules, the "ftdi-elan" module is a - USB client driver that interfaces to the FTDI chip within ELAN's - USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host - controller driver that talks to the OHCI controller within the - CardBus cards that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - It is safe to say M here. - - See also - config USB_SL811_HCD tristate "SL811HS HCD support" depends on HAS_IOMEM diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 5a13712f367d..be4e5245c52f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -76,7 +76,6 @@ obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o -obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c deleted file mode 100644 index 45244c791bcb..000000000000 --- a/drivers/usb/host/u132-hcd.c +++ /dev/null @@ -1,3239 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* -* Host Controller Driver for the Elan Digital Systems U132 adapter -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB host drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - /* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name - */ - -#include "ohci.h" -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); -MODULE_DESCRIPTION("U132 USB Host Controller Driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -INT_MODULE_PARM(testing, 0); -/* Some boards misreport power switching/overcurrent*/ -static bool distrust_firmware = true; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, - "true to distrust firmware power/overcurrentt setup"); -static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); -/* -* u132_module_lock exists to protect access to global variables -* -*/ -static DEFINE_MUTEX(u132_module_lock); -static int u132_exiting; -static int u132_instances; -/* -* end of the global variables protected by u132_module_lock -*/ -static struct workqueue_struct *workqueue; -#define MAX_U132_PORTS 7 -#define MAX_U132_ADDRS 128 -#define MAX_U132_UDEVS 4 -#define MAX_U132_ENDPS 100 -#define MAX_U132_RINGS 4 -static const char *cc_to_text[16] = { - "No Error ", - "CRC Error ", - "Bit Stuff ", - "Data Togg ", - "Stall ", - "DevNotResp ", - "PIDCheck ", - "UnExpPID ", - "DataOver ", - "DataUnder ", - "(for hw) ", - "(for hw) ", - "BufferOver ", - "BuffUnder ", - "(for HCD) ", - "(for HCD) " -}; -struct u132_port { - struct u132 *u132; - int reset; - int enable; - int power; - int Status; -}; -struct u132_addr { - u8 address; -}; -struct u132_udev { - struct kref kref; - struct usb_device *usb_device; - u8 enumeration; - u8 udev_number; - u8 usb_addr; - u8 portnumber; - u8 endp_number_in[16]; - u8 endp_number_out[16]; -}; -#define ENDP_QUEUE_SHIFT 3 -#define ENDP_QUEUE_SIZE (1<platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -#define u132_write_pcimem(u132, member, data) \ - usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -static inline struct u132 *udev_to_u132(struct u132_udev *udev) -{ - u8 udev_number = udev->udev_number; - return container_of(udev, struct u132, udev[udev_number]); -} - -static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd) -{ - return (struct u132 *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *u132_to_hcd(struct u132 *u132) -{ - return container_of((void *)u132, struct usb_hcd, hcd_priv); -} - -static inline void u132_disable(struct u132 *u132) -{ - u132_to_hcd(u132)->state = HC_STATE_HALT; -} - - -#define kref_to_u132(d) container_of(d, struct u132, kref) -#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref) -#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref) -#include "../misc/usb_u132.h" -static const char hcd_name[] = "u132_hcd"; -#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \ - USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \ - USB_PORT_STAT_C_RESET) << 16) -static void u132_hcd_delete(struct kref *kref) -{ - struct u132 *u132 = kref_to_u132(kref); - struct platform_device *pdev = u132->platform_dev; - struct usb_hcd *hcd = u132_to_hcd(u132); - u132->going += 1; - mutex_lock(&u132_module_lock); - u132_instances -= 1; - mutex_unlock(&u132_module_lock); - dev_warn(&u132->platform_dev->dev, - "FREEING the hcd=%p and thus the u132=%p going=%d pdev=%p\n", - hcd, u132, u132->going, pdev); - usb_put_hcd(hcd); -} - -static inline void u132_u132_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static inline void u132_u132_init_kref(struct u132 *u132) -{ - kref_init(&u132->kref); -} - -static void u132_udev_delete(struct kref *kref) -{ - struct u132_udev *udev = kref_to_u132_udev(kref); - udev->udev_number = 0; - udev->usb_device = NULL; - udev->usb_addr = 0; - udev->enumeration = 0; -} - -static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_put(&udev->kref, u132_udev_delete); -} - -static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_get(&udev->kref); -} - -static inline void u132_udev_init_kref(struct u132 *u132, - struct u132_udev *udev) -{ - kref_init(&udev->kref); -} - -static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - if (delta > 0) { - if (queue_delayed_work(workqueue, &ring->scheduler, delta)) - return; - } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) - return; - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - kref_get(&u132->kref); - u132_ring_requeue_work(u132, ring, delta); -} - -static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) -{ - if (cancel_delayed_work(&ring->scheduler)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_endp_delete(struct kref *kref) -{ - struct u132_endp *endp = kref_to_u132_endp(kref); - struct u132 *u132 = endp->u132; - u8 usb_addr = endp->usb_addr; - u8 usb_endp = endp->usb_endp; - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - u8 endp_number = endp->endp_number; - struct usb_host_endpoint *hep = endp->hep; - struct u132_ring *ring = endp->ring; - struct list_head *head = &endp->endp_ring; - ring->length -= 1; - if (endp == ring->curr_endp) { - if (list_empty(head)) { - ring->curr_endp = NULL; - list_del(head); - } else { - struct u132_endp *next_endp = list_entry(head->next, - struct u132_endp, endp_ring); - ring->curr_endp = next_endp; - list_del(head); - } - } else { - list_del(head); - } - if (endp->input) { - udev->endp_number_in[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - if (endp->output) { - udev->endp_number_out[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - u132->endp[endp_number - 1] = NULL; - hep->hcpriv = NULL; - kfree(endp); - u132_u132_put_kref(u132); -} - -static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_get(&endp->kref); -} - -static inline void u132_endp_init_kref(struct u132 *u132, - struct u132_endp *endp) -{ - kref_init(&endp->kref); - kref_get(&u132->kref); -} - -static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, - unsigned int delta) -{ - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); -} - -static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) -{ - if (cancel_delayed_work(&endp->scheduler)) - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_monitor_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) -{ - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_get(&u132->kref); -} - -static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) -{ - if (!queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_cancel_work(struct u132 *u132) -{ - if (cancel_delayed_work(&u132->monitor)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static int read_roothub_info(struct u132 *u132) -{ - u32 revision; - int retval; - struct device *dev = &u132->platform_dev->dev; - - retval = u132_read_pcimem(u132, revision, &revision); - if (retval) { - dev_err(dev, "error %d accessing device control\n", retval); - return retval; - } else if ((revision & 0xFF) == 0x10) { - } else if ((revision & 0xFF) == 0x11) { - } else { - dev_err(dev, "device revision is not valid %08X\n", revision); - return -ENODEV; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) { - dev_err(dev, "error %d accessing device control\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.status, - &u132->hc_roothub_status); - if (retval) { - dev_err(dev, "error %d accessing device reg roothub.status\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); - if (retval) { - dev_err(dev, "error %d accessing device reg roothub.a\n", retval); - return retval; - } - { - int I = u132->num_ports; - int i = 0; - while (I-- > 0) { - retval = u132_read_pcimem(u132, roothub.portstatus[i], - &u132->hc_roothub_portstatus[i]); - if (retval) { - dev_err(dev, "error %d accessing device roothub.portstatus[%d]\n", - retval, i); - return retval; - } else { - i += 1; - } - } - } - return 0; -} - -static void u132_hcd_monitor_work(struct work_struct *work) -{ - struct u132 *u132 = container_of(work, struct u132, monitor.work); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n", - u132->going); - u132_monitor_put_kref(u132); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - u132_monitor_put_kref(u132); - return; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = read_roothub_info(u132); - if (retval) { - struct usb_hcd *hcd = u132_to_hcd(u132); - u132_disable(u132); - u132->going = 1; - mutex_unlock(&u132->sw_lock); - usb_hc_died(hcd); - ftdi_elan_gone_away(u132->platform_dev); - u132_monitor_put_kref(u132); - return; - } else { - u132_monitor_requeue_work(u132, 500); - mutex_unlock(&u132->sw_lock); - return; - } - } -} - -static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - struct u132_ring *ring; - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - ring->in_use = 0; - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb, status); -} - -static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - u132_endp_put_kref(u132, endp); -} - -static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - usb_hcd_giveback_urb(hcd, urb, status); -} - -static inline int edset_input(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_setup(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_single(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_output(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - - -/* -* must not LOCK sw_lock -* -*/ -static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n", - u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - if (urb->actual_length > 0) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, - retval); - } else { - ring->in_use = 0; - endp->active = 0; - endp->jiffies = jiffies + - msecs_to_jiffies(urb->interval); - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - } - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 1 & toggle_bits); - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p giving back INTERRUPT %s\n", - urb, cc_to_text[condition_code]); - } - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n", - u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - urb->actual_length += len; - endp->toggle_bits = toggle_bits; - if (urb->transfer_buffer_length > urb->actual_length) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_bulk_output_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - int retval; - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_DATAUNDERRUN) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - dev_warn(&u132->platform_dev->dev, - "urb=%p(SHORT NOT OK) giving back BULK IN %s\n", - urb, cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - dev_err(&u132->platform_dev->dev, - "urb=%p giving back BULK IN code=%d %s\n", - urb, condition_code, cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - if ((condition_code == TD_CC_NOERROR) || ((condition_code == - TD_DATAUNDERRUN) && ((urb->transfer_flags & - URB_SHORT_NOT_OK) == 0))) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0x3, - u132_hcd_configure_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_STALL) { - mutex_unlock(&u132->scheduler_lock); - dev_warn(&u132->platform_dev->dev, - "giving back SETUP INPUT STALL urb %p\n", urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - dev_err(&u132->platform_dev->dev, - "giving back SETUP INPUT %s urb %p\n", - cc_to_text[condition_code], urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n", - u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n", - u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - if (usb_pipein(urb->pipe)) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - u132->addr[0].address = 0; - endp->usb_addr = udev->usb_addr; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, 0, endp->usb_endp, 0, - u132_hcd_enumeration_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0x3, - u132_hcd_initial_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0, - u132_hcd_initial_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, - "CALLBACK called urb=%p unlinked=%d\n", - urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -/* -* this work function is only executed from the work queue -* -*/ -static void u132_hcd_ring_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring = - container_of(work, struct u132_ring, scheduler.work); - struct u132 *u132 = ring->u132; - mutex_lock(&u132->scheduler_lock); - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else if (ring->curr_endp) { - struct u132_endp *endp, *last_endp = ring->curr_endp; - unsigned long wakeup = 0; - list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) { - if (endp->queue_next == endp->queue_last) { - } else if ((endp->delayed == 0) - || time_after_eq(jiffies, endp->jiffies)) { - ring->curr_endp = endp; - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - } - if (last_endp->queue_next == last_endp->queue_last) { - } else if ((last_endp->delayed == 0) || time_after_eq(jiffies, - last_endp->jiffies)) { - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = last_endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - if (wakeup > 0) { - u132_ring_requeue_work(u132, ring, wakeup); - mutex_unlock(&u132->scheduler_lock); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } -} - -static void u132_hcd_endp_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring; - struct u132_endp *endp = - container_of(work, struct u132_endp, scheduler.work); - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - if (endp->edset_flush) { - endp->edset_flush = 0; - if (endp->dequeueing) - usb_ftdi_elan_edset_flush(u132->platform_dev, - ring->number, endp); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->active) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->queue_next == endp->queue_last) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->pipetype == PIPE_INTERRUPT) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else if (endp->pipetype == PIPE_CONTROL) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (address == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_initial_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (endp->usb_addr == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, 0, 0x2, - u132_hcd_enumeration_address_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - address = u132->addr[endp->usb_addr].address; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_configure_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - if (endp->input) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_input(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } else { /* output pipe */ - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_output_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } - } -} -#ifdef CONFIG_PM - -static void port_power(struct u132 *u132, int pn, int is_on) -{ - u132->port[pn].power = is_on; -} - -#endif - -static void u132_power(struct u132 *u132, int is_on) -{ - struct usb_hcd *hcd = u132_to_hcd(u132) - ; /* hub is inactive unless the port is powered */ - if (is_on) { - if (u132->power) - return; - u132->power = 1; - } else { - u132->power = 0; - hcd->state = HC_STATE_HALT; - } -} - -static int u132_periodic_reinit(struct u132 *u132) -{ - int retval; - u32 fi = u132->hc_fminterval & 0x03fff; - u32 fit; - u32 fminterval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - fit = fminterval & FIT; - retval = u132_write_pcimem(u132, fminterval, - (fit ^ FIT) | u132->hc_fminterval); - if (retval) - return retval; - return u132_write_pcimem(u132, periodicstart, - ((9 * fi) / 10) & 0x3fff); -} - -static char *hcfs2string(int state) -{ - switch (state) { - case OHCI_USB_RESET: - return "reset"; - case OHCI_USB_RESUME: - return "resume"; - case OHCI_USB_OPER: - return "operational"; - case OHCI_USB_SUSPEND: - return "suspend"; - } - return "?"; -} - -static int u132_init(struct u132 *u132) -{ - int retval; - u32 control; - u132_disable(u132); - u132->next_statechange = jiffies; - retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - if (u132->num_ports == 0) { - u32 rh_a = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - u132->num_ports = rh_a & RH_A_NDP; - retval = read_roothub_info(u132); - if (retval) - return retval; - } - if (u132->num_ports > MAX_U132_PORTS) - return -EINVAL; - - return 0; -} - - -/* Start an OHCI controller, set the BUS operational -* resets USB and controller -* enable interrupts -*/ -static int u132_run(struct u132 *u132) -{ - int retval; - u32 control; - u32 status; - u32 fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int first = u132->hc_fminterval == 0; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - u132_disable(u132); - if (first) { - u32 temp; - retval = u132_read_pcimem(u132, fminterval, &temp); - if (retval) - return retval; - u132->hc_fminterval = temp & 0x3fff; - u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) - return retval; - dev_info(&u132->platform_dev->dev, - "resetting from state '%s', control = %08X\n", - hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), - u132->hc_control); - switch (u132->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { - int temp; /* power down each port */ - for (temp = 0; temp < u132->num_ports; temp++) { - retval = u132_write_pcimem(u132, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; -retry: - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra: { - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&u132->platform_dev->dev, - "USB HC reset timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (u132->flags & OHCI_QUIRK_INITRESET) { - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, hcca, 0x00000000); - if (retval) - return retval; - retval = u132_periodic_reinit(u132); - if (retval) - return retval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - retval = u132_read_pcimem(u132, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(u132->flags & OHCI_QUIRK_INITRESET)) { - u132->flags |= OHCI_QUIRK_INITRESET; - goto retry; - } else { - dev_err(&u132->platform_dev->dev, - "init err(%08x %04x)\n", - fminterval, periodicstart); - } - } /* start controller operations */ - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrstatus, mask); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (u132->flags & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = u132_write_pcimem(u132, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - return 0; -} - -static void u132_hcd_stop(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "u132 device %p(hcd=%p) has been removed %d\n", - u132, hcd, u132->going); - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device hcd=%p is being removed\n", hcd); - } else { - mutex_lock(&u132->sw_lock); - msleep(100); - u132_power(u132, 0); - mutex_unlock(&u132->sw_lock); - } -} - -static int u132_hcd_start(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else if (hcd->self.controller) { - int retval; - struct platform_device *pdev = - to_platform_device(hcd->self.controller); - u16 vendor = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->vendor; - u16 device = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->device; - mutex_lock(&u132->sw_lock); - msleep(10); - if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { - u132->flags = OHCI_QUIRK_AMD756; - } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { - dev_err(&u132->platform_dev->dev, - "WARNING: OPTi workarounds unavailable\n"); - } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) - u132->flags |= OHCI_QUIRK_ZFMICRO; - retval = u132_run(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - msleep(100); - mutex_unlock(&u132->sw_lock); - return retval; - } else { - dev_err(&u132->platform_dev->dev, "platform_device missing\n"); - return -ENODEV; - } -} - -static int u132_hcd_reset(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = u132_init(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval)); - return 0; -} - -static int queue_int_on_old_endpoint(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - int ring_number; - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - ring_number = 3; - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - ring_number = 2; - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - ring = endp->ring = &u132->ring[ring_number - 1]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - urb->hcpriv = u132; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; -} - -static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_control(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - u132_endp_init_kref(u132, endp); - u132_endp_get_kref(u132, endp); - if (usb_addr == 0) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_init_kref(u132, udev); - u132_udev_get_kref(u132, udev); - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_get_kref(u132, udev); - udev->enumeration = 2; - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } -} - -static int queue_control_on_old_endpoint(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp) -{ - if (usb_addr == 0) { - if (usb_pipein(urb->pipe)) { - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } else { /* usb_pipeout(urb->pipe) */ - struct u132_addr *addr = &u132->addr[usb_dev->devnum]; - int I = MAX_U132_UDEVS; - int i = 0; - while (--I > 0) { - struct u132_udev *udev = &u132->udev[++i]; - if (udev->usb_device) { - continue; - } else { - udev->enumeration = 1; - u132->addr[0].address = i; - endp->udev_number = i; - udev->udev_number = i; - udev->usb_addr = usb_dev->devnum; - u132_udev_init_kref(u132, udev); - udev->endp_number_in[usb_endp] = - endp->endp_number; - u132_udev_get_kref(u132, udev); - udev->endp_number_out[usb_endp] = - endp->endp_number; - udev->usb_device = usb_dev; - ((u8 *) (urb->setup_packet))[2] = - addr->address = i; - u132_udev_get_kref(u132, udev); - break; - } - } - if (I == 0) { - dev_err(&u132->platform_dev->dev, - "run out of device space\n"); - return -EINVAL; - } - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - urb->hcpriv = u132; - if (udev->enumeration != 2) - udev->enumeration = 2; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } -} - -static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (irqs_disabled()) { - if (gfpflags_allow_blocking(mem_flags)) { - printk(KERN_ERR "invalid context for function that might sleep\n"); - return -EINVAL; - } - } - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device is being removed urb=%p\n", urb); - return -ESHUTDOWN; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - struct usb_device *usb_dev = urb->dev; - if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_int_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, - msecs_to_jiffies(urb->interval)) - ; - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else { /*(endp == NULL) */ - return create_endpoint_and_queue_int(u132, udev, - urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } - } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - dev_err(&u132->platform_dev->dev, - "the hardware does not support PIPE_ISOCHRONOUS\n"); - return -EINVAL; - } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_bulk_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else { - return create_endpoint_and_queue_bulk(u132, - udev, urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } - } else { - struct u132_endp *endp = urb->ep->hcpriv; - u16 urb_size = 8; - u8 *b = urb->setup_packet; - int i = 0; - char data[30 * 3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int l = 0; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - l += w; - } else { - d += sprintf(d, " .."); - } - } - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_control_on_old_endpoint( - u132, urb, usb_dev, - endp, usb_addr, - usb_endp); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else { - return create_endpoint_and_queue_control(u132, - urb, usb_dev, usb_addr, usb_endp, - mem_flags); - } - } - } -} - -static int dequeue_from_overflow_chain(struct u132 *u132, - struct u132_endp *endp, struct urb *urb) -{ - struct u132_urbq *urbq; - - list_for_each_entry(urbq, &endp->urb_more, urb_more) { - if (urbq->urb == urb) { - struct usb_hcd *hcd = u132_to_hcd(u132); - list_del(&urbq->urb_more); - endp->queue_size -= 1; - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, 0); - return 0; - } - } - dev_err(&u132->platform_dev->dev, - "urb=%p not found in endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X\n", - urb, endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - return -EINVAL; -} - -static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - int rc; - - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return rc; - } - if (endp->queue_size == 0) { - dev_err(&u132->platform_dev->dev, - "urb=%p not found in endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", - urb, endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } - if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) { - if (endp->active) { - endp->dequeueing = 1; - endp->edset_flush = 1; - u132_endp_queue_work(u132, endp, 0); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return 0; - } else { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, status); - return 0; - } - } else { - u16 queue_list = 0; - u16 queue_size = endp->queue_size; - u16 queue_scan = endp->queue_next; - struct urb **urb_slot = NULL; - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - if (urb == endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]) { - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - break; - } - } - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - *urb_slot = endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]; - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - } - if (urb_slot) { - struct usb_hcd *hcd = u132_to_hcd(u132); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_size -= 1; - if (list_empty(&endp->urb_more)) { - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, - struct u132_urbq, urb_more); - list_del(next); - *urb_slot = urbq->urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - kfree(urbq); - } - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, status); - return 0; - } else if (list_empty(&endp->urb_more)) { - dev_err(&u132->platform_dev->dev, - "urb=%p not found in endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X\n", - urb, endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', - endp->output ? 'O' : ' ', endp->usb_endp, - endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } else { - int retval; - - usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); - retval = dequeue_from_overflow_chain(u132, endp, - urb); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return retval; - } - } -} - -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - if (usb_pipein(urb->pipe)) { - u8 endp_number = udev->endp_number_in[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } else { - u8 endp_number = udev->endp_number_out[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } - } -} - -static void u132_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, - "u132 device %p(hcd=%p hep=%p) has been removed %d\n", - u132, hcd, hep, u132->going); - } else { - struct u132_endp *endp = hep->hcpriv; - if (endp) - u132_endp_put_kref(u132, endp); - } -} - -static int u132_get_frame(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - mdelay(100); - return 0; - } -} - -static int u132_roothub_descriptor(struct u132 *u132, - struct usb_hub_descriptor *desc) -{ - int retval; - u16 temp; - u32 rh_a = -1; - u32 rh_b = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - desc->bDescriptorType = USB_DT_HUB; - desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = u132->num_ports; - temp = 1 + (u132->num_ports / 8); - desc->bDescLength = 7 + 2 * temp; - temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM; - if (rh_a & RH_A_NPS) - temp |= HUB_CHAR_NO_LPSM; - if (rh_a & RH_A_PSM) - temp |= HUB_CHAR_INDV_PORT_LPSM; - if (rh_a & RH_A_NOCP) - temp |= HUB_CHAR_NO_OCPM; - else if (rh_a & RH_A_OCPM) - temp |= HUB_CHAR_INDV_PORT_OCPM; - desc->wHubCharacteristics = cpu_to_le16(temp); - retval = u132_read_pcimem(u132, roothub.b, &rh_b); - if (retval) - return retval; - memset(desc->u.hs.DeviceRemovable, 0xff, - sizeof(desc->u.hs.DeviceRemovable)); - desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR; - if (u132->num_ports > 7) { - desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; - desc->u.hs.DeviceRemovable[2] = 0xff; - } else { - desc->u.hs.DeviceRemovable[1] = 0xff; - } - return 0; -} - -static int u132_roothub_status(struct u132 *u132, __le32 *desc) -{ - u32 rh_status = -1; - int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status); - *desc = cpu_to_le32(rh_status); - return ret_status; -} - -static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port = wIndex - 1; - u32 rh_portstatus = -1; - int ret_portstatus = u132_read_pcimem(u132, - roothub.portstatus[port], &rh_portstatus); - *desc = cpu_to_le32(rh_portstatus); - if (*(u16 *) (desc + 2)) { - dev_info(&u132->platform_dev->dev, - "Port %d Status Change = %08X\n", port, *desc); - } - return ret_portstatus; - } -} - - -/* this timer value might be vendor-specific ... */ -#define PORT_RESET_HW_MSEC 10 -#define PORT_RESET_MSEC 10 -/* wrap-aware logic morphed from */ -#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) -static int u132_roothub_portreset(struct u132 *u132, int port_index) -{ - int retval; - u32 fmnumber; - u16 now; - u16 reset_done; - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - reset_done = now + PORT_RESET_MSEC; - do { - u32 portstat; - do { - retval = u132_read_pcimem(u132, - roothub.portstatus[port_index], &portstat); - if (retval) - return retval; - if (RH_PS_PRS & portstat) - continue; - else - break; - } while (tick_before(now, reset_done)); - if (RH_PS_PRS & portstat) - return -ENODEV; - if (RH_PS_CCS & portstat) { - if (RH_PS_PRSC & portstat) { - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], - RH_PS_PRSC); - if (retval) - return retval; - } - } else { - break; /* start the next reset, - sleep till it's probably done */ - } - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - RH_PS_PRS); - if (retval) - return retval; - msleep(PORT_RESET_HW_MSEC); - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - } while (tick_before(now, reset_done)); - return 0; -} - -static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - case USB_PORT_FEAT_POWER: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - case USB_PORT_FEAT_RESET: - return u132_roothub_portreset(u132, port_index); - default: - return -EPIPE; - } - } -} - -static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - u32 temp; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - temp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - temp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - temp = RH_PS_POCI; - if ((u132->hc_control & OHCI_CTRL_HCFS) - != OHCI_USB_OPER) { - dev_err(&u132->platform_dev->dev, - "TODO resume_root_hub\n"); - } - break; - case USB_PORT_FEAT_C_SUSPEND: - temp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - temp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - temp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - temp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - temp = RH_PS_PRSC; - break; - default: - return -EPIPE; - } - return u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - } -} - - -/* the virtual root hub timer IRQ checks for hub status*/ -static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device hcd=%p has been removed %d\n", - hcd, u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, - "device hcd=%p is being removed\n", hcd); - return -ESHUTDOWN; - } else { - int i, changed = 0, length = 1; - if (u132->flags & OHCI_QUIRK_AMD756) { - if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { - dev_err(&u132->platform_dev->dev, - "bogus NDP, rereads as NDP=%d\n", - u132->hc_roothub_a & RH_A_NDP); - goto done; - } - } - if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) - buf[0] = changed = 1; - else - buf[0] = 0; - if (u132->num_ports > 7) { - buf[1] = 0; - length++; - } - for (i = 0; i < u132->num_ports; i++) { - if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC | - RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | - RH_PS_PRSC)) { - changed = 1; - if (i < 7) - buf[0] |= 1 << (i + 1); - else - buf[1] |= 1 << (i - 7); - continue; - } - if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) - continue; - - if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) - continue; - } -done: - return changed ? length : 0; - } -} - -static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - mutex_lock(&u132->sw_lock); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case ClearPortFeature:{ - retval = u132_roothub_clearportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - case GetHubDescriptor:{ - retval = u132_roothub_descriptor(u132, - (struct usb_hub_descriptor *)buf); - if (retval) - goto error; - break; - } - case GetHubStatus:{ - retval = u132_roothub_status(u132, - (__le32 *) buf); - if (retval) - goto error; - break; - } - case GetPortStatus:{ - retval = u132_roothub_portstatus(u132, - (__le32 *) buf, wIndex); - if (retval) - goto error; - break; - } - case SetPortFeature:{ - retval = u132_roothub_setportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - default: - goto stall; - error: - u132_disable(u132); - u132->going = 1; - break; - stall: - retval = -EPIPE; - break; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - return 0; - } -} - - -#ifdef CONFIG_PM -static int u132_bus_suspend(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - return 0; - } -} - -static int u132_bus_resume(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - return 0; - } -} - -#else -#define u132_bus_suspend NULL -#define u132_bus_resume NULL -#endif -static const struct hc_driver u132_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct u132), - .irq = NULL, - .flags = HCD_USB11 | HCD_MEMORY, - .reset = u132_hcd_reset, - .start = u132_hcd_start, - .stop = u132_hcd_stop, - .urb_enqueue = u132_urb_enqueue, - .urb_dequeue = u132_urb_dequeue, - .endpoint_disable = u132_endpoint_disable, - .get_frame_number = u132_get_frame, - .hub_status_data = u132_hub_status_data, - .hub_control = u132_hub_control, - .bus_suspend = u132_bus_suspend, - .bus_resume = u132_bus_resume, - .start_port_reset = u132_start_port_reset, -}; - -/* -* This function may be called by the USB core whilst the "usb_all_devices_rwsem" -* is held for writing, thus this module must not call usb_remove_hcd() -* synchronously - but instead should immediately stop activity to the -* device and asynchronously call usb_remove_hcd() -*/ -static int u132_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - - if (u132->going++ > 1) { - dev_err(&u132->platform_dev->dev, - "already being removed\n"); - return -ENODEV; - } else { - int rings = MAX_U132_RINGS; - int endps = MAX_U132_ENDPS; - dev_err(&u132->platform_dev->dev, - "removing device u132.%d\n", - u132->sequence_num); - msleep(100); - mutex_lock(&u132->sw_lock); - u132_monitor_cancel_work(u132); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - u132_ring_cancel_work(u132, ring); - } - while (endps-- > 0) { - struct u132_endp *endp = u132->endp[endps]; - if (endp) - u132_endp_cancel_work(u132, endp); - } - u132->going += 1; - printk(KERN_INFO "removing device u132.%d\n", - u132->sequence_num); - mutex_unlock(&u132->sw_lock); - usb_remove_hcd(hcd); - u132_u132_put_kref(u132); - return 0; - } -} - -static void u132_initialise(struct u132 *u132, struct platform_device *pdev) -{ - int rings = MAX_U132_RINGS; - int ports = MAX_U132_PORTS; - int addrs = MAX_U132_ADDRS; - int udevs = MAX_U132_UDEVS; - int endps = MAX_U132_ENDPS; - u132->board = dev_get_platdata(&pdev->dev); - u132->platform_dev = pdev; - u132->power = 0; - u132->reset = 0; - mutex_init(&u132->sw_lock); - mutex_init(&u132->scheduler_lock); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - ring->u132 = u132; - ring->number = rings + 1; - ring->length = 0; - ring->curr_endp = NULL; - INIT_DELAYED_WORK(&ring->scheduler, - u132_hcd_ring_work_scheduler); - } - mutex_lock(&u132->sw_lock); - INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); - while (ports-- > 0) { - struct u132_port *port = &u132->port[ports]; - port->u132 = u132; - port->reset = 0; - port->enable = 0; - port->power = 0; - port->Status = 0; - } - while (addrs-- > 0) { - struct u132_addr *addr = &u132->addr[addrs]; - addr->address = 0; - } - while (udevs-- > 0) { - struct u132_udev *udev = &u132->udev[udevs]; - int i = ARRAY_SIZE(udev->endp_number_in); - int o = ARRAY_SIZE(udev->endp_number_out); - udev->usb_device = NULL; - udev->udev_number = 0; - udev->usb_addr = 0; - udev->portnumber = 0; - while (i-- > 0) - udev->endp_number_in[i] = 0; - - while (o-- > 0) - udev->endp_number_out[o] = 0; - - } - while (endps-- > 0) - u132->endp[endps] = NULL; - - mutex_unlock(&u132->sw_lock); -} - -static int u132_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - int retval; - u32 control; - u32 rh_a = -1; - - msleep(100); - if (u132_exiting > 0) - return -ENODEV; - - retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a); - if (retval) - return retval; - - /* - * Note that after a successful call of usb_create_hcd(), - * dev_set_drvdata() was called such that platform_get_drvdata(pdev) - * returns hcd later on. - */ - hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - printk(KERN_ERR "failed to create the usb hcd struct for U132\n"); - ftdi_elan_gone_away(pdev); - return -ENOMEM; - } else { - struct u132 *u132 = hcd_to_u132(hcd); - retval = 0; - hcd->rsrc_start = 0; - mutex_lock(&u132_module_lock); - u132->sequence_num = ++u132_instances; - mutex_unlock(&u132_module_lock); - u132_u132_init_kref(u132); - u132_initialise(u132, pdev); - hcd->product_desc = "ELAN U132 Host Controller"; - retval = usb_add_hcd(hcd, 0, 0); - if (retval != 0) { - dev_err(&u132->platform_dev->dev, "init error %d\n", - retval); - u132_u132_put_kref(u132); - return retval; - } else { - device_wakeup_enable(hcd->self.controller); - u132_monitor_queue_work(u132, 100); - return 0; - } - } -} - - -#ifdef CONFIG_PM -/* - * for this device there's no useful distinction between the controller - * and its root hub. - */ -static int u132_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0, ports; - - switch (state.event) { - case PM_EVENT_FREEZE: - retval = u132_bus_suspend(hcd); - break; - case PM_EVENT_SUSPEND: - case PM_EVENT_HIBERNATE: - ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 0); - } - break; - } - return retval; - } -} - -static int u132_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, - "device has been removed %d\n", u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - if (!u132->port[0].power) { - int ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 1); - } - retval = 0; - } else { - retval = u132_bus_resume(hcd); - } - return retval; - } -} - -#else -#define u132_suspend NULL -#define u132_resume NULL -#endif -/* -* this driver is loaded explicitly by ftdi_u132 -* -* the platform_driver struct is static because it is per type of module -*/ -static struct platform_driver u132_platform_driver = { - .probe = u132_probe, - .remove = u132_remove, - .suspend = u132_suspend, - .resume = u132_resume, - .driver = { - .name = hcd_name, - }, -}; -static int __init u132_hcd_init(void) -{ - int retval; - u132_instances = 0; - u132_exiting = 0; - if (usb_disabled()) - return -ENODEV; - workqueue = create_singlethread_workqueue("u132"); - if (!workqueue) - return -ENOMEM; - retval = platform_driver_register(&u132_platform_driver); - if (retval) - destroy_workqueue(workqueue); - - return retval; -} - - -module_init(u132_hcd_init); -static void __exit u132_hcd_exit(void) -{ - mutex_lock(&u132_module_lock); - u132_exiting += 1; - mutex_unlock(&u132_module_lock); - platform_driver_unregister(&u132_platform_driver); - printk(KERN_INFO "u132-hcd driver deregistered\n"); - wait_event(u132_hcd_wait, u132_instances == 0); - destroy_workqueue(workqueue); -} - - -module_exit(u132_hcd_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:u132_hcd"); diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a5f7652db7da..c873cfd4ee86 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -126,8 +126,6 @@ config USB_FTDI_ELAN worked with a USB PEN Drive inserted into the first USB port of the PCCARD. A rather pointless thing to do, but useful for testing. - See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller" - It is safe to say M here. config USB_APPLEDISPLAY -- cgit v1.2.3 From 8be174835f07b2c106b9961c0775486d06112a3c Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Mar 2023 16:09:19 +0100 Subject: usb: ftdi-elan: Delete driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver didn't see real maintainance since several years. It has several trivial issues (check $(scripts/checkpatch.pl -f drivers/usb/misc/ftdi-elan.c)) and some harder ones (difficult locking, explict kref handling, ...). Also today it's hard to find hardware to make actually use of such a card and I suspect the driver is completely unused. So remove it. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230321150919.351947-1-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- arch/mips/configs/mtx1_defconfig | 1 - arch/powerpc/configs/ppc6xx_defconfig | 1 - drivers/usb/misc/Kconfig | 20 - drivers/usb/misc/Makefile | 1 - drivers/usb/misc/ftdi-elan.c | 2780 --------------------------------- 5 files changed, 2803 deletions(-) delete mode 100644 drivers/usb/misc/ftdi-elan.c diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 7b6a2a9daa10..c0c61c37d0b1 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -553,7 +553,6 @@ CONFIG_USB_LCD=m CONFIG_USB_CYPRESS_CY7C63=m CONFIG_USB_CYTHERM=m CONFIG_USB_IDMOUSE=m -CONFIG_USB_FTDI_ELAN=m CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_SISUSBVGA=m CONFIG_USB_LD=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index fd5cc93c4a99..b6366e501f9a 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -907,7 +907,6 @@ CONFIG_USB_SEVSEG=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_IDMOUSE=m -CONFIG_USB_FTDI_ELAN=m CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_SISUSBVGA=m CONFIG_USB_LD=m diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index c873cfd4ee86..08e3cf9efb38 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -108,26 +108,6 @@ config USB_IDMOUSE See also . -config USB_FTDI_ELAN - tristate "Elan PCMCIA CardBus Adapter USB Client" - help - ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters. - Currently only the U132 adapter is available. - - The U132 is specifically designed for CardBus PC cards that contain - an OHCI host controller. Typical PC cards are the Orange Mobile 3G - Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work - with PC cards that do not contain an OHCI controller. To use a U132 - adapter you will need this "ftdi-elan" module as well as the "u132-hcd" - module which is a USB host controller driver that talks to the OHCI - controller within CardBus card that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - It is safe to say M here. - config USB_APPLEDISPLAY tristate "Apple Cinema Display support" select BACKLIGHT_CLASS_DEVICE diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 93581baec3a8..1992cc284d8a 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o -obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_APPLE_MFI_FASTCHARGE) += apple-mfi-fastcharge.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c deleted file mode 100644 index 8ce191e3a4c0..000000000000 --- a/drivers/usb/misc/ftdi-elan.c +++ /dev/null @@ -1,2780 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * USB FTDI client driver for Elan Digital Systems's Uxxx adapters - * - * Copyright(C) 2006 Elan Digital Systems Limited - * http://www.elandigitalsystems.com - * - * Author and Maintainer - Tony Olech - Elan Digital Systems - * tony.olech@elandigitalsystems.com - * - * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) - * based on various USB client drivers in the 2.6.15 linux kernel - * with constant reference to the 3rd Edition of Linux Device Drivers - * published by O'Reilly - * - * The U132 adapter is a USB to CardBus adapter specifically designed - * for PC cards that contain an OHCI host controller. Typical PC cards - * are the Orange Mobile 3G Option GlobeTrotter Fusion card. - * - * The U132 adapter will *NOT *work with PC cards that do not contain - * an OHCI controller. A simple way to test whether a PC card has an - * OHCI controller as an interface is to insert the PC card directly - * into a laptop(or desktop) with a CardBus slot and if "lspci" shows - * a new USB controller and "lsusb -v" shows a new OHCI Host Controller - * then there is a good chance that the U132 adapter will support the - * PC card.(you also need the specific client driver for the PC card) - * - * Please inform the Author and Maintainer about any PC cards that - * contain OHCI Host Controller and work when directly connected to - * an embedded CardBus slot but do not work when they are connected - * via an ELAN U132 adapter. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -MODULE_AUTHOR("Tony Olech"); -MODULE_DESCRIPTION("FTDI ELAN driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -static bool distrust_firmware = 1; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, - "true to distrust firmware power/overcurrent setup"); -extern struct platform_driver u132_platform_driver; -/* - * ftdi_module_lock exists to protect access to global variables - * - */ -static struct mutex ftdi_module_lock; -static int ftdi_instances = 0; -static struct list_head ftdi_static_list; -/* - * end of the global variables protected by ftdi_module_lock - */ -#include "usb_u132.h" -#include -#include - -/* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name - */ - -#include "../host/ohci.h" -/* Define these values to match your devices*/ -#define USB_FTDI_ELAN_VENDOR_ID 0x0403 -#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea -/* table of devices that work with this driver*/ -static const struct usb_device_id ftdi_elan_table[] = { - {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, - { /* Terminating entry */ } -}; - -MODULE_DEVICE_TABLE(usb, ftdi_elan_table); -/* only the jtag(firmware upgrade device) interface requires - * a device file and corresponding minor number, but the - * interface is created unconditionally - I suppose it could - * be configured or not according to a module parameter. - * But since we(now) require one interface per device, - * and since it unlikely that a normal installation would - * require more than a couple of elan-ftdi devices, 8 seems - * like a reasonable limit to have here, and if someone - * really requires more than 8 devices, then they can frig the - * code and recompile - */ -#define USB_FTDI_ELAN_MINOR_BASE 192 -#define COMMAND_BITS 5 -#define COMMAND_SIZE (1<udev->dev, "FREEING ftdi=%p\n", ftdi); - usb_put_dev(ftdi->udev); - ftdi->disconnected += 1; - mutex_lock(&ftdi_module_lock); - list_del_init(&ftdi->ftdi_list); - ftdi_instances -= 1; - mutex_unlock(&ftdi_module_lock); - kfree(ftdi->bulk_in_buffer); - ftdi->bulk_in_buffer = NULL; - kfree(ftdi); -} - -static void ftdi_elan_put_kref(struct usb_ftdi *ftdi) -{ - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_elan_get_kref(struct usb_ftdi *ftdi) -{ - kref_get(&ftdi->kref); -} - -static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) -{ - kref_init(&ftdi->kref); -} - -static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->status_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->status_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->status_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->command_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->command_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->command_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, - unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->respond_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->respond_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->respond_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -void ftdi_elan_gone_away(struct platform_device *pdev) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - ftdi->gone_away += 1; - ftdi_elan_put_kref(ftdi); -} - - -EXPORT_SYMBOL_GPL(ftdi_elan_gone_away); -static void ftdi_release_platform_dev(struct device *dev) -{ - dev->parent = NULL; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length); -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi); -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi); -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi); -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi); -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi); -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi); -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) -{ - if (ftdi->platform_dev.dev.parent) - return -EBUSY; - - ftdi_elan_get_kref(ftdi); - ftdi->platform_data.potpg = 100; - ftdi->platform_data.reset = NULL; - ftdi->platform_dev.id = ftdi->sequence_num; - ftdi->platform_dev.resource = ftdi->resources; - ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); - ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; - ftdi->platform_dev.dev.parent = NULL; - ftdi->platform_dev.dev.release = ftdi_release_platform_dev; - ftdi->platform_dev.dev.dma_mask = NULL; - snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); - ftdi->platform_dev.name = ftdi->device_name; - dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); - request_module("u132_hcd"); - dev_info(&ftdi->udev->dev, "registering '%s'\n", - ftdi->platform_dev.name); - - return platform_device_register(&ftdi->platform_dev); -} - -static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) -{ - mutex_lock(&ftdi->u132_lock); - while (ftdi->respond_next > ftdi->respond_head) { - struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & - ftdi->respond_head++]; - *respond->result = -ESHUTDOWN; - *respond->value = 0; - complete(&respond->wait_completion); - } - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - if (target->active == 1) { - target->condition_code = TD_DEVNOTRESP; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, NULL, 0); - mutex_lock(&ftdi->u132_lock); - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - wait_2:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x90 | (ed_number << 5); - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_2; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) -{ - ftdi_command_queue_work(ftdi, 0); -} - -static void ftdi_elan_command_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, command_work.work); - - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_command_engine(ftdi); - if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval) - dev_err(&ftdi->udev->dev, "command error %d\n", retval); - ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) -{ - ftdi_respond_queue_work(ftdi, 0); -} - -static void ftdi_elan_respond_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, respond_work.work); - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_respond_engine(ftdi); - if (retval == 0) { - } else if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval == -EILSEQ) { - ftdi->disconnected += 1; - } else { - ftdi->disconnected += 1; - dev_err(&ftdi->udev->dev, "respond error %d\n", retval); - } - if (ftdi->disconnected > 0) { - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - } - ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - - -/* - * the sw_lock is initially held and will be freed - * after the FTDI has been synchronized - * - */ -static void ftdi_elan_status_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, status_work.work); - int work_delay_in_msec = 0; - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else if (ftdi->synchronized == 0) { - down(&ftdi->sw_lock); - if (ftdi_elan_synchronize(ftdi) == 0) { - ftdi->synchronized = 1; - ftdi_command_queue_work(ftdi, 1); - ftdi_respond_queue_work(ftdi, 1); - up(&ftdi->sw_lock); - work_delay_in_msec = 100; - } else { - dev_err(&ftdi->udev->dev, "synchronize failed\n"); - up(&ftdi->sw_lock); - work_delay_in_msec = 10 *1000; - } - } else if (ftdi->stuck_status > 0) { - if (ftdi_elan_stuck_waiting(ftdi) == 0) { - ftdi->stuck_status = 0; - ftdi->synchronized = 0; - } else if ((ftdi->stuck_status++ % 60) == 1) { - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - please remove\n"); - } else - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - checked %d times\n", - ftdi->stuck_status); - work_delay_in_msec = 100; - } else if (ftdi->enumerated == 0) { - if (ftdi_elan_enumeratePCI(ftdi) == 0) { - ftdi->enumerated = 1; - work_delay_in_msec = 250; - } else - work_delay_in_msec = 1000; - } else if (ftdi->initialized == 0) { - if (ftdi_elan_setupOHCI(ftdi) == 0) { - ftdi->initialized = 1; - work_delay_in_msec = 500; - } else { - dev_err(&ftdi->udev->dev, "initialized failed - trying again in 10 seconds\n"); - work_delay_in_msec = 1 *1000; - } - } else if (ftdi->registered == 0) { - work_delay_in_msec = 10; - if (ftdi_elan_hcd_init(ftdi) == 0) { - ftdi->registered = 1; - } else - dev_err(&ftdi->udev->dev, "register failed\n"); - work_delay_in_msec = 250; - } else { - if (ftdi_elan_checkingPCI(ftdi) == 0) { - work_delay_in_msec = 250; - } else if (ftdi->controlreg & 0x00400000) { - if (ftdi->gone_away > 0) { - dev_err(&ftdi->udev->dev, "PCI device eject confirmed platform_dev.dev.parent=%p platform_dev.dev=%p\n", - ftdi->platform_dev.dev.parent, - &ftdi->platform_dev.dev); - platform_device_unregister(&ftdi->platform_dev); - ftdi->platform_dev.dev.parent = NULL; - ftdi->registered = 0; - ftdi->enumerated = 0; - ftdi->card_ejected = 0; - ftdi->initialized = 0; - ftdi->gone_away = 0; - } else - ftdi_elan_flush_targets(ftdi); - work_delay_in_msec = 250; - } else { - dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"); - ftdi_elan_cancel_targets(ftdi); - work_delay_in_msec = 500; - ftdi->enumerated = 0; - ftdi->initialized = 0; - } - } - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - ftdi_status_requeue_work(ftdi, - msecs_to_jiffies(work_delay_in_msec)); - return; - } -} - - -/* - * file_operations for the jtag interface - * - * the usage count for the device is incremented on open() - * and decremented on release() - */ -static int ftdi_elan_open(struct inode *inode, struct file *file) -{ - int subminor; - struct usb_interface *interface; - - subminor = iminor(inode); - interface = usb_find_interface(&ftdi_elan_driver, subminor); - - if (!interface) { - pr_err("can't find device for minor %d\n", subminor); - return -ENODEV; - } else { - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - if (!ftdi) { - return -ENODEV; - } else { - if (down_interruptible(&ftdi->sw_lock)) { - return -EINTR; - } else { - ftdi_elan_get_kref(ftdi); - file->private_data = ftdi; - return 0; - } - } - } -} - -static int ftdi_elan_release(struct inode *inode, struct file *file) -{ - struct usb_ftdi *ftdi = file->private_data; - if (ftdi == NULL) - return -ENODEV; - up(&ftdi->sw_lock); /* decrement the count on our device */ - ftdi_elan_put_kref(ftdi); - return 0; -} - - -/* - * - * blocking bulk reads are used to get data from the device - * - */ -static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3 - 1; - int bytes_read = 0; - int retry_on_empty = 10; - int retry_on_timeout = 5; - struct usb_ftdi *ftdi = file->private_data; - if (ftdi->disconnected > 0) { - return -ENODEV; - } - data[0] = 0; -have:if (ftdi->bulk_in_left > 0) { - if (count-- > 0) { - char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; - ftdi->bulk_in_left -= 1; - if (bytes_read < m) { - d += sprintf(d, " %02X", 0x000000FF & *p); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - if (copy_to_user(buffer++, p, 1)) { - return -EFAULT; - } else { - bytes_read += 1; - goto have; - } - } else - return bytes_read; - } -more:if (count > 0) { - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 50); - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else if (bytes_read > 0) { - return bytes_read; - } else - return retval; - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else - return bytes_read; - } else - return retval; - } else - return bytes_read; -} - -static void ftdi_elan_write_bulk_callback(struct urb *urb) -{ - struct usb_ftdi *ftdi = urb->context; - int status = urb->status; - - if (status && !(status == -ENOENT || status == -ECONNRESET || - status == -ESHUTDOWN)) { - dev_err(&ftdi->udev->dev, - "urb=%p write bulk status received: %d\n", urb, status); - } - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); -} - -static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, - char *buf, int command_size, int total_size) -{ - int ed_commands = 0; - int b = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - int F = command->follows; - u8 *f = command->buffer; - if (command->header & 0x80) { - ed_commands |= 1 << (0x3 & (command->header >> 5)); - } - buf[b++] = command->header; - buf[b++] = (command->length >> 0) & 0x00FF; - buf[b++] = (command->length >> 8) & 0x00FF; - buf[b++] = command->address; - buf[b++] = command->width; - while (F-- > 0) { - buf[b++] = *f++; - } - } - return ed_commands; -} - -static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) -{ - int total_size = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - total_size += 5 + command->follows; - } - return total_size; -} - -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) -{ - int retval; - char *buf; - int ed_commands; - int total_size; - struct urb *urb; - int command_size = ftdi->command_next - ftdi->command_head; - if (command_size == 0) - return 0; - total_size = ftdi_elan_total_command_size(ftdi, command_size); - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer to write %d commands totaling %d bytes to the Uxxx\n", - command_size, total_size); - usb_free_urb(urb); - return -ENOMEM; - } - ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, - command_size, total_size); - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, total_size, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (ed_commands) { - char diag[40 *3 + 4]; - char *d = diag; - int m = total_size; - u8 *c = buf; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - } - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write %d commands totaling %d bytes to the Uxxx\n", - retval, urb, command_size, total_size); - usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); - usb_free_urb(urb); - return retval; - } - usb_free_urb(urb); /* release our reference to this urb, - the USB core will eventually free it entirely */ - ftdi->command_head += command_size; - ftdi_elan_kick_respond_queue(ftdi); - return 0; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length) -{ - struct urb *urb = target->urb; - int halted = target->halted; - int skipped = target->skipped; - int actual = target->actual; - int non_null = target->non_null; - int toggle_bits = target->toggle_bits; - int error_count = target->error_count; - int condition_code = target->condition_code; - int repeat_number = target->repeat_number; - void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, - int, int, int, int) = target->callback; - target->active -= 1; - target->callback = NULL; - (*callback) (target->endp, urb, buffer, length, toggle_bits, - error_count, condition_code, repeat_number, halted, skipped, - actual, non_null); -} - -static char *have_ed_set_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - int payload = (ed_length >> 0) & 0x07FF; - mutex_lock(&ftdi->u132_lock); - target->actual = 0; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - if (ed_type == 0x02 || ed_type == 0x03) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } -} - -static char *have_ed_get_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - mutex_lock(&ftdi->u132_lock); - target->condition_code = TD_DEVNOTRESP; - target->actual = (ed_length >> 0) & 0x01FF; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - mutex_unlock(&ftdi->u132_lock); - if (target->active) - ftdi_elan_do_callback(ftdi, target, NULL, 0); - target->abandoning = 0; - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; -} - - -/* - * The engine tries to empty the FTDI fifo - * - * all responses found in the fifo data are dispatched thus - * the response buffer can only ever hold a maximum sized - * response from the Uxxx. - * - */ -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) -{ - u8 *b = ftdi->response + ftdi->received; - int bytes_read = 0; - int retry_on_empty = 1; - int retry_on_timeout = 3; -read:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - char diag[30 *3 + 4]; - char *d = diag; - int m = packet_bytes; - u8 *c = ftdi->bulk_in_buffer; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - goto more; - } else if (bytes_read > 0) { - dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", - bytes_read, diag); - return -ENOMEM; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - return -ENOMEM; - } - } else if (retval == -EILSEQ) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", - retval, packet_bytes, bytes_read, diag); - return retval; - } else if (retval) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", - retval, packet_bytes, bytes_read, diag); - return retval; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } -more:{ - goto read; - } -have:if (ftdi->bulk_in_left > 0) { - u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; - bytes_read += 1; - ftdi->bulk_in_left -= 1; - if (ftdi->received == 0 && c == 0xFF) { - goto have; - } else - *b++ = c; - if (++ftdi->received < ftdi->expected) { - goto have; - } else if (ftdi->ed_found) { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ed_number]; - int payload = (ed_length >> 0) & 0x07FF; - char diag[30 *3 + 4]; - char *d = diag; - int m = payload; - u8 *c = 4 + ftdi->response; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - goto have; - } else if (ftdi->expected == 8) { - u8 buscmd; - int respond_head = ftdi->respond_head++; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & respond_head]; - u32 data = ftdi->response[7]; - data <<= 8; - data |= ftdi->response[6]; - data <<= 8; - data |= ftdi->response[5]; - data <<= 8; - data |= ftdi->response[4]; - *respond->value = data; - *respond->result = 0; - complete(&respond->wait_completion); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - buscmd = (ftdi->response[0] >> 0) & 0x0F; - if (buscmd == 0x00) { - } else if (buscmd == 0x02) { - } else if (buscmd == 0x06) { - } else if (buscmd == 0x0A) { - } else - dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) value = %08X\n", - buscmd, data); - goto have; - } else { - if ((ftdi->response[0] & 0x80) == 0x00) { - ftdi->expected = 8; - goto have; - } else { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - int ed_type = (ftdi->response[0] >> 0) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ - ed_number]; - target->halted = (ftdi->response[0] >> 3) & - 0x01; - target->skipped = (ftdi->response[0] >> 2) & - 0x01; - target->toggle_bits = (ftdi->response[3] >> 6) - & 0x03; - target->error_count = (ftdi->response[3] >> 4) - & 0x03; - target->condition_code = (ftdi->response[ - 3] >> 0) & 0x0F; - if ((ftdi->response[0] & 0x10) == 0x00) { - b = have_ed_set_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } else { - b = have_ed_get_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } - } - } - } else - goto more; -} - - -/* - * create a urb, and a buffer for it, and copy the data to the urb - * - */ -static ssize_t ftdi_elan_write(struct file *file, - const char __user *user_buffer, size_t count, - loff_t *ppos) -{ - int retval = 0; - struct urb *urb; - char *buf; - struct usb_ftdi *ftdi = file->private_data; - - if (ftdi->disconnected > 0) { - return -ENODEV; - } - if (count == 0) { - goto exit; - } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto error_1; - } - buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - goto error_2; - } - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - goto error_3; - } - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, count, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, - "failed submitting write urb, error %d\n", retval); - goto error_3; - } - usb_free_urb(urb); - -exit: - return count; -error_3: - usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma); -error_2: - usb_free_urb(urb); -error_1: - return retval; -} - -static const struct file_operations ftdi_elan_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ftdi_elan_read, - .write = ftdi_elan_write, - .open = ftdi_elan_open, - .release = ftdi_elan_release, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver ftdi_elan_jtag_class = { - .name = "ftdi-%d-jtag", - .fops = &ftdi_elan_fops, - .minor_base = USB_FTDI_ELAN_MINOR_BASE, -}; - -/* - * the following definitions are for the - * ELAN FPGA state machgine processor that - * lies on the other side of the FTDI chip - */ -#define cPCIu132rd 0x0 -#define cPCIu132wr 0x1 -#define cPCIiord 0x2 -#define cPCIiowr 0x3 -#define cPCImemrd 0x6 -#define cPCImemwr 0x7 -#define cPCIcfgrd 0xA -#define cPCIcfgwr 0xB -#define cPCInull 0xF -#define cU132cmd_status 0x0 -#define cU132flash 0x1 -#define cPIDsetup 0x0 -#define cPIDout 0x1 -#define cPIDin 0x2 -#define cPIDinonce 0x3 -#define cCCnoerror 0x0 -#define cCCcrc 0x1 -#define cCCbitstuff 0x2 -#define cCCtoggle 0x3 -#define cCCstall 0x4 -#define cCCnoresp 0x5 -#define cCCbadpid1 0x6 -#define cCCbadpid2 0x7 -#define cCCdataoverrun 0x8 -#define cCCdataunderrun 0x9 -#define cCCbuffoverrun 0xC -#define cCCbuffunderrun 0xD -#define cCCnotaccessed 0xF -static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data) -{ -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | cPCIu132wr; - command->length = 0x04; - command->address = 0x00; - command->width = 0x00; - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 data) -{ - u8 addressofs = config_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCIcfgwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 data) -{ - u8 addressofs = mem_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCImemwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem); -static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) -{ -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | cPCIu132rd; - command->length = 0x04; - respond->address = command->address = cU132cmd_status; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 *data) -{ - u8 addressofs = config_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCIcfgrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 *data) -{ - u8 addressofs = mem_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCImemrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 *data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - if (ftdi->initialized == 0) { - return -ENODEV; - } else - return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem); -static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed << 5); - command->length = 0x8007; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 8; - command->value = 0; - command->buffer = urb->setup_packet; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup); -static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - command->header = 0x82 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input); -static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->length = 0x0000; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty); -static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u8 *b; - u16 urb_size; - int i = 0; - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3 - 1; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = min_t(u32, 1024, - urb->transfer_buffer_length - - urb->actual_length); - command->value = 0; - command->buffer = urb->transfer_buffer + - urb->actual_length; - command->length = 0x8000 | (command->follows - 1); - b = command->buffer; - urb_size = command->follows; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - } else - d += sprintf(d, " .."); - } - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output); -static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x83 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single); -static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, - void *endp) -{ - u8 ed = ed_number - 1; - if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - struct u132_target *target = &ftdi->target[ed]; - mutex_lock(&ftdi->u132_lock); - if (target->abandoning > 0) { - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = - &ftdi->command[COMMAND_MASK & - ftdi->command_next]; - command->header = 0x80 | (ed << 5) | - 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - mutex_unlock(&ftdi->u132_lock); - return 0; - } - } -} - -int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, - void *endp) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_flush(ftdi, ed_number, endp); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush); -static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 20; -more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 100); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", - b1); - if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return retval; - } - } - return -1; -} - - -/* - * send the long flush sequence - * - */ -static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 257; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - while (I-- > 0) - buf[i++] = 0x55; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the flush sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - - -/* - * send the reset sequence - * - */ -static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 4; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - buf[i++] = 0x55; - buf[i++] = 0xAA; - buf[i++] = 0x5A; - buf[i++] = 0xA5; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the reset sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi) -{ - int retval; - int long_stop = 10; - int retry_on_timeout = 5; - int retry_on_empty = 10; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - ftdi->bulk_in_left = 0; - ftdi->bulk_in_last = -1; - while (long_stop-- > 0) { - int read_stop; - int read_stuck; - retval = ftdi_elan_synchronize_flush(ftdi); - if (retval) - return retval; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - reset:retval = ftdi_elan_synchronize_reset(ftdi); - if (retval) - return retval; - read_stop = 100; - read_stuck = 10; - read:{ - int packet_bytes = 0; - retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, - ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - unsigned char c = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - if (c == 0x7E) { - return 0; - } else { - if (c == 0x55) { - goto read; - } else if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } else if (packet_bytes > 1) { - unsigned char s1 = ftdi->bulk_in_buffer[0]; - unsigned char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x00) { - if (read_stuck-- > 0) { - goto read; - } else - goto reset; - } else { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } else if (packet_bytes > 0) { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - continue; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - continue; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", - retval); - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } - } - dev_err(&ftdi->udev->dev, "failed to synchronize\n"); - return -EFAULT; -} - -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 50; -more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 1000); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else - return -EFAULT; - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", b1); - if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return -ENOMEM; - } - } - return -1; -} - -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); - if (UxxxStatus) - return UxxxStatus; - if (ftdi->controlreg & 0x00400000) { - if (ftdi->card_ejected) { - } else { - ftdi->card_ejected = 1; - dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = %08X\n", - ftdi->controlreg); - } - return -ENODEV; - } else { - u8 fn = ftdi->function - 1; - int activePCIfn = fn << 8; - u32 pcidata; - u32 pciVID; - u32 pciPID; - int reg = 0; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if (pciVID == ftdi->platform_data.vendor && pciPID == - ftdi->platform_data.device) { - return 0; - } else { - dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X device=%04X pciPID=%04X\n", - ftdi->platform_data.vendor, pciVID, - ftdi->platform_data.device, pciPID); - return -ENODEV; - } - } -} - - -#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); -#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); - -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) -{ - int devices = 0; - int retval; - u32 hc_control; - int num_ports; - u32 control; - u32 rh_a = -1; - u32 status; - u32 fminterval; - u32 hc_fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - int temp; - retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); - if (retval) - return retval; - num_ports = rh_a & RH_A_NDP; - retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); - if (retval) - return retval; - hc_fminterval &= 0x3fff; - if (hc_fminterval != FI) { - } - hc_fminterval |= FSMP(hc_fminterval) << 16; - retval = ftdi_read_pcimem(ftdi, control, &hc_control); - if (retval) - return retval; - switch (hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { /* power down each port */ - for (temp = 0; temp < num_ports; temp++) { - retval = ftdi_write_pcimem(ftdi, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; -retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra:{ - retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&ftdi->udev->dev, "USB HC reset timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (quirk & OHCI_QUIRK_INITRESET) { - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, fminterval, - ((fminterval & FIT) ^ FIT) | hc_fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, periodicstart, - ((9 *hc_fminterval) / 10) & 0x3fff); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(quirk & OHCI_QUIRK_INITRESET)) { - quirk |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", - fminterval, periodicstart); - } /* start controller operations */ - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrstatus, mask); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (quirk & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - for (temp = 0; temp < num_ports; temp++) { - u32 portstatus; - retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], - &portstatus); - if (retval) - return retval; - if (1 & portstatus) - devices += 1; - } - return devices; -} - -static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xF0000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x06); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - for (reg = 0; reg <= 0x54; reg += 4) { - UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (UxxxStatus) - return UxxxStatus; - } - return 0; -} - -static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0x00000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x00); - if (UxxxStatus) - return UxxxStatus; - return ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, &pcidata); -} - -static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) -{ - int result; - int UxxxStatus; - UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - result = ftdi_elan_check_controller(ftdi, quirk); - UxxxStatus = ftdi_elan_close_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - return result; -} - -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) -{ - u32 controlreg; - u8 sensebits; - int UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); - if (UxxxStatus) - return UxxxStatus; - msleep(750); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); - if (UxxxStatus) - return UxxxStatus; - msleep(250); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - msleep(1000); - sensebits = (controlreg >> 16) & 0x000F; - if (0x0D == sensebits) - return 0; - else - return - ENXIO; -} - -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus; - u32 pcidata; - int reg = 0; - u8 fn; - int activePCIfn = 0; - int max_devices = 0; - int controllers = 0; - int unrecognized = 0; - ftdi->function = 0; - for (fn = 0; (fn < 4); fn++) { - u32 pciVID = 0; - u32 pciPID = 0; - int devices = 0; - activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_AMD756); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_ZFMICRO); - controllers += 1; - } else if (0 == pcidata) { - } else - unrecognized += 1; - if (devices > max_devices) { - max_devices = devices; - ftdi->function = fn + 1; - ftdi->platform_data.vendor = pciVID; - ftdi->platform_data.device = pciPID; - } - } - if (ftdi->function > 0) { - return ftdi_elan_setup_controller(ftdi, ftdi->function - 1); - } else if (controllers > 0) { - return -ENXIO; - } else if (unrecognized > 0) { - return -ENXIO; - } else { - ftdi->enumerated = 0; - return -ENXIO; - } -} - - -/* - * we use only the first bulk-in and bulk-out endpoints - */ -static int ftdi_elan_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *bulk_in, *bulk_out; - int retval; - struct usb_ftdi *ftdi; - - ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (!ftdi) - return -ENOMEM; - - mutex_lock(&ftdi_module_lock); - list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); - ftdi->sequence_num = ++ftdi_instances; - mutex_unlock(&ftdi_module_lock); - ftdi_elan_init_kref(ftdi); - sema_init(&ftdi->sw_lock, 1); - ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); - ftdi->interface = interface; - mutex_init(&ftdi->u132_lock); - ftdi->expected = 4; - - iface_desc = interface->cur_altsetting; - retval = usb_find_common_endpoints(iface_desc, - &bulk_in, &bulk_out, NULL, NULL); - if (retval) { - dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk-out endpoints\n"); - goto error; - } - - ftdi->bulk_in_size = usb_endpoint_maxp(bulk_in); - ftdi->bulk_in_endpointAddr = bulk_in->bEndpointAddress; - ftdi->bulk_in_buffer = kmalloc(ftdi->bulk_in_size, GFP_KERNEL); - if (!ftdi->bulk_in_buffer) { - retval = -ENOMEM; - goto error; - } - - ftdi->bulk_out_endpointAddr = bulk_out->bEndpointAddress; - - dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", - iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, - ftdi->bulk_out_endpointAddr); - usb_set_intfdata(interface, ftdi); - if (iface_desc->desc.bInterfaceNumber == 0 && - ftdi->bulk_in_endpointAddr == 0x81 && - ftdi->bulk_out_endpointAddr == 0x02) { - retval = usb_register_dev(interface, &ftdi_elan_jtag_class); - if (retval) { - dev_err(&ftdi->udev->dev, "Not able to get a minor for this device\n"); - usb_set_intfdata(interface, NULL); - retval = -ENOMEM; - goto error; - } else { - ftdi->class = &ftdi_elan_jtag_class; - dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface %d now attached to ftdi%d\n", - ftdi, iface_desc->desc.bInterfaceNumber, - interface->minor); - return 0; - } - } else if (iface_desc->desc.bInterfaceNumber == 1 && - ftdi->bulk_in_endpointAddr == 0x83 && - ftdi->bulk_out_endpointAddr == 0x04) { - ftdi->class = NULL; - dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now activated\n", - ftdi, iface_desc->desc.bInterfaceNumber); - INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); - INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); - INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); - ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); - return 0; - } else { - dev_err(&ftdi->udev->dev, - "Could not find ELAN's U132 device\n"); - retval = -ENODEV; - goto error; - } -error:if (ftdi) { - ftdi_elan_put_kref(ftdi); - } - return retval; -} - -static void ftdi_elan_disconnect(struct usb_interface *interface) -{ - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - ftdi->disconnected += 1; - if (ftdi->class) { - int minor = interface->minor; - struct usb_class_driver *class = ftdi->class; - usb_set_intfdata(interface, NULL); - usb_deregister_dev(interface, class); - dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on minor %d now disconnected\n", - minor); - } else { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - if (ftdi->registered) { - platform_device_unregister(&ftdi->platform_dev); - ftdi->synchronized = 0; - ftdi->enumerated = 0; - ftdi->initialized = 0; - ftdi->registered = 0; - } - ftdi->disconnected += 1; - usb_set_intfdata(interface, NULL); - dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); - } - ftdi_elan_put_kref(ftdi); -} - -static struct usb_driver ftdi_elan_driver = { - .name = "ftdi-elan", - .probe = ftdi_elan_probe, - .disconnect = ftdi_elan_disconnect, - .id_table = ftdi_elan_table, -}; -static int __init ftdi_elan_init(void) -{ - int result; - pr_info("driver %s\n", ftdi_elan_driver.name); - mutex_init(&ftdi_module_lock); - INIT_LIST_HEAD(&ftdi_static_list); - result = usb_register(&ftdi_elan_driver); - if (result) { - pr_err("usb_register failed. Error number %d\n", result); - } - return result; - -} - -static void __exit ftdi_elan_exit(void) -{ - struct usb_ftdi *ftdi; - struct usb_ftdi *temp; - usb_deregister(&ftdi_elan_driver); - pr_info("ftdi_u132 driver deregistered\n"); - list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - } -} - - -module_init(ftdi_elan_init); -module_exit(ftdi_elan_exit); -- cgit v1.2.3 From 347284984f415e52590373253c6943bbdc806ebf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Mar 2023 17:47:02 +0200 Subject: xhci: mem: Carefully calculate size for memory allocations Carefully calculate size for memory allocations, i.e. with help of size_mul() macro from overflow.h. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d0a9467aa5fc..c385513ad00b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -568,7 +569,7 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, gfp_t mem_flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; + size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs); if (size > MEDIUM_STREAM_ARRAY_SIZE) return dma_alloc_coherent(dev, size, @@ -1660,7 +1661,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) goto fail_sp; xhci->scratchpad->sp_array = dma_alloc_coherent(dev, - num_sp * sizeof(u64), + size_mul(sizeof(u64), num_sp), &xhci->scratchpad->sp_dma, flags); if (!xhci->scratchpad->sp_array) goto fail_sp2; @@ -1799,7 +1800,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_segment *seg; struct xhci_erst_entry *entry; - size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs; + size = size_mul(sizeof(struct xhci_erst_entry), evt_ring->num_segs); erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, size, &erst->erst_dma_addr, flags); if (!erst->entries) @@ -1830,7 +1831,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) if (!ir) return; - erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries); + erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; if (ir->erst.entries) dma_free_coherent(dev, erst_size, ir->erst.entries, -- cgit v1.2.3 From 53ee2663f0df536ccb37d559c4f4c53c4511db7a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Mar 2023 17:47:03 +0200 Subject: xhci: mem: Use dma_poll_zalloc() instead of explicit memset() Use dma_poll_zalloc() instead of explicit memset() call in xhci_alloc_stream_ctx(). Note, that dma_alloc_coherent() is always issues zeroed memory chunk. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c385513ad00b..4ffa6495878d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -575,10 +575,10 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, return dma_alloc_coherent(dev, size, dma, mem_flags); else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_alloc(xhci->small_streams_pool, + return dma_pool_zalloc(xhci->small_streams_pool, mem_flags, dma); else - return dma_pool_alloc(xhci->medium_streams_pool, + return dma_pool_zalloc(xhci->medium_streams_pool, mem_flags, dma); } @@ -643,8 +643,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, mem_flags); if (!stream_info->stream_ctx_array) goto cleanup_ring_array; - memset(stream_info->stream_ctx_array, 0, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs); /* Allocate everything needed to free the stream rings later */ stream_info->free_streams_command = -- cgit v1.2.3 From 85052fdb40a0eb2278d10f016ce12de00672bba9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Mar 2023 17:47:04 +0200 Subject: xhci: mem: Get rid of redundant 'else' In the snippets like the following if (...) return / goto / break / continue ...; else ... the 'else' is redundant. Get rid of it. While at it, make if-chain sorted from testing bigger values to smaller. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-4-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 4ffa6495878d..357883256a5a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -572,14 +572,11 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs); if (size > MEDIUM_STREAM_ARRAY_SIZE) - return dma_alloc_coherent(dev, size, - dma, mem_flags); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_zalloc(xhci->small_streams_pool, - mem_flags, dma); + return dma_alloc_coherent(dev, size, dma, mem_flags); + if (size > SMALL_STREAM_ARRAY_SIZE) + return dma_pool_zalloc(xhci->medium_streams_pool, mem_flags, dma); else - return dma_pool_zalloc(xhci->medium_streams_pool, - mem_flags, dma); + return dma_pool_zalloc(xhci->small_streams_pool, mem_flags, dma); } struct xhci_ring *xhci_dma_to_transfer_ring( @@ -1399,8 +1396,9 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev, if ((udev->speed >= USB_SPEED_SUPER_PLUS) && USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval); + /* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */ - else if (udev->speed >= USB_SPEED_SUPER) + if (udev->speed >= USB_SPEED_SUPER) return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); max_packet = usb_endpoint_maxp(&ep->desc); -- cgit v1.2.3 From 3056a5cafa3cf83c7c83d3fb4029707888d4bb63 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Mar 2023 17:47:05 +0200 Subject: xhci: mem: Drop useless return:s When function returns void and we have if-else-if chain, there is no need to explicitly call return. Drop them and indent lines better. While at it, make if-chain sorted from testing bigger values to smaller. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-5-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 357883256a5a..fa0c4ac2ca7f 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -544,14 +544,11 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci, size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; if (size > MEDIUM_STREAM_ARRAY_SIZE) - dma_free_coherent(dev, size, - stream_ctx, dma); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_free(xhci->small_streams_pool, - stream_ctx, dma); + dma_free_coherent(dev, size, stream_ctx, dma); + else if (size > SMALL_STREAM_ARRAY_SIZE) + dma_pool_free(xhci->medium_streams_pool, stream_ctx, dma); else - return dma_pool_free(xhci->medium_streams_pool, - stream_ctx, dma); + dma_pool_free(xhci->small_streams_pool, stream_ctx, dma); } /* -- cgit v1.2.3 From 76dc910af13c677b504ac8606352c791891166b1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Mar 2023 17:47:06 +0200 Subject: xhci: mem: Use while (i--) pattern to clean up Use more natural while (i--) patter to clean up allocated resources. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-6-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fa0c4ac2ca7f..b8c1465f8d23 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1679,11 +1679,10 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) return 0; fail_sp4: - for (i = i - 1; i >= 0; i--) { + while (i--) dma_free_coherent(dev, xhci->page_size, xhci->scratchpad->sp_buffers[i], xhci->scratchpad->sp_array[i]); - } kfree(xhci->scratchpad->sp_buffers); -- cgit v1.2.3 From 96be93a8c8272d20d20476ba8324e580b6e8a08f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Mar 2023 17:47:07 +0200 Subject: xhci: mem: Replace explicit castings with appropriate specifiers There is no need to have explicit castings when we have specific pointer extensions. Replace the explicit castings with appropriate specifiers. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-7-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index b8c1465f8d23..67ac02d177b5 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -666,8 +666,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, cur_ring->cycle_state; stream_info->stream_ctx_array[cur_stream].stream_ring = cpu_to_le64(addr); - xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", - cur_stream, (unsigned long long) addr); + xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, addr); ret = xhci_update_stream_mapping(cur_ring, mem_flags); if (ret) { @@ -977,16 +976,14 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, if (!dev->out_ctx) goto fail; - xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->out_ctx->dma); + xhci_dbg(xhci, "Slot %d output ctx = 0x%pad (dma)\n", slot_id, &dev->out_ctx->dma); /* Allocate the (input) device context for address device command */ dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); if (!dev->in_ctx) goto fail; - xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->in_ctx->dma); + xhci_dbg(xhci, "Slot %d input ctx = 0x%pad (dma)\n", slot_id, &dev->in_ctx->dma); /* Initialize the cancellation and bandwidth list for each ep */ for (i = 0; i < 31; i++) { @@ -2351,8 +2348,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci->dcbaa->dma = dma; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Device context base array address = 0x%llx (DMA), %p (virt)", - (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); + "// Device context base array address = 0x%pad (DMA), %p (virt)", + &xhci->dcbaa->dma, xhci->dcbaa); xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); /* @@ -2393,8 +2390,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocated command ring at %p", xhci->cmd_ring); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx", - (unsigned long long)xhci->cmd_ring->first_seg->dma); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad", + &xhci->cmd_ring->first_seg->dma); /* Set the address in the Command Ring Control register */ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); -- cgit v1.2.3 From 4feb07d0ada339f7edc0dc3b24581f201848a65b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Mar 2023 17:47:08 +0200 Subject: xhci: mem: Join string literals back For easy grepping on debug purposes join string literals back in the messages. No functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-8-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 67ac02d177b5..7e106bd804ca 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -607,8 +607,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, int ret; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - xhci_dbg(xhci, "Allocating %u streams and %u " - "stream context array entries.\n", + xhci_dbg(xhci, "Allocating %u streams and %u stream context array entries.\n", num_streams, num_stream_ctxs); if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) { xhci_dbg(xhci, "Command ring has no reserved TRBs available\n"); @@ -1950,8 +1949,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, ir->event_ring->dequeue); if (!deq) - xhci_warn(xhci, "WARN something wrong with SW event ring " - "dequeue ptr.\n"); + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp &= ERST_PTR_MASK; @@ -1960,8 +1958,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter */ temp &= ~ERST_EHB; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write event ring dequeue pointer, " - "preserving EHB bit"); + "// Write event ring dequeue pointer, preserving EHB bit"); xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &ir->ir_set->erst_dequeue); } @@ -1994,8 +1991,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, } else if (major_revision <= 0x02) { rhub = &xhci->usb2_rhub; } else { - xhci_warn(xhci, "Ignoring unknown port speed, " - "Ext Cap %p, revision = 0x%x\n", + xhci_warn(xhci, "Ignoring unknown port speed, Ext Cap %p, revision = 0x%x\n", addr, major_revision); /* Ignoring port protocol we can't understand. FIXME */ return; @@ -2010,9 +2006,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, port_offset = XHCI_EXT_PORT_OFF(temp); port_count = XHCI_EXT_PORT_COUNT(temp); xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Ext Cap %p, port offset = %u, " - "count = %u, revision = 0x%x", - addr, port_offset, port_count, major_revision); + "Ext Cap %p, port offset = %u, count = %u, revision = 0x%x", + addr, port_offset, port_count, major_revision); /* Port count includes the current port offset */ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ @@ -2069,10 +2064,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, struct xhci_port *hw_port = &xhci->hw_ports[i]; /* Duplicate entry. Ignore the port if the revisions differ. */ if (hw_port->rhub) { - xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," - " port %u\n", addr, i); - xhci_warn(xhci, "Port was marked as USB %u, " - "duplicated as USB %u\n", + xhci_warn(xhci, "Duplicate port entry, Ext Cap %p, port %u\n", addr, i); + xhci_warn(xhci, "Port was marked as USB %u, duplicated as USB %u\n", hw_port->rhub->maj_rev, major_revision); /* Only adjust the roothub port counts if we haven't * found a similar duplicate. @@ -2411,8 +2404,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) val = readl(&xhci->cap_regs->db_off); val &= DBOFF_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Doorbell array is located at offset 0x%x" - " from cap regs base addr", val); + "// Doorbell array is located at offset 0x%x from cap regs base addr", + val); xhci->dba = (void __iomem *) xhci->cap_regs + val; /* Set ir_set to interrupt register set 0 */ -- cgit v1.2.3 From edf1664f3249a091a2b91182fc087b3253b0b4c2 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 17 Mar 2023 17:47:09 +0200 Subject: xhci: dbc: Provide sysfs option to configure dbc descriptors When DbC is enabled the first port on the xHC host acts as a usb device. xHC provides the descriptors automatically when the DbC device is enumerated. Most of the values are hardcoded, but some fields such as idProduct, idVendor, bcdDevice and bInterfaceProtocol can be modified. Add sysfs entries that allow userspace to change these. User can only change them before dbc is enabled, i.e. before writing "enable" to dbc sysfs file as we don't want these values to change while device is connected, or during enumeration. Add documentation for these entries in Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-9-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-pci-drivers-xhci_hcd | 52 ++++++ drivers/usb/host/xhci-dbgcap.c | 191 ++++++++++++++++++++- drivers/usb/host/xhci-dbgcap.h | 4 + 3 files changed, 243 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd index 0088aba4caa8..5a775b8f6543 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd +++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd @@ -23,3 +23,55 @@ Description: Reading this attribute gives the state of the DbC. It can be one of the following states: disabled, enabled, initialized, connected, configured and stalled. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idVendor +Date: March 2023 +Contact: Mathias Nyman +Description: + This dbc_idVendor attribute lets us change the idVendor field + presented in the USB device descriptor by this xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is 0x1d6b (Linux Foundation). + It can be any 16-bit integer. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idProduct +Date: March 2023 +Contact: Mathias Nyman +Description: + This dbc_idProduct attribute lets us change the idProduct field + presented in the USB device descriptor by this xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is 0x0010. It can be any 16-bit integer. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bcdDevice +Date: March 2023 +Contact: Mathias Nyman +Description: + This dbc_bcdDevice attribute lets us change the bcdDevice field + presented in the USB device descriptor by this xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is 0x0010. (device rev 0.10) + It can be any 16-bit integer. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bInterfaceProtocol +Date: March 2023 +Contact: Mathias Nyman +Description: + This attribute lets us change the bInterfaceProtocol field + presented in the USB Interface descriptor by the xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB descriptor change while + connected to a USB host. + The default value is 1 (GNU Remote Debug command). + Other permissible value is 0 which is for vendor defined debug + target. diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index f1367b53b260..b40d9238d447 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -124,10 +124,10 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length) /* Set DbC context and info registers: */ lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp); - dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL); + dev_info = (dbc->idVendor << 16) | dbc->bInterfaceProtocol; writel(dev_info, &dbc->regs->devinfo1); - dev_info = cpu_to_le32((DBC_DEVICE_REV << 16) | DBC_PRODUCT_ID); + dev_info = (dbc->bcdDevice << 16) | dbc->idProduct; writel(dev_info, &dbc->regs->devinfo2); } @@ -971,7 +971,186 @@ static ssize_t dbc_store(struct device *dev, return count; } +static ssize_t dbc_idVendor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idVendor); +} + +static ssize_t dbc_idVendor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u16 value; + u32 dev_info; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idVendor = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_idProduct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idProduct); +} + +static ssize_t dbc_idProduct_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idProduct = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu)) | value; + writel(dev_info, ptr); + return size; +} + +static ssize_t dbc_bcdDevice_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->bcdDevice); +} + +static ssize_t dbc_bcdDevice_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bcdDevice = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_bInterfaceProtocol_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%02x\n", dbc->bInterfaceProtocol); +} + +static ssize_t dbc_bInterfaceProtocol_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u8 value; + int ret; + + /* bInterfaceProtocol is 8 bit, but xhci only supports values 0 and 1 */ + ret = kstrtou8(buf, 0, &value); + if (ret || value > 1) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bInterfaceProtocol = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffu)) | value; + writel(dev_info, ptr); + + return size; +} + static DEVICE_ATTR_RW(dbc); +static DEVICE_ATTR_RW(dbc_idVendor); +static DEVICE_ATTR_RW(dbc_idProduct); +static DEVICE_ATTR_RW(dbc_bcdDevice); +static DEVICE_ATTR_RW(dbc_bInterfaceProtocol); + +static struct attribute *dbc_dev_attributes[] = { + &dev_attr_dbc.attr, + &dev_attr_dbc_idVendor.attr, + &dev_attr_dbc_idProduct.attr, + &dev_attr_dbc_bcdDevice.attr, + &dev_attr_dbc_bInterfaceProtocol.attr, + NULL +}; + +static const struct attribute_group dbc_dev_attrib_grp = { + .attrs = dbc_dev_attributes, +}; struct xhci_dbc * xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver) @@ -986,6 +1165,10 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * dbc->regs = base; dbc->dev = dev; dbc->driver = driver; + dbc->idProduct = DBC_PRODUCT_ID; + dbc->idVendor = DBC_VENDOR_ID; + dbc->bcdDevice = DBC_DEVICE_REV; + dbc->bInterfaceProtocol = DBC_PROTOCOL; if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE) goto err; @@ -993,7 +1176,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events); spin_lock_init(&dbc->lock); - ret = device_create_file(dev, &dev_attr_dbc); + ret = sysfs_create_group(&dev->kobj, &dbc_dev_attrib_grp); if (ret) goto err; @@ -1012,7 +1195,7 @@ void xhci_dbc_remove(struct xhci_dbc *dbc) xhci_dbc_stop(dbc); /* remove sysfs files */ - device_remove_file(dbc->dev, &dev_attr_dbc); + sysfs_remove_group(&dbc->dev->kobj, &dbc_dev_attrib_grp); kfree(dbc); } diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index ca04192fdab1..51a7ab3ba0ca 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -132,6 +132,10 @@ struct xhci_dbc { struct dbc_str_descs *string; dma_addr_t string_dma; size_t string_size; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 bInterfaceProtocol; enum dbc_state state; struct delayed_work event_work; -- cgit v1.2.3 From 944e7deb4238d10cd16905474574236ac8a8e847 Mon Sep 17 00:00:00 2001 From: Josue David Hernandez Gutierrez Date: Fri, 17 Mar 2023 17:47:10 +0200 Subject: xhci: Avoid PCI MSI/MSIX interrupt reinitialization at resume xhci MSI setup is currently done at the same time as xHC host is started in xhci_run(). This couples the generic xhci code with PCI, and will reconfigure MSI/MSIX interrupts every time xHC is started. Decouple MSI/MSIX configuration from generic xhci code by moving MSI/MSIX part to a PCI specific xhci_pci_run() function overriding xhci_run(). This allows us to remove unnecessay MSI/MSIX reconfiguration done every time PCI xhci resumes from suspend. i.e. remove the xhci_cleanup_msix() call from xhci_resume() and the xhci_try_enale_msi() call in xhci_run() called a bit later by xhci_resume() [minor changes and commit message rewrite -Mathias] Signed-off-by: Josue David Hernandez Gutierrez Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-10-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 15 +++++++++++++++ drivers/usb/host/xhci.c | 8 ++------ drivers/usb/host/xhci.h | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index fb988e4ea924..5f006d199cd6 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -78,14 +78,29 @@ static const char hcd_name[] = "xhci_hcd"; static struct hc_driver __read_mostly xhci_pci_hc_driver; static int xhci_pci_setup(struct usb_hcd *hcd); +static int xhci_pci_run(struct usb_hcd *hcd); static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .reset = xhci_pci_setup, + .start = xhci_pci_run, .update_hub_device = xhci_pci_update_hub_device, }; +static int xhci_pci_run(struct usb_hcd *hcd) +{ + int ret; + + if (usb_hcd_is_primary_hcd(hcd)) { + ret = xhci_try_enable_msi(hcd); + if (ret) + return ret; + } + + return xhci_run(hcd); +} + /* called after powerup, by probe or system-pm "wakeup" */ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6183ce8574b1..d08e2ba744f8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -432,7 +432,7 @@ static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) } } -static int xhci_try_enable_msi(struct usb_hcd *hcd) +int xhci_try_enable_msi(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct pci_dev *pdev; @@ -486,6 +486,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd) hcd->irq = pdev->irq; return 0; } +EXPORT_SYMBOL_GPL(xhci_try_enable_msi); #else @@ -701,10 +702,6 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run"); - ret = xhci_try_enable_msi(hcd); - if (ret) - return ret; - temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -1246,7 +1243,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) spin_unlock_irq(&xhci->lock); if (retval) return retval; - xhci_cleanup_msix(xhci); xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 786002bb35db..26fccc8d9055 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2143,6 +2143,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated); irqreturn_t xhci_irq(struct usb_hcd *hcd); irqreturn_t xhci_msi_irq(int irq, void *hcd); +int xhci_try_enable_msi(struct usb_hcd *hcd); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); int xhci_alloc_tt_info(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, -- cgit v1.2.3 From fabbd95cc47cc412e68d03476367046f4cdbd838 Mon Sep 17 00:00:00 2001 From: Josue David Hernandez Gutierrez Date: Fri, 17 Mar 2023 17:47:11 +0200 Subject: xhci: Move functions to setup msi to xhci-pci Move functions to setup msi from xhci.c to xhci-pci.c to decouple PCI specific code from generic xhci code. No functional changes, functions are an exact copy [commit message rewording -Mathias] Signed-off-by: Josue David Hernandez Gutierrez Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-11-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 129 ++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci-ring.c | 1 + drivers/usb/host/xhci-trace.c | 1 + drivers/usb/host/xhci.c | 134 ------------------------------------------ drivers/usb/host/xhci.h | 1 - 5 files changed, 131 insertions(+), 135 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 5f006d199cd6..2d56b7477fcd 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -88,6 +88,135 @@ static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .update_hub_device = xhci_pci_update_hub_device, }; +/* + * Set up MSI + */ +static int xhci_setup_msi(struct xhci_hcd *xhci) +{ + int ret; + /* + * TODO:Check with MSI Soc for sysdev + */ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "failed to allocate MSI entry"); + return ret; + } + + ret = request_irq(pdev->irq, xhci_msi_irq, + 0, "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "disable MSI interrupt"); + pci_free_irq_vectors(pdev); + } + + return ret; +} + +/* + * Set up MSI-X + */ +static int xhci_setup_msix(struct xhci_hcd *xhci) +{ + int i, ret; + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + /* + * 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. + */ + xhci->msix_count = min(num_online_cpus() + 1, + HCS_MAX_INTRS(xhci->hcs_params1)); + + ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, + PCI_IRQ_MSIX); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Failed to enable MSI-X"); + return ret; + } + + for (i = 0; i < xhci->msix_count; i++) { + ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, + "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) + goto disable_msix; + } + + hcd->msix_enabled = 1; + return ret; + +disable_msix: + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); + while (--i >= 0) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + pci_free_irq_vectors(pdev); + return ret; +} + +static int xhci_try_enable_msi(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev; + int ret; + + /* The xhci platform device has set up IRQs through usb_add_hcd. */ + if (xhci->quirks & XHCI_PLAT) + return 0; + + pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + /* + * Some Fresco Logic host controllers advertise MSI, but fail to + * generate interrupts. Don't even try to enable MSI. + */ + if (xhci->quirks & XHCI_BROKEN_MSI) + goto legacy_irq; + + /* unregister the legacy interrupt */ + if (hcd->irq) + free_irq(hcd->irq, hcd); + hcd->irq = 0; + + ret = xhci_setup_msix(xhci); + if (ret) + /* fall back to msi*/ + ret = xhci_setup_msi(xhci); + + if (!ret) { + hcd->msi_enabled = 1; + return 0; + } + + if (!pdev->irq) { + xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); + return -EINVAL; + } + + legacy_irq: + if (!strlen(hcd->irq_descr)) + snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", + hcd->driver->description, hcd->self.busnum); + + /* fall back to legacy interrupt*/ + ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, + hcd->irq_descr, hcd); + if (ret) { + xhci_err(xhci, "request interrupt %d failed\n", + pdev->irq); + return ret; + } + hcd->irq = pdev->irq; + return 0; +} + static int xhci_pci_run(struct usb_hcd *hcd) { int ret; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index eb788c60c1c0..1ad12d5a4857 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3106,6 +3106,7 @@ irqreturn_t xhci_msi_irq(int irq, void *hcd) { return xhci_irq(hcd); } +EXPORT_SYMBOL_GPL(xhci_msi_irq); /**** Endpoint Ring Operations ****/ diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c index d0070814d1ea..062662d23241 100644 --- a/drivers/usb/host/xhci-trace.c +++ b/drivers/usb/host/xhci-trace.c @@ -12,3 +12,4 @@ #include "xhci-trace.h" EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_quirks); +EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_init); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d08e2ba744f8..9be84e635e1b 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -319,79 +319,6 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) } #ifdef CONFIG_USB_PCI -/* - * Set up MSI - */ -static int xhci_setup_msi(struct xhci_hcd *xhci) -{ - int ret; - /* - * TODO:Check with MSI Soc for sysdev - */ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "failed to allocate MSI entry"); - return ret; - } - - ret = request_irq(pdev->irq, xhci_msi_irq, - 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "disable MSI interrupt"); - pci_free_irq_vectors(pdev); - } - - return ret; -} - -/* - * Set up MSI-X - */ -static int xhci_setup_msix(struct xhci_hcd *xhci) -{ - int i, ret; - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* - * 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. - */ - xhci->msix_count = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); - - ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, - PCI_IRQ_MSIX); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Failed to enable MSI-X"); - return ret; - } - - for (i = 0; i < xhci->msix_count; i++) { - ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, - "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) - goto disable_msix; - } - - hcd->msix_enabled = 1; - return ret; - -disable_msix: - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); - while (--i >= 0) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - pci_free_irq_vectors(pdev); - return ret; -} /* Free any IRQs and disable MSI-X */ static void xhci_cleanup_msix(struct xhci_hcd *xhci) @@ -432,69 +359,8 @@ static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) } } -int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev; - int ret; - - /* The xhci platform device has set up IRQs through usb_add_hcd. */ - if (xhci->quirks & XHCI_PLAT) - return 0; - - pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - /* - * Some Fresco Logic host controllers advertise MSI, but fail to - * generate interrupts. Don't even try to enable MSI. - */ - if (xhci->quirks & XHCI_BROKEN_MSI) - goto legacy_irq; - - /* unregister the legacy interrupt */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = 0; - - ret = xhci_setup_msix(xhci); - if (ret) - /* fall back to msi*/ - ret = xhci_setup_msi(xhci); - - if (!ret) { - hcd->msi_enabled = 1; - return 0; - } - - if (!pdev->irq) { - xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); - return -EINVAL; - } - - legacy_irq: - if (!strlen(hcd->irq_descr)) - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", - hcd->driver->description, hcd->self.busnum); - - /* fall back to legacy interrupt*/ - ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (ret) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); - return ret; - } - hcd->irq = pdev->irq; - return 0; -} -EXPORT_SYMBOL_GPL(xhci_try_enable_msi); - #else -static inline int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - return 0; -} - static inline void xhci_cleanup_msix(struct xhci_hcd *xhci) { } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 26fccc8d9055..786002bb35db 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2143,7 +2143,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated); irqreturn_t xhci_irq(struct usb_hcd *hcd); irqreturn_t xhci_msi_irq(int irq, void *hcd); -int xhci_try_enable_msi(struct usb_hcd *hcd); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); int xhci_alloc_tt_info(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, -- cgit v1.2.3 From ed526ba2ecdfb77bcdbcf4331b8380b646252c20 Mon Sep 17 00:00:00 2001 From: Josue David Hernandez Gutierrez Date: Fri, 17 Mar 2023 17:47:12 +0200 Subject: xhci: move PCI specific MSI/MSIX cleanup away from generic xhci functions Call the PCI specific MSI/MSIX interrupt freeing code from the xhci-pci callbacks instead of generic xhci code, decoupling PCI parts from generic xhci functions. Adds xhci_pci_stop() that overrides xhci_stop() for PCI xHC controllers. This will free MSIX interrupts a bit later in the hc_driver stop callback, but is still earlier than usb core frees "legacy" interrupts, or interrupts for other hosts. Signed-off-by: Josue David Hernandez Gutierrez Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-12-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 12 ++++++++++++ drivers/usb/host/xhci.c | 10 ++++------ drivers/usb/host/xhci.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 2d56b7477fcd..b6cfc028f8f7 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -230,6 +230,16 @@ static int xhci_pci_run(struct usb_hcd *hcd) return xhci_run(hcd); } +static void xhci_pci_stop(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + xhci_stop(hcd); + + if (usb_hcd_is_primary_hcd(hcd)) + xhci_cleanup_msix(xhci); +} + /* called after powerup, by probe or system-pm "wakeup" */ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) { @@ -868,6 +878,7 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); xhci_shutdown(hcd); + xhci_cleanup_msix(xhci); /* Yet another workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) @@ -932,6 +943,7 @@ static int __init xhci_pci_init(void) xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late; xhci_pci_hc_driver.shutdown = xhci_pci_shutdown; #endif + xhci_pci_hc_driver.stop = xhci_pci_stop; return pci_register_driver(&xhci_pci_driver); } module_init(xhci_pci_init); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9be84e635e1b..cf90751125ed 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -321,7 +321,7 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) #ifdef CONFIG_USB_PCI /* Free any IRQs and disable MSI-X */ -static void xhci_cleanup_msix(struct xhci_hcd *xhci) +void xhci_cleanup_msix(struct xhci_hcd *xhci) { struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); @@ -345,6 +345,7 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci) pci_free_irq_vectors(pdev); hcd->msix_enabled = 0; } +EXPORT_SYMBOL_GPL(xhci_cleanup_msix); static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) { @@ -617,7 +618,7 @@ EXPORT_SYMBOL_GPL(xhci_run); * Disable device contexts, disable IRQs, and quiesce the HC. * Reset the HC, finish any completed transactions, and cleanup memory. */ -static void xhci_stop(struct usb_hcd *hcd) +void xhci_stop(struct usb_hcd *hcd) { u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -640,8 +641,6 @@ static void xhci_stop(struct usb_hcd *hcd) xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - /* Deleting Compliance Mode Recovery Timer */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { @@ -668,6 +667,7 @@ static void xhci_stop(struct usb_hcd *hcd) readl(&xhci->op_regs->status)); mutex_unlock(&xhci->mutex); } +EXPORT_SYMBOL_GPL(xhci_stop); /* * Shutdown HC (not bus-specific) @@ -709,8 +709,6 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_shutdown completed - status = %x", readl(&xhci->op_regs->status)); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 786002bb35db..a9111260632c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2125,6 +2125,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us); int xhci_run(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); +void xhci_stop(struct usb_hcd *hcd); void xhci_init_driver(struct hc_driver *drv, const struct xhci_driver_overrides *over); int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, @@ -2143,6 +2144,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated); irqreturn_t xhci_irq(struct usb_hcd *hcd); irqreturn_t xhci_msi_irq(int irq, void *hcd); +void xhci_cleanup_msix(struct xhci_hcd *xhci); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); int xhci_alloc_tt_info(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, -- cgit v1.2.3 From ba47b1aa7640cb98bb3e4c06f37afdbeb5c5d9ba Mon Sep 17 00:00:00 2001 From: Josue David Hernandez Gutierrez Date: Fri, 17 Mar 2023 17:47:13 +0200 Subject: xhci: Move functions to cleanup MSI to xhci-pci Move function to cleanup MSI from xhci.c to xhci-pci.c This is to decouple PCI specific code from generic xhci code. No functional changes, function is an exact copy Signed-off-by: Josue David Hernandez Gutierrez Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-13-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 26 ++++++++++++++++++++++++++ drivers/usb/host/xhci.c | 31 ------------------------------- drivers/usb/host/xhci.h | 1 - 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index b6cfc028f8f7..1e84a842e2a9 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -88,6 +88,32 @@ static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .update_hub_device = xhci_pci_update_hub_device, }; +/* Free any IRQs and disable MSI-X */ +static void xhci_cleanup_msix(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + if (xhci->quirks & XHCI_PLAT) + return; + + /* return if using legacy interrupt */ + if (hcd->irq > 0) + return; + + if (hcd->msix_enabled) { + int i; + + for (i = 0; i < xhci->msix_count; i++) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + } else { + free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); + } + + pci_free_irq_vectors(pdev); + hcd->msix_enabled = 0; +} + /* * Set up MSI */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index cf90751125ed..874dca6dec69 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -320,33 +320,6 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) #ifdef CONFIG_USB_PCI -/* Free any IRQs and disable MSI-X */ -void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - if (xhci->quirks & XHCI_PLAT) - return; - - /* return if using legacy interrupt */ - if (hcd->irq > 0) - return; - - if (hcd->msix_enabled) { - int i; - - for (i = 0; i < xhci->msix_count; i++) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - } else { - free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); - } - - pci_free_irq_vectors(pdev); - hcd->msix_enabled = 0; -} -EXPORT_SYMBOL_GPL(xhci_cleanup_msix); - static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) { struct usb_hcd *hcd = xhci_to_hcd(xhci); @@ -362,10 +335,6 @@ static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) #else -static inline void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ -} - static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci) { } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a9111260632c..08d721921b7b 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2144,7 +2144,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated); irqreturn_t xhci_irq(struct usb_hcd *hcd); irqreturn_t xhci_msi_irq(int irq, void *hcd); -void xhci_cleanup_msix(struct xhci_hcd *xhci); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); int xhci_alloc_tt_info(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, -- cgit v1.2.3 From 0c540438c632005ce57f45436a25cafa499d977f Mon Sep 17 00:00:00 2001 From: Josue David Hernandez Gutierrez Date: Fri, 17 Mar 2023 17:47:14 +0200 Subject: xhci: Call MSI sync function from xhci-pci instead of generic xhci code Call function to sync MSI interrupts from pci specific xhci_pci_suspend() function in xhci-pci.c instead of from generic xhci_suspend() [commit message rewording -Mathias] Signed-off-by: Josue David Hernandez Gutierrez Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-14-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 5 +++++ drivers/usb/host/xhci.c | 7 ++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 1e84a842e2a9..ef55cadc8d14 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -779,6 +779,7 @@ static void xhci_sparse_control_quirk(struct usb_hcd *hcd) writel(reg, hcd->regs + SPARSE_CNTL_ENABLE); } +extern void xhci_msix_sync_irqs(struct xhci_hcd *xhci); static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -802,6 +803,10 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) xhci_sparse_control_quirk(hcd); ret = xhci_suspend(xhci, do_wakeup); + + /* synchronize irq when using MSI-X */ + xhci_msix_sync_irqs(xhci); + if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED)) xhci_ssic_port_unused_quirk(hcd, false); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 874dca6dec69..c0fb34ccd187 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -320,7 +320,7 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) #ifdef CONFIG_USB_PCI -static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) +void xhci_msix_sync_irqs(struct xhci_hcd *xhci) { struct usb_hcd *hcd = xhci_to_hcd(xhci); @@ -332,6 +332,7 @@ static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) synchronize_irq(pci_irq_vector(pdev, i)); } } +EXPORT_SYMBOL_GPL(xhci_msix_sync_irqs); #else @@ -969,10 +970,6 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) __func__); } - /* step 5: remove core well power */ - /* synchronize irq when using MSI-X */ - xhci_msix_sync_irqs(xhci); - return rc; } EXPORT_SYMBOL_GPL(xhci_suspend); -- cgit v1.2.3 From 9abe15d55dccec92d361705741ee80f13b4d0888 Mon Sep 17 00:00:00 2001 From: Josue David Hernandez Gutierrez Date: Fri, 17 Mar 2023 17:47:15 +0200 Subject: xhci: Move xhci MSI sync function to to xhci-pci Move function to sync MSI from xhci.c to xhci-pci.c to decouple PCI specific code from generic xhci code. No functional changes, function is an exact copy [commit message rewording -Mathias] Signed-off-by: Josue David Hernandez Gutierrez Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20230317154715.535523-15-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 14 +++++++++++++- drivers/usb/host/xhci.c | 24 ------------------------ 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index ef55cadc8d14..a53ecc8ff8c5 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -88,6 +88,19 @@ static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .update_hub_device = xhci_pci_update_hub_device, }; +static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + + if (hcd->msix_enabled) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + int i; + + for (i = 0; i < xhci->msix_count; i++) + synchronize_irq(pci_irq_vector(pdev, i)); + } +} + /* Free any IRQs and disable MSI-X */ static void xhci_cleanup_msix(struct xhci_hcd *xhci) { @@ -779,7 +792,6 @@ static void xhci_sparse_control_quirk(struct usb_hcd *hcd) writel(reg, hcd->regs + SPARSE_CNTL_ENABLE); } -extern void xhci_msix_sync_irqs(struct xhci_hcd *xhci); static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c0fb34ccd187..cc9fde8cba78 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -318,30 +318,6 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) return 0; } -#ifdef CONFIG_USB_PCI - -void xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - - if (hcd->msix_enabled) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int i; - - for (i = 0; i < xhci->msix_count; i++) - synchronize_irq(pci_irq_vector(pdev, i)); - } -} -EXPORT_SYMBOL_GPL(xhci_msix_sync_irqs); - -#else - -static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ -} - -#endif - static void compliance_mode_recovery(struct timer_list *t) { struct xhci_hcd *xhci; -- cgit v1.2.3 From a0c7f9f659825e9761f8db423001de4e5147b60c Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Fri, 17 Mar 2023 14:16:51 +0800 Subject: usb: chipidea: debug: remove redundant 'role' debug file Two 'role' file exist in different position but with totally same function. 1. /sys/devices/platform/soc@0/xxxxxxxx.usb/ci_hdrc.0/role 2. /sys/kernel/debug/usb/ci_hdrc.0/role This will remove the 2rd redundant 'role' debug file (under debugfs) and keep the one which is more closer to user. Acked-by: Peter Chen Signed-off-by: Xu Yang Link: https://lore.kernel.org/r/20230317061651.2457567-1-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/debug.c | 55 -------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index bbc610e5bd69..e72c43615d77 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -247,60 +247,6 @@ static int ci_otg_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(ci_otg); -static int ci_role_show(struct seq_file *s, void *data) -{ - struct ci_hdrc *ci = s->private; - - if (ci->role != CI_ROLE_END) - seq_printf(s, "%s\n", ci_role(ci)->name); - - return 0; -} - -static ssize_t ci_role_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct ci_hdrc *ci = s->private; - enum ci_role role; - char buf[8]; - int ret; - - if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) - if (ci->roles[role] && - !strncmp(buf, ci->roles[role]->name, - strlen(ci->roles[role]->name))) - break; - - if (role == CI_ROLE_END || role == ci->role) - return -EINVAL; - - pm_runtime_get_sync(ci->dev); - disable_irq(ci->irq); - ci_role_stop(ci); - ret = ci_role_start(ci, role); - enable_irq(ci->irq); - pm_runtime_put_sync(ci->dev); - - return ret ? ret : count; -} - -static int ci_role_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_role_show, inode->i_private); -} - -static const struct file_operations ci_role_fops = { - .open = ci_role_open, - .write = ci_role_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ci_registers_show(struct seq_file *s, void *unused) { struct ci_hdrc *ci = s->private; @@ -354,7 +300,6 @@ void dbg_create_files(struct ci_hdrc *ci) if (ci_otg_is_fsm_mode(ci)) debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops); - debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops); debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops); } -- cgit v1.2.3 From 1ad715857018893776fd61706da5b2188d67c650 Mon Sep 17 00:00:00 2001 From: Yu Zhe Date: Thu, 16 Mar 2023 16:23:38 +0800 Subject: usb: typec: tcpm: remove unnecessary (void*) conversions Pointer variables of void * type do not require type cast. Signed-off-by: Yu Zhe Acked-by: Heikki Krogerus Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230316082338.18388-1-yuzhe@nfschina.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/fusb302.c | 2 +- drivers/usb/typec/tcpm/tcpm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 592b0aec782f..62ba53357612 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -190,7 +190,7 @@ static void fusb302_log(struct fusb302_chip *chip, const char *fmt, ...) static int fusb302_debug_show(struct seq_file *s, void *v) { - struct fusb302_chip *chip = (struct fusb302_chip *)s->private; + struct fusb302_chip *chip = s->private; int tail; mutex_lock(&chip->logbuffer_lock); diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a0d943d78580..e8bfe3f57ab4 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -737,7 +737,7 @@ static void tcpm_log_source_caps(struct tcpm_port *port) static int tcpm_debug_show(struct seq_file *s, void *v) { - struct tcpm_port *port = (struct tcpm_port *)s->private; + struct tcpm_port *port = s->private; int tail; mutex_lock(&port->logbuffer_lock); -- cgit v1.2.3 From a88b3c9eef83b605ef7016471a56db9129ae2529 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 19 Mar 2023 11:59:10 -0400 Subject: usb: gadget: udc: remove unused usbf_ep_dma_reg_clrset function clang with W=1 reports drivers/usb/gadget/udc/renesas_usbf.c:548:20: error: unused function 'usbf_ep_dma_reg_clrset' [-Werror,-Wunused-function] static inline void usbf_ep_dma_reg_clrset(struct usbf_ep *ep, uint offset, ^ This function is not used, so remove it. Signed-off-by: Tom Rix Acked-by: Herve Codina Link: https://lore.kernel.org/r/20230319155910.1706294-1-trix@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/renesas_usbf.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c index cb23e62e8a87..84ac9fe4ce7f 100644 --- a/drivers/usb/gadget/udc/renesas_usbf.c +++ b/drivers/usb/gadget/udc/renesas_usbf.c @@ -545,17 +545,6 @@ static inline void usbf_ep_dma_reg_bitclr(struct usbf_ep *ep, uint offset, usbf_ep_dma_reg_writel(ep, offset, tmp); } -static inline void usbf_ep_dma_reg_clrset(struct usbf_ep *ep, uint offset, - u32 clr, u32 set) -{ - u32 tmp; - - tmp = usbf_ep_dma_reg_readl(ep, offset); - tmp &= ~clr; - tmp |= set; - usbf_ep_dma_reg_writel(ep, offset, tmp); -} - static void usbf_ep0_send_null(struct usbf_ep *ep0, bool is_data1) { u32 set; -- cgit v1.2.3 From 2271b2727aeca2e09d07f63bc61dc9757c3a5a3c Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 19 Mar 2023 10:10:53 -0400 Subject: usb: typec: tcpci_mt6360: remove unused mt6360_tcpc_read16 function clang with W=1 reports drivers/usb/typec/tcpm/tcpci_mt6360.c:46:19: error: unused function 'mt6360_tcpc_read16' [-Werror,-Wunused-function] static inline int mt6360_tcpc_read16(struct regmap *regmap, ^ This function is not used, so remove it. Signed-off-by: Tom Rix Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20230319141053.1703937-1-trix@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci_mt6360.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c index 1b7c31278ebb..6fa8fd5c8041 100644 --- a/drivers/usb/typec/tcpm/tcpci_mt6360.c +++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c @@ -43,12 +43,6 @@ struct mt6360_tcpc_info { int irq; }; -static inline int mt6360_tcpc_read16(struct regmap *regmap, - unsigned int reg, u16 *val) -{ - return regmap_raw_read(regmap, reg, val, sizeof(u16)); -} - static inline int mt6360_tcpc_write16(struct regmap *regmap, unsigned int reg, u16 val) { -- cgit v1.2.3 From 766eae980611f5377ee54518f58da11b4d866f59 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 19 Mar 2023 09:37:32 -0400 Subject: usb: typec: tipd: remove unused tps6598x_write16,32 functions clang with W=1 reports drivers/usb/typec/tipd/core.c:180:19: error: unused function 'tps6598x_write16' [-Werror,-Wunused-function] static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val) ^ drivers/usb/typec/tipd/core.c:185:19: error: unused function 'tps6598x_write32' [-Werror,-Wunused-function] static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val) ^ These static functions are not used, so remove them. Signed-off-by: Tom Rix Reviewed-by: Heikki Krogerus Reviewed-by: Jun Nie Link: https://lore.kernel.org/r/20230319133732.1702841-1-trix@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 485b90c13078..af6ecb54b52c 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -177,16 +177,6 @@ static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val) return tps6598x_block_read(tps, reg, val, sizeof(u64)); } -static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val) -{ - return tps6598x_block_write(tps, reg, &val, sizeof(u16)); -} - -static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val) -{ - return tps6598x_block_write(tps, reg, &val, sizeof(u32)); -} - static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val) { return tps6598x_block_write(tps, reg, &val, sizeof(u64)); -- cgit v1.2.3 From 8c1b63b3c2358024181674e0ada901d50b919d3e Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Tue, 21 Mar 2023 14:12:55 -0400 Subject: USB: serial: quatech2: remove unused qt2_setdevice function clang with W=1 reports drivers/usb/serial/quatech2.c:179:19: error: unused function 'qt2_setdevice' [-Werror,-Wunused-function] static inline int qt2_setdevice(struct usb_device *dev, u8 *data) ^ This function is not used, so remove it. Signed-off-by: Tom Rix Link: https://lore.kernel.org/r/20230321181255.1825963-1-trix@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/quatech2.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 6fca40ace83a..fee581409bf6 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -176,14 +176,6 @@ static inline int qt2_control_msg(struct usb_device *dev, NULL, 0, QT2_USB_TIMEOUT); } -static inline int qt2_setdevice(struct usb_device *dev, u8 *data) -{ - u16 x = ((u16) (data[1] << 8) | (u16) (data[0])); - - return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0); -} - - static inline int qt2_getregister(struct usb_device *dev, u8 uart, u8 reg, -- cgit v1.2.3 From 092a2a78e618ee8ebd5c86cac61a404d0bec3310 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 23 Mar 2023 11:55:30 +0800 Subject: dt-bindings: usb: snps,dwc3: correct i.MX8MQ support The previous i.MX8MQ support breaks rockchip,dwc3 support, so use select to restrict i.MX8MQ support and avoid break others. Fixes: 3754c41c7686 ("dt-bindings: usb: snps,dwc3: support i.MX8MQ") Signed-off-by: Peng Fan Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230323035531.3808192-1-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml | 48 ++++++++++++++++++++++ .../devicetree/bindings/usb/snps,dwc3.yaml | 12 +++--- 2 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml diff --git a/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml b/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml new file mode 100644 index 000000000000..50569d3ee767 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/fsl,imx8mq-dwc3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP iMX8MQ Soc USB Controller + +maintainers: + - Li Jun + - Peng Fan + +select: + properties: + compatible: + contains: + enum: + - fsl,imx8mq-dwc3 + required: + - compatible + +properties: + compatible: + items: + - const: fsl,imx8mq-dwc3 + - const: snps,dwc3 + +allOf: + - $ref: snps,dwc3.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + usb_dwc3_1: usb@38200000 { + compatible = "fsl,imx8mq-dwc3", "snps,dwc3"; + reg = <0x38200000 0x10000>; + clocks = <&clk IMX8MQ_CLK_USB2_CTRL_ROOT>, + <&clk IMX8MQ_CLK_USB_CORE_REF>, + <&clk IMX8MQ_CLK_32K>; + clock-names = "bus_early", "ref", "suspend"; + interrupts = ; + phys = <&usb3_phy1>, <&usb3_phy1>; + phy-names = "usb2-phy", "usb3-phy"; + }; diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index 16c7d06c9172..c167fd577cae 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -30,13 +30,11 @@ allOf: properties: compatible: - oneOf: - - items: - - const: fsl,imx8mq-dwc3 - - const: snps,dwc3 - - const: snps,dwc3 - - const: synopsys,dwc3 - deprecated: true + contains: + oneOf: + - const: snps,dwc3 + - const: synopsys,dwc3 + deprecated: true reg: maxItems: 1 -- cgit v1.2.3 From fcd3f50845be909c9e0f8ac402874a2fb4b09c6c Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 23 Mar 2023 11:55:31 +0800 Subject: arm64: dts: imx8mq: drop usb3-resume-missing-cas from usb The property is NXP downstream property that there is no user in upstream, drop it. Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230323035531.3808192-2-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/freescale/imx8mq.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi index 98fbba4c99a9..aa4f4f28ca9f 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi @@ -1445,7 +1445,6 @@ phys = <&usb3_phy0>, <&usb3_phy0>; phy-names = "usb2-phy", "usb3-phy"; power-domains = <&pgc_otg1>; - usb3-resume-missing-cas; status = "disabled"; }; @@ -1477,7 +1476,6 @@ phys = <&usb3_phy1>, <&usb3_phy1>; phy-names = "usb2-phy", "usb3-phy"; power-domains = <&pgc_otg2>; - usb3-resume-missing-cas; status = "disabled"; }; -- cgit v1.2.3 From fe70f2c83e28df6b18e77a4de092b5313e26ca62 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:18 +0100 Subject: usb: phy: ab8500: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-ab8500-usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 4c52ba96f17e..408f47e39025 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -965,7 +965,7 @@ static int ab8500_usb_probe(struct platform_device *pdev) return 0; } -static int ab8500_usb_remove(struct platform_device *pdev) +static void ab8500_usb_remove(struct platform_device *pdev) { struct ab8500_usb *ab = platform_get_drvdata(pdev); @@ -977,8 +977,6 @@ static int ab8500_usb_remove(struct platform_device *pdev) ab8500_usb_host_phy_dis(ab); else if (ab->mode == USB_PERIPHERAL) ab8500_usb_peri_phy_dis(ab); - - return 0; } static const struct platform_device_id ab8500_usb_devtype[] = { @@ -989,7 +987,7 @@ MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype); static struct platform_driver ab8500_usb_driver = { .probe = ab8500_usb_probe, - .remove = ab8500_usb_remove, + .remove_new = ab8500_usb_remove, .id_table = ab8500_usb_devtype, .driver = { .name = "abx5x0-usb", -- cgit v1.2.3 From c123905f5c563c1b43ef5a745b8f403e5e8e1879 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:19 +0100 Subject: usb: phy: am335x: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-3-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-am335x.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 8524475d942d..e39665cf4b4a 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -82,12 +82,11 @@ static int am335x_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&am_phy->usb_phy_gen.phy); } -static int am335x_phy_remove(struct platform_device *pdev) +static void am335x_phy_remove(struct platform_device *pdev) { struct am335x_phy *am_phy = platform_get_drvdata(pdev); usb_remove_phy(&am_phy->usb_phy_gen.phy); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -134,7 +133,7 @@ MODULE_DEVICE_TABLE(of, am335x_phy_ids); static struct platform_driver am335x_phy_driver = { .probe = am335x_phy_probe, - .remove = am335x_phy_remove, + .remove_new = am335x_phy_remove, .driver = { .name = "am335x-phy-driver", .pm = &am335x_pm_ops, -- cgit v1.2.3 From ba1e43522f3290165ef9e881c3db7b0adcc3a1f0 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:20 +0100 Subject: usb: phy: fsl: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-4-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-fsl-usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 972704262b02..79617bb0a70e 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -983,7 +983,7 @@ static int fsl_otg_probe(struct platform_device *pdev) return ret; } -static int fsl_otg_remove(struct platform_device *pdev) +static void fsl_otg_remove(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -998,13 +998,11 @@ static int fsl_otg_remove(struct platform_device *pdev) if (pdata->exit) pdata->exit(pdev); - - return 0; } struct platform_driver fsl_otg_driver = { .probe = fsl_otg_probe, - .remove = fsl_otg_remove, + .remove_new = fsl_otg_remove, .driver = { .name = driver_name, .owner = THIS_MODULE, -- cgit v1.2.3 From a8095f9c5238070366e8813f6c6e330de9d2d32b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:21 +0100 Subject: usb: phy: generic: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-5-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-generic.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index c1309ea24a52..770081b828a4 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -330,13 +330,11 @@ static int usb_phy_generic_probe(struct platform_device *pdev) return 0; } -static int usb_phy_generic_remove(struct platform_device *pdev) +static void usb_phy_generic_remove(struct platform_device *pdev) { struct usb_phy_generic *nop = platform_get_drvdata(pdev); usb_remove_phy(&nop->phy); - - return 0; } static const struct of_device_id nop_xceiv_dt_ids[] = { @@ -348,7 +346,7 @@ MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); static struct platform_driver usb_phy_generic_driver = { .probe = usb_phy_generic_probe, - .remove = usb_phy_generic_remove, + .remove_new = usb_phy_generic_remove, .driver = { .name = "usb_phy_generic", .of_match_table = nop_xceiv_dt_ids, -- cgit v1.2.3 From 399d011772afb910fbf60bc0cea93fccd44d1ecb Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:22 +0100 Subject: usb: phy: gpio-vbus: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20230319092428.283054-6-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-gpio-vbus-usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 12dfeff7de3d..817c242a76ca 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -325,7 +325,7 @@ static int gpio_vbus_probe(struct platform_device *pdev) return 0; } -static int gpio_vbus_remove(struct platform_device *pdev) +static void gpio_vbus_remove(struct platform_device *pdev) { struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); @@ -333,8 +333,6 @@ static int gpio_vbus_remove(struct platform_device *pdev) cancel_delayed_work_sync(&gpio_vbus->work); usb_remove_phy(&gpio_vbus->phy); - - return 0; } #ifdef CONFIG_PM @@ -386,7 +384,7 @@ static struct platform_driver gpio_vbus_driver = { .of_match_table = gpio_vbus_of_match, }, .probe = gpio_vbus_probe, - .remove = gpio_vbus_remove, + .remove_new = gpio_vbus_remove, }; module_platform_driver(gpio_vbus_driver); -- cgit v1.2.3 From 744e004bf2be5daf56332369c8f95da77195550a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:23 +0100 Subject: usb: phy: keystone: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-7-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-keystone.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index f75912279b39..bd9a98ad1b30 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -88,13 +88,11 @@ static int keystone_usbphy_probe(struct platform_device *pdev) return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); } -static int keystone_usbphy_remove(struct platform_device *pdev) +static void keystone_usbphy_remove(struct platform_device *pdev) { struct keystone_usbphy *k_phy = platform_get_drvdata(pdev); usb_remove_phy(&k_phy->usb_phy_gen.phy); - - return 0; } static const struct of_device_id keystone_usbphy_ids[] = { @@ -105,7 +103,7 @@ MODULE_DEVICE_TABLE(of, keystone_usbphy_ids); static struct platform_driver keystone_usbphy_driver = { .probe = keystone_usbphy_probe, - .remove = keystone_usbphy_remove, + .remove_new = keystone_usbphy_remove, .driver = { .name = "keystone-usbphy", .of_match_table = keystone_usbphy_ids, -- cgit v1.2.3 From 25b979e46f0bda69e100b9cb01ac63bfbd373111 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:24 +0100 Subject: usb: phy: mv: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-8-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-mv-usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 86503b7d695c..df7c27474a75 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -644,7 +644,7 @@ static const struct attribute_group *mv_otg_groups[] = { NULL, }; -static int mv_otg_remove(struct platform_device *pdev) +static void mv_otg_remove(struct platform_device *pdev) { struct mv_otg *mvotg = platform_get_drvdata(pdev); @@ -654,8 +654,6 @@ static int mv_otg_remove(struct platform_device *pdev) mv_otg_disable(mvotg); usb_remove_phy(&mvotg->phy); - - return 0; } static int mv_otg_probe(struct platform_device *pdev) @@ -869,7 +867,7 @@ static int mv_otg_resume(struct platform_device *pdev) static struct platform_driver mv_otg_driver = { .probe = mv_otg_probe, - .remove = mv_otg_remove, + .remove_new = mv_otg_remove, .driver = { .name = driver_name, .dev_groups = mv_otg_groups, -- cgit v1.2.3 From 8471b0fa61947f27eeba1b012a8bfbf78bd6ab59 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:25 +0100 Subject: usb: phy: mxs: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20230319092428.283054-9-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-mxs-usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 0a8e3fd699ca..e1a2b2ea098b 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -801,13 +801,11 @@ static int mxs_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&mxs_phy->phy); } -static int mxs_phy_remove(struct platform_device *pdev) +static void mxs_phy_remove(struct platform_device *pdev) { struct mxs_phy *mxs_phy = platform_get_drvdata(pdev); usb_remove_phy(&mxs_phy->phy); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -853,7 +851,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 = mxs_phy_remove, + .remove_new = mxs_phy_remove, .driver = { .name = DRIVER_NAME, .of_match_table = mxs_phy_dt_ids, -- cgit v1.2.3 From e5c1b349efc132553b7e7542f7296a31184f4233 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:26 +0100 Subject: usb: phy: tahvo: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-10-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-tahvo.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index f2d2cc586c5b..47562d49dfc1 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -412,7 +412,7 @@ err_disable_clk: return ret; } -static int tahvo_usb_remove(struct platform_device *pdev) +static void tahvo_usb_remove(struct platform_device *pdev) { struct tahvo_usb *tu = platform_get_drvdata(pdev); @@ -420,13 +420,11 @@ static int tahvo_usb_remove(struct platform_device *pdev) usb_remove_phy(&tu->phy); if (!IS_ERR(tu->ick)) clk_disable(tu->ick); - - return 0; } static struct platform_driver tahvo_usb_driver = { .probe = tahvo_usb_probe, - .remove = tahvo_usb_remove, + .remove_new = tahvo_usb_remove, .driver = { .name = "tahvo-usb", .dev_groups = tahvo_groups, -- cgit v1.2.3 From d95a0ce2fc03322440f404a2971ec528a56af345 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:27 +0100 Subject: usb: phy: tegra: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-11-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-tegra-usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 4d207ce3ddf2..8b2ff3a8882d 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -1486,18 +1486,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&tegra_phy->u_phy); } -static int tegra_usb_phy_remove(struct platform_device *pdev) +static void tegra_usb_phy_remove(struct platform_device *pdev) { struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev); usb_remove_phy(&tegra_phy->u_phy); - - return 0; } static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, - .remove = tegra_usb_phy_remove, + .remove_new = tegra_usb_phy_remove, .driver = { .name = "tegra-phy", .of_match_table = tegra_usb_phy_id_table, -- cgit v1.2.3 From 17eb81908084047c8b08ae99863dccada5efd5e2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 19 Mar 2023 10:24:28 +0100 Subject: usb: phy: twl6030: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230319092428.283054-12-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-twl6030-usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index ab3c38a7d8ac..c3ce6b1054f1 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -409,7 +409,7 @@ err_put_regulator: return status; } -static int twl6030_usb_remove(struct platform_device *pdev) +static void twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); @@ -422,8 +422,6 @@ static int twl6030_usb_remove(struct platform_device *pdev) free_irq(twl->irq2, twl); regulator_put(twl->usb3v3); cancel_work_sync(&twl->set_vbus_work); - - return 0; } static const struct of_device_id twl6030_usb_id_table[] = { @@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table); static struct platform_driver twl6030_usb_driver = { .probe = twl6030_usb_probe, - .remove = twl6030_usb_remove, + .remove_new = twl6030_usb_remove, .driver = { .name = "twl6030_usb", .of_match_table = of_match_ptr(twl6030_usb_id_table), -- cgit v1.2.3 From 62b5412b1f4afab27d8df90ddcabb8e1e11a00ad Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 21 Mar 2023 14:21:41 +0100 Subject: usb: typec: ucsi: add PMIC Glink UCSI driver Introduce the UCSI PMIC Glink aux driver that communicates with the aDSP firmware with the UCSI protocol which handles the USB-C Port(s) Power Delivery. The UCSI messaging is necessary on newer Qualcomm SoCs to provide USB role switch and altmode notifications. Reviewed-by: Heikki Krogerus Signed-off-by: Neil Armstrong Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230130-topic-sm8450-upstream-pmic-glink-v5-1-552f3b721f9e@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/Kconfig | 10 ++ drivers/usb/typec/ucsi/Makefile | 1 + drivers/usb/typec/ucsi/ucsi_glink.c | 345 ++++++++++++++++++++++++++++++++++++ 3 files changed, 356 insertions(+) create mode 100644 drivers/usb/typec/ucsi/ucsi_glink.c diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 8f9c4b9f31f7..b3bb0191987e 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -58,4 +58,14 @@ config UCSI_STM32G0 To compile the driver as a module, choose M here: the module will be called ucsi_stm32g0. +config UCSI_PMIC_GLINK + tristate "UCSI Qualcomm PMIC GLINK Interface Driver" + depends on QCOM_PMIC_GLINK + help + This driver enables UCSI support on platforms that expose UCSI + interface as PMIC GLINK device. + + To compile the driver as a module, choose M here: the module will be + called ucsi_glink. + endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index 480d533d762f..77f09e136956 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -18,3 +18,4 @@ endif obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o +obj-$(CONFIG_UCSI_PMIC_GLINK) += ucsi_glink.o diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c new file mode 100644 index 000000000000..b454a5159896 --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include "ucsi.h" + +#define UCSI_BUF_SIZE 48 + +#define MSG_TYPE_REQ_RESP 1 +#define UCSI_BUF_SIZE 48 + +#define UC_NOTIFY_RECEIVER_UCSI 0x0 +#define UC_UCSI_READ_BUF_REQ 0x11 +#define UC_UCSI_WRITE_BUF_REQ 0x12 +#define UC_UCSI_USBC_NOTIFY_IND 0x13 + +struct ucsi_read_buf_req_msg { + struct pmic_glink_hdr hdr; +}; + +struct ucsi_read_buf_resp_msg { + struct pmic_glink_hdr hdr; + u8 buf[UCSI_BUF_SIZE]; + u32 ret_code; +}; + +struct ucsi_write_buf_req_msg { + struct pmic_glink_hdr hdr; + u8 buf[UCSI_BUF_SIZE]; + u32 reserved; +}; + +struct ucsi_write_buf_resp_msg { + struct pmic_glink_hdr hdr; + u32 ret_code; +}; + +struct ucsi_notify_ind_msg { + struct pmic_glink_hdr hdr; + u32 notification; + u32 receiver; + u32 reserved; +}; + +struct pmic_glink_ucsi { + struct device *dev; + + struct pmic_glink_client *client; + + struct ucsi *ucsi; + struct completion read_ack; + struct completion write_ack; + struct completion sync_ack; + bool sync_pending; + struct mutex lock; /* protects concurrent access to PMIC Glink interface */ + + int sync_val; + + struct work_struct notify_work; + struct work_struct register_work; + + u8 read_buf[UCSI_BUF_SIZE]; +}; + +static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, + void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + struct ucsi_read_buf_req_msg req = {}; + unsigned long left; + int ret; + + req.hdr.owner = PMIC_GLINK_OWNER_USBC; + req.hdr.type = MSG_TYPE_REQ_RESP; + req.hdr.opcode = UC_UCSI_READ_BUF_REQ; + + mutex_lock(&ucsi->lock); + memset(ucsi->read_buf, 0, sizeof(ucsi->read_buf)); + reinit_completion(&ucsi->read_ack); + + ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); + if (ret < 0) { + dev_err(ucsi->dev, "failed to send UCSI read request: %d\n", ret); + goto out_unlock; + } + + left = wait_for_completion_timeout(&ucsi->read_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI read response\n"); + ret = -ETIMEDOUT; + goto out_unlock; + } + + memcpy(val, &ucsi->read_buf[offset], val_len); + ret = 0; + +out_unlock: + mutex_unlock(&ucsi->lock); + + return ret; +} + +static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct ucsi_write_buf_req_msg req = {}; + unsigned long left; + int ret; + + req.hdr.owner = PMIC_GLINK_OWNER_USBC; + req.hdr.type = MSG_TYPE_REQ_RESP; + req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ; + memcpy(&req.buf[offset], val, val_len); + + reinit_completion(&ucsi->write_ack); + + ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); + if (ret < 0) { + dev_err(ucsi->dev, "failed to send UCSI write request: %d\n", ret); + return ret; + } + + left = wait_for_completion_timeout(&ucsi->write_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI write response\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int pmic_glink_ucsi_async_write(struct ucsi *__ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + int ret; + + mutex_lock(&ucsi->lock); + ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + mutex_unlock(&ucsi->lock); + + return ret; +} + +static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + unsigned long left; + int ret; + + /* TOFIX: Downstream forces recipient to CON when UCSI_GET_ALTERNATE_MODES command */ + + mutex_lock(&ucsi->lock); + ucsi->sync_val = 0; + reinit_completion(&ucsi->sync_ack); + ucsi->sync_pending = true; + ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + mutex_unlock(&ucsi->lock); + + left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI sync write response\n"); + ret = -ETIMEDOUT; + } else if (ucsi->sync_val) { + dev_err(ucsi->dev, "sync write returned: %d\n", ucsi->sync_val); + } + + ucsi->sync_pending = false; + + return ret; +} + +static const struct ucsi_operations pmic_glink_ucsi_ops = { + .read = pmic_glink_ucsi_read, + .sync_write = pmic_glink_ucsi_sync_write, + .async_write = pmic_glink_ucsi_async_write +}; + +static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) +{ + const struct ucsi_read_buf_resp_msg *resp = data; + + if (resp->ret_code) + return; + + memcpy(ucsi->read_buf, resp->buf, UCSI_BUF_SIZE); + complete(&ucsi->read_ack); +} + +static void pmic_glink_ucsi_write_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) +{ + const struct ucsi_write_buf_resp_msg *resp = data; + + if (resp->ret_code) + return; + + ucsi->sync_val = resp->ret_code; + complete(&ucsi->write_ack); +} + +static void pmic_glink_ucsi_notify(struct work_struct *work) +{ + struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, notify_work); + unsigned int con_num; + u32 cci; + int ret; + + ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_CCI, &cci, sizeof(cci)); + if (ret) { + dev_err(ucsi->dev, "failed to read CCI on notification\n"); + return; + } + + con_num = UCSI_CCI_CONNECTOR(cci); + if (con_num) + ucsi_connector_change(ucsi->ucsi, con_num); + + if (ucsi->sync_pending && cci & UCSI_CCI_BUSY) { + ucsi->sync_val = -EBUSY; + complete(&ucsi->sync_ack); + } else if (ucsi->sync_pending && + (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) { + complete(&ucsi->sync_ack); + } +} + +static void pmic_glink_ucsi_register(struct work_struct *work) +{ + struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); + + ucsi_register(ucsi->ucsi); +} + +static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) +{ + struct pmic_glink_ucsi *ucsi = priv; + const struct pmic_glink_hdr *hdr = data; + + switch (hdr->opcode) { + case UC_UCSI_READ_BUF_REQ: + pmic_glink_ucsi_read_ack(ucsi, data, len); + break; + case UC_UCSI_WRITE_BUF_REQ: + pmic_glink_ucsi_write_ack(ucsi, data, len); + break; + case UC_UCSI_USBC_NOTIFY_IND: + schedule_work(&ucsi->notify_work); + break; + }; +} + +static void pmic_glink_ucsi_pdr_notify(void *priv, int state) +{ + struct pmic_glink_ucsi *ucsi = priv; + + if (state == SERVREG_SERVICE_STATE_UP) + schedule_work(&ucsi->register_work); + else if (state == SERVREG_SERVICE_STATE_DOWN) + ucsi_unregister(ucsi->ucsi); +} + +static void pmic_glink_ucsi_destroy(void *data) +{ + struct pmic_glink_ucsi *ucsi = data; + + /* Protect to make sure we're not in a middle of a transaction from a glink callback */ + mutex_lock(&ucsi->lock); + ucsi_destroy(ucsi->ucsi); + mutex_unlock(&ucsi->lock); +} + +static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct pmic_glink_ucsi *ucsi; + struct device *dev = &adev->dev; + int ret; + + ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL); + if (!ucsi) + return -ENOMEM; + + ucsi->dev = dev; + dev_set_drvdata(dev, ucsi); + + INIT_WORK(&ucsi->notify_work, pmic_glink_ucsi_notify); + INIT_WORK(&ucsi->register_work, pmic_glink_ucsi_register); + init_completion(&ucsi->read_ack); + init_completion(&ucsi->write_ack); + init_completion(&ucsi->sync_ack); + mutex_init(&ucsi->lock); + + ucsi->ucsi = ucsi_create(dev, &pmic_glink_ucsi_ops); + if (IS_ERR(ucsi->ucsi)) + return PTR_ERR(ucsi->ucsi); + + /* Make sure we destroy *after* pmic_glink unregister */ + ret = devm_add_action_or_reset(dev, pmic_glink_ucsi_destroy, ucsi); + if (ret) + return ret; + + ucsi_set_drvdata(ucsi->ucsi, ucsi); + + ucsi->client = devm_pmic_glink_register_client(dev, + PMIC_GLINK_OWNER_USBC, + pmic_glink_ucsi_callback, + pmic_glink_ucsi_pdr_notify, + ucsi); + return PTR_ERR_OR_ZERO(ucsi->client); +} + +static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) +{ + struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev); + + /* Unregister first to stop having read & writes */ + ucsi_unregister(ucsi->ucsi); +} + +static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = { + { .name = "pmic_glink.ucsi", }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, pmic_glink_ucsi_id_table); + +static struct auxiliary_driver pmic_glink_ucsi_driver = { + .name = "pmic_glink_ucsi", + .probe = pmic_glink_ucsi_probe, + .remove = pmic_glink_ucsi_remove, + .id_table = pmic_glink_ucsi_id_table, +}; + +module_auxiliary_driver(pmic_glink_ucsi_driver); + +MODULE_DESCRIPTION("Qualcomm PMIC GLINK UCSI driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From a33113f7369395a70de8b52d6e9fda17aa548aad Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 21 Mar 2023 14:21:45 +0100 Subject: dt-bindings: usb: snps,dwc3: document HS & SS OF graph ports Document the optional ports subnode to describe the High-Speed and Super-Speed connections as separate OF graph links. The ports property is an alternative to the already documented single port subnode property. Reviewed-by: Rob Herring Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20230130-topic-sm8450-upstream-pmic-glink-v5-5-552f3b721f9e@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/snps,dwc3.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index c167fd577cae..eb58ba96b850 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -377,6 +377,22 @@ properties: This port is used with the 'usb-role-switch' property to connect the dwc3 to type C connector. + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Those ports should be used with any connector to the data bus of this + controller using the OF graph bindings specified if the "usb-role-switch" + property is used. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: High Speed (HS) data bus. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Super Speed (SS) data bus. + wakeup-source: $ref: /schemas/types.yaml#/definitions/flag description: -- cgit v1.2.3 From 84364a00b264885a97f83c328df8e63d3ec7aefa Mon Sep 17 00:00:00 2001 From: Aswath Govindraju Date: Thu, 16 Mar 2023 15:12:24 +0200 Subject: usb: dwc3-am62: Add support for system wakeup based on USB events The USB2SS IP in TI's AM62 SoC is capable of supporting wakeup from deep sleep based on the following events, 1) VBUS state change 2) Overcurrent detection 3) Line state change Wakeup from these events can enabled by setting their corresponding bits in the WAKEUP_CONFIG register. The events to be enabled are decided based on the current role of the controller. When the role of the controller is host, the comparators for detecting VBUS state change are disabled while entering low power mode. This is done as VBUS state is not used in host mode and disabling the comparators helps in reducing the power consumption. So, wakeup from VBUS state change should be disabled in host mode. While operating in peripheral mode all the wakeup events can be enabled. Therefore, add support for the same in the suspend/resume hooks. Signed-off-by: Aswath Govindraju Signed-off-by: Roger Quadros Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20230316131226.89540-2-rogerq@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-am62.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index 173cf3579c55..867bfa1252b8 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -17,6 +17,8 @@ #include #include +#include "core.h" + /* USB WRAPPER register offsets */ #define USBSS_PID 0x0 #define USBSS_OVERCURRENT_CTRL 0x4 @@ -45,6 +47,10 @@ #define USBSS_PHY_VBUS_SEL_SHIFT 1 #define USBSS_PHY_LANE_REVERSE BIT(0) +/* CORE STAT register bits */ +#define USBSS_CORE_OPERATIONAL_MODE_MASK GENMASK(13, 12) +#define USBSS_CORE_OPERATIONAL_MODE_SHIFT 12 + /* MODE CONTROL register bits */ #define USBSS_MODE_VALID BIT(0) @@ -233,6 +239,9 @@ static int dwc3_ti_probe(struct platform_device *pdev) reg |= USBSS_MODE_VALID; dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg); + /* Device has capability to wakeup system from sleep */ + device_set_wakeup_capable(dev, true); + /* Setting up autosuspend */ pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(dev); @@ -281,6 +290,22 @@ static int dwc3_ti_remove(struct platform_device *pdev) static int dwc3_ti_suspend_common(struct device *dev) { struct dwc3_data *data = dev_get_drvdata(dev); + u32 reg, current_prtcap_dir; + + if (device_may_wakeup(dev)) { + reg = dwc3_ti_readl(data, USBSS_CORE_STAT); + current_prtcap_dir = (reg & USBSS_CORE_OPERATIONAL_MODE_MASK) + >> USBSS_CORE_OPERATIONAL_MODE_SHIFT; + /* Set wakeup config enable bits */ + reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG); + if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) { + reg |= USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN; + } else { + reg |= USBSS_WAKEUP_CFG_OVERCURRENT_EN | USBSS_WAKEUP_CFG_LINESTATE_EN | + USBSS_WAKEUP_CFG_VBUSVALID_EN; + } + dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg); + } clk_disable_unprepare(data->usb2_refclk); @@ -290,9 +315,23 @@ static int dwc3_ti_suspend_common(struct device *dev) static int dwc3_ti_resume_common(struct device *dev) { struct dwc3_data *data = dev_get_drvdata(dev); + u32 reg; clk_prepare_enable(data->usb2_refclk); + if (device_may_wakeup(dev)) { + /* Clear wakeup config enable bits */ + reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG); + reg &= ~(USBSS_WAKEUP_CFG_OVERCURRENT_EN | USBSS_WAKEUP_CFG_LINESTATE_EN | + USBSS_WAKEUP_CFG_VBUSVALID_EN); + dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg); + } + + reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT); + /* Clear the wakeup status with wakeup clear bit */ + reg |= USBSS_WAKEUP_STAT_CLR; + dwc3_ti_writel(data, USBSS_WAKEUP_STAT, reg); + return 0; } -- cgit v1.2.3 From 4e3972b589da0519bf57ed386974b64b9c8572fd Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 16 Mar 2023 15:12:25 +0200 Subject: usb: dwc3-am62: Enable as a wakeup source by default USB module can wakeup system. Enable it as a wakeup source by default. Finer grain wakeup enable/disable can be done from the power/wakeup system control file of the respective USB device. Signed-off-by: Roger Quadros Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20230316131226.89540-3-rogerq@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-am62.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index 867bfa1252b8..859b48279658 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -241,6 +241,9 @@ static int dwc3_ti_probe(struct platform_device *pdev) /* Device has capability to wakeup system from sleep */ device_set_wakeup_capable(dev, true); + ret = device_wakeup_enable(dev); + if (ret) + dev_err(dev, "couldn't enable device as a wakeup source: %d\n", ret); /* Setting up autosuspend */ pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY); -- cgit v1.2.3 From 8c4853c48d6cd56611446ec767c5e8365bdd964b Mon Sep 17 00:00:00 2001 From: Li Jun Date: Fri, 17 Mar 2023 16:55:28 +0800 Subject: usb: dwc3: add several registers dump for debugfs Add 5 missing register dump for debugfs as they are in use now. Signed-off-by: Li Jun Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/1679043328-13425-1-git-send-email-jun.li@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/debugfs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 850df0e6bcab..e4a2560b9dc0 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -88,6 +88,9 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GPRTBIMAP_HS1), dump_register(GPRTBIMAP_FS0), dump_register(GPRTBIMAP_FS1), + dump_register(GUCTL2), + dump_register(VER_NUMBER), + dump_register(VER_TYPE), dump_register(GUSB2PHYCFG(0)), dump_register(GUSB2PHYCFG(1)), @@ -229,6 +232,8 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GEVNTCOUNT(0)), dump_register(GHWPARAMS8), + dump_register(GUCTL3), + dump_register(GFLADJ), dump_register(DCFG), dump_register(DCTL), dump_register(DEVTEN), -- cgit v1.2.3 From 2b947f8769be8b8181dc795fd292d3e7120f5204 Mon Sep 17 00:00:00 2001 From: Zheng Wang Date: Mon, 20 Mar 2023 14:29:31 +0800 Subject: usb: gadget: udc: renesas_usb3: Fix use after free bug in renesas_usb3_remove due to race condition In renesas_usb3_probe, role_work is bound with renesas_usb3_role_work. renesas_usb3_start will be called to start the work. If we remove the driver which will call usbhs_remove, there may be an unfinished work. The possible sequence is as follows: CPU0 CPU1 renesas_usb3_role_work renesas_usb3_remove usb_role_switch_unregister device_unregister kfree(sw) //free usb3->role_sw usb_role_switch_set_role //use usb3->role_sw The usb3->role_sw could be freed under such circumstance and then used in usb_role_switch_set_role. This bug was found by static analysis. And note that removing a driver is a root-only operation, and should never happen in normal case. But the root user may directly remove the device which will also trigger the remove function. Fix it by canceling the work before cleanup in the renesas_usb3_remove. Fixes: 39facfa01c9f ("usb: gadget: udc: renesas_usb3: Add register of usb role switch") Signed-off-by: Zheng Wang Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20230320062931.505170-1-zyytlz.wz@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/renesas_usb3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 17e765d2e093..aac8bc185afa 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2660,6 +2660,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) debugfs_remove_recursive(usb3->dentry); device_remove_file(&pdev->dev, &dev_attr_role); + cancel_work_sync(&usb3->role_work); usb_role_switch_unregister(usb3->role_sw); usb_del_gadget_udc(&usb3->gadget); -- cgit v1.2.3 From 0d6a119cecd7ffa059970dbc5b557bfce737945f Mon Sep 17 00:00:00 2001 From: Aswath Govindraju Date: Fri, 24 Mar 2023 15:18:53 +0200 Subject: usb: typec: tps6598x: Add support for polling interrupts status Some development boards don't have the interrupt line connected. In such cases we can resort to polling the interrupt status. Signed-off-by: Aswath Govindraju Signed-off-by: Roger Quadros Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20230324131853.41102-1-rogerq@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index af6ecb54b52c..8b075ca82ef6 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "tps6598x.h" #include "trace.h" @@ -97,6 +98,8 @@ struct tps6598x { int wakeup; u16 pwr_status; + struct delayed_work wq_poll; + irq_handler_t irq_handler; }; static enum power_supply_property tps6598x_psy_props[] = { @@ -558,6 +561,18 @@ err_unlock: return IRQ_NONE; } +/* Time interval for Polling */ +#define POLL_INTERVAL 500 /* msecs */ +static void tps6598x_poll_work(struct work_struct *work) +{ + struct tps6598x *tps = container_of(to_delayed_work(work), + struct tps6598x, wq_poll); + + tps->irq_handler(0, tps); + queue_delayed_work(system_power_efficient_wq, + &tps->wq_poll, msecs_to_jiffies(POLL_INTERVAL)); +} + static int tps6598x_check_mode(struct tps6598x *tps) { char mode[5] = { }; @@ -736,6 +751,7 @@ static int tps6598x_probe(struct i2c_client *client) TPS_REG_INT_PLUG_EVENT; } + tps->irq_handler = irq_handler; /* Make sure the controller has application firmware running */ ret = tps6598x_check_mode(tps); if (ret) @@ -827,10 +843,18 @@ static int tps6598x_probe(struct i2c_client *client) dev_err(&client->dev, "failed to register partner\n"); } - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - irq_handler, - IRQF_SHARED | IRQF_ONESHOT, - dev_name(&client->dev), tps); + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, + irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + dev_name(&client->dev), tps); + } else { + dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n"); + INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work); + queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, + msecs_to_jiffies(POLL_INTERVAL)); + } + if (ret) goto err_disconnect; @@ -838,7 +862,7 @@ static int tps6598x_probe(struct i2c_client *client) fwnode_handle_put(fwnode); tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source"); - if (tps->wakeup) { + if (tps->wakeup && client->irq) { device_init_wakeup(&client->dev, true); enable_irq_wake(client->irq); } @@ -877,6 +901,9 @@ static int __maybe_unused tps6598x_suspend(struct device *dev) enable_irq_wake(client->irq); } + if (!client->irq) + cancel_delayed_work_sync(&tps->wq_poll); + return 0; } @@ -890,6 +917,10 @@ static int __maybe_unused tps6598x_resume(struct device *dev) enable_irq(client->irq); } + if (client->irq) + queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, + msecs_to_jiffies(POLL_INTERVAL)); + return 0; } -- cgit v1.2.3 From 7bf1c56a90decd3bec4d49815289d2e40bb771ae Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 9 Mar 2023 10:58:25 +0000 Subject: usb: gadget: uvc: Make bmControls attr read/write For the Processing Unit and Camera Terminal descriptors defined in the UVC Gadget we currently hard-code values into their bmControls fields, which enumerates which controls the gadget is able to support. This isn't appropriate since only the userspace companion program to the kernel driver will know which controls are supported. Make the configfs attributes that point to those fields read/write so userspace can set them to appropriate values. Document the new behaviour at the same time so the functionality is clear. Signed-off-by: Daniel Scally Link: https://lore.kernel.org/r/20230309105825.216745-1-dan.scally@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/configfs-usb-gadget-uvc | 4 +- Documentation/usb/gadget_uvc.rst | 28 +++++ drivers/usb/gadget/function/uvc_configfs.c | 121 +++++++++++++++++++++- 3 files changed, 149 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 80b98a4a4d0f..4feb692c4c1d 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -76,7 +76,7 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Default camera terminal descriptors - All attributes read only: + All attributes read only except bmControls, which is read/write: ======================== ==================================== bmControls bitmap specifying which controls are @@ -101,7 +101,7 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Default processing unit descriptors - All attributes read only: + All attributes read only except bmControls, which is read/write: =============== ======================================== iProcessing index of string descriptor diff --git a/Documentation/usb/gadget_uvc.rst b/Documentation/usb/gadget_uvc.rst index 6d22faceb1a0..62bd81ba3dd1 100644 --- a/Documentation/usb/gadget_uvc.rst +++ b/Documentation/usb/gadget_uvc.rst @@ -275,6 +275,34 @@ out with 0x00, for example: bNrInPins and baSourceID function in the same way. +Configuring Supported Controls for Camera Terminal and Processing Unit +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Camera Terminal and Processing Units in the UVC chain also have bmControls +attributes which function similarly to the same field in an Extension Unit. +Unlike XUs however, the meaning of the bitflag for these units is defined in +the UVC specification; you should consult the "Camera Terminal Descriptor" and +"Processing Unit Descriptor" sections for an enumeration of the flags. + +.. code-block:: bash + + # Set the Processing Unit's bmControls, flagging Brightness, Contrast + # and Hue as available controls: + echo 0x05 > $FUNCTION/control/processing/default/bmControls + + # Set the Camera Terminal's bmControls, flagging Focus Absolute and + # Focus Relative as available controls: + echo 0x60 > $FUNCTION/control/terminal/camera/default/bmControls + +If you do not set these fields then by default the Auto-Exposure Mode control +for the Camera Terminal and the Brightness control for the Processing Unit will +be flagged as available; if they are not supported you should set the field to +0x00. + +Note that the size of the bmControls field for a Camera Terminal or Processing +Unit is fixed by the UVC specification, and so the bControlSize attribute is +read-only here. + Custom Strings Support ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 62b759bb7613..9bf0e985acfa 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -334,6 +334,64 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8); #undef UVCG_DEFAULT_PROCESSING_ATTR +static ssize_t uvcg_default_processing_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_processing_unit_descriptor *pd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + pd = &opts->uvc_processing; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > pd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + pd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_processing_bm_controls_show( struct config_item *item, char *page) { @@ -363,7 +421,7 @@ static ssize_t uvcg_default_processing_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_processing_attrs[] = { &uvcg_default_processing_attr_b_unit_id, @@ -445,6 +503,65 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, #undef UVCG_DEFAULT_CAMERA_ATTR +static ssize_t uvcg_default_camera_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_camera_terminal_descriptor *cd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> + ci_parent; + opts = to_f_uvc_opts(opts_item); + cd = &opts->uvc_camera_terminal; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > cd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + cd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_camera_bm_controls_show( struct config_item *item, char *page) { @@ -474,7 +591,7 @@ static ssize_t uvcg_default_camera_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_camera_attrs[] = { &uvcg_default_camera_attr_b_terminal_id, -- cgit v1.2.3 From f54134b3fc7954dbaa4da42198286e49bcb48ed7 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Mon, 27 Mar 2023 18:12:15 +0800 Subject: usb: gadget: ffs: remove ENTER() macro ENTER() used to show function name which called during runtime, ftrace can be used to get same information, let's remove it. Signed-off-by: Linyu Yuan Link: https://lore.kernel.org/r/1679911940-4727-1-git-send-email-quic_linyyuan@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 94 -------------------------------------- drivers/usb/gadget/function/u_fs.h | 2 - drivers/usb/gadget/legacy/g_ffs.c | 9 ---- 3 files changed, 105 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index a277c70aac84..8830847fbf97 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -335,8 +335,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ssize_t ret; char *data; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -512,8 +510,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, size_t n; int ret; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -612,8 +608,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_private; - ENTER(); - if (ffs->state == FFS_CLOSING) return -EBUSY; @@ -627,8 +621,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file) { struct ffs_data *ffs = file->private_data; - ENTER(); - ffs_data_closed(ffs); return 0; @@ -640,8 +632,6 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) struct usb_gadget *gadget = ffs->gadget; long ret; - ENTER(); - if (code == FUNCTIONFS_INTERFACE_REVMAP) { struct ffs_function *func = ffs->func; ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; @@ -715,7 +705,6 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) { struct ffs_io_data *io_data = req->context; - ENTER(); if (req->status) io_data->status = req->status; else @@ -856,8 +845,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, struct ffs_io_data *io_data = req->context; struct ffs_data *ffs = io_data->ffs; - ENTER(); - io_data->status = req->status ? req->status : req->actual; usb_ep_free_request(_ep, req); @@ -1161,8 +1148,6 @@ ffs_epfile_open(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1179,8 +1164,6 @@ static int ffs_aio_cancel(struct kiocb *kiocb) unsigned long flags; int value; - ENTER(); - spin_lock_irqsave(&epfile->ffs->eps_lock, flags); if (io_data && io_data->ep && io_data->req) @@ -1198,8 +1181,6 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1235,8 +1216,6 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1284,8 +1263,6 @@ ffs_epfile_release(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - __ffs_epfile_read_buffer_free(epfile); ffs_data_closed(epfile->ffs); @@ -1299,8 +1276,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, struct ffs_ep *ep; int ret; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1399,8 +1374,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data, { struct inode *inode; - ENTER(); - inode = new_inode(sb); if (inode) { @@ -1432,8 +1405,6 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb, struct dentry *dentry; struct inode *inode; - ENTER(); - dentry = d_alloc_name(sb->s_root, name); if (!dentry) return NULL; @@ -1468,8 +1439,6 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc) struct inode *inode; struct ffs_data *ffs = data->ffs_data; - ENTER(); - ffs->sb = sb; data->ffs_data = NULL; sb->s_fs_info = ffs; @@ -1521,8 +1490,6 @@ static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param) struct fs_parse_result result; int opt; - ENTER(); - opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result); if (opt < 0) return opt; @@ -1572,8 +1539,6 @@ static int ffs_fs_get_tree(struct fs_context *fc) struct ffs_data *ffs; int ret; - ENTER(); - if (!fc->source) return invalf(fc, "No source specified"); @@ -1640,8 +1605,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc) static void ffs_fs_kill_sb(struct super_block *sb) { - ENTER(); - kill_litter_super(sb); if (sb->s_fs_info) ffs_data_closed(sb->s_fs_info); @@ -1663,8 +1626,6 @@ static int functionfs_init(void) { int ret; - ENTER(); - ret = register_filesystem(&ffs_fs_type); if (!ret) pr_info("file system registered\n"); @@ -1676,8 +1637,6 @@ static int functionfs_init(void) static void functionfs_cleanup(void) { - ENTER(); - pr_info("unloading\n"); unregister_filesystem(&ffs_fs_type); } @@ -1690,15 +1649,11 @@ static void ffs_data_reset(struct ffs_data *ffs); static void ffs_data_get(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); } static void ffs_data_opened(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); if (atomic_add_return(1, &ffs->opened) == 1 && ffs->state == FFS_DEACTIVATED) { @@ -1709,8 +1664,6 @@ static void ffs_data_opened(struct ffs_data *ffs) static void ffs_data_put(struct ffs_data *ffs) { - ENTER(); - if (refcount_dec_and_test(&ffs->ref)) { pr_info("%s(): freeing\n", __func__); ffs_data_clear(ffs); @@ -1729,8 +1682,6 @@ static void ffs_data_closed(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - if (atomic_dec_and_test(&ffs->opened)) { if (ffs->no_disconnect) { ffs->state = FFS_DEACTIVATED; @@ -1765,8 +1716,6 @@ static struct ffs_data *ffs_data_new(const char *dev_name) if (!ffs) return NULL; - ENTER(); - ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name); if (!ffs->io_completion_wq) { kfree(ffs); @@ -1793,8 +1742,6 @@ static void ffs_data_clear(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - ffs_closed(ffs); BUG_ON(ffs->gadget); @@ -1826,8 +1773,6 @@ static void ffs_data_clear(struct ffs_data *ffs) static void ffs_data_reset(struct ffs_data *ffs) { - ENTER(); - ffs_data_clear(ffs); ffs->raw_descs_data = NULL; @@ -1861,8 +1806,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) struct usb_gadget_strings **lang; int first_id; - ENTER(); - if (WARN_ON(ffs->state != FFS_ACTIVE || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) return -EBADFD; @@ -1894,8 +1837,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) static void functionfs_unbind(struct ffs_data *ffs) { - ENTER(); - if (!WARN_ON(!ffs->gadget)) { /* dequeue before freeing ep0req */ usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req); @@ -1914,8 +1855,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs) struct ffs_epfile *epfile, *epfiles; unsigned i, count; - ENTER(); - count = ffs->eps_count; epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); if (!epfiles) @@ -1946,8 +1885,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) { struct ffs_epfile *epfile = epfiles; - ENTER(); - for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex)); if (epfile->dentry) { @@ -2064,8 +2001,6 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, u8 length; int ret; - ENTER(); - /* At least two bytes are required: length and type */ if (len < 2) { pr_vdebug("descriptor too short\n"); @@ -2204,8 +2139,6 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, unsigned long num = 0; int current_class = -1; - ENTER(); - for (;;) { int ret; @@ -2243,8 +2176,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, struct ffs_desc_helper *helper = priv; struct usb_endpoint_descriptor *d; - ENTER(); - switch (type) { case FFS_DESCRIPTOR: break; @@ -2329,8 +2260,6 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len, int ret; const unsigned _len = len; - ENTER(); - /* loop over all ext compat/ext prop descriptors */ while (feature_count--) { ret = entity(type, h, data, len, priv); @@ -2352,8 +2281,6 @@ static int __must_check ffs_do_os_descs(unsigned count, const unsigned _len = len; unsigned long num = 0; - ENTER(); - for (num = 0; num < count; ++num) { int ret; enum ffs_os_desc_type type; @@ -2416,8 +2343,6 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, struct ffs_data *ffs = priv; u8 length; - ENTER(); - switch (type) { case FFS_OS_DESC_EXT_COMPAT: { struct usb_ext_compat_desc *d = data; @@ -2493,8 +2418,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, int ret = -EINVAL, i; struct ffs_desc_helper helper; - ENTER(); - if (get_unaligned_le32(data + 4) != len) goto error; @@ -2625,8 +2548,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, const char *data = _data; struct usb_string *s; - ENTER(); - if (len < 16 || get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || get_unaligned_le32(data + 4) != len) @@ -3085,8 +3006,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, struct ffs_data *ffs_data; int ret; - ENTER(); - /* * Legacy gadget triggers binding in functionfs_ready_callback, * which already uses locking; taking the same lock here would @@ -3163,8 +3082,6 @@ static int _ffs_func_bind(struct usb_configuration *c, vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); char *vlabuf; - ENTER(); - /* Has descriptors only for speeds gadget does not support */ if (!(full | high | super)) return -ENOTSUPP; @@ -3368,8 +3285,6 @@ static int ffs_func_setup(struct usb_function *f, unsigned long flags; int ret; - ENTER(); - pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); @@ -3444,13 +3359,11 @@ static bool ffs_func_req_match(struct usb_function *f, static void ffs_func_suspend(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); } static void ffs_func_resume(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); } @@ -3614,7 +3527,6 @@ static void ffs_func_unbind(struct usb_configuration *c, unsigned count = ffs->eps_count; unsigned long flags; - ENTER(); if (ffs->func == func) { ffs_func_eps_disable(func); ffs->func = NULL; @@ -3654,8 +3566,6 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) { struct ffs_function *func; - ENTER(); - func = kzalloc(sizeof(*func), GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); @@ -3756,7 +3666,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) int ret = 0; struct ffs_dev *ffs_dev; - ENTER(); ffs_dev_lock(); ffs_dev = _ffs_find_dev(dev_name); @@ -3779,7 +3688,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) static void ffs_release_dev(struct ffs_dev *ffs_dev) { - ENTER(); ffs_dev_lock(); if (ffs_dev && ffs_dev->mounted) { @@ -3801,7 +3709,6 @@ static int ffs_ready(struct ffs_data *ffs) struct ffs_dev *ffs_obj; int ret = 0; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; @@ -3834,7 +3741,6 @@ static void ffs_closed(struct ffs_data *ffs) struct f_fs_opts *opts; struct config_item *ci; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index f102ec23f3af..4b3365f23fd7 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -32,8 +32,6 @@ # define ffs_dump_mem(prefix, ptr, len) do { } while (0) #endif /* VERBOSE_DEBUG */ -#define ENTER() pr_vdebug("%s()\n", __func__) - struct f_fs_opts; struct ffs_dev { diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index ae6d8f7092b8..097854683e5b 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -180,8 +180,6 @@ static int __init gfs_init(void) int i; int ret = 0; - ENTER(); - if (func_num < 2) { gfs_single_func = true; func_num = 1; @@ -242,8 +240,6 @@ static void __exit gfs_exit(void) { int i; - ENTER(); - if (gfs_registered) usb_composite_unregister(&gfs_driver); gfs_registered = false; @@ -316,8 +312,6 @@ static int gfs_bind(struct usb_composite_dev *cdev) #endif int ret, i; - ENTER(); - if (missing_funcs) return -ENODEV; #if defined CONFIG_USB_FUNCTIONFS_ETH @@ -445,9 +439,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev) { int i; - ENTER(); - - #ifdef CONFIG_USB_FUNCTIONFS_RNDIS usb_put_function(f_rndis); usb_put_function_instance(fi_rndis); -- cgit v1.2.3 From 130eac4170859fb368681e00d390f20f44bbf27b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 28 Mar 2023 15:10:43 +0200 Subject: xhci: use pm_ptr() instead of #ifdef for CONFIG_PM conditionals A recent patch caused an unused-function warning in builds with CONFIG_PM disabled, after the function became marked 'static': drivers/usb/host/xhci-pci.c:91:13: error: 'xhci_msix_sync_irqs' defined but not used [-Werror=unused-function] 91 | static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) | ^~~~~~~~~~~~~~~~~~~ This could be solved by adding another #ifdef, but as there is a trend towards removing CONFIG_PM checks in favor of helper macros, do the same conversion here and use pm_ptr() to get either a function pointer or NULL but avoid the warning. As the hidden functions reference some other symbols, make sure those are visible at compile time, at the minimal cost of a few extra bytes for 'struct usb_device'. Fixes: 9abe15d55dcc ("xhci: Move xhci MSI sync function to to xhci-pci") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230328131114.1296430-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 16 +++++----------- include/linux/usb.h | 3 +-- include/linux/usb/hcd.h | 2 -- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index a53ecc8ff8c5..bbbb01282038 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -728,7 +728,6 @@ static void xhci_pci_remove(struct pci_dev *dev) usb_hcd_pci_remove(dev); } -#ifdef CONFIG_PM /* * In some Intel xHCI controllers, in order to get D3 working, * through a vendor specific SSIC CONFIG register at offset 0x883c, @@ -927,7 +926,6 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd) if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) pci_set_power_state(pdev, PCI_D3hot); } -#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -970,9 +968,7 @@ static struct pci_driver xhci_pci_driver = { .shutdown = usb_hcd_pci_shutdown, .driver = { -#ifdef CONFIG_PM - .pm = &usb_hcd_pci_pm_ops, -#endif + .pm = pm_ptr(&usb_hcd_pci_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; @@ -980,12 +976,10 @@ static struct pci_driver xhci_pci_driver = { static int __init xhci_pci_init(void) { xhci_init_driver(&xhci_pci_hc_driver, &xhci_pci_overrides); -#ifdef CONFIG_PM - xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend; - xhci_pci_hc_driver.pci_resume = xhci_pci_resume; - xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late; - xhci_pci_hc_driver.shutdown = xhci_pci_shutdown; -#endif + xhci_pci_hc_driver.pci_suspend = pm_ptr(xhci_pci_suspend); + xhci_pci_hc_driver.pci_resume = pm_ptr(xhci_pci_resume); + xhci_pci_hc_driver.pci_poweroff_late = pm_ptr(xhci_pci_poweroff_late); + xhci_pci_hc_driver.shutdown = pm_ptr(xhci_pci_shutdown); xhci_pci_hc_driver.stop = xhci_pci_stop; return pci_register_driver(&xhci_pci_driver); } diff --git a/include/linux/usb.h b/include/linux/usb.h index 9642ee02d713..d510fabcafa2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -704,13 +704,12 @@ struct usb_device { unsigned long active_duration; -#ifdef CONFIG_PM unsigned long connect_time; unsigned do_remote_wakeup:1; unsigned reset_resume:1; unsigned port_is_suspended:1; -#endif + struct wusb_dev *wusb_dev; int slot_id; struct usb2_lpm_parameters l1_params; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index b51c07111729..094c77eaf455 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -488,9 +488,7 @@ extern void usb_hcd_pci_shutdown(struct pci_dev *dev); extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); -#ifdef CONFIG_PM extern const struct dev_pm_ops usb_hcd_pci_pm_ops; -#endif #endif /* CONFIG_USB_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ -- cgit v1.2.3 From df9ba6a245b34332e82df07b078988abf0ac1f09 Mon Sep 17 00:00:00 2001 From: Deming Wang Date: Sat, 25 Mar 2023 02:38:32 -0400 Subject: usb: dwc2: Fix spelling mistake "schduler" -> "scheduler" There is a spelling mistakes in dev_warn messages. Fix them. Signed-off-by: Deming Wang Link: https://lore.kernel.org/r/20230325063832.1642-1-wangdeming@inspur.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 0a1145592fc7..0d4495c6b9f7 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -1078,7 +1078,7 @@ static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) earliest_frame = dwc2_frame_num_inc(frame_number, 1); next_active_frame = earliest_frame; - /* Get the "no microframe schduler" out of the way... */ + /* Get the "no microframe scheduler" out of the way... */ if (!hsotg->params.uframe_sched) { if (qh->do_split) /* Splits are active at microframe 0 minus 1 */ -- cgit v1.2.3 From c03ff66dc0e0cbad9ed0c29500843e1da8533118 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 23 Mar 2023 20:40:22 +0100 Subject: usb: pci-quirks: Reduce the length of a spinlock section in usb_amd_find_chipset_info() 'info' is local to the function. There is no need to zeroing it within a spin_lock section. Moreover, there is no need to explicitly initialize the .need_pll_quirk field. Initialize the structure when defined and remove the now useless memset(). Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/08ee42fced6af6bd56892cd14f2464380ab071fa.1679600396.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index ef08d68b9714..2665832f9add 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -207,8 +207,7 @@ EXPORT_SYMBOL_GPL(sb800_prefetch); static void usb_amd_find_chipset_info(void) { unsigned long flags; - struct amd_chipset_info info; - info.need_pll_quirk = false; + struct amd_chipset_info info = { }; spin_lock_irqsave(&amd_lock, flags); @@ -218,7 +217,6 @@ static void usb_amd_find_chipset_info(void) spin_unlock_irqrestore(&amd_lock, flags); return; } - memset(&info, 0, sizeof(info)); spin_unlock_irqrestore(&amd_lock, flags); if (!amd_chipset_sb_type_init(&info)) { -- cgit v1.2.3 From db2c2b161d4a8f4a81e6f643848b1531517a67a5 Mon Sep 17 00:00:00 2001 From: Mingxuan Xiang Date: Fri, 24 Mar 2023 14:09:34 +0800 Subject: usb: dwc3: host: remove dead code in dwc3_host_get_irq() According to the description of platform_get_irq() * Return: non-zero IRQ number on success, negative error number on failure. and the code, platform_get_irq() will return -EINVAL instead of IRQ0. So platform_get_irq() no longer returns 0, there is no need to check whether the return value is 0. Found by Smatch: drivers/usb/dwc3/host.c:60 dwc3_host_get_irq() warn: platform_get_irq() does not return zero Signed-off-by: Mingxuan Xiang Reviewed-by: Dan Carpenter Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20230324060934.1686859-1-mx_xiang@hust.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/host.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index f6f13e7f1ba1..61f57fe5bb78 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -52,13 +52,8 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) goto out; irq = platform_get_irq(dwc3_pdev, 0); - if (irq > 0) { + if (irq > 0) dwc3_host_fill_xhci_irq_res(dwc, irq, NULL); - goto out; - } - - if (!irq) - irq = -EINVAL; out: return irq; -- cgit v1.2.3 From 2926c5275028e44f6a2ac31b37d75d6d6e260306 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 24 Mar 2023 13:44:29 +0200 Subject: usb: dwc3-am62: Fix up wake-up configuration and spurious wake up Explicitly set and clear wakeup config so we don't leave anything to chance. Clear wakeup status on suspend so we know what caused wake up. The LINESTATE wake up should not be enabled in device mode if we are not connected to a USB host and in USB suspend (U2/L3) else it will cause spurious wake up. For now, don't enable LINESTATE. This means wake up from USB resume will not work but at least we won't have any spurious wake ups. Signed-off-by: Roger Quadros Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20230324114429.21838-1-rogerq@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-am62.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index 859b48279658..b22fb78bc8e7 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -60,6 +60,13 @@ #define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1) #define USBSS_WAKEUP_CFG_VBUSVALID_EN BIT(0) +#define USBSS_WAKEUP_CFG_ALL (USBSS_WAKEUP_CFG_VBUSVALID_EN | \ + USBSS_WAKEUP_CFG_SESSVALID_EN | \ + USBSS_WAKEUP_CFG_LINESTATE_EN | \ + USBSS_WAKEUP_CFG_OVERCURRENT_EN) + +#define USBSS_WAKEUP_CFG_NONE 0 + /* WAKEUP STAT register bits */ #define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4) #define USBSS_WAKEUP_STAT_LINESTATE BIT(3) @@ -103,6 +110,7 @@ struct dwc3_data { struct regmap *syscon; unsigned int offset; unsigned int vbus_divider; + u32 wakeup_stat; }; static const int dwc3_ti_rate_table[] = { /* in KHZ */ @@ -302,12 +310,17 @@ static int dwc3_ti_suspend_common(struct device *dev) /* Set wakeup config enable bits */ reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG); if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) { - reg |= USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN; + reg = USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN; } else { - reg |= USBSS_WAKEUP_CFG_OVERCURRENT_EN | USBSS_WAKEUP_CFG_LINESTATE_EN | - USBSS_WAKEUP_CFG_VBUSVALID_EN; + reg = USBSS_WAKEUP_CFG_VBUSVALID_EN | USBSS_WAKEUP_CFG_SESSVALID_EN; + /* + * Enable LINESTATE wake up only if connected to bus + * and in U2/L3 state else it causes spurious wake-up. + */ } dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg); + /* clear wakeup status so we know what caused the wake up */ + dwc3_ti_writel(data, USBSS_WAKEUP_STAT, USBSS_WAKEUP_STAT_CLR); } clk_disable_unprepare(data->usb2_refclk); @@ -324,16 +337,11 @@ static int dwc3_ti_resume_common(struct device *dev) if (device_may_wakeup(dev)) { /* Clear wakeup config enable bits */ - reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG); - reg &= ~(USBSS_WAKEUP_CFG_OVERCURRENT_EN | USBSS_WAKEUP_CFG_LINESTATE_EN | - USBSS_WAKEUP_CFG_VBUSVALID_EN); - dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg); + dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, USBSS_WAKEUP_CFG_NONE); } reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT); - /* Clear the wakeup status with wakeup clear bit */ - reg |= USBSS_WAKEUP_STAT_CLR; - dwc3_ti_writel(data, USBSS_WAKEUP_STAT, reg); + data->wakeup_stat = reg; return 0; } -- cgit v1.2.3 From 4e99c98e3071bd7fd4d7f20440f1a5c3bf533149 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Mar 2023 20:20:16 +0300 Subject: thunderbolt: Get rid of redundant 'else' In the snippets like the following if (...) return / goto / break / continue ...; else ... the 'else' is redundant. Get rid of it. Signed-off-by: Andy Shevchenko Signed-off-by: Mika Westerberg --- drivers/thunderbolt/acpi.c | 2 +- drivers/thunderbolt/ctl.c | 2 +- drivers/thunderbolt/nhi.c | 3 ++- drivers/thunderbolt/switch.c | 4 ++-- drivers/thunderbolt/usb4.c | 6 +++--- drivers/thunderbolt/xdomain.c | 24 ++++++++++-------------- 6 files changed, 19 insertions(+), 22 deletions(-) diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c index 628225deb8fe..3514bf65b7a4 100644 --- a/drivers/thunderbolt/acpi.c +++ b/drivers/thunderbolt/acpi.c @@ -341,7 +341,7 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev) */ if (tb_is_switch(dev)) return tb_acpi_switch_find_companion(tb_to_switch(dev)); - else if (tb_is_usb4_port_device(dev)) + if (tb_is_usb4_port_device(dev)) return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent), tb_to_usb4_port_device(dev)->port->port); return NULL; diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 6e7d28e8d81a..3a213322ec7a 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -1033,7 +1033,7 @@ static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space, if (res->tb_error == TB_CFG_ERROR_LOCK) return -EACCES; - else if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED) + if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED) return -ENOTCONN; return -EIO; diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 4dce2edd86ea..4400e1383e3e 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -515,7 +515,8 @@ static int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring) ring->hop); ret = -EBUSY; goto err_unlock; - } else if (!ring->is_tx && nhi->rx_rings[ring->hop]) { + } + if (!ring->is_tx && nhi->rx_rings[ring->hop]) { dev_warn(&nhi->pdev->dev, "RX hop %d already allocated\n", ring->hop); ret = -EBUSY; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 3370e18ba05f..0a34880a6636 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -271,9 +271,9 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only) } sw->nvm->authenticating = true; return usb4_switch_nvm_authenticate(sw); - } else if (auth_only) { - return -EOPNOTSUPP; } + if (auth_only) + return -EOPNOTSUPP; sw->nvm->authenticating = true; if (!tb_route(sw)) { diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index 1e5e9c147a31..28e3ec2d7633 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -851,7 +851,7 @@ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in) */ if (ret == -EOPNOTSUPP) return true; - else if (ret) + if (ret) return false; return !status; @@ -877,7 +877,7 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in) &status); if (ret == -EOPNOTSUPP) return 0; - else if (ret) + if (ret) return ret; return status ? -EBUSY : 0; @@ -900,7 +900,7 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in) &status); if (ret == -EOPNOTSUPP) return 0; - else if (ret) + if (ret) return ret; return status ? -EIO : 0; diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index a48335c95d39..e2b54887d331 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -1178,9 +1178,8 @@ static int tb_xdomain_get_uuid(struct tb_xdomain *xd) if (xd->state_retries-- > 0) { dev_dbg(&xd->dev, "failed to request UUID, retrying\n"); return -EAGAIN; - } else { - dev_dbg(&xd->dev, "failed to read remote UUID\n"); } + dev_dbg(&xd->dev, "failed to read remote UUID\n"); return ret; } @@ -1367,12 +1366,10 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd) dev_dbg(&xd->dev, "failed to request remote properties, retrying\n"); return -EAGAIN; - } else { - /* Give up now */ - dev_err(&xd->dev, - "failed read XDomain properties from %pUb\n", - xd->remote_uuid); } + /* Give up now */ + dev_err(&xd->dev, "failed read XDomain properties from %pUb\n", + xd->remote_uuid); return ret; } @@ -2179,13 +2176,12 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw, if (xd->remote_uuid && uuid_equal(xd->remote_uuid, lookup->uuid)) return xd; - } else if (lookup->link && - lookup->link == xd->link && - lookup->depth == xd->depth) { - return xd; - } else if (lookup->route && - lookup->route == xd->route) { - return xd; + } else { + if (lookup->link && lookup->link == xd->link && + lookup->depth == xd->depth) + return xd; + if (lookup->route && lookup->route == xd->route) + return xd; } } else if (tb_port_has_remote(port)) { xd = switch_find_xdomain(port->remote->sw, lookup); -- cgit v1.2.3 From 5d88366807fce55ab5bd1bf94055e1d1d0032604 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Mar 2023 20:20:17 +0300 Subject: thunderbolt: Make use of SI units from units.h In a couple of places it seems reasonable to use MEGA intead of explicit number. It makes code more readable and robust. Signed-off-by: Andy Shevchenko Signed-off-by: Mika Westerberg --- drivers/thunderbolt/usb4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index 28e3ec2d7633..8dcdde61a15f 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -9,6 +9,7 @@ #include #include +#include #include "sb_regs.h" #include "tb.h" @@ -1968,7 +1969,7 @@ static unsigned int usb3_bw_to_mbps(u32 bw, u8 scale) unsigned long uframes; uframes = bw * 512UL << scale; - return DIV_ROUND_CLOSEST(uframes * 8000, 1000 * 1000); + return DIV_ROUND_CLOSEST(uframes * 8000, MEGA); } static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale) @@ -1976,7 +1977,7 @@ static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale) unsigned long uframes; /* 1 uframe is 1/8 ms (125 us) -> 1 / 8000 s */ - uframes = ((unsigned long)mbps * 1000 * 1000) / 8000; + uframes = ((unsigned long)mbps * MEGA) / 8000; return DIV_ROUND_UP(uframes, 512UL << scale); } -- cgit v1.2.3 From 580f4ea2cd1666bac76a67167d0901536e93c58c Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:24:55 +0800 Subject: dt-bindings: usb: usbmisc-imx: convert to DT schema Convert usbmisc-imx to DT schema format, add missing compatibles Reviewed-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-2-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/fsl,usbmisc.yaml | 68 ++++++++++++++++++++++ .../devicetree/bindings/usb/usbmisc-imx.txt | 19 ------ 2 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml delete mode 100644 Documentation/devicetree/bindings/usb/usbmisc-imx.txt diff --git a/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml new file mode 100644 index 000000000000..2d3589d284b2 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/fsl,usbmisc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX wrapper module for Chipidea USB2 controller + +maintainers: + - Xu Yang + - Peng Fan + +properties: + compatible: + oneOf: + - enum: + - fsl,imx25-usbmisc + - fsl,imx27-usbmisc + - fsl,imx35-usbmisc + - fsl,imx51-usbmisc + - fsl,imx53-usbmisc + - fsl,imx6q-usbmisc + - fsl,vf610-usbmisc + - items: + - enum: + - fsl,imx6ul-usbmisc + - fsl,imx6sl-usbmisc + - fsl,imx6sx-usbmisc + - fsl,imx7d-usbmisc + - const: fsl,imx6q-usbmisc + - items: + - enum: + - fsl,imx7ulp-usbmisc + - fsl,imx8mm-usbmisc + - fsl,imx8mn-usbmisc + - const: fsl,imx7d-usbmisc + - const: fsl,imx6q-usbmisc + - items: + - const: fsl,imx6sll-usbmisc + - const: fsl,imx6ul-usbmisc + - const: fsl,imx6q-usbmisc + + clocks: + maxItems: 1 + + reg: + maxItems: 1 + + '#index-cells': + const: 1 + description: Cells used to describe usb controller index. + deprecated: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + usbmisc@2184800 { + compatible = "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; + #index-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt deleted file mode 100644 index 29b8f65ff849..000000000000 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ /dev/null @@ -1,19 +0,0 @@ -* Freescale i.MX non-core registers - -Required properties: -- #index-cells: Cells used to describe usb controller index. Should be <1> -- compatible: Should be one of below: - "fsl,imx6q-usbmisc" for imx6q - "fsl,vf610-usbmisc" for Vybrid vf610 - "fsl,imx6sx-usbmisc" for imx6sx - "fsl,imx7d-usbmisc" for imx7d - "fsl,imx7ulp-usbmisc" for imx7ulp - "fsl,imx8mm-usbmisc" for imx8mm -- reg: Should contain registers location and length - -Examples: -usbmisc@2184800 { - #index-cells = <1>; - compatible = "fsl,imx6q-usbmisc"; - reg = <0x02184800 0x200>; -}; -- cgit v1.2.3 From 4c8375d35f72f2daef1ac0c35831c43a36357d81 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:24:56 +0800 Subject: dt-bindings: usb: ci-hdrc-usb2: convert to DT schema format Convert the binding to DT schema format. To fix the dtbs_check error, some properties were also added, such as nvidia,phy, reset-names ulpi; missing compatibles are added. Signed-off-by: Peng Fan Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230322052504.2629429-3-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/ci-hdrc-usb2.txt | 159 -------- .../devicetree/bindings/usb/ci-hdrc-usb2.yaml | 447 +++++++++++++++++++++ 2 files changed, 447 insertions(+), 159 deletions(-) delete mode 100644 Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt create mode 100644 Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt deleted file mode 100644 index 72ceea575d58..000000000000 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ /dev/null @@ -1,159 +0,0 @@ -* USB2 ChipIdea USB controller for ci13xxx - -Required properties: -- compatible: should be one of: - "fsl,imx23-usb" - "fsl,imx27-usb" - "fsl,imx28-usb" - "fsl,imx6q-usb" - "fsl,imx6sl-usb" - "fsl,imx6sx-usb" - "fsl,imx6ul-usb" - "fsl,imx7d-usb" - "fsl,imx7ulp-usb" - "fsl,imx8mm-usb" - "lsi,zevio-usb" - "qcom,ci-hdrc" - "chipidea,usb2" - "xlnx,zynq-usb-2.20a" - "nvidia,tegra20-udc" - "nvidia,tegra30-udc" - "nvidia,tegra114-udc" - "nvidia,tegra124-udc" -- reg: base address and length of the registers -- interrupts: interrupt for the USB controller - -Recommended properies: -- phy_type: the type of the phy connected to the core. Should be one - of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this - property the PORTSC register won't be touched. -- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" - -Deprecated properties: -- usb-phy: phandle for the PHY device. Use "phys" instead. -- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead. - -Optional properties: -- clocks: reference to the USB clock -- phys: reference to the USB PHY -- phy-names: should be "usb-phy" -- vbus-supply: reference to the VBUS regulator -- maximum-speed: limit the maximum connection speed to "full-speed". -- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts -- itc-setting: interrupt threshold control register control, the setting - should be aligned with ITC bits at register USBCMD. -- ahb-burst-config: it is vendor dependent, the required value should be - aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This - property is used to change AHB burst configuration, check the chipidea - spec for meaning of each value. If this property is not existed, it - will use the reset value. -- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword - (4 bytes), This register represents the maximum length of a the burst - in 32-bit words while moving data from system memory to the USB - bus, the value of this property will only take effect if property - "ahb-burst-config" is set to 0, if this property is missing the reset - default of the hardware implementation will be used. -- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword - (4 bytes), This register represents the maximum length of a the burst - in 32-bit words while moving data from the USB bus to system memory, - the value of this property will only take effect if property - "ahb-burst-config" is set to 0, if this property is missing the reset - default of the hardware implementation will be used. -- extcon: phandles to external connector devices. First phandle should point to - external connector, which provide "USB" cable events, the second should point - to external connector device, which provide "USB-HOST" cable events. If one - of the external connector devices is not required, empty <0> phandle should - be specified. -- phy-clkgate-delay-us: the delay time (us) between putting the PHY into - low power mode and gating the PHY clock. -- non-zero-ttctrl-ttha: after setting this property, the value of register - ttctrl.ttha will be 0x7f; if not, the value will be 0x0, this is the default - value. It needs to be very carefully for setting this property, it is - recommended that consult with your IC engineer before setting this value. - On the most of chipidea platforms, the "usage_tt" flag at RTL is 0, so this - property only affects siTD. - If this property is not set, the max packet size is 1023 bytes, and if - the total of packet size for pervious transactions are more than 256 bytes, - it can't accept any transactions within this frame. The use case is single - transaction, but higher frame rate. - If this property is set, the max packet size is 188 bytes, it can handle - more transactions than above case, it can accept transactions until it - considers the left room size within frame is less than 188 bytes, software - needs to make sure it does not send more than 90% - maximum_periodic_data_per_frame. The use case is multiple transactions, but - less frame rate. -- mux-controls: The mux control for toggling host/device output of this - controller. It's expected that a mux state of 0 indicates device mode and a - mux state of 1 indicates host mode. -- mux-control-names: Shall be "usb_switch" if mux-controls is specified. -- pinctrl-names: Names for optional pin modes in "default", "host", "device". - In case of HSIC-mode, "idle" and "active" pin modes are mandatory. In this - case, the "idle" state needs to pull down the data and strobe pin - and the "active" state needs to pull up the strobe pin. -- pinctrl-n: alternate pin modes - -i.mx specific properties -- fsl,usbmisc: phandler of non-core register device, with one - argument that indicate usb controller index -- disable-over-current: disable over current detect -- over-current-active-low: over current signal polarity is active low. -- over-current-active-high: over current signal polarity is active high. - It's recommended to specify the over current polarity. -- power-active-high: power signal polarity is active high -- external-vbus-divider: enables off-chip resistor divider for Vbus -- samsung,picophy-pre-emp-curr-control: HS Transmitter Pre-Emphasis Current - Control. This signal controls the amount of current sourced to the - USB_OTG*_DP and USB_OTG*_DN pins after a J-to-K or K-to-J transition. - The range is from 0x0 to 0x3, the default value is 0x1. - Details can refer to TXPREEMPAMPTUNE0 bits of USBNC_n_PHY_CFG1. -- samsung,picophy-dc-vol-level-adjust: HS DC Voltage Level Adjustment. - Adjust the high-speed transmitter DC level voltage. - The range is from 0x0 to 0xf, the default value is 0x3. - Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1. - -Example: - - usb@f7ed0000 { - compatible = "chipidea,usb2"; - reg = <0xf7ed0000 0x10000>; - interrupts = ; - clocks = <&chip CLKID_USB0>; - phys = <&usb_phy0>; - phy-names = "usb-phy"; - vbus-supply = <®_usb0_vbus>; - itc-setting = <0x4>; /* 4 micro-frames */ - /* Incremental burst of unspecified length */ - ahb-burst-config = <0x0>; - tx-burst-size-dword = <0x10>; /* 64 bytes */ - rx-burst-size-dword = <0x10>; - extcon = <0>, <&usb_id>; - phy-clkgate-delay-us = <400>; - mux-controls = <&usb_switch>; - mux-control-names = "usb_switch"; - }; - -Example for HSIC: - - usb@2184400 { - compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; - reg = <0x02184400 0x200>; - interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks IMX6QDL_CLK_USBOH3>; - fsl,usbphy = <&usbphynop1>; - fsl,usbmisc = <&usbmisc 2>; - phy_type = "hsic"; - dr_mode = "host"; - ahb-burst-config = <0x0>; - tx-burst-size-dword = <0x10>; - rx-burst-size-dword = <0x10>; - pinctrl-names = "idle", "active"; - pinctrl-0 = <&pinctrl_usbh2_idle>; - pinctrl-1 = <&pinctrl_usbh2_active>; - #address-cells = <1>; - #size-cells = <0>; - - usbnet: ethernet@1 { - compatible = "usb424,9730"; - reg = <1>; - }; - }; diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml new file mode 100644 index 000000000000..e5e4dbc5a7a0 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml @@ -0,0 +1,447 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ci-hdrc-usb2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: USB2 ChipIdea USB controller + +maintainers: + - Xu Yang + - Peng Fan + +properties: + compatible: + oneOf: + - enum: + - chipidea,usb2 + - lsi,zevio-usb + - nvidia,tegra20-ehci + - nvidia,tegra20-udc + - nvidia,tegra30-ehci + - nvidia,tegra30-udc + - nvidia,tegra114-udc + - nvidia,tegra124-udc + - qcom,ci-hdrc + - items: + - enum: + - nvidia,tegra114-ehci + - nvidia,tegra124-ehci + - nvidia,tegra210-ehci + - const: nvidia,tegra30-ehci + - items: + - enum: + - fsl,imx23-usb + - fsl,imx25-usb + - fsl,imx28-usb + - fsl,imx50-usb + - fsl,imx51-usb + - fsl,imx53-usb + - fsl,imx6q-usb + - fsl,imx6sl-usb + - fsl,imx6sx-usb + - fsl,imx6ul-usb + - fsl,imx7d-usb + - fsl,vf610-usb + - const: fsl,imx27-usb + - items: + - const: fsl,imx8dxl-usb + - const: fsl,imx7ulp-usb + - const: fsl,imx6ul-usb + - items: + - enum: + - fsl,imx8mm-usb + - fsl,imx8mn-usb + - const: fsl,imx7d-usb + - const: fsl,imx27-usb + - items: + - enum: + - fsl,imx6sll-usb + - fsl,imx7ulp-usb + - const: fsl,imx6ul-usb + - const: fsl,imx27-usb + - items: + - const: xlnx,zynq-usb-2.20a + - const: chipidea,usb2 + + reg: + minItems: 1 + maxItems: 2 + + interrupts: + minItems: 1 + maxItems: 2 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + + dr_mode: true + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + maxItems: 1 + + "#reset-cells": + const: 1 + + phy_type: true + + itc-setting: + description: + interrupt threshold control register control, the setting should be + aligned with ITC bits at register USBCMD. + $ref: /schemas/types.yaml#/definitions/uint32 + + ahb-burst-config: + description: + it is vendor dependent, the required value should be aligned with + AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This property is + used to change AHB burst configuration, check the chipidea spec for + meaning of each value. If this property is not existed, it will use + the reset value. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x7 + + tx-burst-size-dword: + description: + it is vendor dependent, the tx burst size in dword (4 bytes), This + register represents the maximum length of a the burst in 32-bit + words while moving data from system memory to the USB bus, the value + of this property will only take effect if property "ahb-burst-config" + is set to 0, if this property is missing the reset default of the + hardware implementation will be used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x20 + + rx-burst-size-dword: + description: + it is vendor dependent, the rx burst size in dword (4 bytes), This + register represents the maximum length of a the burst in 32-bit words + while moving data from the USB bus to system memory, the value of + this property will only take effect if property "ahb-burst-config" + is set to 0, if this property is missing the reset default of the + hardware implementation will be used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x20 + + extcon: + description: + Phandles to external connector devices. First phandle should point + to external connector, which provide "USB" cable events, the second + should point to external connector device, which provide "USB-HOST" + cable events. If one of the external connector devices is not + required, empty <0> phandle should be specified. + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + items: + - description: vbus extcon + - description: id extcon + + phy-clkgate-delay-us: + description: + The delay time (us) between putting the PHY into low power mode and + gating the PHY clock. + + non-zero-ttctrl-ttha: + description: + After setting this property, the value of register ttctrl.ttha + will be 0x7f; if not, the value will be 0x0, this is the default + value. It needs to be very carefully for setting this property, it + is recommended that consult with your IC engineer before setting + this value. On the most of chipidea platforms, the "usage_tt" flag + at RTL is 0, so this property only affects siTD. + + If this property is not set, the max packet size is 1023 bytes, and + if the total of packet size for pervious transactions are more than + 256 bytes, it can't accept any transactions within this frame. The + use case is single transaction, but higher frame rate. + + If this property is set, the max packet size is 188 bytes, it can + handle more transactions than above case, it can accept transactions + until it considers the left room size within frame is less than 188 + bytes, software needs to make sure it does not send more than 90% + maximum_periodic_data_per_frame. The use case is multiple + transactions, but less frame rate. + type: boolean + + mux-controls: + description: + The mux control for toggling host/device output of this controller. + It's expected that a mux state of 0 indicates device mode and a mux + state of 1 indicates host mode. + maxItems: 1 + + mux-control-names: + const: usb_switch + + operating-points-v2: + description: A phandle to the OPP table containing the performance states. + $ref: /schemas/types.yaml#/definitions/phandle + + pinctrl-names: + description: + Names for optional pin modes in "default", "host", "device". + In case of HSIC-mode, "idle" and "active" pin modes are mandatory. + In this case, the "idle" state needs to pull down the data and + strobe pin and the "active" state needs to pull up the strobe pin. + oneOf: + - items: + - const: idle + - const: active + - items: + - const: default + - enum: + - host + - device + - items: + - const: default + + pinctrl-0: + maxItems: 1 + + pinctrl-1: + maxItems: 1 + + phys: + maxItems: 1 + + phy-names: + const: usb-phy + + phy-select: + description: + Phandler of TCSR node with two argument that indicate register + offset, and phy index + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - description: phandle to TCSR node + - description: register offset + - description: phy index + + vbus-supply: + description: reference to the VBUS regulator. + + fsl,usbmisc: + description: + Phandler of non-core register device, with one argument that + indicate usb controller index + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to usbmisc node + - description: index of usb controller + + fsl,anatop: + description: phandle for the anatop node. + $ref: /schemas/types.yaml#/definitions/phandle + + disable-over-current: + type: boolean + description: disable over current detect + + over-current-active-low: + type: boolean + description: over current signal polarity is active low + + over-current-active-high: + type: boolean + description: + Over current signal polarity is active high. It's recommended to + specify the over current polarity. + + power-active-high: + type: boolean + description: power signal polarity is active high + + external-vbus-divider: + type: boolean + description: enables off-chip resistor divider for Vbus + + samsung,picophy-pre-emp-curr-control: + description: + HS Transmitter Pre-Emphasis Current Control. This signal controls + the amount of current sourced to the USB_OTG*_DP and USB_OTG*_DN + pins after a J-to-K or K-to-J transition. The range is from 0x0 to + 0x3, the default value is 0x1. Details can refer to TXPREEMPAMPTUNE0 + bits of USBNC_n_PHY_CFG1. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x3 + + samsung,picophy-dc-vol-level-adjust: + description: + HS DC Voltage Level Adjustment. Adjust the high-speed transmitter DC + level voltage. The range is from 0x0 to 0xf, the default value is + 0x3. Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0xf + + usb-phy: + description: phandle for the PHY device. Use "phys" instead. + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + + fsl,usbphy: + description: phandle of usb phy that connects to the port. Use "phys" instead. + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + + nvidia,phy: + description: phandle of usb phy that connects to the port. Use "phys" instead. + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + + nvidia,needs-double-reset: + description: Indicates double reset or not. + type: boolean + deprecated: true + + port: + description: + Any connector to the data bus of this controller should be modelled + using the OF graph bindings specified, if the "usb-role-switch" + property is used. + $ref: /schemas/graph.yaml#/properties/port + + reset-gpios: + maxItems: 1 + + ulpi: + type: object + properties: + phy: + description: The phy child node for Qcom chips. + type: object + $ref: /schemas/phy/qcom,usb-hs-phy.yaml + +dependencies: + port: [ usb-role-switch ] + mux-controls: [ mux-control-names ] + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: usb-hcd.yaml# + - $ref: usb-drd.yaml# + - if: + properties: + phy_type: + const: hsic + required: + - phy_type + then: + properties: + pinctrl-names: + items: + - const: idle + - const: active + else: + properties: + pinctrl-names: + minItems: 1 + maxItems: 2 + oneOf: + - items: + - const: default + - enum: + - host + - device + - items: + - const: default + - if: + properties: + compatible: + contains: + enum: + - chipidea,usb2 + - lsi,zevio-usb + - nvidia,tegra20-udc + - nvidia,tegra30-udc + - nvidia,tegra114-udc + - nvidia,tegra124-udc + - qcom,ci-hdrc + - xlnx,zynq-usb-2.20a + then: + properties: + fsl,usbmisc: false + disable-over-current: false + over-current-active-low: false + over-current-active-high: false + power-active-high: false + external-vbus-divider: false + samsung,picophy-pre-emp-curr-control: false + samsung,picophy-dc-vol-level-adjust: false + +unevaluatedProperties: false + +examples: + - | + #include + #include + + usb@f7ed0000 { + compatible = "chipidea,usb2"; + reg = <0xf7ed0000 0x10000>; + interrupts = ; + clocks = <&chip CLKID_USB0>; + phys = <&usb_phy0>; + phy-names = "usb-phy"; + vbus-supply = <®_usb0_vbus>; + itc-setting = <0x4>; /* 4 micro-frames */ + /* Incremental burst of unspecified length */ + ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; /* 64 bytes */ + rx-burst-size-dword = <0x10>; + extcon = <0>, <&usb_id>; + phy-clkgate-delay-us = <400>; + mux-controls = <&usb_switch>; + mux-control-names = "usb_switch"; + }; + + # Example for HSIC: + - | + #include + #include + + usb@2184400 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184400 0x200>; + interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_USBOH3>; + fsl,usbphy = <&usbphynop1>; + fsl,usbmisc = <&usbmisc 2>; + phy_type = "hsic"; + dr_mode = "host"; + ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; + rx-burst-size-dword = <0x10>; + pinctrl-names = "idle", "active"; + pinctrl-0 = <&pinctrl_usbh2_idle>; + pinctrl-1 = <&pinctrl_usbh2_active>; + #address-cells = <1>; + #size-cells = <0>; + + ethernet@1 { + compatible = "usb424,9730"; + reg = <1>; + }; + }; + +... -- cgit v1.2.3 From 64de129680a45a25b822bd0bf4c4aeb62f1b9c2f Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:24:57 +0800 Subject: dt-bindings: usb: usb-nop-xceiv: add power-domains property Add power-domains optional property Acked-by: Rob Herring Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-4-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml index 921b986adc47..6734f4d3aa78 100644 --- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml +++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml @@ -27,6 +27,9 @@ properties: vcc-supply: description: phandle to the regulator that provides power to the PHY. + power-domains: + maxItems: 1 + reset-gpios: maxItems: 1 -- cgit v1.2.3 From 835765da87d8d07db20218a5676bb5b3d9f2e7c6 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:24:58 +0800 Subject: arm64: dts: imx8mn: update usb compatible Update usb compatible per binding doc Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-5-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/freescale/imx8mn.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi index 9e0ddd6b7a32..7b58660d9ef4 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@ -1091,7 +1091,7 @@ }; usbotg1: usb@32e40000 { - compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb"; + compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x32e40000 0x200>; interrupts = ; clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>; @@ -1105,7 +1105,8 @@ }; usbmisc1: usbmisc@32e40200 { - compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x32e40200 0x200>; }; -- cgit v1.2.3 From 69fef68e4c8f5f80539b6a7d4f76af0de0732da3 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:24:59 +0800 Subject: arm64: dts: imx8mm: update usb compatible Update usb compatible per binding doc Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-6-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/freescale/imx8mm.dtsi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 31f4548f85cf..719e38223bef 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -1198,7 +1198,7 @@ }; usbotg1: usb@32e40000 { - compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb"; + compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x32e40000 0x200>; interrupts = ; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; @@ -1212,13 +1212,14 @@ }; usbmisc1: usbmisc@32e40200 { - compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x32e40200 0x200>; }; usbotg2: usb@32e50000 { - compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb"; + compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x32e50000 0x200>; interrupts = ; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; @@ -1232,7 +1233,8 @@ }; usbmisc2: usbmisc@32e50200 { - compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x32e50200 0x200>; }; -- cgit v1.2.3 From 276dd9a66e7157a0f317a7a59bf9fbe8ec0cd3d0 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:25:00 +0800 Subject: arm64: dts: imx8: update usb compatible Update usb compatible per binding doc Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-7-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi index 4852760adeee..6ed084862345 100644 --- a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi @@ -35,7 +35,7 @@ conn_subsys: bus@5b000000 { }; usbotg1: usb@5b0d0000 { - compatible = "fsl,imx7ulp-usb"; + compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb"; reg = <0x5b0d0000 0x200>; interrupt-parent = <&gic>; interrupts = ; @@ -51,7 +51,7 @@ conn_subsys: bus@5b000000 { usbmisc1: usbmisc@5b0d0200 { #index-cells = <1>; - compatible = "fsl,imx7ulp-usbmisc", "fsl,imx6q-usbmisc"; + compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc"; reg = <0x5b0d0200 0x200>; }; -- cgit v1.2.3 From 2656e9f5119f8dfb9796e4ba11082ffe49d8cecc Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:25:01 +0800 Subject: arm64: dts: imx8dxl: update usb compatible Update usb compatible per binding doc Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-8-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi index ca195e6d8f37..88913869ae9c 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi @@ -34,7 +34,7 @@ }; usbotg2: usb@5b0e0000 { - compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb"; + compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb", "fsl,imx6ul-usb"; reg = <0x5b0e0000 0x200>; interrupt-parent = <&gic>; interrupts = ; @@ -63,7 +63,7 @@ usbmisc2: usbmisc@5b0e0200 { #index-cells = <1>; - compatible = "fsl,imx7ulp-usbmisc"; + compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc"; reg = <0x5b0e0200 0x200>; }; -- cgit v1.2.3 From 6304876355fb6ac60fef306fff6da71bb08401b7 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:25:02 +0800 Subject: arm64: dts: imx8dxl: drop #stream-id-cells for usb node There is no SMMU in i.MX8DXL, drop #stream-id-cells which is for SMMU-v2. Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-9-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi index 88913869ae9c..652493ae4bb5 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi @@ -49,7 +49,6 @@ ahb-burst-config = <0x0>; tx-burst-size-dword = <0x10>; rx-burst-size-dword = <0x10>; - #stream-id-cells = <1>; power-domains = <&pd IMX_SC_R_USB_1>; status = "disabled"; -- cgit v1.2.3 From 79e94aa19736ec8f38ec02880eeec37cc5900bd8 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 22 Mar 2023 13:25:04 +0800 Subject: ARM64: dts: imx7ulp: update usb compatible Per binding doc, update the compatible Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230322052504.2629429-11-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx7ulp.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi index 7f7d2d5122fb..f91bf719d4e2 100644 --- a/arch/arm/boot/dts/imx7ulp.dtsi +++ b/arch/arm/boot/dts/imx7ulp.dtsi @@ -189,7 +189,7 @@ }; usbotg1: usb@40330000 { - compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb"; + compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb"; reg = <0x40330000 0x200>; interrupts = ; clocks = <&pcc2 IMX7ULP_CLK_USB0>; @@ -202,7 +202,8 @@ }; usbmisc1: usbmisc@40330200 { - compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x40330200 0x200>; }; -- cgit v1.2.3 From b93c2a68f3d9dc98ec30dcb342ae47c1c8d09d18 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Fri, 24 Mar 2023 14:47:57 -0700 Subject: usb: gadget: Properly configure the device for remote wakeup The wakeup bit in the bmAttributes field indicates whether the device is configured for remote wakeup. But this field should be allowed to set only if the UDC supports such wakeup mechanism. So configure this field based on UDC capability. Also inform the UDC whether the device is configured for remote wakeup by implementing a gadget op. Reviewed-by: Thinh Nguyen Signed-off-by: Elson Roy Serrao Link: https://lore.kernel.org/r/1679694482-16430-2-git-send-email-quic_eserrao@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 18 ++++++++++++++++++ drivers/usb/gadget/configfs.c | 3 +++ drivers/usb/gadget/udc/core.c | 27 +++++++++++++++++++++++++++ drivers/usb/gadget/udc/trace.h | 5 +++++ include/linux/usb/composite.h | 2 ++ include/linux/usb/gadget.h | 8 ++++++++ 6 files changed, 63 insertions(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f1ecd12b62c3..00c89571de2a 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -513,6 +513,19 @@ static u8 encode_bMaxPower(enum usb_device_speed speed, return min(val, 900U) / 8; } +void check_remote_wakeup_config(struct usb_gadget *g, + struct usb_configuration *c) +{ + if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) { + /* Reset the rw bit if gadget is not capable of it */ + if (!g->wakeup_capable && g->ops->set_remote_wakeup) { + WARN(c->cdev, "Clearing wakeup bit for config c.%d\n", + c->bConfigurationValue); + c->bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; + } + } +} + static int config_buf(struct usb_configuration *config, enum usb_device_speed speed, void *buf, u8 type) { @@ -994,6 +1007,11 @@ static int set_config(struct usb_composite_dev *cdev, power = min(power, 500U); else power = min(power, 900U); + + if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) + usb_gadget_set_remote_wakeup(gadget, 1); + else + usb_gadget_set_remote_wakeup(gadget, 0); done: if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) usb_gadget_set_selfpowered(gadget); diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index b9f1136aa0a2..4c639e9ddedc 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1761,6 +1761,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget, if (gadget_is_otg(gadget)) c->descriptors = otg_desc; + /* Properly configure the bmAttributes wakeup bit */ + check_remote_wakeup_config(gadget, c); + cfg = container_of(c, struct config_usb_cfg, c); if (!list_empty(&cfg->string_list)) { i = 0; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 23b0629a8774..3dcbba739db6 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -513,6 +513,33 @@ out: } EXPORT_SYMBOL_GPL(usb_gadget_wakeup); +/** + * usb_gadget_set_remote_wakeup - configures the device remote wakeup feature. + * @gadget:the device being configured for remote wakeup + * @set:value to be configured. + * + * set to one to enable remote wakeup feature and zero to disable it. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set) +{ + int ret = 0; + + if (!gadget->ops->set_remote_wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_remote_wakeup(gadget, set); + +out: + trace_usb_gadget_set_remote_wakeup(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_set_remote_wakeup); + /** * usb_gadget_set_selfpowered - sets the device selfpowered feature. * @gadget:the device being declared as self-powered diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h index abdbcb1bacb0..a5ed26fbc2da 100644 --- a/drivers/usb/gadget/udc/trace.h +++ b/drivers/usb/gadget/udc/trace.h @@ -91,6 +91,11 @@ DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup, TP_ARGS(g, ret) ); +DEFINE_EVENT(udc_log_gadget, usb_gadget_set_remote_wakeup, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered, TP_PROTO(struct usb_gadget *g, int ret), TP_ARGS(g, ret) diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 608dc962748b..d949e91ceb48 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -413,6 +413,8 @@ extern int composite_dev_prepare(struct usb_composite_driver *composite, extern int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, struct usb_ep *ep0); void composite_dev_cleanup(struct usb_composite_dev *cdev); +void check_remote_wakeup_config(struct usb_gadget *g, + struct usb_configuration *c); static inline struct usb_composite_driver *to_cdriver( struct usb_gadget_driver *gdrv) diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 00750f7020f3..1d796128030b 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -310,6 +310,7 @@ struct usb_udc; struct usb_gadget_ops { int (*get_frame)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); + int (*set_remote_wakeup)(struct usb_gadget *, int set); int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); int (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_draw) (struct usb_gadget *, unsigned mA); @@ -384,6 +385,8 @@ struct usb_gadget_ops { * @connected: True if gadget is connected. * @lpm_capable: If the gadget max_speed is FULL or HIGH, this flag * indicates that it supports LPM as per the LPM ECN & errata. + * @wakeup_capable: True if gadget is capable of sending remote wakeup. + * @wakeup_armed: True if gadget is armed by the host for remote wakeup. * @irq: the interrupt number for device controller. * @id_number: a unique ID number for ensuring that gadget names are distinct * @@ -445,6 +448,8 @@ struct usb_gadget { unsigned deactivated:1; unsigned connected:1; unsigned lpm_capable:1; + unsigned wakeup_capable:1; + unsigned wakeup_armed:1; int irq; int id_number; }; @@ -601,6 +606,7 @@ static inline int gadget_is_otg(struct usb_gadget *g) #if IS_ENABLED(CONFIG_USB_GADGET) int usb_gadget_frame_number(struct usb_gadget *gadget); int usb_gadget_wakeup(struct usb_gadget *gadget); +int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set); int usb_gadget_set_selfpowered(struct usb_gadget *gadget); int usb_gadget_clear_selfpowered(struct usb_gadget *gadget); int usb_gadget_vbus_connect(struct usb_gadget *gadget); @@ -616,6 +622,8 @@ static inline int usb_gadget_frame_number(struct usb_gadget *gadget) { return 0; } static inline int usb_gadget_wakeup(struct usb_gadget *gadget) { return 0; } +static inline int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set) +{ return 0; } static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget) { return 0; } static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) -- cgit v1.2.3 From 047161686b813ae9035a3fb342ba8b6932053492 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Fri, 24 Mar 2023 14:47:58 -0700 Subject: usb: dwc3: Add remote wakeup handling An usb device can initate a remote wakeup and bring the link out of suspend as dictated by the DEVICE_REMOTE_WAKEUP feature selector. Add support to handle this packet and set the remote wakeup capability. Some hosts may take longer time to initiate the resume signaling after device triggers a remote wakeup. So add async support to the wakeup API by enabling link status change events. Acked-by: Thinh Nguyen Signed-off-by: Elson Roy Serrao Link: https://lore.kernel.org/r/1679694482-16430-3-git-send-email-quic_eserrao@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/ep0.c | 7 +++++ drivers/usb/dwc3/gadget.c | 76 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 912208585da2..8541708ed2cb 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1113,6 +1113,7 @@ struct dwc3_scratchpad_array { * 3 - Reserved * @dis_metastability_quirk: set to disable metastability quirk. * @dis_split_quirk: set to disable split boundary. + * @wakeup_configured: set if the device is configured for remote wakeup. * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @max_cfg_eps: current max number of IN eps used across all USB configs. @@ -1331,6 +1332,7 @@ struct dwc3 { unsigned dis_split_quirk:1; unsigned async_callbacks:1; + unsigned wakeup_configured:1; u16 imod_interval; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 61de693461da..8aa14a596406 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -356,6 +356,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; if (reg & DWC3_DCTL_INITU2ENA) usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } else { + usb_status |= dwc->gadget->wakeup_armed << + USB_DEVICE_REMOTE_WAKEUP; } break; @@ -476,6 +479,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: + if (dwc->wakeup_configured) + dwc->gadget->wakeup_armed = set; + else + ret = -EINVAL; break; /* * 9.4.1 says only for SS, in AddressState only for diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 29f8f9311d77..7ceff08a1b8c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -258,7 +258,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, return ret; } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc); +static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async); /** * dwc3_send_gadget_ep_cmd - issue an endpoint command @@ -325,7 +325,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, fallthrough; case DWC3_LINK_STATE_U3: - ret = __dwc3_gadget_wakeup(dwc); + ret = __dwc3_gadget_wakeup(dwc, false); dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", ret); break; @@ -2273,6 +2273,22 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = { /* -------------------------------------------------------------------------- */ +static void dwc3_gadget_enable_linksts_evts(struct dwc3 *dwc, bool set) +{ + u32 reg; + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + + reg = dwc3_readl(dwc->regs, DWC3_DEVTEN); + if (set) + reg |= DWC3_DEVTEN_ULSTCNGEN; + else + reg &= ~DWC3_DEVTEN_ULSTCNGEN; + + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); +} + static int dwc3_gadget_get_frame(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); @@ -2280,7 +2296,7 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) return __dwc3_gadget_get_frame(dwc); } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc) +static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) { int retries; @@ -2311,9 +2327,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) return -EINVAL; } + if (async) + dwc3_gadget_enable_linksts_evts(dwc, true); + ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); if (ret < 0) { dev_err(dwc->dev, "failed to put link in Recovery\n"); + dwc3_gadget_enable_linksts_evts(dwc, false); return ret; } @@ -2325,6 +2345,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); } + /* + * Since link status change events are enabled we will receive + * an U0 event when wakeup is successful. So bail out. + */ + if (async) + return 0; + /* poll until Link State changes to ON */ retries = 20000; @@ -2350,13 +2377,36 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) unsigned long flags; int ret; + if (!dwc->wakeup_configured) { + dev_err(dwc->dev, "remote wakeup not configured\n"); + return -EINVAL; + } + spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_wakeup(dwc); + if (!dwc->gadget->wakeup_armed) { + dev_err(dwc->dev, "not armed for remote wakeup\n"); + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + ret = __dwc3_gadget_wakeup(dwc, true); + spin_unlock_irqrestore(&dwc->lock, flags); return ret; } +static int dwc3_gadget_set_remote_wakeup(struct usb_gadget *g, int set) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + dwc->wakeup_configured = !!set; + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, int is_selfpowered) { @@ -2982,6 +3032,7 @@ static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable) static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, + .set_remote_wakeup = dwc3_gadget_set_remote_wakeup, .set_selfpowered = dwc3_gadget_set_selfpowered, .pullup = dwc3_gadget_pullup, .udc_start = dwc3_gadget_start, @@ -3827,6 +3878,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->gadget->speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; + dwc->gadget->wakeup_armed = false; + dwc3_gadget_enable_linksts_evts(dwc, false); usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); if (dwc->ep0state != EP0_SETUP_PHASE) { @@ -3920,6 +3973,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_TSTCTRL_MASK; dwc3_gadget_dctl_write_safe(dwc, reg); dwc->test_mode = false; + dwc->gadget->wakeup_armed = false; + dwc3_gadget_enable_linksts_evts(dwc, false); dwc3_clear_stall_all_ep(dwc); /* Reset device address to zero */ @@ -4072,7 +4127,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) */ } -static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) +static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { /* * TODO take core out of low power mode when that's @@ -4084,6 +4139,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) dwc->gadget_driver->resume(dwc->gadget); spin_lock(&dwc->lock); } + + dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; } static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, @@ -4165,6 +4222,12 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } switch (next) { + case DWC3_LINK_STATE_U0: + if (dwc->gadget->wakeup_armed) { + dwc3_gadget_enable_linksts_evts(dwc, false); + dwc3_resume_gadget(dwc); + } + break; case DWC3_LINK_STATE_U1: if (dwc->speed == USB_SPEED_SUPER) dwc3_suspend_gadget(dwc); @@ -4233,7 +4296,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc3_gadget_conndone_interrupt(dwc); break; case DWC3_DEVICE_EVENT_WAKEUP: - dwc3_gadget_wakeup_interrupt(dwc); + dwc3_gadget_wakeup_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_HIBER_REQ: if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, @@ -4481,6 +4544,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget->sg_supported = true; dwc->gadget->name = "dwc3-gadget"; dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable; + dwc->gadget->wakeup_capable = true; /* * FIXME We might be setting max_speed to Date: Fri, 24 Mar 2023 14:47:59 -0700 Subject: usb: gadget: Add function wakeup support USB3.2 spec section 9.2.5.4 quotes that a function may signal that it wants to exit from Function Suspend by sending a Function Wake Notification to the host if it is enabled for function remote wakeup. Add an api in composite layer that can be used by the function drivers to support this feature. Also expose a gadget op so that composite layer can trigger a wakeup request to the UDC driver. Reviewed-by: Thinh Nguyen Signed-off-by: Elson Roy Serrao Link: https://lore.kernel.org/r/1679694482-16430-4-git-send-email-quic_eserrao@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/usb/composite.h | 6 ++++++ include/linux/usb/gadget.h | 1 + 3 files changed, 47 insertions(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 00c89571de2a..d3fd2d1d8096 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -492,6 +492,46 @@ int usb_interface_id(struct usb_configuration *config, } EXPORT_SYMBOL_GPL(usb_interface_id); +/** + * usb_func_wakeup - sends function wake notification to the host. + * @func: function that sends the remote wakeup notification. + * + * Applicable to devices operating at enhanced superspeed when usb + * functions are put in function suspend state and armed for function + * remote wakeup. On completion, function wake notification is sent. If + * the device is in low power state it tries to bring the device to active + * state before sending the wake notification. Since it is a synchronous + * call, caller must take care of not calling it in interrupt context. + * For devices operating at lower speeds returns negative errno. + * + * Returns zero on success, else negative errno. + */ +int usb_func_wakeup(struct usb_function *func) +{ + struct usb_gadget *gadget = func->config->cdev->gadget; + int id; + + if (!gadget->ops->func_wakeup) + return -EOPNOTSUPP; + + if (!func->func_wakeup_armed) { + ERROR(func->config->cdev, "not armed for func remote wakeup\n"); + return -EINVAL; + } + + for (id = 0; id < MAX_CONFIG_INTERFACES; id++) + if (func->config->interface[id] == func) + break; + + if (id == MAX_CONFIG_INTERFACES) { + ERROR(func->config->cdev, "Invalid function\n"); + return -EINVAL; + } + + return gadget->ops->func_wakeup(gadget, id); +} +EXPORT_SYMBOL_GPL(usb_func_wakeup); + static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) { diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index d949e91ceb48..a2448e98854f 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -150,6 +150,9 @@ struct usb_os_desc_table { * GetStatus() request when the recipient is Interface. * @func_suspend: callback to be called when * SetFeature(FUNCTION_SUSPEND) is reseived + * @func_suspended: Indicates whether the function is in function suspend state. + * @func_wakeup_armed: Indicates whether the function is armed by the host for + * wakeup signaling. * * A single USB function uses one or more interfaces, and should in most * cases support operation at both full and high speeds. Each function is @@ -220,6 +223,8 @@ struct usb_function { int (*get_status)(struct usb_function *); int (*func_suspend)(struct usb_function *, u8 suspend_opt); + bool func_suspended; + bool func_wakeup_armed; /* private: */ /* internals */ struct list_head list; @@ -241,6 +246,7 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g, struct usb_function *f, int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, struct usb_ep *_ep); +int usb_func_wakeup(struct usb_function *func); #define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 1d796128030b..75bda0783395 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -310,6 +310,7 @@ struct usb_udc; struct usb_gadget_ops { int (*get_frame)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); + int (*func_wakeup)(struct usb_gadget *gadget, int intf_id); int (*set_remote_wakeup)(struct usb_gadget *, int set); int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); int (*vbus_session) (struct usb_gadget *, int is_active); -- cgit v1.2.3 From 92c08a84b53e5dd1f2150e870db2ae9e5a5459e1 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Fri, 24 Mar 2023 14:48:00 -0700 Subject: usb: dwc3: Add function suspend and function wakeup support USB host sends function suspend and function resume notifications to the interface through SET_FEATURE/CLEAR_FEATURE setup packets. Add support to handle these packets by delegating the requests to composite layer. Also add support to handle function wake notification requests to exit from function suspend state. Acked-by: Thinh Nguyen Signed-off-by: Elson Roy Serrao Link: https://lore.kernel.org/r/1679694482-16430-5-git-send-email-quic_eserrao@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/debug.h | 2 ++ drivers/usb/dwc3/ep0.c | 12 ++++-------- drivers/usb/dwc3/gadget.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 8541708ed2cb..26c8efefbff9 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -527,6 +527,7 @@ #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c #define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 +#define DWC3_DGCMD_DEV_NOTIFICATION 0x07 #define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F) #define DWC3_DGCMD_CMDACT BIT(10) @@ -539,6 +540,8 @@ #define DWC3_DGCMDPAR_TX_FIFO BIT(5) #define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0) #define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(0) +#define DWC3_DGCMDPAR_DN_FUNC_WAKE BIT(0) +#define DWC3_DGCMDPAR_INTF_SEL(n) ((n) << 4) /* Device Endpoint Command Register */ #define DWC3_DEPCMD_PARAM_SHIFT 16 diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 8bb2c9e3b9ac..09d703852a92 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -72,6 +72,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd) return "Set Endpoint Prime"; case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: return "Run SoC Bus Loopback Test"; + case DWC3_DGCMD_DEV_NOTIFICATION: + return "Device Notification"; default: return "UNKNOWN"; } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 8aa14a596406..953b752a5052 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -30,6 +30,8 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, dma_addr_t buf_dma, u32 len, u32 type, bool chain) @@ -368,7 +370,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + return dwc3_ep0_delegate_req(dwc, ctrl); case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -517,13 +519,7 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, switch (wValue) { case USB_INTRF_FUNC_SUSPEND: - /* - * REVISIT: Ideally we would enable some low power mode here, - * however it's unclear what we should be doing here. - * - * For now, we're not doing anything, just making sure we return - * 0 so USB Command Verifier tests pass without any errors. - */ + ret = dwc3_ep0_delegate_req(dwc, ctrl); break; default: ret = -EINVAL; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7ceff08a1b8c..287ea6ee2463 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2395,6 +2395,47 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) return ret; } +static void dwc3_resume_gadget(struct dwc3 *dwc); + +static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + int ret; + int link_state; + + if (!dwc->wakeup_configured) { + dev_err(dwc->dev, "remote wakeup not configured\n"); + return -EINVAL; + } + + spin_lock_irqsave(&dwc->lock, flags); + /* + * If the link is in U3, signal for remote wakeup and wait for the + * link to transition to U0 before sending device notification. + */ + link_state = dwc3_gadget_get_link_state(dwc); + if (link_state == DWC3_LINK_STATE_U3) { + ret = __dwc3_gadget_wakeup(dwc, false); + if (ret) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + dwc3_resume_gadget(dwc); + dwc->link_state = DWC3_LINK_STATE_U0; + } + + ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION, + DWC3_DGCMDPAR_DN_FUNC_WAKE | + DWC3_DGCMDPAR_INTF_SEL(intf_id)); + if (ret) + dev_err(dwc->dev, "function remote wakeup failed, ret:%d\n", ret); + + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; +} + static int dwc3_gadget_set_remote_wakeup(struct usb_gadget *g, int set) { struct dwc3 *dwc = gadget_to_dwc(g); @@ -3032,6 +3073,7 @@ static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable) static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, + .func_wakeup = dwc3_gadget_func_wakeup, .set_remote_wakeup = dwc3_gadget_set_remote_wakeup, .set_selfpowered = dwc3_gadget_set_selfpowered, .pullup = dwc3_gadget_pullup, -- cgit v1.2.3 From 481c225c4802be62e52aabddae5338ed1705b232 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Fri, 24 Mar 2023 14:48:01 -0700 Subject: usb: gadget: Handle function suspend feature selector When host sends function suspend feature selector to the device, inspect the received packet and trigger function suspend or function resume accordingly. Inspect the remote wakeup bit and arm the function for remote wakeup if it is wakeup capable. Also host queries the function wakeup capability through a get status request before sending function resume. Handle such requests in composite layer. Signed-off-by: Elson Roy Serrao Reviewed-by: Thinh Nguyen Link: https://lore.kernel.org/r/1679694482-16430-6-git-send-email-quic_eserrao@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 65 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index d3fd2d1d8096..1b3489149e5e 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -941,6 +941,9 @@ static void reset_config(struct usb_composite_dev *cdev) if (f->disable) f->disable(f); + /* Section 9.1.1.6, disable remote wakeup when device is reset */ + f->func_wakeup_armed = false; + bitmap_zero(f->endpoints, 32); } cdev->config = NULL; @@ -2006,9 +2009,20 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) f = cdev->config->interface[intf]; if (!f) break; - status = f->get_status ? f->get_status(f) : 0; - if (status < 0) - break; + + if (f->get_status) { + status = f->get_status(f); + if (status < 0) + break; + } else { + /* Set D0 and D1 bits based on func wakeup capability */ + if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { + status |= USB_INTRF_STAT_FUNC_RW_CAP; + if (f->func_wakeup_armed) + status |= USB_INTRF_STAT_FUNC_RW; + } + } + put_unaligned_le16(status & 0x0000ffff, req->buf); break; /* @@ -2030,8 +2044,44 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!f) break; value = 0; - if (f->func_suspend) + if (f->func_suspend) { value = f->func_suspend(f, w_index >> 8); + /* SetFeature(FUNCTION_SUSPEND) */ + } else if (ctrl->bRequest == USB_REQ_SET_FEATURE) { + if (!(f->config->bmAttributes & + USB_CONFIG_ATT_WAKEUP) && + (w_index & USB_INTRF_FUNC_SUSPEND_RW)) + break; + + f->func_wakeup_armed = !!(w_index & + USB_INTRF_FUNC_SUSPEND_RW); + + if (w_index & USB_INTRF_FUNC_SUSPEND_LP) { + if (f->suspend && !f->func_suspended) { + f->suspend(f); + f->func_suspended = true; + } + /* + * Handle cases where host sends function resume + * through SetFeature(FUNCTION_SUSPEND) but low power + * bit reset + */ + } else { + if (f->resume && f->func_suspended) { + f->resume(f); + f->func_suspended = false; + } + } + /* ClearFeature(FUNCTION_SUSPEND) */ + } else if (ctrl->bRequest == USB_REQ_CLEAR_FEATURE) { + f->func_wakeup_armed = false; + + if (f->resume && f->func_suspended) { + f->resume(f); + f->func_suspended = false; + } + } + if (value < 0) { ERROR(cdev, "func_suspend() returned error %d\n", @@ -2573,7 +2623,12 @@ void composite_resume(struct usb_gadget *gadget) cdev->driver->resume(cdev); if (cdev->config) { list_for_each_entry(f, &cdev->config->functions, list) { - if (f->resume) + /* + * Check for func_suspended flag to see if the function is + * in USB3 FUNCTION_SUSPEND state. In this case resume is + * done via FUNCTION_SUSPEND feature selector. + */ + if (f->resume && !f->func_suspended) f->resume(f); } -- cgit v1.2.3 From 0a1af6dfa0772ffedaef422127f1338fa0ddfed3 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Fri, 24 Mar 2023 14:48:02 -0700 Subject: usb: gadget: f_ecm: Add suspend/resume and remote wakeup support When host sends suspend notification to the device, handle the suspend callbacks in the function driver. Depending on the remote wakeup capability the device can either trigger a remote wakeup or wait for the host initiated resume to resume data transfer. Signed-off-by: Elson Roy Serrao Reviewed-by: Thinh Nguyen Link: https://lore.kernel.org/r/1679694482-16430-7-git-send-email-quic_eserrao@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_ecm.c | 22 ++++++++++++ drivers/usb/gadget/function/u_ether.c | 63 +++++++++++++++++++++++++++++++++++ drivers/usb/gadget/function/u_ether.h | 4 +++ 3 files changed, 89 insertions(+) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index a7ab30e603e2..c6e63ad77a40 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -885,6 +885,26 @@ static struct usb_function_instance *ecm_alloc_inst(void) return &opts->func_inst; } +static void ecm_suspend(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Suspend\n"); + + gether_suspend(&ecm->port); +} + +static void ecm_resume(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Resume\n"); + + gether_resume(&ecm->port); +} + static void ecm_free(struct usb_function *f) { struct f_ecm *ecm; @@ -952,6 +972,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) ecm->port.func.setup = ecm_setup; ecm->port.func.disable = ecm_disable; ecm->port.func.free_func = ecm_free; + ecm->port.func.suspend = ecm_suspend; + ecm->port.func.resume = ecm_resume; return &ecm->port.func; } diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index f259975dfba4..6956ad8ba8dd 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -437,6 +437,20 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } +static int ether_wakeup_host(struct gether *port) +{ + int ret; + struct usb_function *func = &port->func; + struct usb_gadget *gadget = func->config->cdev->gadget; + + if (func->func_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + return ret; +} + static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -456,6 +470,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, in = NULL; cdc_filter = 0; } + + if (dev->port_usb && dev->port_usb->is_suspend) { + DBG(dev, "Port suspended. Triggering wakeup\n"); + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->lock, flags); + ether_wakeup_host(dev->port_usb); + return NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&dev->lock, flags); if (!in) { @@ -1014,6 +1037,45 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) } EXPORT_SYMBOL_GPL(gether_set_ifname); +void gether_suspend(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (atomic_read(&dev->tx_qlen)) { + /* + * There is a transfer in progress. So we trigger a remote + * wakeup to inform the host. + */ + ether_wakeup_host(dev->port_usb); + return; + } + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = true; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_suspend); + +void gether_resume(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (netif_queue_stopped(dev->net)) + netif_start_queue(dev->net); + + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = false; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_resume); + /* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep @@ -1176,6 +1238,7 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = NULL; + link->is_suspend = false; spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(gether_disconnect); diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 40144546d1b0..851ee10d6e63 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -79,6 +79,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); + bool is_suspend; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ @@ -258,6 +259,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len); void gether_cleanup(struct eth_dev *dev); +void gether_suspend(struct gether *link); +void gether_resume(struct gether *link); + /* connect/disconnect is handled by individual functions */ struct net_device *gether_connect(struct gether *); void gether_disconnect(struct gether *); -- cgit v1.2.3 From d629c0e221cd99198b843d8351a0a9bfec6c0423 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 29 Mar 2023 09:51:25 +0200 Subject: usb: move config USB_USS720 to usb's misc Kconfig The USS720 parport driver source code is in drivers/usb/misc/, the corresponding config is defined in drivers/usb/Kconfig. Some digging in the kernel's history revealed no good reason why it needs to be defined in USB's top-level Kconfig file, and why the config for the USS720 parport driver should be the first in the list of USB port drivers, while all other configs for drivers in drivers/usb/misc are in the USB Miscellaneous driver configuration file. Most probably, it was simply considered a bit more special when the USB Miscellaneous driver configuration file (drivers/usb/misc/Config.in back then) was initially created, and this config simply survived to remain at the top-level USB Kconfig file with all further code/Kconfig transformations and additions later on. Users rarely notice this config being at this position, as CONFIG_PARPORT (Parallel port support) needs to be enabled and only few users enable that. Nowadays, this USB_USS720 driver is probably not that special that it needs to be listed as first item of the USB port drivers. Move the configuration of the USS720 parport driver to the top of the USB Miscellaneous drivers section, as the configurations does not have a lot of specific ordering USB Miscellaneous drivers. This way, the USS720 parport driver is moved to the comment "USB Miscellaneous drivers", fitting to the driver's source code location, but still is at the top of the list for those few acquainted users of Kconfig UIs that might be looking for the config that was once at the top of the list of the USB port drivers. Put this config definition to a more local place. No semantic change. Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20230329075125.32352-1-lukas.bulwahn@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 29 ----------------------------- drivers/usb/misc/Kconfig | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index a871a988829d..7f33bcc315f2 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -133,35 +133,6 @@ comment "USB port drivers" if USB -config USB_USS720 - tristate "USS720 parport driver" - depends on PARPORT - select PARPORT_NOT_PC - help - This driver is for USB parallel port adapters that use the Lucent - Technologies USS-720 chip. These cables are plugged into your USB - port and provide USB compatibility to peripherals designed with - parallel port interfaces. - - The chip has two modes: automatic mode and manual mode. In automatic - mode, it looks to the computer like a standard USB printer. Only - printers may be connected to the USS-720 in this mode. The generic - USB printer driver ("USB Printer support", above) may be used in - that mode, and you can say N here if you want to use the chip only - in this mode. - - Manual mode is not limited to printers, any parallel port - device should work. This driver utilizes manual mode. - Note however that some operations are three orders of magnitude - slower than on a PCI/ISA Parallel Port, so timing critical - applications might not work. - - Say Y here if you own an USS-720 USB->Parport cable and intend to - connect anything other than a printer to it. - - To compile this driver as a module, choose M here: the - module will be called uss720. - source "drivers/usb/serial/Kconfig" source "drivers/usb/misc/Kconfig" diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 08e3cf9efb38..99b15b77dfd5 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -4,6 +4,35 @@ # comment "USB Miscellaneous drivers" +config USB_USS720 + tristate "USS720 parport driver" + depends on PARPORT + select PARPORT_NOT_PC + help + This driver is for USB parallel port adapters that use the Lucent + Technologies USS-720 chip. These cables are plugged into your USB + port and provide USB compatibility to peripherals designed with + parallel port interfaces. + + The chip has two modes: automatic mode and manual mode. In automatic + mode, it looks to the computer like a standard USB printer. Only + printers may be connected to the USS-720 in this mode. The generic + USB printer driver ("USB Printer support", above) may be used in + that mode, and you can say N here if you want to use the chip only + in this mode. + + Manual mode is not limited to printers, any parallel port + device should work. This driver utilizes manual mode. + Note however that some operations are three orders of magnitude + slower than on a PCI/ISA Parallel Port, so timing critical + applications might not work. + + Say Y here if you own an USS-720 USB->Parport cable and intend to + connect anything other than a printer to it. + + To compile this driver as a module, choose M here: the + module will be called uss720. + config USB_EMI62 tristate "EMI 6|2m USB Audio interface support" help -- cgit v1.2.3 From 1f15af76784cc902a1fe85e864c7ddf3d74b4130 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 Mar 2023 13:23:42 +0300 Subject: thunderbolt: Introduce usb4_port_sb_opcode_err_to_errno() helper The usb4_port_sb_opcode_err_to_errno() converts from USB4 error codes to the Linux errno space. In particular, this makes the intention of the repeating usb4_port_retimer_read() call in the usb4_port_retimer_nvm_authenticate_status() clearer. Signed-off-by: Andy Shevchenko Signed-off-by: Mika Westerberg --- drivers/thunderbolt/usb4.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index 8dcdde61a15f..bcc3ec2eb221 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -1303,6 +1303,20 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target, return 0; } +static int usb4_port_sb_opcode_err_to_errno(u32 val) +{ + switch (val) { + case 0: + return 0; + case USB4_SB_OPCODE_ERR: + return -EAGAIN; + case USB4_SB_OPCODE_ONS: + return -EOPNOTSUPP; + default: + return -EIO; + } +} + static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target, u8 index, enum usb4_sb_opcode opcode, int timeout_msec) { @@ -1325,21 +1339,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target, if (ret) return ret; - switch (val) { - case 0: - return 0; - - case USB4_SB_OPCODE_ERR: - return -EAGAIN; - - case USB4_SB_OPCODE_ONS: - return -EOPNOTSUPP; - - default: - if (val != opcode) - return -EIO; - break; - } + if (val != opcode) + return usb4_port_sb_opcode_err_to_errno(val); } while (ktime_before(ktime_get(), timeout)); return -ETIMEDOUT; @@ -1800,12 +1801,13 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, if (ret) return ret; - switch (val) { + ret = usb4_port_sb_opcode_err_to_errno(val); + switch (ret) { case 0: *status = 0; return 0; - case USB4_SB_OPCODE_ERR: + case -EAGAIN: ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata, sizeof(metadata)); if (ret) @@ -1814,11 +1816,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, *status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK; return 0; - case USB4_SB_OPCODE_ONS: - return -EOPNOTSUPP; - default: - return -EIO; + return ret; } } -- cgit v1.2.3 From ad813605f77553f5e73cd23913fa7591b0d794f6 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Tue, 21 Mar 2023 14:12:55 -0400 Subject: USB: serial: quatech2: remove unused qt2_setdevice function clang with W=1 reports drivers/usb/serial/quatech2.c:179:19: error: unused function 'qt2_setdevice' [-Werror,-Wunused-function] static inline int qt2_setdevice(struct usb_device *dev, u8 *data) ^ This function is not used, so remove it. Signed-off-by: Tom Rix Signed-off-by: Johan Hovold --- drivers/usb/serial/quatech2.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 6fca40ace83a..fee581409bf6 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -176,14 +176,6 @@ static inline int qt2_control_msg(struct usb_device *dev, NULL, 0, QT2_USB_TIMEOUT); } -static inline int qt2_setdevice(struct usb_device *dev, u8 *data) -{ - u16 x = ((u16) (data[1] << 8) | (u16) (data[0])); - - return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0); -} - - static inline int qt2_getregister(struct usb_device *dev, u8 uart, u8 reg, -- cgit v1.2.3 From a9042796f9d00643856c31bd3f216305cc5d9dfa Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:00 +0200 Subject: usb: musb: da8xx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230405141009.3400693-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/da8xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index d47e5c94587b..912e32b78ac6 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -576,14 +576,12 @@ static int da8xx_probe(struct platform_device *pdev) return ret; } -static int da8xx_remove(struct platform_device *pdev) +static void da8xx_remove(struct platform_device *pdev) { struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->usb_phy); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -626,7 +624,7 @@ MODULE_DEVICE_TABLE(of, da8xx_id_table); static struct platform_driver da8xx_driver = { .probe = da8xx_probe, - .remove = da8xx_remove, + .remove_new = da8xx_remove, .driver = { .name = "musb-da8xx", .pm = &da8xx_pm_ops, -- cgit v1.2.3 From c5477ce3bc3d137c553180eaccf88f4b85fa70fc Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:01 +0200 Subject: usb: musb: jz4740: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20230405141009.3400693-3-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/jz4740.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index c7b1d2a394d9..5aabdd7e2511 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -308,14 +308,12 @@ err_platform_device_put: return ret; } -static int jz4740_remove(struct platform_device *pdev) +static void jz4740_remove(struct platform_device *pdev) { struct jz4740_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->pdev); clk_disable_unprepare(glue->clk); - - return 0; } static const struct of_device_id jz4740_musb_of_match[] = { @@ -327,7 +325,7 @@ MODULE_DEVICE_TABLE(of, jz4740_musb_of_match); static struct platform_driver jz4740_driver = { .probe = jz4740_probe, - .remove = jz4740_remove, + .remove_new = jz4740_remove, .driver = { .name = "musb-jz4740", .of_match_table = jz4740_musb_of_match, -- cgit v1.2.3 From ace4e2637c016d0e693a15760df9f4add1bcbe9c Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:02 +0200 Subject: usb: musb: mediatek: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230405141009.3400693-4-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/mediatek.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c index 27b9bd258340..598ee5c0bf34 100644 --- a/drivers/usb/musb/mediatek.c +++ b/drivers/usb/musb/mediatek.c @@ -508,15 +508,13 @@ err_unregister_usb_phy: return ret; } -static int mtk_musb_remove(struct platform_device *pdev) +static void mtk_musb_remove(struct platform_device *pdev) { struct mtk_glue *glue = platform_get_drvdata(pdev); struct platform_device *usb_phy = glue->usb_phy; platform_device_unregister(glue->musb_pdev); usb_phy_generic_unregister(usb_phy); - - return 0; } #ifdef CONFIG_OF @@ -529,7 +527,7 @@ MODULE_DEVICE_TABLE(of, mtk_musb_match); static struct platform_driver mtk_musb_driver = { .probe = mtk_musb_probe, - .remove = mtk_musb_remove, + .remove_new = mtk_musb_remove, .driver = { .name = "musb-mtk", .of_match_table = of_match_ptr(mtk_musb_match), -- cgit v1.2.3 From 37e7750091ad5f3911a8266564e89394c6ac94a1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:03 +0200 Subject: usb: musb: mpfs: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230405141009.3400693-5-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/mpfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c index cea2e8108867..24b98716f7fc 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -235,15 +235,13 @@ err_phy_release: return ret; } -static int mpfs_remove(struct platform_device *pdev) +static void mpfs_remove(struct platform_device *pdev) { struct mpfs_glue *glue = platform_get_drvdata(pdev); clk_disable_unprepare(glue->clk); platform_device_unregister(glue->musb); usb_phy_generic_unregister(pdev); - - return 0; } #ifdef CONFIG_OF @@ -256,7 +254,7 @@ MODULE_DEVICE_TABLE(of, mpfs_id_table); static struct platform_driver mpfs_musb_driver = { .probe = mpfs_probe, - .remove = mpfs_remove, + .remove_new = mpfs_remove, .driver = { .name = "mpfs-musb", .of_match_table = of_match_ptr(mpfs_id_table) -- cgit v1.2.3 From aa846a29e1cc733e6c966bde918bdd1d3a5c5e8a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:04 +0200 Subject: usb: musb: musb_core: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230405141009.3400693-6-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 648bb6021c5e..d162afbbe19f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2621,7 +2621,7 @@ static int musb_probe(struct platform_device *pdev) return musb_init_controller(dev, irq, base); } -static int musb_remove(struct platform_device *pdev) +static void musb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct musb *musb = dev_to_musb(dev); @@ -2657,7 +2657,6 @@ static int musb_remove(struct platform_device *pdev) usb_phy_shutdown(musb->xceiv); musb_free(musb); device_init_wakeup(dev, 0); - return 0; } #ifdef CONFIG_PM @@ -2955,7 +2954,7 @@ static struct platform_driver musb_driver = { .dev_groups = musb_groups, }, .probe = musb_probe, - .remove = musb_remove, + .remove_new = musb_remove, }; module_platform_driver(musb_driver); -- cgit v1.2.3 From e6547b5e5c2c493bbd3b6add3177e8498ff0e063 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:05 +0200 Subject: usb: musb: musb_dsps: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230405141009.3400693-7-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_dsps.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index f75cde0f2b43..9119b1d51370 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -915,7 +915,7 @@ err: return ret; } -static int dsps_remove(struct platform_device *pdev) +static void dsps_remove(struct platform_device *pdev) { struct dsps_glue *glue = platform_get_drvdata(pdev); @@ -923,8 +923,6 @@ static int dsps_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); iounmap(glue->usbss_base); - - return 0; } static const struct dsps_musb_wrapper am33xx_driver_data = { @@ -1036,7 +1034,7 @@ static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, - .remove = dsps_remove, + .remove_new = dsps_remove, .driver = { .name = "musb-dsps", .pm = &dsps_pm_ops, -- cgit v1.2.3 From cb020bf52253327fe382e10bcae02a4f1da33c04 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:06 +0200 Subject: usb: musb: omap2430: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230405141009.3400693-8-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/omap2430.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 7f305b352591..b4a4c1df4e0d 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -471,14 +471,12 @@ err0: return ret; } -static int omap2430_remove(struct platform_device *pdev) +static void omap2430_remove(struct platform_device *pdev) { struct omap2430_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); pm_runtime_disable(glue->dev); - - return 0; } #ifdef CONFIG_PM @@ -610,7 +608,7 @@ MODULE_DEVICE_TABLE(of, omap2430_id_table); static struct platform_driver omap2430_driver = { .probe = omap2430_probe, - .remove = omap2430_remove, + .remove_new = omap2430_remove, .driver = { .name = "musb-omap2430", .pm = DEV_PM_OPS, -- cgit v1.2.3 From 2a21aceed2fe94816d596969a761f6829954d879 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:07 +0200 Subject: usb: musb: sunxi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20230405141009.3400693-9-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/sunxi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 9b622cd9b2bd..c5c6c4e09300 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -805,15 +805,13 @@ err_unregister_usb_phy: return ret; } -static int sunxi_musb_remove(struct platform_device *pdev) +static void sunxi_musb_remove(struct platform_device *pdev) { struct sunxi_glue *glue = platform_get_drvdata(pdev); struct platform_device *usb_phy = glue->usb_phy; platform_device_unregister(glue->musb_pdev); usb_phy_generic_unregister(usb_phy); - - return 0; } static const struct sunxi_musb_cfg sun4i_a10_musb_cfg = { @@ -862,7 +860,7 @@ MODULE_DEVICE_TABLE(of, sunxi_musb_match); static struct platform_driver sunxi_musb_driver = { .probe = sunxi_musb_probe, - .remove = sunxi_musb_remove, + .remove_new = sunxi_musb_remove, .driver = { .name = "musb-sunxi", .of_match_table = sunxi_musb_match, -- cgit v1.2.3 From 969c9528ad05763f468a60b7287486afa62deb23 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:08 +0200 Subject: usb: musb: tusb6010: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230405141009.3400693-10-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/tusb6010.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 5609b4e84d40..a1f29dbc62e6 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1258,19 +1258,17 @@ static int tusb_probe(struct platform_device *pdev) return 0; } -static int tusb_remove(struct platform_device *pdev) +static void tusb_remove(struct platform_device *pdev) { struct tusb6010_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->phy); - - return 0; } static struct platform_driver tusb_driver = { .probe = tusb_probe, - .remove = tusb_remove, + .remove_new = tusb_remove, .driver = { .name = "musb-tusb", }, -- cgit v1.2.3 From 8000540218439e06ee1161b039a1472718798646 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 5 Apr 2023 16:10:09 +0200 Subject: usb: musb: ux500: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230405141009.3400693-11-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/ux500.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 8ea62c344328..c8d9d2a1d2f0 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -303,14 +303,12 @@ err0: return ret; } -static int ux500_remove(struct platform_device *pdev) +static void ux500_remove(struct platform_device *pdev) { struct ux500_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); clk_disable_unprepare(glue->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -357,7 +355,7 @@ MODULE_DEVICE_TABLE(of, ux500_match); static struct platform_driver ux500_driver = { .probe = ux500_probe, - .remove = ux500_remove, + .remove_new = ux500_remove, .driver = { .name = "musb-ux500", .pm = &ux500_pm_ops, -- cgit v1.2.3 From d56de8c9a17d8f5202d0f37dd06ce186cc512586 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Tue, 28 Mar 2023 16:23:04 +0800 Subject: usb: typec: tcpm: try to get role switch from tcpc fwnode Try to get usb role switch from tcpc fwnode if failed to get role switch from port dev, this is for case the port for role switch endpoint is located in connector node, as per connector binding doc, port@0 for HS is required. ptn5110: tcpc@50 { compatible = "nxp,ptn5110"; ... status = "okay"; connector { compatible = "usb-c-connector"; label = "USB-C"; ... ports { #address-cells = <1>; #size-cells = <0>; port@0 { reg = <0>; typec_conn: endpoint { remote-endpoint = <&usb2_controller>; }; }; }; }; }; Signed-off-by: Li Jun Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/1679991784-25500-1-git-send-email-jun.li@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index ab3a54662ed9..4e276d2f15d1 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -6577,6 +6577,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->port_type = port->typec_caps.type; port->role_sw = usb_role_switch_get(port->dev); + if (!port->role_sw) + port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); if (IS_ERR(port->role_sw)) { err = PTR_ERR(port->role_sw); goto out_destroy_wq; -- cgit v1.2.3 From be15c65ad027f467c856ae9d2cbabaa62680506a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 30 Mar 2023 17:17:36 +0800 Subject: dt-bindings: usb: typec-tcpci: convert to DT schema format Convert the binding to DT schema format, and rename it to nxp,ptn5110.yaml Signed-off-by: Peng Fan Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230330091736.1873121-1-peng.fan@oss.nxp.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/nxp,ptn5110.yaml | 72 ++++++++++++++++++++++ .../devicetree/bindings/usb/typec-tcpci.txt | 49 --------------- 2 files changed, 72 insertions(+), 49 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml delete mode 100644 Documentation/devicetree/bindings/usb/typec-tcpci.txt diff --git a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml new file mode 100644 index 000000000000..28eb25ecba74 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/nxp,ptn5110.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PTN5110 Typec Port Cotroller + +maintainers: + - Li Jun + +properties: + compatible: + const: nxp,ptn5110 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + connector: + type: object + $ref: /schemas/connector/usb-connector.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - connector + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tcpci@50 { + compatible = "nxp,ptn5110"; + reg = <0x50>; + interrupt-parent = <&gpio3>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/typec-tcpci.txt b/Documentation/devicetree/bindings/usb/typec-tcpci.txt deleted file mode 100644 index 2082522b1c32..000000000000 --- a/Documentation/devicetree/bindings/usb/typec-tcpci.txt +++ /dev/null @@ -1,49 +0,0 @@ -TCPCI(Typec port cotroller interface) binding ---------------------------------------------- - -Required properties: -- compatible: should be set one of following: - - "nxp,ptn5110" for NXP USB PD TCPC PHY IC ptn5110. - -- reg: the i2c slave address of typec port controller device. -- interrupt-parent: the phandle to the interrupt controller which provides - the interrupt. -- interrupts: interrupt specification for tcpci alert. - -Required sub-node: -- connector: The "usb-c-connector" attached to the tcpci chip, the bindings - of connector node are specified in - Documentation/devicetree/bindings/connector/usb-connector.yaml - -Example: - -ptn5110@50 { - compatible = "nxp,ptn5110"; - reg = <0x50>; - interrupt-parent = <&gpio3>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; - - usb_con: connector { - compatible = "usb-c-connector"; - label = "USB-C"; - data-role = "dual"; - power-role = "dual"; - try-power-role = "sink"; - source-pdos = ; - sink-pdos = ; - op-sink-microwatt = <10000000>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@1 { - reg = <1>; - usb_con_ss: endpoint { - remote-endpoint = <&usb3_data_ss>; - }; - }; - }; - }; -}; -- cgit v1.2.3 From 03f009a9d41f902e4e9e2dd618b35b712e4b67df Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 24 Mar 2023 15:37:41 +0200 Subject: dt-bindings: usb: tps6598x: make interrupts optional The driver can poll for interrupt status so interrupts can be optional. It is still recommended to use the interrupt line. Polling should only be used for debug and prototyping. Signed-off-by: Roger Quadros Acked-by: Heikki Krogerus Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230324133741.43408-1-rogerq@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/ti,tps6598x.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml index 7d9c5e786e42..39f8d8a5780a 100644 --- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml +++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml @@ -35,8 +35,6 @@ properties: required: - compatible - reg - - interrupts - - interrupt-names additionalProperties: true -- cgit v1.2.3 From 917dc99b659114a4aad2ee8b20bcdc05c80e5f09 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Apr 2023 14:20:01 +0300 Subject: usb: dwc3: pci: Change PCI device macros Use PCI_DEVICE_DATA() macro. No functional changes are expected. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230405112001.39695-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 132 ++++++++++++-------------------------------- 1 file changed, 34 insertions(+), 98 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index a23ddbb81979..a97a6d346665 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -387,104 +387,40 @@ static void dwc3_pci_remove(struct pci_dev *pci) } static const struct pci_device_id dwc3_pci_id_table[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT), - (kernel_ulong_t) &dwc3_pci_intel_byt_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD), - (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_PCH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN_PCH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLM), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB), - (kernel_ulong_t) &dwc3_pci_amd_swnode, }, - - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MR), - (kernel_ulong_t)&dwc3_pci_amd_mr_swnode, }, + { PCI_DEVICE_DATA(INTEL, BSW, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BYT, &dwc3_pci_intel_byt_swnode) }, + { PCI_DEVICE_DATA(INTEL, MRFLD, &dwc3_pci_intel_mrfld_swnode) }, + { PCI_DEVICE_DATA(INTEL, CMLLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CMLH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, SPTLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, SPTH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT_M, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, APL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, KBP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, GLK, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ICLLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, EHL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGPLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGPH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, JSP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADL_PCH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLN, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLN_PCH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, RPLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLM, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGL, &dwc3_pci_intel_swnode) }, + + { PCI_DEVICE_DATA(AMD, NL_USB, &dwc3_pci_amd_swnode) }, + { PCI_DEVICE_DATA(AMD, MR, &dwc3_pci_amd_mr_swnode) }, { } /* Terminating Entry */ }; -- cgit v1.2.3 From 326e1c208f3f24d14b93f910b8ae32c94923d22c Mon Sep 17 00:00:00 2001 From: Samuel Čavoj Date: Wed, 5 Apr 2023 16:44:56 +0300 Subject: usb: typec: ucsi: acpi: add quirk for ASUS Zenbook UM325 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some ACPI platforms (namely the ASUS Zenbook UM325) the _DSM method must not be called after a notification is received but instead the mailbox should be read immediately from RAM. This is because the ACPI interrupt handler destroys the CCI in ERAM after copying to system memory, and when _DSM is later called to perform a second copy, it retrieves a garbage value. Instead, the _DSM(read) method should only be called when necessary, i.e. for polling the state after reset and for retrieving the version. Other reads should not call _DSM and only peek into the RAM region. This adds a separate read operation for the Zenbook that syncs the ACPI mailbox only with polled commands. Link: https://lore.kernel.org/linux-usb/20210823180626.tb6m7h5tp6adhvt2@fastboi.localdomain/ Signed-off-by: Samuel Čavoj [ heikki : handling everything in ucsi_acpi.c with DMI quirk ] Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20230405134456.49607-1-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_acpi.c | 44 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 62206a6b8ea7..217355f1f9b9 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "ucsi.h" @@ -23,6 +24,7 @@ struct ucsi_acpi { struct completion complete; unsigned long flags; guid_t guid; + u64 cmd; }; static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) @@ -62,6 +64,7 @@ static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset, struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); memcpy(ua->base + offset, val, val_len); + ua->cmd = *(u64 *)val; return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); } @@ -93,13 +96,46 @@ static const struct ucsi_operations ucsi_acpi_ops = { .async_write = ucsi_acpi_async_write }; +static int +ucsi_zenbook_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len) +{ + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + int ret; + + if (offset == UCSI_VERSION || UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) { + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (ret) + return ret; + } + + memcpy(val, ua->base + offset, val_len); + + return 0; +} + +static const struct ucsi_operations ucsi_zenbook_ops = { + .read = ucsi_zenbook_read, + .sync_write = ucsi_acpi_sync_write, + .async_write = ucsi_acpi_async_write +}; + +static const struct dmi_system_id zenbook_dmi_id[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), + }, + }, + { } +}; + static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ucsi_acpi *ua = data; u32 cci; int ret; - ret = ucsi_acpi_read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); + ret = ua->ucsi->ops->read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); if (ret) return; @@ -114,6 +150,7 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) static int ucsi_acpi_probe(struct platform_device *pdev) { struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); + const struct ucsi_operations *ops = &ucsi_acpi_ops; struct ucsi_acpi *ua; struct resource *res; acpi_status status; @@ -143,7 +180,10 @@ static int ucsi_acpi_probe(struct platform_device *pdev) init_completion(&ua->complete); ua->dev = &pdev->dev; - ua->ucsi = ucsi_create(&pdev->dev, &ucsi_acpi_ops); + if (dmi_check_system(zenbook_dmi_id)) + ops = &ucsi_zenbook_ops; + + ua->ucsi = ucsi_create(&pdev->dev, ops); if (IS_ERR(ua->ucsi)) return PTR_ERR(ua->ucsi); -- cgit v1.2.3 From c336fae2c5be3689a7a74562458a23afb88b655e Mon Sep 17 00:00:00 2001 From: Thomas Ballasi Date: Thu, 30 Mar 2023 18:16:37 -0400 Subject: usb: chipidea: imx: avoid unnecessary probe defer The changes brought by commit 73de93440186 have been inadvertidly removed, causing ci_hdrc_imx's probe to be loaded before usbmisc_imx's, despite ci_hdrc_imx needing usbmisc_imx. This condition may cause unexpected behaviors, especially when the ChipIdea node is being referred to under /sys/class/udc/: $ ls -l /sys/class/udc/ $ when it should show as the following: $ ls -l /sys/class/udc/ ci_hdrc.0 -> ../../devices/[...]/ci_hdrc.0/udc/ci_hdrc.0 Some userspace tools may depend on this feature[1]. [1]: https://github.com/nxp-imx/imx-uuc/blob/69029e71b0642ded83a6c9bfa03102bb310c88ed/linuxrc#L148 Fixes: 95caa2ae70fd ("usb: chipidea: allow disabling glue drivers if EMBEDDED") Signed-off-by: Thomas Ballasi Link: https://lore.kernel.org/r/20230330221637.1605161-1-thomas.ballasi@savoirfairelinux.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 6f4a3deced35..71afeab97e83 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -14,5 +14,5 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o obj-$(CONFIG_USB_CHIPIDEA_GENERIC) += ci_hdrc_usb2.o obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o -obj-$(CONFIG_USB_CHIPIDEA_IMX) += ci_hdrc_imx.o usbmisc_imx.o +obj-$(CONFIG_USB_CHIPIDEA_IMX) += usbmisc_imx.o ci_hdrc_imx.o obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o -- cgit v1.2.3 From 72958d337859626c8538fcd3a5f905825820b72e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 3 Apr 2023 21:18:48 +0200 Subject: dt-bindings: usb: mediatek,mtk-xhci: drop assigned-clocks The meta schema from DT schema already defines assigned-clocks, so there is no need for device schema to mention it at all. There are also no benefits of having it here. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230403191850.374839-1-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 556bedb96165..72639c6b4e1c 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -87,14 +87,6 @@ properties: - const: dma_ck - const: xhci_ck - assigned-clocks: - minItems: 1 - maxItems: 5 - - assigned-clock-parents: - minItems: 1 - maxItems: 5 - phys: description: List of all PHYs used on this HCD, it's better to keep PHYs in order -- cgit v1.2.3 From d024ebb274573baaf999914ba33a361141b66bef Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 3 Apr 2023 21:18:49 +0200 Subject: dt-bindings: usb: ti,j721e-usb: drop assigned-clocks The meta schema from DT schema already defines assigned-clocks, so there is no need for device schema to mention it at all. There are also no benefits of having it here. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230403191850.374839-2-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml index fd36dd02fe74..95ff9791baea 100644 --- a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml +++ b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml @@ -53,12 +53,6 @@ properties: VBUS pin of the SoC via a 1/3 voltage divider. type: boolean - assigned-clocks: - maxItems: 1 - - assigned-clock-parents: - maxItems: 1 - '#address-cells': const: 2 -- cgit v1.2.3 From 0246b15bbb43404d8d6f0ec86121c05515e0ed0b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 3 Apr 2023 21:18:50 +0200 Subject: dt-bindings: usb: ti,keystone-dwc3: drop assigned-clocks The meta schema from DT schema already defines assigned-clocks, so there is no need for device schema to mention it at all. There are also no benefits of having it here. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230403191850.374839-3-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml index c1f0194ad0d5..9252d893f694 100644 --- a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml @@ -34,14 +34,6 @@ properties: minItems: 1 maxItems: 2 - assigned-clocks: - minItems: 1 - maxItems: 2 - - assigned-clock-parents: - minItems: 1 - maxItems: 2 - power-domains: maxItems: 1 description: Should contain a phandle to a PM domain provider node -- cgit v1.2.3 From a095edfc15f0832e046ae23964e249ef5c95af87 Mon Sep 17 00:00:00 2001 From: Arınç ÜNAL Date: Mon, 17 Apr 2023 18:20:03 +0300 Subject: USB: serial: option: add UNISOC vendor and TOZED LT70C product MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add UNISOC vendor ID and TOZED LT70-C modem which is based from UNISOC SL8563. The modem supports the NCM mode. Interface 0 is used for running the AT commands. Interface 12 is the ADB interface. T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 6 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1782 ProdID=4055 Rev=04.04 S: Manufacturer=Unisoc Phone S: Product=Unisoc Phone S: SerialNumber= C: #Ifs=14 Cfg#= 1 Atr=c0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0d Prot=00 Driver=cdc_ncm E: Ad=82(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#=10 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#=11 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=08(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8c(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#=12 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=09(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#=13 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=0a(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0d Prot=00 Driver=cdc_ncm E: Ad=84(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 3 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 4 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0d Prot=00 Driver=cdc_ncm E: Ad=86(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 5 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 6 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0d Prot=00 Driver=cdc_ncm E: Ad=88(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 7 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 8 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 9 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms Signed-off-by: Arınç ÜNAL Link: https://lore.kernel.org/r/20230417152003.243248-1-arinc.unal@arinc9.com Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/option.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e6d8d9b35ad0..d0d7c4b3f515 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -595,6 +595,11 @@ static void option_instat_callback(struct urb *urb); #define SIERRA_VENDOR_ID 0x1199 #define SIERRA_PRODUCT_EM9191 0x90d3 +/* UNISOC (Spreadtrum) products */ +#define UNISOC_VENDOR_ID 0x1782 +/* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */ +#define TOZED_PRODUCT_LT70C 0x4055 + /* Device flags */ /* Highest interface number which can be used with NCTRL() and RSVD() */ @@ -2215,6 +2220,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.3 From 5629d31955297ca47b9283c64fff70f2f34aa528 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 5 Apr 2023 19:18:53 +0100 Subject: usb: gadget: tegra-xudc: Fix crash in vbus_draw Commit ac82b56bda5f ("usb: gadget: tegra-xudc: Add vbus_draw support") populated the vbus_draw callback for the Tegra XUDC driver. The function tegra_xudc_gadget_vbus_draw(), that was added by this commit, assumes that the pointer 'curr_usbphy' has been initialised, which is not always the case because this is only initialised when the USB role is updated. Fix this crash, by checking that the 'curr_usbphy' is valid before dereferencing. Fixes: ac82b56bda5f ("usb: gadget: tegra-xudc: Add vbus_draw support") Reviewed-by: Thierry Reding Signed-off-by: Jon Hunter Link: https://lore.kernel.org/r/20230405181854.42355-1-jonathanh@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/tegra-xudc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 2b71b33725f1..5bccd64847ff 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -2167,7 +2167,7 @@ static int tegra_xudc_gadget_vbus_draw(struct usb_gadget *gadget, dev_dbg(xudc->dev, "%s: %u mA\n", __func__, m_a); - if (xudc->curr_usbphy->chg_type == SDP_TYPE) + if (xudc->curr_usbphy && xudc->curr_usbphy->chg_type == SDP_TYPE) ret = usb_phy_set_power(xudc->curr_usbphy, m_a); return ret; -- cgit v1.2.3 From 9d9a7614a75989a2356c8d2db736ce1a69d92fe4 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 5 Apr 2023 19:18:54 +0100 Subject: usb: gadget: tegra-xudc: Remove unneeded return variable The 'ret' variable in the function tegra_xudc_gadget_vbus_draw() is not needed and so remove this variable. Reviewed-by: Thierry Reding Signed-off-by: Jon Hunter Link: https://lore.kernel.org/r/20230405181854.42355-2-jonathanh@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/tegra-xudc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 5bccd64847ff..34e9c1df54c7 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -2162,15 +2162,14 @@ static int tegra_xudc_gadget_stop(struct usb_gadget *gadget) static int tegra_xudc_gadget_vbus_draw(struct usb_gadget *gadget, unsigned int m_a) { - int ret = 0; struct tegra_xudc *xudc = to_xudc(gadget); dev_dbg(xudc->dev, "%s: %u mA\n", __func__, m_a); if (xudc->curr_usbphy && xudc->curr_usbphy->chg_type == SDP_TYPE) - ret = usb_phy_set_power(xudc->curr_usbphy, m_a); + return usb_phy_set_power(xudc->curr_usbphy, m_a); - return ret; + return 0; } static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on) -- cgit v1.2.3 From 091b813d3d1078afba6ed74fa8df2a5bbc9bf124 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 10 Apr 2023 18:26:38 -0500 Subject: usb: Add explicit of.h of_platform.h include Several USB drivers use of_platform_* functions which are declared in of_platform.h. of_platform.h gets implicitly included by of_device.h, but that is going to be removed soon. Nothing else depends on of_device.h so it can be dropped. Acked-by: Thinh Nguyen Acked-by: Chunfeng Yun Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230410232639.1561152-1-robh@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-am62.c | 2 +- drivers/usb/gadget/udc/rzv2m_usb3drd.c | 2 +- drivers/usb/mtu3/mtu3_host.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index b22fb78bc8e7..cda9458c809b 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c index 8855d8e8d793..589c7252e014 100644 --- a/drivers/usb/gadget/udc/rzv2m_usb3drd.c +++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c index f3903367a6a0..177d2caf887c 100644 --- a/drivers/usb/mtu3/mtu3_host.c +++ b/drivers/usb/mtu3/mtu3_host.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "mtu3.h" -- cgit v1.2.3 From 735baf1b23458f71a8b15cb924af22c9ff9cd125 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 5 Apr 2023 11:03:42 +0200 Subject: xhci: fix debugfs register accesses while suspended Wire up the debugfs regset device pointer so that the controller is resumed before accessing registers to avoid crashing or locking up if it happens to be runtime suspended. Fixes: 02b6fdc2a153 ("usb: xhci: Add debugfs interface for xHCI driver") Cc: stable@vger.kernel.org # 4.15: 30332eeefec8: debugfs: regset32: Add Runtime PM support Cc: stable@vger.kernel.org # 4.15 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230405090342.7363-1-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-debugfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 0bc7fe11f749..99baa60ef50f 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -133,6 +133,7 @@ static void xhci_debugfs_regset(struct xhci_hcd *xhci, u32 base, regset->regs = regs; regset->nregs = nregs; regset->base = hcd->regs + base; + regset->dev = hcd->self.controller; debugfs_create_regset32((const char *)rgs->name, 0444, parent, regset); } -- cgit v1.2.3 From f3588ea40aa17273c3303789b1828b3aa6b80748 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 6 Apr 2023 08:46:05 +0900 Subject: usb: host: xhci-plat: Use dev_is_pci() helper Use common dev_is_pci() helper for checking PCI devices. And if CONFIG_PCI is not defined, dev_is_pci returns false. Therefore, CONFIG_PCI is also unnecessary, so remove it. Signed-off-by: Nobuhiro Iwamatsu Link: https://lore.kernel.org/r/20230405234605.2310155-1-nobuhiro1.iwamatsu@toshiba.co.jp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index b9f9625467d6..76c5a84616ea 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -362,10 +362,8 @@ static int xhci_generic_plat_probe(struct platform_device *pdev) if (is_of_node(sysdev->fwnode) || is_acpi_device_node(sysdev->fwnode)) break; -#ifdef CONFIG_PCI - else if (sysdev->bus == &pci_bus_type) + else if (dev_is_pci(sysdev)) break; -#endif } if (!sysdev) -- cgit v1.2.3 From 9134c1fd05034dd29a1a2f010abd178af409171e Mon Sep 17 00:00:00 2001 From: Stanley Chang Date: Fri, 7 Apr 2023 14:07:31 +0800 Subject: usb: xhci: plat: Add USB 3.0 phy support For Realtek SoC, the usb xhci uses different driver for u2phy and u3phy. Therefore, add a hook to retrieve the USB 3.0 PHY to XHCI plat. Signed-off-by: Stanley Chang Link: https://lore.kernel.org/r/20230407060731.20537-1-stanley_chang@realtek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 76c5a84616ea..b0c8e8efc43b 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -291,6 +291,21 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s goto dealloc_usb2_hcd; } + xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, + "usb-phy", 1); + if (IS_ERR(xhci->shared_hcd->usb_phy)) { + if (PTR_ERR(xhci->shared_hcd->usb_phy) != -ENODEV) + dev_err(sysdev, "%s get usb3phy fail (ret=%d)\n", + __func__, + (int)PTR_ERR(xhci->shared_hcd->usb_phy)); + xhci->shared_hcd->usb_phy = NULL; + } else { + ret = usb_phy_init(xhci->shared_hcd->usb_phy); + if (ret) + dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n", + __func__, ret); + } + xhci->shared_hcd->tpl_support = hcd->tpl_support; } -- cgit v1.2.3 From 4076c4f37bd9ef8415a7ab6acb6e2b5d6fddaf05 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 7 Apr 2023 14:24:05 +0800 Subject: dt-bindings: usb: mtk-xhci: add an optional frame count clock Add optional clock 'frmcnt_ck' used on 4nm or advanced process SoC Reviewed-by: AngeloGioacchino Del Regno Acked-by: Krzysztof Kozlowski Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230407062406.12575-1-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 72639c6b4e1c..e9644e333d78 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -77,6 +77,7 @@ properties: - description: Mcu bus clock for register access - description: DMA bus clock for data transfer - description: controller clock + - description: frame count clock clock-names: minItems: 1 @@ -86,6 +87,7 @@ properties: - const: mcu_ck - const: dma_ck - const: xhci_ck + - const: frmcnt_ck phys: description: -- cgit v1.2.3 From 6a14ffc05c60fb4d5b7beb95460ac5642293e03f Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 7 Apr 2023 14:24:06 +0800 Subject: usb: xhci-mtk: add optional frame count clock Add optional clock frmcnt_ck used on 4nm or advanced process SoC Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230407062406.12575-2-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk.c | 1 + drivers/usb/host/xhci-mtk.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index f7cbb08fc506..90cf40d6d0c3 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -398,6 +398,7 @@ static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) clks[2].id = "ref_ck"; clks[3].id = "mcu_ck"; clks[4].id = "dma_ck"; + clks[5].id = "frmcnt_ck"; return devm_clk_bulk_get_optional(mtk->dev, BULK_CLKS_NUM, clks); } diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index 1174a510dd38..faaaf05e36ce 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -15,7 +15,7 @@ #include "xhci.h" -#define BULK_CLKS_NUM 5 +#define BULK_CLKS_NUM 6 #define BULK_VREGS_NUM 2 /* support at most 64 ep, use 32 size hash table */ -- cgit v1.2.3 From 236d835302bd4e11697dfe65eb24a219ea5c70eb Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 14 Apr 2023 10:41:34 +0200 Subject: usb: dwc2: improve error handling in __dwc2_lowlevel_hw_enable Add error handling in __dwc2_lowlevel_hw_enable() that may leave the clocks and regulators enabled upon error. Acked-by: Minas Harutyunyan Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20230414084137.1050487-2-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/platform.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index d1589ba7d322..c431ce6c119f 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -104,7 +104,7 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) if (hsotg->clk) { ret = clk_prepare_enable(hsotg->clk); if (ret) - return ret; + goto err_dis_reg; } if (hsotg->uphy) { @@ -113,10 +113,25 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); } else { ret = phy_init(hsotg->phy); - if (ret == 0) + if (ret == 0) { ret = phy_power_on(hsotg->phy); + if (ret) + phy_exit(hsotg->phy); + } } + if (ret) + goto err_dis_clk; + + return 0; + +err_dis_clk: + if (hsotg->clk) + clk_disable_unprepare(hsotg->clk); + +err_dis_reg: + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); + return ret; } -- cgit v1.2.3 From 28f75a39d8a878d9e8e57fd2aa0a1ad262d257bd Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 14 Apr 2023 10:41:35 +0200 Subject: dt-bindings: usb: dwc2: add utmi optional clock utmi clock is typically provided by PHY output. Add this optional clock, as the core could use other clocks depending on the SoC where it's used. This is needed on stm32mp15, when using the integrated full-speed PHY. Acked-by: Krzysztof Kozlowski Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20230414084137.1050487-3-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/dwc2.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml index 371ba93f3ce5..d3506090f8b1 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml @@ -75,11 +75,14 @@ properties: maxItems: 1 clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 clock-names: items: - const: otg + - const: utmi + minItems: 1 disable-over-current: type: boolean -- cgit v1.2.3 From 02329adeae1f92b0133cfc1a2b06645f4c496c1b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 14 Apr 2023 10:41:36 +0200 Subject: usb: dwc2: platform: add support for utmi optional clock Add support for the utmi clock. It's needed on STM32MP15, when using the integrated full-speed PHY. This clock is an output of USBPHYC, but HS USBPHYC is not attached as PHY in this case: Full-Speed PHY is directly managed in dwc2 glue, through GGPIO register. Typical DT when using FS PHY &usbotg_hs { compatible = "st,stm32mp15-fsotg", "snps,dwc2"; pinctrl-names = "default"; pinctrl-0 = <&usbotg_hs_pins_a &usbotg_fs_dp_dm_pins_a>; vbus-supply = <&vbus_otg>; status = "okay"; }; In this configuration, USBPHYC clock output must be defined, so it can be properly enabled as a clock provider: clocks = <&rcc USBO_K>, <&usbphyc>; clock-names = "otg", "utmi"; Acked-by: Minas Harutyunyan Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20230414084137.1050487-4-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core.h | 2 ++ drivers/usb/dwc2/platform.c | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 40cf2880d7e5..0bb4c0c845bf 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1003,6 +1003,7 @@ struct dwc2_hregs_backup { * @ctrl_out_desc: EP0 OUT data phase desc chain pointer * @irq: Interrupt request line number * @clk: Pointer to otg clock + * @utmi_clk: Pointer to utmi_clk clock * @reset: Pointer to dwc2 reset controller * @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10. * @regset: A pointer to a struct debugfs_regset32, which contains @@ -1065,6 +1066,7 @@ struct dwc2_hsotg { void *priv; int irq; struct clk *clk; + struct clk *utmi_clk; struct reset_control *reset; struct reset_control *reset_ecc; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index c431ce6c119f..5aee284018c0 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -101,10 +101,16 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) if (ret) return ret; + if (hsotg->utmi_clk) { + ret = clk_prepare_enable(hsotg->utmi_clk); + if (ret) + goto err_dis_reg; + } + if (hsotg->clk) { ret = clk_prepare_enable(hsotg->clk); if (ret) - goto err_dis_reg; + goto err_dis_utmi_clk; } if (hsotg->uphy) { @@ -129,6 +135,10 @@ err_dis_clk: if (hsotg->clk) clk_disable_unprepare(hsotg->clk); +err_dis_utmi_clk: + if (hsotg->utmi_clk) + clk_disable_unprepare(hsotg->utmi_clk); + err_dis_reg: regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); @@ -171,6 +181,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) if (hsotg->clk) clk_disable_unprepare(hsotg->clk); + if (hsotg->utmi_clk) + clk_disable_unprepare(hsotg->utmi_clk); + return regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); } @@ -247,6 +260,11 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) if (IS_ERR(hsotg->clk)) return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->clk), "cannot get otg clock\n"); + hsotg->utmi_clk = devm_clk_get_optional(hsotg->dev, "utmi"); + if (IS_ERR(hsotg->utmi_clk)) + return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->utmi_clk), + "cannot get utmi clock\n"); + /* Regulators */ for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i]; -- cgit v1.2.3 From 21d018b75f4f1c183be565d302fde7a01ae79fb0 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 14 Apr 2023 10:41:37 +0200 Subject: ARM: dts: stm32: add USB OTG UTMI clock on stm32mp151 It's needed on STM32MP15, when using the integrated full-speed PHY. This clock is an output of USBPHYC, and the HS USBPHYC is not attached as PHY in this case (managed directly by dwc2 ggpio glue): &usbotg_hs { compatible = "st,stm32mp15-fsotg", "snps,dwc2"; pinctrl-names = "default"; pinctrl-0 = <&usbotg_hs_pins_a &usbotg_fs_dp_dm_pins_a>; vbus-supply = <&vbus_otg>; status = "okay"; }; USBPHYC clock output must be used, so it can be properly enabled as a clock provider. Without this, currently, when the dualport High-Speed USBPHYC isn't requested by either USBH or OTG, it remains uninitialized when probing OTG: OTG configured with full-speed PHY isn't properly clocked, resulting in error log like: [ 2.383138] dwc2 49000000.usb-otg: dwc2_core_reset: HANG! Soft Reset timeout GRSTCTL_CSFTRST. Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20230414084137.1050487-5-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/stm32mp151.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi index 4e437d3f2ed6..63f4c78fcc1d 100644 --- a/arch/arm/boot/dts/stm32mp151.dtsi +++ b/arch/arm/boot/dts/stm32mp151.dtsi @@ -1130,8 +1130,8 @@ usbotg_hs: usb-otg@49000000 { compatible = "st,stm32mp15-hsotg", "snps,dwc2"; reg = <0x49000000 0x10000>; - clocks = <&rcc USBO_K>; - clock-names = "otg"; + clocks = <&rcc USBO_K>, <&usbphyc>; + clock-names = "otg", "utmi"; resets = <&rcc USBO_R>; reset-names = "dwc2"; interrupts = ; -- cgit v1.2.3 From 9a8ad10c9f2e0925ff26308ec6756b93fc2f4977 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:14 +0200 Subject: USB: dwc3: fix runtime pm imbalance on probe errors Make sure not to suspend the device when probe fails to avoid disabling clocks and phys multiple times. Fixes: 328082376aea ("usb: dwc3: fix runtime PM in error path") Cc: stable@vger.kernel.org # 4.8 Cc: Roger Quadros Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-2-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ed0ab90d3fac..d2350a87450e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1895,13 +1895,11 @@ static int dwc3_probe(struct platform_device *pdev) spin_lock_init(&dwc->lock); mutex_init(&dwc->mutex); + pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto err1; pm_runtime_forbid(dev); @@ -1966,12 +1964,10 @@ err3: dwc3_free_event_buffers(dwc); err2: - pm_runtime_allow(&pdev->dev); - -err1: - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - + pm_runtime_allow(dev); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); disable_clks: dwc3_clk_disable(dwc); assert_reset: -- cgit v1.2.3 From 44d257e9012ee8040e41d224d0e5bfb5ef5427ea Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:15 +0200 Subject: USB: dwc3: fix runtime pm imbalance on unbind Make sure to balance the runtime PM usage count on driver unbind by adding back the pm_runtime_allow() call that had been erroneously removed. Fixes: 266d0493900a ("usb: dwc3: core: don't trigger runtime pm when remove driver") Cc: stable@vger.kernel.org # 5.9 Cc: Li Jun Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-3-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d2350a87450e..ad48b7ebd880 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1991,6 +1991,7 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); + pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); -- cgit v1.2.3 From 6b3b2402ca5be6a19f92968a5654bc64d3996d16 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:16 +0200 Subject: USB: dwc3: disable autosuspend on unbind Add the missing calls to disable autosuspend on probe errors and on driver unbind. Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-4-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ad48b7ebd880..bb737c3bd58a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1966,6 +1966,7 @@ err3: err2: pm_runtime_allow(dev); pm_runtime_disable(dev); + pm_runtime_dont_use_autosuspend(dev); pm_runtime_set_suspended(dev); pm_runtime_put_noidle(dev); disable_clks: @@ -1993,6 +1994,7 @@ static int dwc3_remove(struct platform_device *pdev) pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); -- cgit v1.2.3 From bdb19d01026a5cccfa437be8adcf2df472c5889e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:17 +0200 Subject: USB: dwc3: gadget: drop dead hibernation code The hibernation code is broken and has never been enabled in mainline and should thus be dropped. Remove the hibernation bits from the gadget code, which effectively reverts commits e1dadd3b0f27 ("usb: dwc3: workaround: bogus hibernation events") and 7b2a0368bbc9 ("usb: dwc3: gadget: set KEEP_CONNECT in case of hibernation") except for the spurious interrupt warning. Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-5-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 46 ++++++---------------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 287ea6ee2463..087efbad94f7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2569,7 +2569,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCFG, reg); } -static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) +static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) { u32 reg; u32 timeout = 2000; @@ -2588,17 +2588,11 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) reg &= ~DWC3_DCTL_KEEP_CONNECT; reg |= DWC3_DCTL_RUN_STOP; - if (dwc->has_hibernation) - reg |= DWC3_DCTL_KEEP_CONNECT; - __dwc3_gadget_set_speed(dwc); dwc->pullups_connected = true; } else { reg &= ~DWC3_DCTL_RUN_STOP; - if (dwc->has_hibernation && !suspend) - reg &= ~DWC3_DCTL_KEEP_CONNECT; - dwc->pullups_connected = false; } @@ -2665,7 +2659,7 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) * remaining event generated by the controller while polling for * DSTS.DEVCTLHLT. */ - return dwc3_gadget_run_stop(dwc, false, false); + return dwc3_gadget_run_stop(dwc, false); } static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) @@ -2719,7 +2713,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) dwc3_event_buffers_setup(dwc); __dwc3_gadget_start(dwc); - ret = dwc3_gadget_run_stop(dwc, true, false); + ret = dwc3_gadget_run_stop(dwc, true); } pm_runtime_put(dwc->dev); @@ -4300,30 +4294,6 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, dwc->link_state = next; } -static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, - unsigned int evtinfo) -{ - unsigned int is_ss = evtinfo & BIT(4); - - /* - * WORKAROUND: DWC3 revision 2.20a with hibernation support - * have a known issue which can cause USB CV TD.9.23 to fail - * randomly. - * - * Because of this issue, core could generate bogus hibernation - * events which SW needs to ignore. - * - * Refers to: - * - * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0 - * Device Fallback from SuperSpeed - */ - if (is_ss ^ (dwc->speed == USB_SPEED_SUPER)) - return; - - /* enter hibernation here */ -} - static void dwc3_gadget_interrupt(struct dwc3 *dwc, const struct dwc3_event_devt *event) { @@ -4341,11 +4311,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc3_gadget_wakeup_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_HIBER_REQ: - if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, - "unexpected hibernation event\n")) - break; - - dwc3_gadget_hibernation_interrupt(dwc, event->event_info); + dev_WARN_ONCE(dwc->dev, true, "unexpected hibernation event\n"); break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); @@ -4678,7 +4644,7 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) if (!dwc->gadget_driver) return 0; - dwc3_gadget_run_stop(dwc, false, false); + dwc3_gadget_run_stop(dwc, false); spin_lock_irqsave(&dwc->lock, flags); dwc3_disconnect_gadget(dwc); @@ -4699,7 +4665,7 @@ int dwc3_gadget_resume(struct dwc3 *dwc) if (ret < 0) goto err0; - ret = dwc3_gadget_run_stop(dwc, true, false); + ret = dwc3_gadget_run_stop(dwc, true); if (ret < 0) goto err1; -- cgit v1.2.3 From f56d0d29b018b6c19b4d5c60e768b5f90bb20c8d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:18 +0200 Subject: USB: dwc3: drop dead hibernation code The hibernation code is broken and has never been enabled in mainline and should thus be dropped. Specifically, the scratch buffer DMA mapping would have been leaked on every suspend cycle since commit 51f5d49ad6f0 ("usb: dwc3: core: simplify suspend/resume operations") if this feature was ever enabled. The related error handling was also broken and could have resulted in attempts to unmap never mapped buffers, etc. This effectively revert commit 0ffcaf3798bf ("usb: dwc3: core: allocate scratch buffers"). Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-6-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 103 +----------------------------------------------- drivers/usb/dwc3/core.h | 8 ---- 2 files changed, 1 insertion(+), 110 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index bb737c3bd58a..4ed98855bf64 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -534,90 +534,6 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); } -static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) -{ - if (!dwc->has_hibernation) - return 0; - - if (!dwc->nr_scratch) - return 0; - - dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, - DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); - if (!dwc->scratchbuf) - return -ENOMEM; - - return 0; -} - -static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) -{ - dma_addr_t scratch_addr; - u32 param; - int ret; - - if (!dwc->has_hibernation) - return 0; - - if (!dwc->nr_scratch) - return 0; - - /* should never fall here */ - if (!WARN_ON(dwc->scratchbuf)) - return 0; - - scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf, - dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dwc->sysdev, scratch_addr)) { - dev_err(dwc->sysdev, "failed to map scratch buffer\n"); - ret = -EFAULT; - goto err0; - } - - dwc->scratch_addr = scratch_addr; - - param = lower_32_bits(scratch_addr); - - ret = dwc3_send_gadget_generic_command(dwc, - DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); - if (ret < 0) - goto err1; - - param = upper_32_bits(scratch_addr); - - ret = dwc3_send_gadget_generic_command(dwc, - DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); - if (ret < 0) - goto err1; - - return 0; - -err1: - dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * - DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); - -err0: - return ret; -} - -static void dwc3_free_scratch_buffers(struct dwc3 *dwc) -{ - if (!dwc->has_hibernation) - return; - - if (!dwc->nr_scratch) - return; - - /* should never fall here */ - if (!WARN_ON(dwc->scratchbuf)) - return; - - dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * - DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); - kfree(dwc->scratchbuf); -} - static void dwc3_core_num_eps(struct dwc3 *dwc) { struct dwc3_hwparams *parms = &dwc->hwparams; @@ -887,7 +803,6 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) static void dwc3_core_setup_global_control(struct dwc3 *dwc) { - u32 hwparams4 = dwc->hwparams.hwparams4; u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GCTL); @@ -915,9 +830,6 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) reg &= ~DWC3_GCTL_DSBLCLKGTNG; break; case DWC3_GHWPARAMS1_EN_PWROPT_HIB: - /* enable hibernation here */ - dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); - /* * REVISIT Enabling this bit so that host-mode hibernation * will work. Device-mode hibernation is not yet implemented. @@ -1161,10 +1073,6 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); - ret = dwc3_setup_scratch_buffers(dwc); - if (ret) - goto err1; - /* Set power down scale of suspend_clk */ dwc3_set_power_down_clk_scale(dwc); @@ -1920,14 +1828,10 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) goto err3; - ret = dwc3_alloc_scratch_buffers(dwc); - if (ret) - goto err3; - ret = dwc3_core_init(dwc); if (ret) { dev_err_probe(dev, ret, "failed to initialize core\n"); - goto err4; + goto err3; } dwc3_check_params(dwc); @@ -1956,10 +1860,6 @@ err5: phy_exit(dwc->usb3_generic_phy); dwc3_ulpi_exit(dwc); - -err4: - dwc3_free_scratch_buffers(dwc); - err3: dwc3_free_event_buffers(dwc); @@ -1999,7 +1899,6 @@ static int dwc3_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); dwc3_free_event_buffers(dwc); - dwc3_free_scratch_buffers(dwc); if (dwc->usb_psy) power_supply_put(dwc->usb_psy); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 26c8efefbff9..19490dca7937 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -973,12 +973,10 @@ struct dwc3_scratchpad_array { * @drd_work: workqueue used for role swapping * @ep0_trb: trb which is used for the ctrl_req * @bounce: address of bounce buffer - * @scratchbuf: address of scratch buffer * @setup_buf: used while precessing STD USB requests * @ep0_trb_addr: dma address of @ep0_trb * @bounce_addr: dma address of @bounce * @ep0_usb_req: dummy req used while handling STD USB requests - * @scratch_addr: dma address of scratchbuf * @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing * @mutex: for mode switching @@ -1003,7 +1001,6 @@ struct dwc3_scratchpad_array { * @current_otg_role: current role of operation while using the OTG block * @desired_otg_role: desired role of operation while using the OTG block * @otg_restart_host: flag that OTG controller needs to restart host - * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) * @max_ssp_rate: SuperSpeed Plus maximum signaling rate and lane count @@ -1060,7 +1057,6 @@ struct dwc3_scratchpad_array { * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer - * @has_hibernation: true when dwc3 was configured with Hibernation * @sysdev_is_parent: true when dwc3 device has a parent driver * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that * there's now way for software to detect this in runtime. @@ -1130,11 +1126,9 @@ struct dwc3 { struct work_struct drd_work; struct dwc3_trb *ep0_trb; void *bounce; - void *scratchbuf; u8 *setup_buf; dma_addr_t ep0_trb_addr; dma_addr_t bounce_addr; - dma_addr_t scratch_addr; struct dwc3_request ep0_usb_req; struct completion ep0_in_setup; @@ -1194,7 +1188,6 @@ struct dwc3 { u32 current_otg_role; u32 desired_otg_role; bool otg_restart_host; - u32 nr_scratch; u32 u1u2; u32 maximum_speed; u32 gadget_max_speed; @@ -1291,7 +1284,6 @@ struct dwc3 { unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; - unsigned has_hibernation:1; unsigned sysdev_is_parent:1; unsigned has_lpm_erratum:1; unsigned is_utmi_l1_suspend:1; -- cgit v1.2.3 From fe296046c7219c3b156cddc90a0efaa52a5eb996 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:19 +0200 Subject: USB: dwc3: clean up probe error labels Use descriptive names consistently for the probe error labels. Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-7-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4ed98855bf64..e9cba095394c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1717,7 +1717,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->reset = devm_reset_control_array_get_optional_shared(dev); if (IS_ERR(dwc->reset)) { ret = PTR_ERR(dwc->reset); - goto put_usb_psy; + goto err_put_psy; } if (dev->of_node) { @@ -1731,7 +1731,7 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(dwc->bus_clk)) { ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), "could not get bus clock\n"); - goto put_usb_psy; + goto err_put_psy; } if (dwc->bus_clk == NULL) { @@ -1739,7 +1739,7 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(dwc->bus_clk)) { ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), "could not get bus clock\n"); - goto put_usb_psy; + goto err_put_psy; } } @@ -1747,7 +1747,7 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(dwc->ref_clk)) { ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), "could not get ref clock\n"); - goto put_usb_psy; + goto err_put_psy; } if (dwc->ref_clk == NULL) { @@ -1755,7 +1755,7 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(dwc->ref_clk)) { ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), "could not get ref clock\n"); - goto put_usb_psy; + goto err_put_psy; } } @@ -1763,7 +1763,7 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(dwc->susp_clk)) { ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), "could not get suspend clock\n"); - goto put_usb_psy; + goto err_put_psy; } if (dwc->susp_clk == NULL) { @@ -1771,23 +1771,23 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(dwc->susp_clk)) { ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), "could not get suspend clock\n"); - goto put_usb_psy; + goto err_put_psy; } } } ret = reset_control_deassert(dwc->reset); if (ret) - goto put_usb_psy; + goto err_put_psy; ret = dwc3_clk_enable(dwc); if (ret) - goto assert_reset; + goto err_assert_reset; if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; - goto disable_clks; + goto err_disable_clks; } platform_set_drvdata(pdev, dwc); @@ -1797,7 +1797,7 @@ static int dwc3_probe(struct platform_device *pdev) DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) { ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); if (ret) - goto disable_clks; + goto err_disable_clks; } spin_lock_init(&dwc->lock); @@ -1815,23 +1815,23 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; - goto err2; + goto err_allow_rpm; } dwc->edev = dwc3_get_extcon(dwc); if (IS_ERR(dwc->edev)) { ret = dev_err_probe(dwc->dev, PTR_ERR(dwc->edev), "failed to get extcon\n"); - goto err3; + goto err_free_event_buffers; } ret = dwc3_get_dr_mode(dwc); if (ret) - goto err3; + goto err_free_event_buffers; ret = dwc3_core_init(dwc); if (ret) { dev_err_probe(dev, ret, "failed to initialize core\n"); - goto err3; + goto err_free_event_buffers; } dwc3_check_params(dwc); @@ -1839,13 +1839,13 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_core_init_mode(dwc); if (ret) - goto err5; + goto err_exit_debugfs; pm_runtime_put(dev); return 0; -err5: +err_exit_debugfs: dwc3_debugfs_exit(dwc); dwc3_event_buffers_cleanup(dwc); @@ -1860,20 +1860,19 @@ err5: phy_exit(dwc->usb3_generic_phy); dwc3_ulpi_exit(dwc); -err3: +err_free_event_buffers: dwc3_free_event_buffers(dwc); - -err2: +err_allow_rpm: pm_runtime_allow(dev); pm_runtime_disable(dev); pm_runtime_dont_use_autosuspend(dev); pm_runtime_set_suspended(dev); pm_runtime_put_noidle(dev); -disable_clks: +err_disable_clks: dwc3_clk_disable(dwc); -assert_reset: +err_assert_reset: reset_control_assert(dwc->reset); -put_usb_psy: +err_put_psy: if (dwc->usb_psy) power_supply_put(dwc->usb_psy); -- cgit v1.2.3 From c8e9eccf6ed29f6c20fa489286eee1059566d035 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:20 +0200 Subject: USB: dwc3: clean up phy init error handling While there likely are no platforms out there that mix generic and legacy PHYs the driver should still be able to handle that, if only for consistency reasons. Add the missing calls to shutdown any legacy PHYs if generic PHY initialisation fails. Note that we continue to happily ignore potential errors from the legacy PHY callbacks... Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-8-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index e9cba095394c..c2326a37cd74 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1041,15 +1041,14 @@ static int dwc3_core_init(struct dwc3 *dwc) usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); + ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) - goto err0a; + goto err_shutdown_usb3_phy; ret = phy_init(dwc->usb3_generic_phy); - if (ret < 0) { - phy_exit(dwc->usb2_generic_phy); - goto err0a; - } + if (ret < 0) + goto err_exit_usb2_phy; ret = dwc3_core_soft_reset(dwc); if (ret) @@ -1225,11 +1224,12 @@ err2: usb_phy_set_suspend(dwc->usb3_phy, 1); err1: - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); - +err_exit_usb2_phy: + phy_exit(dwc->usb2_generic_phy); +err_shutdown_usb3_phy: + usb_phy_shutdown(dwc->usb3_phy); + usb_phy_shutdown(dwc->usb2_phy); err0a: dwc3_ulpi_exit(dwc); -- cgit v1.2.3 From d2f197822d5807d48bf27e713e2fd569e7017610 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:21 +0200 Subject: USB: dwc3: clean up core init error handling Clean up the core init error handling by using descriptive names for the error labels and releasing resourcing in reverse order consistently. Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-9-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c2326a37cd74..a83e9fc4668e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1018,7 +1018,7 @@ static int dwc3_core_init(struct dwc3 *dwc) ret = dwc3_phy_setup(dwc); if (ret) - goto err0; + return ret; if (!dwc->ulpi_ready) { ret = dwc3_core_ulpi_init(dwc); @@ -1027,7 +1027,7 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_core_soft_reset(dwc); ret = -EPROBE_DEFER; } - goto err0; + return ret; } dwc->ulpi_ready = true; } @@ -1035,7 +1035,7 @@ static int dwc3_core_init(struct dwc3 *dwc) if (!dwc->phys_ready) { ret = dwc3_core_get_phy(dwc); if (ret) - goto err0a; + goto err_exit_ulpi; dwc->phys_ready = true; } @@ -1052,7 +1052,7 @@ static int dwc3_core_init(struct dwc3 *dwc) ret = dwc3_core_soft_reset(dwc); if (ret) - goto err1; + goto err_exit_usb3_phy; if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { @@ -1087,16 +1087,16 @@ static int dwc3_core_init(struct dwc3 *dwc) usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) - goto err2; + goto err_suspend_usb3_phy; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) - goto err3; + goto err_power_off_usb2_phy; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err4; + goto err_power_off_usb3_phy; } /* @@ -1213,27 +1213,23 @@ static int dwc3_core_init(struct dwc3 *dwc) return 0; -err4: +err_power_off_usb3_phy: phy_power_off(dwc->usb3_generic_phy); - -err3: +err_power_off_usb2_phy: phy_power_off(dwc->usb2_generic_phy); - -err2: - usb_phy_set_suspend(dwc->usb2_phy, 1); +err_suspend_usb3_phy: usb_phy_set_suspend(dwc->usb3_phy, 1); - -err1: + usb_phy_set_suspend(dwc->usb2_phy, 1); +err_exit_usb3_phy: phy_exit(dwc->usb3_generic_phy); err_exit_usb2_phy: phy_exit(dwc->usb2_generic_phy); err_shutdown_usb3_phy: usb_phy_shutdown(dwc->usb3_phy); usb_phy_shutdown(dwc->usb2_phy); -err0a: +err_exit_ulpi: dwc3_ulpi_exit(dwc); -err0: return ret; } -- cgit v1.2.3 From 1d72fab476567a0e4f51ee0a93882208ba28dc54 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:22 +0200 Subject: USB: dwc3: refactor phy handling Refactor the PHY handling using four new helpers to initialise, deinitialise, power on and power off all the PHYs. Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-10-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 143 +++++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 57 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a83e9fc4668e..16f6270eb9ff 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -731,6 +731,76 @@ static int dwc3_phy_setup(struct dwc3 *dwc) return 0; } +static int dwc3_phy_init(struct dwc3 *dwc) +{ + int ret; + + usb_phy_init(dwc->usb2_phy); + usb_phy_init(dwc->usb3_phy); + + ret = phy_init(dwc->usb2_generic_phy); + if (ret < 0) + goto err_shutdown_usb3_phy; + + ret = phy_init(dwc->usb3_generic_phy); + if (ret < 0) + goto err_exit_usb2_phy; + + return 0; + +err_exit_usb2_phy: + phy_exit(dwc->usb2_generic_phy); +err_shutdown_usb3_phy: + usb_phy_shutdown(dwc->usb3_phy); + usb_phy_shutdown(dwc->usb2_phy); + + return ret; +} + +static void dwc3_phy_exit(struct dwc3 *dwc) +{ + phy_exit(dwc->usb3_generic_phy); + phy_exit(dwc->usb2_generic_phy); + + usb_phy_shutdown(dwc->usb3_phy); + usb_phy_shutdown(dwc->usb2_phy); +} + +static int dwc3_phy_power_on(struct dwc3 *dwc) +{ + int ret; + + usb_phy_set_suspend(dwc->usb2_phy, 0); + usb_phy_set_suspend(dwc->usb3_phy, 0); + + ret = phy_power_on(dwc->usb2_generic_phy); + if (ret < 0) + goto err_suspend_usb3_phy; + + ret = phy_power_on(dwc->usb3_generic_phy); + if (ret < 0) + goto err_power_off_usb2_phy; + + return 0; + +err_power_off_usb2_phy: + phy_power_off(dwc->usb2_generic_phy); +err_suspend_usb3_phy: + usb_phy_set_suspend(dwc->usb3_phy, 1); + usb_phy_set_suspend(dwc->usb2_phy, 1); + + return ret; +} + +static void dwc3_phy_power_off(struct dwc3 *dwc) +{ + phy_power_off(dwc->usb3_generic_phy); + phy_power_off(dwc->usb2_generic_phy); + + usb_phy_set_suspend(dwc->usb3_phy, 1); + usb_phy_set_suspend(dwc->usb2_phy, 1); +} + static int dwc3_clk_enable(struct dwc3 *dwc) { int ret; @@ -766,17 +836,8 @@ static void dwc3_clk_disable(struct dwc3 *dwc) static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); - - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - phy_power_off(dwc->usb2_generic_phy); - phy_power_off(dwc->usb3_generic_phy); - - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - + dwc3_phy_power_off(dwc); + dwc3_phy_exit(dwc); dwc3_clk_disable(dwc); reset_control_assert(dwc->reset); } @@ -1039,20 +1100,13 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc->phys_ready = true; } - usb_phy_init(dwc->usb2_phy); - usb_phy_init(dwc->usb3_phy); - - ret = phy_init(dwc->usb2_generic_phy); - if (ret < 0) - goto err_shutdown_usb3_phy; - - ret = phy_init(dwc->usb3_generic_phy); - if (ret < 0) - goto err_exit_usb2_phy; + ret = dwc3_phy_init(dwc); + if (ret) + goto err_exit_ulpi; ret = dwc3_core_soft_reset(dwc); if (ret) - goto err_exit_usb3_phy; + goto err_exit_phy; if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { @@ -1083,20 +1137,14 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_set_incr_burst_type(dwc); - usb_phy_set_suspend(dwc->usb2_phy, 0); - usb_phy_set_suspend(dwc->usb3_phy, 0); - ret = phy_power_on(dwc->usb2_generic_phy); - if (ret < 0) - goto err_suspend_usb3_phy; - - ret = phy_power_on(dwc->usb3_generic_phy); - if (ret < 0) - goto err_power_off_usb2_phy; + dwc3_phy_power_on(dwc); + if (ret) + goto err_exit_phy; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err_power_off_usb3_phy; + goto err_power_off_phy; } /* @@ -1213,20 +1261,10 @@ static int dwc3_core_init(struct dwc3 *dwc) return 0; -err_power_off_usb3_phy: - phy_power_off(dwc->usb3_generic_phy); -err_power_off_usb2_phy: - phy_power_off(dwc->usb2_generic_phy); -err_suspend_usb3_phy: - usb_phy_set_suspend(dwc->usb3_phy, 1); - usb_phy_set_suspend(dwc->usb2_phy, 1); -err_exit_usb3_phy: - phy_exit(dwc->usb3_generic_phy); -err_exit_usb2_phy: - phy_exit(dwc->usb2_generic_phy); -err_shutdown_usb3_phy: - usb_phy_shutdown(dwc->usb3_phy); - usb_phy_shutdown(dwc->usb2_phy); +err_power_off_phy: + dwc3_phy_power_off(dwc); +err_exit_phy: + dwc3_phy_exit(dwc); err_exit_ulpi: dwc3_ulpi_exit(dwc); @@ -1844,17 +1882,8 @@ static int dwc3_probe(struct platform_device *pdev) err_exit_debugfs: dwc3_debugfs_exit(dwc); dwc3_event_buffers_cleanup(dwc); - - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - phy_power_off(dwc->usb2_generic_phy); - phy_power_off(dwc->usb3_generic_phy); - - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - + dwc3_phy_power_off(dwc); + dwc3_phy_exit(dwc); dwc3_ulpi_exit(dwc); err_free_event_buffers: dwc3_free_event_buffers(dwc); -- cgit v1.2.3 From bd82857424d37897ad994381f7c580dacf2e2988 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:23 +0200 Subject: USB: dwc3: refactor clock lookups The probe callback has become unwieldy so break out the clock lookups into a new helper function to improve readability. Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-11-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 116 +++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 16f6270eb9ff..31dd9f21820e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1704,6 +1704,64 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) return edev; } +static int dwc3_get_clocks(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + + if (!dev->of_node) + return 0; + + /* + * Clocks are optional, but new DT platforms should support all clocks + * as required by the DT-binding. + * Some devices have different clock names in legacy device trees, + * check for them to retain backwards compatibility. + */ + dwc->bus_clk = devm_clk_get_optional(dev, "bus_early"); + if (IS_ERR(dwc->bus_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->bus_clk), + "could not get bus clock\n"); + } + + if (dwc->bus_clk == NULL) { + dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk"); + if (IS_ERR(dwc->bus_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->bus_clk), + "could not get bus clock\n"); + } + } + + dwc->ref_clk = devm_clk_get_optional(dev, "ref"); + if (IS_ERR(dwc->ref_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->ref_clk), + "could not get ref clock\n"); + } + + if (dwc->ref_clk == NULL) { + dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk"); + if (IS_ERR(dwc->ref_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->ref_clk), + "could not get ref clock\n"); + } + } + + dwc->susp_clk = devm_clk_get_optional(dev, "suspend"); + if (IS_ERR(dwc->susp_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->susp_clk), + "could not get suspend clock\n"); + } + + if (dwc->susp_clk == NULL) { + dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk"); + if (IS_ERR(dwc->susp_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->susp_clk), + "could not get suspend clock\n"); + } + } + + return 0; +} + static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1754,61 +1812,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err_put_psy; } - if (dev->of_node) { - /* - * Clocks are optional, but new DT platforms should support all - * clocks as required by the DT-binding. - * Some devices have different clock names in legacy device trees, - * check for them to retain backwards compatibility. - */ - dwc->bus_clk = devm_clk_get_optional(dev, "bus_early"); - if (IS_ERR(dwc->bus_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), - "could not get bus clock\n"); - goto err_put_psy; - } - - if (dwc->bus_clk == NULL) { - dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk"); - if (IS_ERR(dwc->bus_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), - "could not get bus clock\n"); - goto err_put_psy; - } - } - - dwc->ref_clk = devm_clk_get_optional(dev, "ref"); - if (IS_ERR(dwc->ref_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), - "could not get ref clock\n"); - goto err_put_psy; - } - - if (dwc->ref_clk == NULL) { - dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk"); - if (IS_ERR(dwc->ref_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), - "could not get ref clock\n"); - goto err_put_psy; - } - } - - dwc->susp_clk = devm_clk_get_optional(dev, "suspend"); - if (IS_ERR(dwc->susp_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), - "could not get suspend clock\n"); - goto err_put_psy; - } - - if (dwc->susp_clk == NULL) { - dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk"); - if (IS_ERR(dwc->susp_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), - "could not get suspend clock\n"); - goto err_put_psy; - } - } - } + ret = dwc3_get_clocks(dwc); + if (ret) + goto err_put_psy; ret = reset_control_deassert(dwc->reset); if (ret) -- cgit v1.2.3 From 9a4d7dd1990383df8ffa09d6879cecb0534405e1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 4 Apr 2023 09:25:24 +0200 Subject: USB: dwc3: clean up probe declarations Clean up the probe variable declarations by removing the stray newlines. Acked-by: Thinh Nguyen Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230404072524.19014-12-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 31dd9f21820e..435a4ad780d8 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1766,12 +1766,10 @@ static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res, dwc_res; + void __iomem *regs; struct dwc3 *dwc; - int ret; - void __iomem *regs; - dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); if (!dwc) return -ENOMEM; -- cgit v1.2.3 From dac3b192107b978198e89ec0f77375738352e0c8 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Thu, 16 Mar 2023 16:11:49 +0800 Subject: usb: typec: tcpm: fix multiple times discover svids error PD3.0 Spec 6.4.4.3.2 say that only Responder supports 12 or more SVIDs, the Discover SVIDs Command Shall be executed multiple times until a Discover SVIDs VDO is returned ending either with a SVID value of 0x0000 in the last part of the last VDO or with a VDO containing two SVIDs with values of 0x0000. In the current implementation, if the last VDO does not find that the Discover SVIDs Command would be executed multiple times even if the Responder SVIDs are less than 12, and we found some odd dockers just meet this case. So fix it. Acked-by: Heikki Krogerus Signed-off-by: Frank Wang Link: https://lore.kernel.org/r/20230316081149.24519-1-frank.wang@rock-chips.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 4e276d2f15d1..3c6b0c8e2d3a 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1523,7 +1523,21 @@ static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt) pmdata->svids[pmdata->nsvids++] = svid; tcpm_log(port, "SVID %d: 0x%x", pmdata->nsvids, svid); } - return true; + + /* + * PD3.0 Spec 6.4.4.3.2: The SVIDs are returned 2 per VDO (see Table + * 6-43), and can be returned maximum 6 VDOs per response (see Figure + * 6-19). If the Respondersupports 12 or more SVID then the Discover + * SVIDs Command Shall be executed multiple times until a Discover + * SVIDs VDO is returned ending either with a SVID value of 0x0000 in + * the last part of the last VDO or with a VDO containing two SVIDs + * with values of 0x0000. + * + * However, some odd dockers support SVIDs less than 12 but without + * 0x0000 in the last VDO, so we need to break the Discover SVIDs + * request and return false here. + */ + return cnt == 7; abort: tcpm_log(port, "SVID_DISCOVERY_MAX(%d) too low!", SVID_DISCOVERY_MAX); return false; -- cgit v1.2.3 From 511b74e7c0b8ecd78b8175f5ee84dc0b6e014c19 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 12 Apr 2023 18:17:34 +0200 Subject: usb: typec: ucsi: don't print PPM init deferred errors ucsi_init() may be deferred as usb_role_sw may be deferred in ucsi_register_port(). This results in several PPM init failed (-517) messages maybe printed several times upon boot, like on stm32mp135f-dk board, until the role_switch driver gets probed. [ 19.880945] dwc2 49000000.usb: supply vusb_d not found, using dummy regulator [ 19.887136] dwc2 49000000.usb: supply vusb_a not found, using dummy regulator [ 19.975432] ucsi-stm32g0-i2c 0-0053: PPM init failed (-517) [ 20.155746] dwc2 49000000.usb: EPs: 9, dedicated fifos, 952 entries in SPRAM [ 20.175429] ucsi-stm32g0-i2c 0-0053: PPM init failed (-517) [ 20.184242] dwc2 49000000.usb: DWC OTG Controller Adopt dev_err_probe() instead of dev_err(), to only print other errors. Also print an error in case the wait count has expired. Reviewed-by: Heikki Krogerus Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20230412161734.3425090-1-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 8d1baf28df55..2b472ec01dc4 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1444,11 +1444,13 @@ static void ucsi_init_work(struct work_struct *work) ret = ucsi_init(ucsi); if (ret) - dev_err(ucsi->dev, "PPM init failed (%d)\n", ret); + dev_err_probe(ucsi->dev, ret, "PPM init failed\n"); if (ret == -EPROBE_DEFER) { - if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT) + if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT) { + dev_err(ucsi->dev, "PPM init failed, stop trying\n"); return; + } queue_delayed_work(system_long_wq, &ucsi->work, UCSI_ROLE_SWITCH_INTERVAL); -- cgit v1.2.3 From 0db213ea8eed5534a5169e807f28103cbc9d23df Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Fri, 7 Apr 2023 03:07:40 +0000 Subject: usb: gadget: udc: core: Invoke usb_gadget_connect only when started usb_udc_connect_control does not check to see if the udc has already been started. This causes gadget->ops->pullup to be called through usb_gadget_connect when invoked from usb_udc_vbus_handler even before usb_gadget_udc_start is called. Guard this by checking for udc->started in usb_udc_connect_control before invoking usb_gadget_connect. Guarding udc->vbus, udc->started, gadget->connect, gadget->deactivate related functions with connect_lock. usb_gadget_connect_locked, usb_gadget_disconnect_locked, usb_udc_connect_control_locked, usb_gadget_udc_start_locked, usb_gadget_udc_stop_locked are called with this lock held as they can be simulataneously invoked from different code paths. Adding an additional check to make sure udc is started(udc->started) before pullup callback is invoked. Fixes: 628ef0d273a6 ("usb: udc: add usb_udc_vbus_handler") Cc: stable@vger.kernel.org Signed-off-by: Badhri Jagan Sridharan Link: https://lore.kernel.org/r/20230407030741.3163220-1-badhri@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 148 +++++++++++++++++++++++++++++------------- 1 file changed, 104 insertions(+), 44 deletions(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 3dcbba739db6..af92c2e8e10c 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -37,6 +37,10 @@ static struct bus_type gadget_bus_type; * @vbus: for udcs who care about vbus status, this value is real vbus status; * for udcs who do not care about vbus status, this value is always true * @started: the UDC's started state. True if the UDC had started. + * @connect_lock: protects udc->vbus, udc->started, gadget->connect, gadget->deactivate related + * functions. usb_gadget_connect_locked, usb_gadget_disconnect_locked, + * usb_udc_connect_control_locked, usb_gadget_udc_start_locked, usb_gadget_udc_stop_locked are + * called with this lock held. * * This represents the internal data structure which is used by the UDC-class * to hold information about udc driver and gadget together. @@ -48,6 +52,7 @@ struct usb_udc { struct list_head list; bool vbus; bool started; + struct mutex connect_lock; }; static struct class *udc_class; @@ -687,17 +692,9 @@ out: } EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); -/** - * usb_gadget_connect - software-controlled connect to USB host - * @gadget:the peripheral being connected - * - * Enables the D+ (or potentially D-) pullup. The host will start - * enumerating this gadget when the pullup is active and a VBUS session - * is active (the link is powered). - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_connect(struct usb_gadget *gadget) +/* Internal version of usb_gadget_connect needs to be called with connect_lock held. */ +static int usb_gadget_connect_locked(struct usb_gadget *gadget) + __must_hold(&gadget->udc->connect_lock) { int ret = 0; @@ -706,10 +703,12 @@ int usb_gadget_connect(struct usb_gadget *gadget) goto out; } - if (gadget->deactivated) { + if (gadget->deactivated || !gadget->udc->started) { /* * If gadget is deactivated we only save new state. * Gadget will be connected automatically after activation. + * + * udc first needs to be started before gadget can be pulled up. */ gadget->connected = true; goto out; @@ -724,22 +723,32 @@ out: return ret; } -EXPORT_SYMBOL_GPL(usb_gadget_connect); /** - * usb_gadget_disconnect - software-controlled disconnect from USB host - * @gadget:the peripheral being disconnected - * - * Disables the D+ (or potentially D-) pullup, which the host may see - * as a disconnect (when a VBUS session is active). Not all systems - * support software pullup controls. + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected * - * Following a successful disconnect, invoke the ->disconnect() callback - * for the current gadget driver so that UDC drivers don't need to. + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). * * Returns zero on success, else negative errno. */ -int usb_gadget_disconnect(struct usb_gadget *gadget) +int usb_gadget_connect(struct usb_gadget *gadget) +{ + int ret; + + mutex_lock(&gadget->udc->connect_lock); + ret = usb_gadget_connect_locked(gadget); + mutex_unlock(&gadget->udc->connect_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_connect); + +/* Internal version of usb_gadget_disconnect needs to be called with connect_lock held. */ +static int usb_gadget_disconnect_locked(struct usb_gadget *gadget) + __must_hold(&gadget->udc->connect_lock) { int ret = 0; @@ -751,10 +760,12 @@ int usb_gadget_disconnect(struct usb_gadget *gadget) if (!gadget->connected) goto out; - if (gadget->deactivated) { + if (gadget->deactivated || !gadget->udc->started) { /* * If gadget is deactivated we only save new state. * Gadget will stay disconnected after activation. + * + * udc should have been started before gadget being pulled down. */ gadget->connected = false; goto out; @@ -774,6 +785,30 @@ out: return ret; } + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * Following a successful disconnect, invoke the ->disconnect() callback + * for the current gadget driver so that UDC drivers don't need to. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_disconnect(struct usb_gadget *gadget) +{ + int ret; + + mutex_lock(&gadget->udc->connect_lock); + ret = usb_gadget_disconnect_locked(gadget); + mutex_unlock(&gadget->udc->connect_lock); + + return ret; +} EXPORT_SYMBOL_GPL(usb_gadget_disconnect); /** @@ -794,10 +829,11 @@ int usb_gadget_deactivate(struct usb_gadget *gadget) if (gadget->deactivated) goto out; + mutex_lock(&gadget->udc->connect_lock); if (gadget->connected) { - ret = usb_gadget_disconnect(gadget); + ret = usb_gadget_disconnect_locked(gadget); if (ret) - goto out; + goto unlock; /* * If gadget was being connected before deactivation, we want @@ -807,6 +843,8 @@ int usb_gadget_deactivate(struct usb_gadget *gadget) } gadget->deactivated = true; +unlock: + mutex_unlock(&gadget->udc->connect_lock); out: trace_usb_gadget_deactivate(gadget, ret); @@ -830,6 +868,7 @@ int usb_gadget_activate(struct usb_gadget *gadget) if (!gadget->deactivated) goto out; + mutex_lock(&gadget->udc->connect_lock); gadget->deactivated = false; /* @@ -837,7 +876,8 @@ int usb_gadget_activate(struct usb_gadget *gadget) * while it was being deactivated, we call usb_gadget_connect(). */ if (gadget->connected) - ret = usb_gadget_connect(gadget); + ret = usb_gadget_connect_locked(gadget); + mutex_unlock(&gadget->udc->connect_lock); out: trace_usb_gadget_activate(gadget, ret); @@ -1078,12 +1118,13 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state); /* ------------------------------------------------------------------------- */ -static void usb_udc_connect_control(struct usb_udc *udc) +/* Acquire connect_lock before calling this function. */ +static void usb_udc_connect_control_locked(struct usb_udc *udc) __must_hold(&udc->connect_lock) { - if (udc->vbus) - usb_gadget_connect(udc->gadget); + if (udc->vbus && udc->started) + usb_gadget_connect_locked(udc->gadget); else - usb_gadget_disconnect(udc->gadget); + usb_gadget_disconnect_locked(udc->gadget); } /** @@ -1099,10 +1140,12 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) { struct usb_udc *udc = gadget->udc; + mutex_lock(&udc->connect_lock); if (udc) { udc->vbus = status; - usb_udc_connect_control(udc); + usb_udc_connect_control_locked(udc); } + mutex_unlock(&udc->connect_lock); } EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); @@ -1124,7 +1167,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget, EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); /** - * usb_gadget_udc_start - tells usb device controller to start up + * usb_gadget_udc_start_locked - tells usb device controller to start up * @udc: The UDC to be started * * This call is issued by the UDC Class driver when it's about @@ -1135,8 +1178,11 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); * necessary to have it powered on. * * Returns zero on success, else negative errno. + * + * Caller should acquire connect_lock before invoking this function. */ -static inline int usb_gadget_udc_start(struct usb_udc *udc) +static inline int usb_gadget_udc_start_locked(struct usb_udc *udc) + __must_hold(&udc->connect_lock) { int ret; @@ -1153,7 +1199,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc) } /** - * usb_gadget_udc_stop - tells usb device controller we don't need it anymore + * usb_gadget_udc_stop_locked - tells usb device controller we don't need it anymore * @udc: The UDC to be stopped * * This call is issued by the UDC Class driver after calling @@ -1162,8 +1208,11 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc) * The details are implementation specific, but it can go as * far as powering off UDC completely and disable its data * line pullups. + * + * Caller should acquire connect lock before invoking this function. */ -static inline void usb_gadget_udc_stop(struct usb_udc *udc) +static inline void usb_gadget_udc_stop_locked(struct usb_udc *udc) + __must_hold(&udc->connect_lock) { if (!udc->started) { dev_err(&udc->dev, "UDC had already stopped\n"); @@ -1322,6 +1371,7 @@ int usb_add_gadget(struct usb_gadget *gadget) udc->gadget = gadget; gadget->udc = udc; + mutex_init(&udc->connect_lock); udc->started = false; @@ -1523,11 +1573,15 @@ static int gadget_bind_driver(struct device *dev) if (ret) goto err_bind; - ret = usb_gadget_udc_start(udc); - if (ret) + mutex_lock(&udc->connect_lock); + ret = usb_gadget_udc_start_locked(udc); + if (ret) { + mutex_unlock(&udc->connect_lock); goto err_start; + } usb_gadget_enable_async_callbacks(udc); - usb_udc_connect_control(udc); + usb_udc_connect_control_locked(udc); + mutex_unlock(&udc->connect_lock); kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); return 0; @@ -1558,12 +1612,14 @@ static void gadget_unbind_driver(struct device *dev) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - usb_gadget_disconnect(gadget); + mutex_lock(&udc->connect_lock); + usb_gadget_disconnect_locked(gadget); usb_gadget_disable_async_callbacks(udc); if (gadget->irq) synchronize_irq(gadget->irq); udc->driver->unbind(gadget); - usb_gadget_udc_stop(udc); + usb_gadget_udc_stop_locked(udc); + mutex_unlock(&udc->connect_lock); mutex_lock(&udc_lock); driver->is_bound = false; @@ -1649,11 +1705,15 @@ static ssize_t soft_connect_store(struct device *dev, } if (sysfs_streq(buf, "connect")) { - usb_gadget_udc_start(udc); - usb_gadget_connect(udc->gadget); + mutex_lock(&udc->connect_lock); + usb_gadget_udc_start_locked(udc); + usb_gadget_connect_locked(udc->gadget); + mutex_unlock(&udc->connect_lock); } else if (sysfs_streq(buf, "disconnect")) { - usb_gadget_disconnect(udc->gadget); - usb_gadget_udc_stop(udc); + mutex_lock(&udc->connect_lock); + usb_gadget_disconnect_locked(udc->gadget); + usb_gadget_udc_stop_locked(udc); + mutex_unlock(&udc->connect_lock); } else { dev_err(dev, "unsupported command '%s'\n", buf); ret = -EINVAL; -- cgit v1.2.3 From a3afbf5cc887fc3401f012fe629810998ed61859 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Fri, 7 Apr 2023 03:07:41 +0000 Subject: usb: gadget: udc: core: Prevent redundant calls to pullup usb_gadget_connect calls gadget->ops->pullup without checking whether gadget->connected was previously set. Make this symmetric to usb_gadget_disconnect by returning early if gadget->connected is already set. Fixes: 5a1da544e572 ("usb: gadget: core: do not try to disconnect gadget if it is not connected") Cc: stable@vger.kernel.org Signed-off-by: Badhri Jagan Sridharan Link: https://lore.kernel.org/r/20230407030741.3163220-2-badhri@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index af92c2e8e10c..1c5403ce9e7c 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -703,6 +703,9 @@ static int usb_gadget_connect_locked(struct usb_gadget *gadget) goto out; } + if (gadget->connected) + goto out; + if (gadget->deactivated || !gadget->udc->started) { /* * If gadget is deactivated we only save new state. -- cgit v1.2.3 From d6f712f53b79f5017cdcefafb7a5aea9ec52da5d Mon Sep 17 00:00:00 2001 From: Yinhao Hu Date: Wed, 12 Apr 2023 13:58:52 +0800 Subject: usb: chipidea: fix missing goto in `ci_hdrc_probe` From the comment of ci_usb_phy_init, it returns an error code if usb_phy_init has failed, and it should do some clean up, not just return directly. Fix this by goto the error handling. Fixes: 74475ede784d ("usb: chipidea: move PHY operation to core") Reviewed-by: Dongliang Mu Acked-by: Peter Chen Signed-off-by: Yinhao Hu Link: https://lore.kernel.org/r/20230412055852.971991-1-dddddd@hust.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index d1d252c87e4f..798cb077867a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -1108,7 +1108,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) ret = ci_usb_phy_init(ci); if (ret) { dev_err(dev, "unable to init phy: %d\n", ret); - return ret; + goto ulpi_exit; } ci->hw_bank.phys = res->start; -- cgit v1.2.3 From c507565aac2e8c4ca8dd36afcd40e15e4b459d93 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 17 Apr 2023 10:51:57 +0800 Subject: usb: mtu3: give back request when rx error happens When the Rx enconnter errors, currently, only print error logs, that may cause class driver's RX halt, shall give back the request with error status meanwhile. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230417025203.18097-1-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_qmu.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c index a2fdab8b63b2..a4da1af0b2c0 100644 --- a/drivers/usb/mtu3/mtu3_qmu.c +++ b/drivers/usb/mtu3/mtu3_qmu.c @@ -466,6 +466,37 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum) mtu3_qmu_resume(mep); } +/* + * when rx error happens (except zlperr), QMU will stop, and RQCPR saves + * the GPD encountered error, Done irq will arise after resuming QMU again. + */ +static void qmu_error_rx(struct mtu3 *mtu, u8 epnum) +{ + struct mtu3_ep *mep = mtu->out_eps + epnum; + struct mtu3_gpd_ring *ring = &mep->gpd_ring; + struct qmu_gpd *gpd_current = NULL; + struct mtu3_request *mreq; + dma_addr_t cur_gpd_dma; + + cur_gpd_dma = read_rxq_cur_addr(mtu->mac_base, epnum); + gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma); + + mreq = next_request(mep); + if (!mreq || mreq->gpd != gpd_current) { + dev_err(mtu->dev, "no correct RX req is found\n"); + return; + } + + mreq->request.status = -EAGAIN; + + /* by pass the current GDP */ + gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO); + mtu3_qmu_resume(mep); + + dev_dbg(mtu->dev, "%s EP%d, current=%p, req=%p\n", + __func__, epnum, gpd_current, mreq); +} + /* * NOTE: request list maybe is already empty as following case: * queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)--> @@ -571,14 +602,18 @@ static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status) if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) { errval = mtu3_readl(mbase, U3D_RQERRIR0); + mtu3_writel(mbase, U3D_RQERRIR0, errval); + for (i = 1; i < mtu->num_eps; i++) { if (errval & QMU_RX_CS_ERR(i)) dev_err(mtu->dev, "Rx %d CS error!\n", i); if (errval & QMU_RX_LEN_ERR(i)) dev_err(mtu->dev, "RX %d Length error\n", i); + + if (errval & (QMU_RX_CS_ERR(i) | QMU_RX_LEN_ERR(i))) + qmu_error_rx(mtu, i); } - mtu3_writel(mbase, U3D_RQERRIR0, errval); } if (qmu_status & RXQ_ZLPERR_INT) { -- cgit v1.2.3 From 3481769cd05b2ff3fa00d0aab526eb64de994fad Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 17 Apr 2023 10:51:58 +0800 Subject: usb: mtu3: use boolean return value Prefer to use boolean value due to gpd_ring_empty() return true or false. See "16) Function return values and names" in coding-style.rst Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230417025203.18097-2-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_qmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c index a4da1af0b2c0..6be4977a5db5 100644 --- a/drivers/usb/mtu3/mtu3_qmu.c +++ b/drivers/usb/mtu3/mtu3_qmu.c @@ -221,7 +221,7 @@ static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring) } /* check if a ring is emtpy */ -static int gpd_ring_empty(struct mtu3_gpd_ring *ring) +static bool gpd_ring_empty(struct mtu3_gpd_ring *ring) { struct qmu_gpd *enq = ring->enqueue; struct qmu_gpd *next; -- cgit v1.2.3 From d28f4091ea7ec3510fd6a3c6d433234e7a2bef14 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 17 Apr 2023 10:51:59 +0800 Subject: usb: mtu3: fix kernel panic at qmu transfer done irq handler When handle qmu transfer irq, it will unlock @mtu->lock before give back request, if another thread handle disconnect event at the same time, and try to disable ep, it may lock @mtu->lock and free qmu ring, then qmu irq hanlder may get a NULL gpd, avoid the KE by checking gpd's value before handling it. e.g. qmu done irq on cpu0 thread running on cpu1 qmu_done_tx() handle gpd [0] mtu3_requ_complete() mtu3_gadget_ep_disable() unlock @mtu->lock give back request lock @mtu->lock mtu3_ep_disable() mtu3_gpd_ring_free() unlock @mtu->lock lock @mtu->lock get next gpd [1] [1]: goto [0] to handle next gpd, and next gpd may be NULL. Fixes: 48e0d3735aa5 ("usb: mtu3: supports new QMU format") Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230417025203.18097-3-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_qmu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c index 6be4977a5db5..3d77408e3133 100644 --- a/drivers/usb/mtu3/mtu3_qmu.c +++ b/drivers/usb/mtu3/mtu3_qmu.c @@ -210,6 +210,7 @@ static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring) return ring->enqueue; } +/* @dequeue may be NULL if ring is unallocated or freed */ static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring) { if (ring->dequeue < ring->end) @@ -522,7 +523,7 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum) dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", __func__, epnum, gpd, gpd_current, ring->enqueue); - while (gpd != gpd_current && !GET_GPD_HWO(gpd)) { + while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) { mreq = next_request(mep); @@ -561,7 +562,7 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum) dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", __func__, epnum, gpd, gpd_current, ring->enqueue); - while (gpd != gpd_current && !GET_GPD_HWO(gpd)) { + while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) { mreq = next_request(mep); -- cgit v1.2.3 From ed50be81d536cdb25d00befe6ca21cd02f1c509d Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 17 Apr 2023 10:52:00 +0800 Subject: usb: mtu3: unlock @mtu->lock just before giving back request No need unlock @mtu->lock when unmap request, unlock it just before giving back request, due to we do not lock this spinlock when map the request. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230417025203.18097-4-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index c0264d5426bf..ad0eeac4332d 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -23,7 +23,6 @@ __acquires(mep->mtu->lock) req->status = status; trace_mtu3_req_complete(mreq); - spin_unlock(&mtu->lock); /* ep0 makes use of PIO, needn't unmap it */ if (mep->epnum) @@ -32,6 +31,7 @@ __acquires(mep->mtu->lock) dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n", mep->name, req, req->status, req->actual, req->length); + spin_unlock(&mtu->lock); usb_gadget_giveback_request(&mep->ep, req); spin_lock(&mtu->lock); } -- cgit v1.2.3 From 976a5c256e34085207c0abf0941b5c967d8d1c18 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 17 Apr 2023 10:52:01 +0800 Subject: usb: mtu3: expose role-switch control to userspace The allow_userspace_control flag enables manual role switch from userspace, turn this feature on like several other USB DRD controller drivers. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230417025203.18097-5-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_dr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index 9b8aded3d95e..8191b7ed3852 100644 --- a/drivers/usb/mtu3/mtu3_dr.c +++ b/drivers/usb/mtu3/mtu3_dr.c @@ -294,6 +294,7 @@ static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx) role_sx_desc.get = ssusb_role_sw_get; role_sx_desc.fwnode = dev_fwnode(dev); role_sx_desc.driver_data = ssusb; + role_sx_desc.allow_userspace_control = true; otg_sx->role_sw = usb_role_switch_register(dev, &role_sx_desc); if (IS_ERR(otg_sx->role_sw)) return PTR_ERR(otg_sx->role_sw); -- cgit v1.2.3 From d10cb206acb45b9a0aa83318f0101bb56c33b7de Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 17 Apr 2023 10:52:02 +0800 Subject: dt-bindings: usb: mtu3: add two optional clocks Add optional clock 'xhci_ck' and 'frmcnt_ck'; Reviewed-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230417025203.18097-6-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml index 5b908c457e3d..478214ab045e 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml @@ -66,6 +66,8 @@ properties: - description: Reference clock used by low power mode etc - description: Mcu bus clock for register access - description: DMA bus clock for data transfer + - description: DRD controller clock + - description: Frame count clock clock-names: minItems: 1 @@ -74,6 +76,8 @@ properties: - const: ref_ck - const: mcu_ck - const: dma_ck + - const: xhci_ck + - const: frmcnt_ck phys: description: -- cgit v1.2.3 From 41792870dc1cb8305ca04d563cabd63833e94762 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 17 Apr 2023 10:52:03 +0800 Subject: usb: mtu3: add optional clock xhci_ck and frmcnt_ck Add optional clock 'xhci_ck' which is usually the same as sys_ck, but some SoC use two separated clocks when the controller supports dual role mode; Add optional clock 'frmcnt_ck' used on 4nm or advanced process SoC. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20230417025203.18097-7-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3.h | 2 +- drivers/usb/mtu3/mtu3_plat.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 2d7b57e07eee..b4a7662dded5 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -90,7 +90,7 @@ struct mtu3_request; */ #define EP0_RESPONSE_BUF 6 -#define BULK_CLKS_CNT 4 +#define BULK_CLKS_CNT 6 /* device operated link and speed got from DEVICE_CONF register */ enum mtu3_speed { diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index d78ae52b4e26..6f264b129243 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -234,6 +234,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) clks[1].id = "ref_ck"; clks[2].id = "mcu_ck"; clks[3].id = "dma_ck"; + clks[4].id = "xhci_ck"; + clks[5].id = "frmcnt_ck"; ret = devm_clk_bulk_get_optional(dev, BULK_CLKS_CNT, clks); if (ret) return ret; -- cgit v1.2.3 From a804a47658ced9e9cc6b6000846ddf208362f1b3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 20 Apr 2023 08:50:51 +0200 Subject: dt-bindings: usb: ci-hdrc-usb2: allow multiple PHYs Qualcomm MSM8974 comes with USB HS phy in two variants, although final DTS chooses only one. Allow such combination in the ChipIdea USB2 bindings and also disallow any other properties in the ulpi node. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230420065051.22994-1-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml index e5e4dbc5a7a0..b26d26c2b023 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml @@ -322,8 +322,9 @@ properties: ulpi: type: object - properties: - phy: + additionalProperties: false + patternProperties: + "^phy(-[0-9])?$": description: The phy child node for Qcom chips. type: object $ref: /schemas/phy/qcom,usb-hs-phy.yaml -- cgit v1.2.3 From d21a797a3eeb2b001e07ff943e5611eab67a71a3 Mon Sep 17 00:00:00 2001 From: Stanley Chang Date: Wed, 19 Apr 2023 10:00:42 +0800 Subject: usb: dwc3: core: add support for disabling High-speed park mode Setting the PARKMODE_DISABLE_HS bit in the DWC3_USB3_GUCTL1. When this bit is set to '1' all HS bus instances in park mode are disabled For some USB wifi devices, if enable this feature it will reduce the performance. Therefore, add an option for disabling HS park mode by device-tree. In Synopsys's dwc3 data book: In a few high speed devices when an IN request is sent within 900ns of the ACK of the previous packet, these devices send a NAK. When connected to these devices, if required, the software can disable the park mode if you see performance drop in your system. When park mode is disabled, pipelining of multiple packet is disabled and instead one packet at a time is requested by the scheduler. This allows up to 12 NAKs in a micro-frame and improves performance of these slow devices. Acked-by: Thinh Nguyen Signed-off-by: Stanley Chang Link: https://lore.kernel.org/r/20230419020044.15475-1-stanley_chang@realtek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 5 +++++ drivers/usb/dwc3/core.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 435a4ad780d8..0beaab932e7d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1198,6 +1198,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->parkmode_disable_ss_quirk) reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; + if (dwc->parkmode_disable_hs_quirk) + reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS; + if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && (dwc->maximum_speed == USB_SPEED_HIGH || dwc->maximum_speed == USB_SPEED_FULL)) @@ -1509,6 +1512,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,ulpi-ext-vbus-drv"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, "snps,parkmode-disable-ss-quirk"); + dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev, + "snps,parkmode-disable-hs-quirk"); dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev, "snps,gfladj-refclk-lpm-sel-quirk"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 19490dca7937..d56457c02996 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -263,6 +263,7 @@ #define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) +#define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16) #define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10) /* Global Status Register */ @@ -1104,6 +1105,8 @@ struct dwc3_scratchpad_array { * VBUS with an external supply. * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed * instances in park mode. + * @parkmode_disable_hs_quirk: set if we need to disable all HishSpeed + * instances in park mode. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -1318,6 +1321,7 @@ struct dwc3 { unsigned resume_hs_terminations:1; unsigned ulpi_ext_vbus_drv:1; unsigned parkmode_disable_ss_quirk:1; + unsigned parkmode_disable_hs_quirk:1; unsigned gfladj_refclk_lpm_sel:1; unsigned tx_de_emphasis_quirk:1; -- cgit v1.2.3 From 4a2f152af1c478d42bd4f535788d4dbec015704f Mon Sep 17 00:00:00 2001 From: Stanley Chang Date: Wed, 19 Apr 2023 10:00:43 +0800 Subject: dt-bindings: usb: snps,dwc3: Add 'snps,parkmode-disable-hs-quirk' quirk Add a new 'snps,parkmode-disable-hs-quirk' DT quirk to dwc3 core for disable the high-speed parkmode. For some USB wifi devices, if enable this feature it will reduce the performance. Therefore, add an option for disabling HS park mode by device-tree. In Synopsys's dwc3 data book: In a few high speed devices when an IN request is sent within 900ns of the ACK of the previous packet, these devices send a NAK. When connected to these devices, if required, the software can disable the park mode if you see performance drop in your system. When park mode is disabled, pipelining of multiple packet is disabled and instead one packet at a time is requested by the scheduler. This allows up to 12 NAKs in a micro-frame and improves performance of these slow devices. Acked-by: Rob Herring Signed-off-by: Stanley Chang Link: https://lore.kernel.org/r/20230419020044.15475-2-stanley_chang@realtek.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/snps,dwc3.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index eb58ba96b850..50edc4da780e 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -236,6 +236,11 @@ properties: When set, all SuperSpeed bus instances in park mode are disabled. type: boolean + snps,parkmode-disable-hs-quirk: + description: + When set, all HighSpeed bus instances in park mode are disabled. + type: boolean + snps,dis_metastability_quirk: description: When set, disable metastability workaround. CAUTION! Use only if you are -- cgit v1.2.3 From 02435a739b81ae24aff5d6e930efef9458e2af3c Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Thu, 13 Apr 2023 12:57:40 -0700 Subject: usb: dwc3: gadget: Stall and restart EP0 if host is unresponsive It was observed that there are hosts that may complete pending SETUP transactions before the stop active transfers and controller halt occurs, leading to lingering endxfer commands on DEPs on subsequent pullup/gadget start iterations. dwc3_gadget_ep_disable name=ep8in flags=0x3009 direction=1 dwc3_gadget_ep_disable name=ep4in flags=1 direction=1 dwc3_gadget_ep_disable name=ep3out flags=1 direction=0 usb_gadget_disconnect deactivated=0 connected=0 ret=0 The sequence shows that the USB gadget disconnect (dwc3_gadget_pullup(0)) routine completed successfully, allowing for the USB gadget to proceed with a USB gadget connect. However, if this occurs the system runs into an issue where: BUG: spinlock already unlocked on CPU spin_bug+0x0 dwc3_remove_requests+0x278 dwc3_ep0_out_start+0xb0 __dwc3_gadget_start+0x25c This is due to the pending endxfers, leading to gadget start (w/o lock held) to execute the remove requests, which will unlock the dwc3 spinlock as part of giveback. To mitigate this, resolve the pending endxfers on the pullup disable path by re-locating the SETUP phase check after stop active transfers, since that is where the DWC3_EP_DELAY_STOP is potentially set. This also allows for handling of a host that may be unresponsive by using the completion timeout to trigger the stall and restart for EP0. Fixes: c96683798e27 ("usb: dwc3: ep0: Don't prepare beyond Setup stage") Cc: stable@vger.kernel.org Acked-by: Thinh Nguyen Signed-off-by: Wesley Cheng Link: https://lore.kernel.org/r/20230413195742.11821-2-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 49 +++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 087efbad94f7..9f492c8a7d0b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2617,29 +2617,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc); static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) { unsigned long flags; + int ret; spin_lock_irqsave(&dwc->lock, flags); dwc->connected = false; /* - * Per databook, when we want to stop the gadget, if a control transfer - * is still in process, complete it and get the core into setup phase. + * Attempt to end pending SETUP status phase, and not wait for the + * function to do so. */ - if (dwc->ep0state != EP0_SETUP_PHASE) { - int ret; - - if (dwc->delayed_status) - dwc3_ep0_send_delayed_status(dwc); - - reinit_completion(&dwc->ep0_in_setup); - - spin_unlock_irqrestore(&dwc->lock, flags); - ret = wait_for_completion_timeout(&dwc->ep0_in_setup, - msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); - spin_lock_irqsave(&dwc->lock, flags); - if (ret == 0) - dev_warn(dwc->dev, "timed out waiting for SETUP phase\n"); - } + if (dwc->delayed_status) + dwc3_ep0_send_delayed_status(dwc); /* * In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a @@ -2652,6 +2640,33 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) __dwc3_gadget_stop(dwc); spin_unlock_irqrestore(&dwc->lock, flags); + /* + * Per databook, when we want to stop the gadget, if a control transfer + * is still in process, complete it and get the core into setup phase. + * In case the host is unresponsive to a SETUP transaction, forcefully + * stall the transfer, and move back to the SETUP phase, so that any + * pending endxfers can be executed. + */ + if (dwc->ep0state != EP0_SETUP_PHASE) { + reinit_completion(&dwc->ep0_in_setup); + + ret = wait_for_completion_timeout(&dwc->ep0_in_setup, + msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); + if (ret == 0) { + unsigned int dir; + + dev_warn(dwc->dev, "wait for SETUP phase timed out\n"); + spin_lock_irqsave(&dwc->lock, flags); + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + dwc3_ep0_stall_and_restart(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + } + } + /* * Note: if the GEVNTCOUNT indicates events in the event buffer, the * driver needs to acknowledge them before the controller can halt. -- cgit v1.2.3 From 13890626501ffda22b18213ddaf7930473da5792 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Apr 2023 15:37:07 -0400 Subject: USB: core: Add routines for endpoint checks in old drivers Many of the older USB drivers in the Linux USB stack were written based simply on a vendor's device specification. They use the endpoint information in the spec and assume these endpoints will always be present, with the properties listed, in any device matching the given vendor and product IDs. While that may have been true back then, with spoofing and fuzzing it is not true any more. More and more we are finding that those old drivers need to perform at least a minimum of checking before they try to use any endpoint other than ep0. To make this checking as simple as possible, we now add a couple of utility routines to the USB core. usb_check_bulk_endpoints() and usb_check_int_endpoints() take an interface pointer together with a list of endpoint addresses (numbers and directions). They check that the interface's current alternate setting includes endpoints with those addresses and that each of these endpoints has the right type: bulk or interrupt, respectively. Although we already have usb_find_common_endpoints() and related routines meant for a similar purpose, they are not well suited for this kind of checking. Those routines find endpoints of various kinds, but only one (either the first or the last) of each kind, and they don't verify that the endpoints' addresses agree with what the caller expects. In theory the new routines could be more general: They could take a particular altsetting as their argument instead of always using the interface's current altsetting. In practice I think this won't matter too much; multiple altsettings tend to be used for transferring media (audio or visual) over isochronous endpoints, not bulk or interrupt. Drivers for such devices will generally require more sophisticated checking than these simplistic routines provide. Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/dd2c8e8c-2c87-44ea-ba17-c64b97e201c9@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb.h | 5 ++++ 2 files changed, 81 insertions(+) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 34742fbbd84d..901ec732321c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -206,6 +206,82 @@ int usb_find_common_endpoints_reverse(struct usb_host_interface *alt, } EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse); +/** + * usb_find_endpoint() - Given an endpoint address, search for the endpoint's + * usb_host_endpoint structure in an interface's current altsetting. + * @intf: the interface whose current altsetting should be searched + * @ep_addr: the endpoint address (number and direction) to find + * + * Search the altsetting's list of endpoints for one with the specified address. + * + * Return: Pointer to the usb_host_endpoint if found, %NULL otherwise. + */ +static const struct usb_host_endpoint *usb_find_endpoint( + const struct usb_interface *intf, unsigned int ep_addr) +{ + int n; + const struct usb_host_endpoint *ep; + + n = intf->cur_altsetting->desc.bNumEndpoints; + ep = intf->cur_altsetting->endpoint; + for (; n > 0; (--n, ++ep)) { + if (ep->desc.bEndpointAddress == ep_addr) + return ep; + } + return NULL; +} + +/** + * usb_check_bulk_endpoints - Check whether an interface's current altsetting + * contains a set of bulk endpoints with the given addresses. + * @intf: the interface whose current altsetting should be searched + * @ep_addrs: 0-terminated array of the endpoint addresses (number and + * direction) to look for + * + * Search for endpoints with the specified addresses and check their types. + * + * Return: %true if all the endpoints are found and are bulk, %false otherwise. + */ +bool usb_check_bulk_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs) +{ + const struct usb_host_endpoint *ep; + + for (; *ep_addrs; ++ep_addrs) { + ep = usb_find_endpoint(intf, *ep_addrs); + if (!ep || !usb_endpoint_xfer_bulk(&ep->desc)) + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(usb_check_bulk_endpoints); + +/** + * usb_check_int_endpoints - Check whether an interface's current altsetting + * contains a set of interrupt endpoints with the given addresses. + * @intf: the interface whose current altsetting should be searched + * @ep_addrs: 0-terminated array of the endpoint addresses (number and + * direction) to look for + * + * Search for endpoints with the specified addresses and check their types. + * + * Return: %true if all the endpoints are found and are interrupt, + * %false otherwise. + */ +bool usb_check_int_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs) +{ + const struct usb_host_endpoint *ep; + + for (; *ep_addrs; ++ep_addrs) { + ep = usb_find_endpoint(intf, *ep_addrs); + if (!ep || !usb_endpoint_xfer_int(&ep->desc)) + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(usb_check_int_endpoints); + /** * usb_find_alt_setting() - Given a configuration, find the alternate setting * for the given interface. diff --git a/include/linux/usb.h b/include/linux/usb.h index d510fabcafa2..4ae0466c846c 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -291,6 +291,11 @@ void usb_put_intf(struct usb_interface *intf); #define USB_MAXINTERFACES 32 #define USB_MAXIADS (USB_MAXINTERFACES/2) +bool usb_check_bulk_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs); +bool usb_check_int_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs); + /* * USB Resume Timer: Every Host controller driver should drive the resume * signalling on the bus for the amount of time defined by this macro. -- cgit v1.2.3 From df05a9b05e466a46725564528b277d0c570d0104 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Apr 2023 15:38:22 -0400 Subject: USB: sisusbvga: Add endpoint checks The syzbot fuzzer was able to provoke a WARNING from the sisusbvga driver: ------------[ cut here ]------------ usb 1-1: BOGUS urb xfer, pipe 3 != type 1 WARNING: CPU: 1 PID: 26 at drivers/usb/core/urb.c:504 usb_submit_urb+0xed6/0x1880 drivers/usb/core/urb.c:504 Modules linked in: CPU: 1 PID: 26 Comm: kworker/1:1 Not tainted 6.2.0-rc5-syzkaller-00199-g5af6ce704936 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/12/2023 Workqueue: usb_hub_wq hub_event RIP: 0010:usb_submit_urb+0xed6/0x1880 drivers/usb/core/urb.c:504 Code: 7c 24 18 e8 6c 50 80 fb 48 8b 7c 24 18 e8 62 1a 01 ff 41 89 d8 44 89 e1 4c 89 ea 48 89 c6 48 c7 c7 60 b1 fa 8a e8 84 b0 be 03 <0f> 0b e9 58 f8 ff ff e8 3e 50 80 fb 48 81 c5 c0 05 00 00 e9 84 f7 RSP: 0018:ffffc90000a1ed18 EFLAGS: 00010282 RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000 RDX: ffff888012783a80 RSI: ffffffff816680ec RDI: fffff52000143d95 RBP: ffff888079020000 R08: 0000000000000005 R09: 0000000000000000 R10: 0000000080000000 R11: 0000000000000000 R12: 0000000000000003 R13: ffff888017d33370 R14: 0000000000000003 R15: ffff888021213600 FS: 0000000000000000(0000) GS:ffff8880b9900000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00005592753a60b0 CR3: 0000000022899000 CR4: 00000000003506e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: sisusb_bulkout_msg drivers/usb/misc/sisusbvga/sisusbvga.c:224 [inline] sisusb_send_bulk_msg.constprop.0+0x904/0x1230 drivers/usb/misc/sisusbvga/sisusbvga.c:379 sisusb_send_bridge_packet drivers/usb/misc/sisusbvga/sisusbvga.c:567 [inline] sisusb_do_init_gfxdevice drivers/usb/misc/sisusbvga/sisusbvga.c:2077 [inline] sisusb_init_gfxdevice+0x87b/0x4000 drivers/usb/misc/sisusbvga/sisusbvga.c:2177 sisusb_probe+0x9cd/0xbe2 drivers/usb/misc/sisusbvga/sisusbvga.c:2869 ... The problem was caused by the fact that the driver does not check whether the endpoints it uses are actually present and have the appropriate types. This can be fixed by adding a simple check of the endpoints. Link: https://syzkaller.appspot.com/bug?extid=23be03b56c5259385d79 Reported-and-tested-by: syzbot+23be03b56c5259385d79@syzkaller.appspotmail.com Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/48ef98f7-51ae-4f63-b8d3-0ef2004bb60a@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusbvga.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/usb/misc/sisusbvga/sisusbvga.c b/drivers/usb/misc/sisusbvga/sisusbvga.c index 654a79fd3231..febf34f9f049 100644 --- a/drivers/usb/misc/sisusbvga/sisusbvga.c +++ b/drivers/usb/misc/sisusbvga/sisusbvga.c @@ -2778,6 +2778,20 @@ static int sisusb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct sisusb_usb_data *sisusb; int retval = 0, i; + static const u8 ep_addresses[] = { + SISUSB_EP_GFX_IN | USB_DIR_IN, + SISUSB_EP_GFX_OUT | USB_DIR_OUT, + SISUSB_EP_GFX_BULK_OUT | USB_DIR_OUT, + SISUSB_EP_GFX_LBULK_OUT | USB_DIR_OUT, + SISUSB_EP_BRIDGE_IN | USB_DIR_IN, + SISUSB_EP_BRIDGE_OUT | USB_DIR_OUT, + 0}; + + /* Are the expected endpoints present? */ + if (!usb_check_bulk_endpoints(intf, ep_addresses)) { + dev_err(&intf->dev, "Invalid USB2VGA device\n"); + return -EINVAL; + } dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", dev->devnum); -- cgit v1.2.3 From 76e31045ba030e94e72105c01b2e98f543d175ac Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Apr 2023 15:40:05 -0400 Subject: media: radio-shark: Add endpoint checks The syzbot fuzzer was able to provoke a WARNING from the radio-shark2 driver: ------------[ cut here ]------------ usb 1-1: BOGUS urb xfer, pipe 1 != type 3 WARNING: CPU: 0 PID: 3271 at drivers/usb/core/urb.c:504 usb_submit_urb+0xed2/0x1880 drivers/usb/core/urb.c:504 Modules linked in: CPU: 0 PID: 3271 Comm: kworker/0:3 Not tainted 6.1.0-rc4-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022 Workqueue: usb_hub_wq hub_event RIP: 0010:usb_submit_urb+0xed2/0x1880 drivers/usb/core/urb.c:504 Code: 7c 24 18 e8 00 36 ea fb 48 8b 7c 24 18 e8 36 1c 02 ff 41 89 d8 44 89 e1 4c 89 ea 48 89 c6 48 c7 c7 a0 b6 90 8a e8 9a 29 b8 03 <0f> 0b e9 58 f8 ff ff e8 d2 35 ea fb 48 81 c5 c0 05 00 00 e9 84 f7 RSP: 0018:ffffc90003876dd0 EFLAGS: 00010282 RAX: 0000000000000000 RBX: 0000000000000003 RCX: 0000000000000000 RDX: ffff8880750b0040 RSI: ffffffff816152b8 RDI: fffff5200070edac RBP: ffff8880172d81e0 R08: 0000000000000005 R09: 0000000000000000 R10: 0000000080000000 R11: 0000000000000000 R12: 0000000000000001 R13: ffff8880285c5040 R14: 0000000000000002 R15: ffff888017158200 FS: 0000000000000000(0000) GS:ffff8880b9a00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ffe03235b90 CR3: 000000000bc8e000 CR4: 00000000003506f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: usb_start_wait_urb+0x101/0x4b0 drivers/usb/core/message.c:58 usb_bulk_msg+0x226/0x550 drivers/usb/core/message.c:387 shark_write_reg+0x1ff/0x2e0 drivers/media/radio/radio-shark2.c:88 ... The problem was caused by the fact that the driver does not check whether the endpoints it uses are actually present and have the appropriate types. This can be fixed by adding a simple check of these endpoints (and similarly for the radio-shark driver). Link: https://syzkaller.appspot.com/bug?extid=4b3f8190f6e13b3efd74 Reported-and-tested-by: syzbot+4b3f8190f6e13b3efd74@syzkaller.appspotmail.com Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/e2858ab4-4adf-46e5-bbf6-c56742034547@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/media/radio/radio-shark.c | 10 ++++++++++ drivers/media/radio/radio-shark2.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c index 8230da828d0e..127a3be0e0f0 100644 --- a/drivers/media/radio/radio-shark.c +++ b/drivers/media/radio/radio-shark.c @@ -316,6 +316,16 @@ static int usb_shark_probe(struct usb_interface *intf, { struct shark_device *shark; int retval = -ENOMEM; + static const u8 ep_addresses[] = { + SHARK_IN_EP | USB_DIR_IN, + SHARK_OUT_EP | USB_DIR_OUT, + 0}; + + /* Are the expected endpoints present? */ + if (!usb_check_int_endpoints(intf, ep_addresses)) { + dev_err(&intf->dev, "Invalid radioSHARK device\n"); + return -EINVAL; + } shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL); if (!shark) diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c index d150f12382c6..f1c5c0a6a335 100644 --- a/drivers/media/radio/radio-shark2.c +++ b/drivers/media/radio/radio-shark2.c @@ -282,6 +282,16 @@ static int usb_shark_probe(struct usb_interface *intf, { struct shark_device *shark; int retval = -ENOMEM; + static const u8 ep_addresses[] = { + SHARK_IN_EP | USB_DIR_IN, + SHARK_OUT_EP | USB_DIR_OUT, + 0}; + + /* Are the expected endpoints present? */ + if (!usb_check_int_endpoints(intf, ep_addresses)) { + dev_err(&intf->dev, "Invalid radioSHARK2 device\n"); + return -EINVAL; + } shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL); if (!shark) -- cgit v1.2.3 From 39674be56fba1cd3a03bf4617f523a35f85fd2c1 Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Thu, 20 Apr 2023 14:27:58 -0700 Subject: usb: dwc3: gadget: Execute gadget stop after halting the controller Do not call gadget stop until the poll for controller halt is completed. DEVTEN is cleared as part of gadget stop, so the intention to allow ep0 events to continue while waiting for controller halt is not happening. Fixes: c96683798e27 ("usb: dwc3: ep0: Don't prepare beyond Setup stage") Cc: stable@vger.kernel.org Acked-by: Thinh Nguyen Signed-off-by: Wesley Cheng Link: https://lore.kernel.org/r/20230420212759.29429-2-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9f492c8a7d0b..dd6057bad37e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2637,7 +2637,6 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) * bit. */ dwc3_stop_active_transfers(dwc); - __dwc3_gadget_stop(dwc); spin_unlock_irqrestore(&dwc->lock, flags); /* @@ -2674,7 +2673,19 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) * remaining event generated by the controller while polling for * DSTS.DEVCTLHLT. */ - return dwc3_gadget_run_stop(dwc, false); + ret = dwc3_gadget_run_stop(dwc, false); + + /* + * Stop the gadget after controller is halted, so that if needed, the + * events to update EP0 state can still occur while the run/stop + * routine polls for the halted state. DEVTEN is cleared as part of + * gadget stop. + */ + spin_lock_irqsave(&dwc->lock, flags); + __dwc3_gadget_stop(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; } static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) -- cgit v1.2.3 From 8f40fc0808137c157dd408d2632e63bfca2aecdb Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Thu, 20 Apr 2023 14:27:59 -0700 Subject: usb: dwc3: gadget: Refactor EP0 forced stall/restart into a separate API Several sequences utilize the same routine for forcing the control endpoint back into the SETUP phase. This is required, because those operations need to ensure that EP0 is back in the default state. Acked-by: Thinh Nguyen Signed-off-by: Wesley Cheng Link: https://lore.kernel.org/r/20230420212759.29429-3-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 53 +++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index dd6057bad37e..c0ca4d12f95d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -139,6 +139,24 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) return -ETIMEDOUT; } +static void dwc3_ep0_reset_state(struct dwc3 *dwc) +{ + unsigned int dir; + + if (dwc->ep0state != EP0_SETUP_PHASE) { + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + + dwc->eps[0]->trb_enqueue = 0; + dwc->eps[1]->trb_enqueue = 0; + + dwc3_ep0_stall_and_restart(dwc); + } +} + /** * dwc3_ep_inc_trb - increment a trb index. * @index: Pointer to the TRB index to increment. @@ -2652,16 +2670,9 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) ret = wait_for_completion_timeout(&dwc->ep0_in_setup, msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); if (ret == 0) { - unsigned int dir; - dev_warn(dwc->dev, "wait for SETUP phase timed out\n"); spin_lock_irqsave(&dwc->lock, flags); - dir = !!dwc->ep0_expect_in; - if (dwc->ep0state == EP0_DATA_PHASE) - dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); - else - dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); - dwc3_ep0_stall_and_restart(dwc); + dwc3_ep0_reset_state(dwc); spin_unlock_irqrestore(&dwc->lock, flags); } } @@ -3944,16 +3955,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc3_gadget_enable_linksts_evts(dwc, false); usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); - if (dwc->ep0state != EP0_SETUP_PHASE) { - unsigned int dir; - - dir = !!dwc->ep0_expect_in; - if (dwc->ep0state == EP0_DATA_PHASE) - dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); - else - dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); - dwc3_ep0_stall_and_restart(dwc); - } + dwc3_ep0_reset_state(dwc); } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) @@ -4007,20 +4009,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) * phase. So ensure that EP0 is in setup phase by issuing a stall * and restart if EP0 is not in setup phase. */ - if (dwc->ep0state != EP0_SETUP_PHASE) { - unsigned int dir; - - dir = !!dwc->ep0_expect_in; - if (dwc->ep0state == EP0_DATA_PHASE) - dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); - else - dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); - - dwc->eps[0]->trb_enqueue = 0; - dwc->eps[1]->trb_enqueue = 0; - - dwc3_ep0_stall_and_restart(dwc); - } + dwc3_ep0_reset_state(dwc); /* * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a -- cgit v1.2.3