diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index 839054923530..94c98be1329a 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -2704,6 +2704,9 @@ ... 185 = /dev/ttyNX15 Hilscher netX serial port 15 186 = /dev/ttyJ0 JTAG1 DCC protocol based serial port emulation + + If maximum number of uartlite serial ports is more than 4, then the driver + uses dynamic allocation instead of static allocation for major number. 187 = /dev/ttyUL0 Xilinx uartlite - port 0 ... 190 = /dev/ttyUL3 Xilinx uartlite - port 3 diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index fe047ce1a7ec..33ecb6b76ea5 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6937,6 +6937,9 @@ pause after every control message); o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra delay after resetting its port); + p = USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT + (Reduce timeout of the SET_ADDRESS + request from 5000 ms to 500 ms); Example: quirks=0781:5580:bk,0a5c:5834:gij usbhid.mousepoll= diff --git a/Documentation/admin-guide/sysrq.rst b/Documentation/admin-guide/sysrq.rst index 51906e47327b..2f2e5bd440f9 100644 --- a/Documentation/admin-guide/sysrq.rst +++ b/Documentation/admin-guide/sysrq.rst @@ -75,10 +75,19 @@ On other submit a patch to be included in this section. On all - Write a character to /proc/sysrq-trigger. e.g.:: + Write a single character to /proc/sysrq-trigger. + Only the first character is processed, the rest of the string is + ignored. However, it is not recommended to write any extra characters + as the behavior is undefined and might change in the future versions. + E.g.:: echo t > /proc/sysrq-trigger + Alternatively, write multiple characters prepended by underscore. + This way, all characters will be processed. E.g.:: + + echo _reisub > /proc/sysrq-trigger + The :kbd:`` is case sensitive. What are the 'command' keys? diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index 7c8a3e8430d3..fb216ce68bb3 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -66,7 +66,6 @@ properties: Particularly, if use an output GPIO to control a VBUS regulator, should model it as a regulator. See bindings/regulator/fixed-regulator.yaml - # The following are optional properties for "usb-c-connector". power-role: description: Determines the power role that the Type C connector will support. "dual" refers to Dual Role Port (DRP). @@ -119,30 +118,6 @@ properties: # The following are optional properties for "usb-c-connector" with power # delivery support. - source-pdos: - description: An array of u32 with each entry providing supported power - source data object(PDO), the detailed bit definitions of PDO can be found - in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 - Source_Capabilities Message, the order of each entry(PDO) should follow - the PD spec chapter 6.4.1. Required for power source and power dual role. - User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() - defined in dt-bindings/usb/pd.h. - minItems: 1 - maxItems: 7 - $ref: /schemas/types.yaml#/definitions/uint32-array - - sink-pdos: - description: An array of u32 with each entry providing supported power sink - data object(PDO), the detailed bit definitions of PDO can be found in - "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 - Sink Capabilities Message, the order of each entry(PDO) should follow the - PD spec chapter 6.4.1. Required for power sink and power dual role. User - can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined - in dt-bindings/usb/pd.h. - minItems: 1 - maxItems: 7 - $ref: /schemas/types.yaml#/definitions/uint32-array - sink-vdos: description: An array of u32 with each entry, a Vendor Defined Message Object (VDO), providing additional information corresponding to the product, the detailed bit @@ -166,10 +141,43 @@ properties: maxItems: 6 $ref: /schemas/types.yaml#/definitions/uint32-array - op-sink-microwatt: - description: Sink required operating power in microwatt, if source can't - offer the power, Capability Mismatch is set. Required for power sink and - power dual role. + accessory-mode-audio: + type: boolean + description: Whether the device supports Audio Adapter Accessory Mode. This + is only necessary if there are no other means to discover supported + alternative modes (e.g. through the UCSI firmware interface). + + accessory-mode-debug: + type: boolean + description: Whether the device supports Debug Accessory Mode. This + is only necessary if there are no other means to discover supported + alternative modes (e.g. through the UCSI firmware interface). + + altmodes: + type: object + description: List of Alternative Modes supported by the schematics on the + particular device. This is only necessary if there are no other means to + discover supported alternative modes (e.g. through the UCSI firmware + interface). + + additionalProperties: false + + patternProperties: + "^(displayport)$": + type: object + description: + A single USB-C Alternative Mode as supported by the USB-C connector logic. + + additionalProperties: false + + properties: + svid: + $ref: /schemas/types.yaml#/definitions/uint16 + description: Unique value assigned by USB-IF to the Vendor / AltMode. + enum: [ 0xff01 ] + vdo: + $ref: /schemas/types.yaml#/definitions/uint32 + description: VDO returned by Discover Modes USB PD command. port: $ref: /schemas/graph.yaml#/properties/port @@ -231,6 +239,20 @@ properties: SNK_READY for non-pd link. type: boolean + capabilities: + description: A child node to contain all the selectable USB Power Delivery capabilities. + type: object + + patternProperties: + "^caps-[0-9]+$": + description: Child nodes under "capabilities" node. Each node contains a selectable USB + Power Delivery capability. + type: object + $ref: "#/$defs/capabilities" + unevaluatedProperties: false + + additionalProperties: false + dependencies: sink-vdos-v1: [ sink-vdos ] sink-vdos: [ sink-vdos-v1 ] @@ -238,7 +260,42 @@ dependencies: required: - compatible +$defs: + capabilities: + type: object + + properties: + source-pdos: + description: An array of u32 with each entry providing supported power + source data object(PDO), the detailed bit definitions of PDO can be found + in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 + Source_Capabilities Message, the order of each entry(PDO) should follow + the PD spec chapter 6.4.1. Required for power source and power dual role. + User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() + defined in dt-bindings/usb/pd.h. + minItems: 1 + maxItems: 7 + $ref: /schemas/types.yaml#/definitions/uint32-array + + sink-pdos: + description: An array of u32 with each entry providing supported power sink + data object(PDO), the detailed bit definitions of PDO can be found in + "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 + Sink Capabilities Message, the order of each entry(PDO) should follow the + PD spec chapter 6.4.1. Required for power sink and power dual role. User + can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined + in dt-bindings/usb/pd.h. + minItems: 1 + maxItems: 7 + $ref: /schemas/types.yaml#/definitions/uint32-array + + op-sink-microwatt: + description: Sink required operating power in microwatt, if source can't + offer the power, Capability Mismatch is set. Required for power sink and + power dual role. + allOf: + - $ref: "#/$defs/capabilities" - if: properties: compatible: @@ -267,7 +324,7 @@ anyOf: - typec-power-opmode - new-source-frs-typec-current -additionalProperties: false +unevaluatedProperties: false examples: # Micro-USB connector with HS lines routed via controller (MUIC). @@ -289,6 +346,13 @@ examples: compatible = "usb-c-connector"; label = "USB-C"; + altmodes { + displayport { + svid = /bits/ 16 <0xff01>; + vdo = <0x00001c46>; + }; + }; + ports { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/serial/arm,dcc.yaml b/Documentation/devicetree/bindings/serial/arm,dcc.yaml new file mode 100644 index 000000000000..fd0589356617 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/arm,dcc.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/arm,dcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM DCC (Data communication channel) serial emulation + +maintainers: + - Michal Simek + +description: | + ARM DCC (Data communication channel) serial emulation interface available + via JTAG can be also used as one of serial line tightly coupled with every + ARM CPU available in the system. + +properties: + compatible: + const: arm,dcc + +required: + - compatible + +additionalProperties: false + +examples: + - | + serial { + compatible = "arm,dcc"; + }; diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml index 920539926d7e..7a105551fa6a 100644 --- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml @@ -13,7 +13,7 @@ description: | https://www.nxp.com/webapp/Download?colCode=S32V234RM. maintainers: - - Chester Lin + - Chester Lin allOf: - $ref: serial.yaml# diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml index 83035553044a..9c6dc16f88a6 100644 --- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml @@ -9,10 +9,6 @@ title: Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART) maintainers: - Fabio Estevam -allOf: - - $ref: serial.yaml# - - $ref: rs485.yaml# - properties: compatible: oneOf: @@ -68,7 +64,11 @@ properties: - const: tx interrupts: - maxItems: 1 + items: + - description: UART RX Interrupt + - description: UART TX Interrupt + - description: UART RTS Interrupt + minItems: 1 wakeup-source: true @@ -110,6 +110,25 @@ required: - clock-names - interrupts +allOf: + - $ref: serial.yaml# + - $ref: rs485.yaml# + + - if: + properties: + compatible: + contains: + const: fsl,imx1-uart + then: + properties: + interrupts: + minItems: 3 + maxItems: 3 + else: + properties: + interrupts: + maxItems: 1 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml index ee52bf8e8917..e0fa363ad7e2 100644 --- a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml +++ b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml @@ -48,9 +48,17 @@ properties: - const: tx - const: rx + interconnects: + maxItems: 1 + interrupts: maxItems: 1 + operating-points-v2: true + + power-domains: + maxItems: 1 + qcom,rx-crci: $ref: /schemas/types.yaml#/definitions/uint32 description: @@ -99,7 +107,9 @@ unevaluatedProperties: false examples: - | + #include #include + #include serial@f991e000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; @@ -109,4 +119,7 @@ examples: clock-names = "core", "iface"; dmas = <&dma0 0>, <&dma0 1>; dma-names = "tx", "rx"; + power-domains = <&rpmpd MSM8996_VDDCX>; + operating-points-v2 = <&uart_opp_table>; + interconnects = <&pnoc MASTER_BLSP_1 &bimc SLAVE_EBI_CH0>; }; diff --git a/Documentation/devicetree/bindings/serial/renesas,sci.yaml b/Documentation/devicetree/bindings/serial/renesas,sci.yaml index 9f7305200c47..64d3db6e54e5 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,sci.yaml @@ -17,7 +17,7 @@ properties: oneOf: - items: - enum: - - renesas,r9a07g043-sci # RZ/G2UL + - renesas,r9a07g043-sci # RZ/G2UL and RZ/Five - renesas,r9a07g044-sci # RZ/G2{L,LC} - renesas,r9a07g054-sci # RZ/V2L - const: renesas,sci # generic SCI compatible UART diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 17c553123f96..1001d2a6ace8 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: serial.yaml# + - $ref: rs485.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.yaml b/Documentation/devicetree/bindings/serial/sprd-uart.yaml index 28ff77aa86c8..f4dbb6dc2b6e 100644 --- a/Documentation/devicetree/bindings/serial/sprd-uart.yaml +++ b/Documentation/devicetree/bindings/serial/sprd-uart.yaml @@ -20,6 +20,7 @@ properties: - sprd,sc9860-uart - sprd,sc9863a-uart - sprd,ums512-uart + - sprd,ums9620-uart - const: sprd,sc9836-uart - const: sprd,sc9836-uart diff --git a/Documentation/devicetree/bindings/usb/generic-xhci.yaml b/Documentation/devicetree/bindings/usb/generic-xhci.yaml index 594ebb3ee432..6ceafa4af292 100644 --- a/Documentation/devicetree/bindings/usb/generic-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-xhci.yaml @@ -9,9 +9,6 @@ title: USB xHCI Controller maintainers: - Mathias Nyman -allOf: - - $ref: usb-xhci.yaml# - properties: compatible: oneOf: @@ -25,6 +22,11 @@ properties: - marvell,armada-380-xhci - marvell,armada-8k-xhci - const: generic-xhci + - description: Broadcom SoCs with power domains + items: + - enum: + - brcm,bcm2711-xhci + - const: brcm,xhci-brcm-v2 - description: Broadcom STB SoCs with xHCI enum: - brcm,xhci-brcm-v2 @@ -49,6 +51,9 @@ properties: - const: core - const: reg + power-domains: + maxItems: 1 + unevaluatedProperties: false required: @@ -56,6 +61,20 @@ required: - reg - interrupts +allOf: + - $ref: usb-xhci.yaml# + - if: + properties: + compatible: + contains: + const: brcm,bcm2711-xhci + then: + required: + - power-domains + else: + properties: + power-domains: false + examples: - | usb@f0931000 { diff --git a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml index ee08b9c3721f..37cf5249e526 100644 --- a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml +++ b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml @@ -29,6 +29,11 @@ properties: description: the regulator that provides 3.3V core power to the hub. + peer-hub: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the peer hub on the controller. + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index e9644e333d78..924fd3d748a8 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -124,6 +124,17 @@ properties: defined in the xHCI spec on MTK's controller. default: 5000 + rx-fifo-depth: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + It is a quirk used to work around Gen1 isoc-in endpoint transfer issue + that still send out unexpected ACK after device finishes the burst + transfer with a short packet and cause an exception, specially on a 4K + camera device, it happens on controller before about IPM v1.6.0; + the side-effect is that it may cause performance drop about 10%, + including bulk transfer, prefer to use 3k here. The size is in bytes. + enum: [1024, 2048, 3072, 4096] + # the following properties are only used for case 1 wakeup-source: description: enable USB remote wakeup, see power/wakeup-source.txt diff --git a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml index 28eb25ecba74..eaedb4cc6b6c 100644 --- a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml +++ b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/usb/nxp,ptn5110.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: NXP PTN5110 Typec Port Cotroller +title: NXP PTN5110 Type-C Port Controller maintainers: - Li Jun diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 915c8205623b..63d150b216c5 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -46,6 +46,8 @@ properties: - qcom,sm8350-dwc3 - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 + - qcom,x1e80100-dwc3 - const: qcom,dwc3 reg: @@ -97,12 +99,29 @@ properties: - const: apps-usb interrupts: - minItems: 1 - maxItems: 4 + description: | + Different types of interrupts are used based on HS PHY used on target: + - pwr_event: Used for wakeup based on other power events. + - hs_phY_irq: Apart from DP/DM/QUSB2 PHY interrupts, there is + hs_phy_irq which is not triggered by default and its + functionality is mutually exclusive to that of + {dp/dm}_hs_phy_irq and qusb2_phy_irq. + - qusb2_phy: SoCs with QUSB2 PHY do not have separate DP/DM IRQs and + expose only a single IRQ whose behavior can be modified + by the QUSB2PHY_INTR_CTRL register. The required DPSE/ + DMSE configuration is done in QUSB2PHY_INTR_CTRL register + of PHY address space. + - {dp/dm}_hs_phy_irq: These IRQ's directly reflect changes on the DP/ + DM pads of the SoC. These are used for wakeup + only on SoCs with non-QUSB2 targets with + exception of SDM670/SDM845/SM6350. + - ss_phy_irq: Used for remote wakeup in Super Speed mode of operation. + minItems: 2 + maxItems: 5 interrupt-names: - minItems: 1 - maxItems: 4 + minItems: 2 + maxItems: 5 qcom,select-utmi-as-pipe-clk: description: @@ -263,6 +282,7 @@ allOf: contains: enum: - qcom,sc8280xp-dwc3 + - qcom,x1e80100-dwc3 then: properties: clocks: @@ -288,8 +308,8 @@ allOf: then: properties: clocks: - minItems: 5 - maxItems: 6 + minItems: 4 + maxItems: 5 clock-names: oneOf: - items: @@ -298,13 +318,11 @@ allOf: - const: iface - const: sleep - const: mock_utmi - - const: bus - items: - const: cfg_noc - const: core - const: sleep - const: mock_utmi - - const: bus - if: properties: @@ -318,6 +336,7 @@ allOf: - qcom,sm8250-dwc3 - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 then: properties: clocks: @@ -357,131 +376,96 @@ allOf: compatible: contains: enum: - - qcom,ipq4019-dwc3 + - qcom,ipq5018-dwc3 - qcom,ipq6018-dwc3 - - qcom,ipq8064-dwc3 - qcom,ipq8074-dwc3 - - qcom,msm8994-dwc3 + - qcom,msm8953-dwc3 + - qcom,msm8998-dwc3 + then: + properties: + interrupts: + minItems: 2 + maxItems: 3 + interrupt-names: + items: + - const: pwr_event + - const: qusb2_phy + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-dwc3 - qcom,qcs404-dwc3 + - qcom,sdm660-dwc3 + - qcom,sm6115-dwc3 + - qcom,sm6125-dwc3 + then: + properties: + interrupts: + minItems: 3 + maxItems: 4 + interrupt-names: + items: + - const: pwr_event + - const: qusb2_phy + - const: hs_phy_irq + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq5332-dwc3 + - qcom,x1e80100-dwc3 + then: + properties: + interrupts: + maxItems: 4 + interrupt-names: + items: + - const: pwr_event + - const: dp_hs_phy_irq + - const: dm_hs_phy_irq + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq4019-dwc3 + - qcom,ipq8064-dwc3 + - qcom,msm8994-dwc3 + - qcom,sa8775p-dwc3 - qcom,sc7180-dwc3 + - qcom,sc7280-dwc3 + - qcom,sc8280xp-dwc3 - qcom,sdm670-dwc3 - qcom,sdm845-dwc3 - qcom,sdx55-dwc3 - qcom,sdx65-dwc3 - qcom,sdx75-dwc3 - qcom,sm4250-dwc3 - - qcom,sm6125-dwc3 - qcom,sm6350-dwc3 - qcom,sm8150-dwc3 - qcom,sm8250-dwc3 - qcom,sm8350-dwc3 - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 then: properties: interrupts: - items: - - description: The interrupt that is asserted - when a wakeup event is received on USB2 bus. - - description: The interrupt that is asserted - when a wakeup event is received on USB3 bus. - - description: Wakeup event on DM line. - - description: Wakeup event on DP line. - interrupt-names: - items: - - const: hs_phy_irq - - const: ss_phy_irq - - const: dm_hs_phy_irq - - const: dp_hs_phy_irq - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8953-dwc3 - - qcom,msm8996-dwc3 - - qcom,msm8998-dwc3 - - qcom,sm6115-dwc3 - then: - properties: - interrupts: - maxItems: 2 - interrupt-names: - items: - - const: hs_phy_irq - - const: ss_phy_irq - - - if: - properties: - compatible: - contains: - enum: - - qcom,ipq5018-dwc3 - - qcom,ipq5332-dwc3 - - qcom,sdm660-dwc3 - then: - properties: - interrupts: - minItems: 1 - maxItems: 2 - interrupt-names: - minItems: 1 - items: - - const: hs_phy_irq - - const: ss_phy_irq - - - if: - properties: - compatible: - contains: - enum: - - qcom,sc7280-dwc3 - then: - properties: - interrupts: - minItems: 3 - maxItems: 4 - interrupt-names: - minItems: 3 - items: - - const: hs_phy_irq - - const: dp_hs_phy_irq - - const: dm_hs_phy_irq - - const: ss_phy_irq - - - if: - properties: - compatible: - contains: - enum: - - qcom,sc8280xp-dwc3 - then: - properties: - interrupts: - maxItems: 4 + minItems: 4 + maxItems: 5 interrupt-names: items: - const: pwr_event - - const: dp_hs_phy_irq - - const: dm_hs_phy_irq - - const: ss_phy_irq - - - if: - properties: - compatible: - contains: - enum: - - qcom,sa8775p-dwc3 - then: - properties: - interrupts: - minItems: 3 - maxItems: 4 - interrupt-names: - minItems: 3 - items: - - const: pwr_event + - const: hs_phy_irq - const: dp_hs_phy_irq - const: dm_hs_phy_irq - const: ss_phy_irq @@ -519,12 +503,13 @@ examples: <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <150000000>; - interrupts = , - , + interrupts = , + , + , , - ; - interrupt-names = "hs_phy_irq", "ss_phy_irq", - "dm_hs_phy_irq", "dp_hs_phy_irq"; + ; + interrupt-names = "pwr_event", "hs_phy_irq", + "dp_hs_phy_irq", "dm_hs_phy_irq", "ss_phy_irq"; power-domains = <&gcc USB30_PRIM_GDSC>; diff --git a/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml b/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml new file mode 100644 index 000000000000..7ddfd3313a18 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/qcom,wcd939x-usbss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WCD9380/WCD9385 USB SubSystem Altmode/Analog Audio Switch + +maintainers: + - Neil Armstrong + +description: + Qualcomm WCD9390/WCD9395 is a standalone Hi-Fi audio codec IC with a + functionally separate USB SubSystem for Altmode/Analog Audio Switch + accessible over an I2C interface. + The Audio Headphone and Microphone data path between the Codec and the + USB-C Mux subsystems are external to the IC, thus requiring DT port-endpoint + graph description to handle USB-C altmode & orientation switching for Audio + Accessory Mode. + +properties: + compatible: + oneOf: + - const: qcom,wcd9390-usbss + - items: + - const: qcom,wcd9395-usbss + - const: qcom,wcd9390-usbss + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + vdd-supply: + description: USBSS VDD power supply + + mode-switch: + description: Flag the port as possible handle of altmode switching + type: boolean + + orientation-switch: + description: Flag the port as possible handler of orientation switching + type: boolean + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + A port node to link the WCD939x USB SubSystem to a TypeC controller for the + purpose of handling altmode muxing and orientation switching. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + A port node to link the WCD939x USB SubSystem to the Codec SubSystem for the + purpose of handling USB-C Audio Accessory Mode muxing and orientation switching. + +required: + - compatible + - reg + - ports + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + typec-mux@42 { + compatible = "qcom,wcd9390-usbss"; + reg = <0x42>; + + vdd-supply = <&vreg_bob>; + + mode-switch; + orientation-switch; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + wcd9390_usbss_sbu: endpoint { + remote-endpoint = <&typec_sbu>; + }; + }; + port@1 { + reg = <1>; + wcd9390_usbss_codec: endpoint { + remote-endpoint = <&wcd9390_codec_usbss>; + }; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml index bad55dfb2fa0..40ada78f2328 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml @@ -19,7 +19,7 @@ properties: - items: - enum: - renesas,usbhs-r7s9210 # RZ/A2 - - renesas,usbhs-r9a07g043 # RZ/G2UL + - renesas,usbhs-r9a07g043 # RZ/G2UL and RZ/Five - renesas,usbhs-r9a07g044 # RZ/G2{L,LC} - renesas,usbhs-r9a07g054 # RZ/V2L - const: renesas,rza2-usbhs diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index ee5af4b381b1..203a1eb66691 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -432,6 +432,10 @@ properties: items: enum: [1, 4, 8, 16, 32, 64, 128, 256] + num-hc-interrupters: + maximum: 8 + default: 1 + port: $ref: /schemas/graph.yaml#/properties/port description: diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml index 323d664ae06a..1745e28b3110 100644 --- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml +++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml @@ -38,6 +38,10 @@ properties: - const: main - const: patch-address + reset-gpios: + description: GPIO used for the HRESET pin. + maxItems: 1 + wakeup-source: true interrupts: @@ -90,6 +94,7 @@ additionalProperties: false examples: - | + #include #include i2c { #address-cells = <1>; @@ -106,6 +111,7 @@ examples: pinctrl-names = "default"; pinctrl-0 = <&typec_pins>; + reset-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; typec_con: connector { compatible = "usb-c-connector"; diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.yaml b/Documentation/devicetree/bindings/usb/usb-xhci.yaml index 180a261c3e8f..4238ae896ef6 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/usb-xhci.yaml @@ -29,6 +29,12 @@ properties: description: Interrupt moderation interval default: 5000 + num-hc-interrupters: + description: Maximum number of interrupters to allocate + $ref: /schemas/types.yaml#/definitions/uint16 + minimum: 1 + maximum: 1024 + additionalProperties: true examples: diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index 29072c166d23..8cd62c466d20 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -448,15 +448,17 @@ Function-specific configfs interface The function name to use when creating the function directory is "ncm". The NCM function provides these attributes in its function directory: - =============== ================================================== - ifname network device interface name associated with this - function instance - qmult queue length multiplier for high and super speed - host_addr MAC address of host's end of this - Ethernet over USB link - dev_addr MAC address of device's end of this - Ethernet over USB link - =============== ================================================== + =============== ================================================== + ifname network device interface name associated with this + function instance + qmult queue length multiplier for high and super speed + host_addr MAC address of host's end of this + Ethernet over USB link + dev_addr MAC address of device's end of this + Ethernet over USB link + max_segment_size Segment size required for P2P connections. This + will set MTU to (max_segment_size - 14 bytes) + =============== ================================================== and after creating the functions/ncm. they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst index 818a1648b387..59b2132b584d 100644 --- a/Documentation/usb/raw-gadget.rst +++ b/Documentation/usb/raw-gadget.rst @@ -81,9 +81,6 @@ feature must be kept in the implementation. Potential future improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Report more events (suspend, resume, etc.) through - ``USB_RAW_IOCTL_EVENT_FETCH``. - - Support ``O_NONBLOCK`` I/O. This would be another mode of operation, where Raw Gadget would not wait until the completion of each USB request. diff --git a/MAINTAINERS b/MAINTAINERS index a97c50e1096e..c8b6db2eca83 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23192,7 +23192,6 @@ M: Amit Shah L: virtualization@lists.linux.dev S: Maintained F: drivers/char/virtio_console.c -F: include/linux/virtio_console.h F: include/uapi/linux/virtio_console.h VIRTIO CORE AND NET DRIVERS diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index d6139dbae4ac..feaf89f6936b 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -53,7 +53,7 @@ srmcons_do_receive_chars(struct tty_port *port) do { result.as_long = callback_getc(0); if (result.bits.status < 2) { - tty_insert_flip_char(port, (char)result.bits.c, 0); + tty_insert_flip_char(port, (u8)result.bits.c, 0); count++; } } while((result.bits.status & 1) && (++loops < 10)); @@ -88,30 +88,27 @@ srmcons_receive_chars(struct timer_list *t) } /* called with callback_lock held */ -static int -srmcons_do_write(struct tty_port *port, const char *buf, int count) +static void +srmcons_do_write(struct tty_port *port, const u8 *buf, size_t count) { - static char str_cr[1] = "\r"; - long c, remaining = count; + size_t c; srmcons_result result; - char *cur; - int need_cr; - for (cur = (char *)buf; remaining > 0; ) { - need_cr = 0; + while (count > 0) { + bool need_cr = false; /* * Break it up into reasonable size chunks to allow a chance * for input to get in */ - for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++) - if (cur[c] == '\n') - need_cr = 1; + for (c = 0; c < min_t(size_t, 128U, count) && !need_cr; c++) + if (buf[c] == '\n') + need_cr = true; while (c > 0) { - result.as_long = callback_puts(0, cur, c); + result.as_long = callback_puts(0, buf, c); c -= result.bits.c; - remaining -= result.bits.c; - cur += result.bits.c; + count -= result.bits.c; + buf += result.bits.c; /* * Check for pending input iff a tty port was provided @@ -121,12 +118,11 @@ srmcons_do_write(struct tty_port *port, const char *buf, int count) } while (need_cr) { - result.as_long = callback_puts(0, str_cr, 1); + result.as_long = callback_puts(0, "\r", 1); if (result.bits.c > 0) - need_cr = 0; + need_cr = false; } } - return count; } static ssize_t @@ -135,7 +131,7 @@ srmcons_write(struct tty_struct *tty, const u8 *buf, size_t count) unsigned long flags; spin_lock_irqsave(&srmcons_callback_lock, flags); - srmcons_do_write(tty->port, (const char *) buf, count); + srmcons_do_write(tty->port, buf, count); spin_unlock_irqrestore(&srmcons_callback_lock, flags); return count; diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi index 98817a6675b9..d233a191c139 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "bcm2835-rpi.dtsi" +#include #include / { @@ -76,3 +77,7 @@ &vchiq { interrupts = ; }; + +&xhci { + power-domains = <&power RPI_POWER_DOMAIN_USB>; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi b/arch/arm/boot/dts/broadcom/bcm2711.dtsi index 4a379a14966d..22c7f1561344 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi @@ -604,6 +604,20 @@ }; }; + xhci: usb@7e9c0000 { + compatible = "brcm,bcm2711-xhci", "brcm,xhci-brcm-v2"; + reg = <0x0 0x7e9c0000 0x100000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + /* DWC2 and this IP block share the same USB PHY, + * enabling both at the same time results in lockups. + * So keep this node disabled and let the bootloader + * decide which interface should be enabled. + */ + status = "disabled"; + }; + v3d: gpu@7ec00000 { compatible = "brcm,2711-v3d"; reg = <0x0 0x7ec00000 0x4000>, diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi index bbdcd441c049..3c6079edda19 100644 --- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi @@ -1294,6 +1294,7 @@ &xhci0 { status = "okay"; + rx-fifo-depth = <3072>; vusb33-supply = <&mt6359_vusb_ldo_reg>; vbus-supply = <&usb_vbus>; }; @@ -1301,6 +1302,7 @@ &xhci1 { status = "okay"; + rx-fifo-depth = <3072>; vusb33-supply = <&mt6359_vusb_ldo_reg>; vbus-supply = <&usb_vbus>; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 7f8327b0dbdb..e423c57ddd41 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -540,9 +540,6 @@ compatible = "qcom,msm8916-bimc"; reg = <0x00400000 0x62000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; tsens: thermal-sensor@4a9000 { @@ -575,18 +572,12 @@ compatible = "qcom,msm8916-pcnoc"; reg = <0x00500000 0x11000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, - <&rpmcc RPM_SMD_PCNOC_A_CLK>; }; snoc: interconnect@580000 { compatible = "qcom,msm8916-snoc"; reg = <0x00580000 0x14000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; stm: stm@802000 { diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi index 29f6bd9df2eb..82d85ff61045 100644 --- a/arch/arm64/boot/dts/qcom/msm8939.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi @@ -602,9 +602,6 @@ bimc: interconnect@400000 { compatible = "qcom,msm8939-bimc"; reg = <0x00400000 0x62000>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; #interconnect-cells = <1>; }; @@ -648,25 +645,16 @@ pcnoc: interconnect@500000 { compatible = "qcom,msm8939-pcnoc"; reg = <0x00500000 0x11000>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, - <&rpmcc RPM_SMD_PCNOC_A_CLK>; #interconnect-cells = <1>; }; snoc: interconnect@580000 { compatible = "qcom,msm8939-snoc"; reg = <0x00580000 0x14080>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; #interconnect-cells = <1>; snoc_mm: interconnect-snoc { compatible = "qcom,msm8939-snoc-mm"; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SYSMMNOC_CLK>, - <&rpmcc RPM_SMD_SYSMMNOC_A_CLK>; #interconnect-cells = <1>; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 8c6a7efa90c4..8d41ed261adf 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -838,9 +838,6 @@ compatible = "qcom,msm8996-bimc"; reg = <0x00408000 0x5a000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; tsens0: thermal-sensor@4a9000 { @@ -891,18 +888,12 @@ compatible = "qcom,msm8996-cnoc"; reg = <0x00500000 0x1000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_CNOC_CLK>, - <&rpmcc RPM_SMD_CNOC_A_CLK>; }; snoc: interconnect@524000 { compatible = "qcom,msm8996-snoc"; reg = <0x00524000 0x1c000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; a0noc: interconnect@543000 { @@ -922,19 +913,14 @@ compatible = "qcom,msm8996-a1noc"; reg = <0x00562000 0x5000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>, - <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>; }; a2noc: interconnect@583000 { compatible = "qcom,msm8996-a2noc"; reg = <0x00583000 0x7000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a", "aggre2_ufs_axi", "ufs_axi"; - clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>, - <&gcc GCC_AGGRE2_UFS_AXI_CLK>, + clock-names = "aggre2_ufs_axi", "ufs_axi"; + clocks = <&gcc GCC_AGGRE2_UFS_AXI_CLK>, <&gcc GCC_UFS_AXI_CLK>; }; @@ -942,19 +928,14 @@ compatible = "qcom,msm8996-mnoc"; reg = <0x005a4000 0x1c000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a", "iface"; - clocks = <&rpmcc RPM_SMD_MMAXI_CLK>, - <&rpmcc RPM_SMD_MMAXI_A_CLK>, - <&mmcc AHB_CLK_SRC>; + clock-names = "iface"; + clocks = <&mmcc AHB_CLK_SRC>; }; pnoc: interconnect@5c0000 { compatible = "qcom,msm8996-pnoc"; reg = <0x005c0000 0x3000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, - <&rpmcc RPM_SMD_PCNOC_A_CLK>; }; tcsr_mutex: hwlock@740000 { @@ -2486,9 +2467,8 @@ "handover", "stop-ack"; - clocks = <&xo_board>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - clock-names = "xo", "aggre2"; + clocks = <&xo_board>; + clock-names = "xo"; memory-region = <&slpi_mem>; @@ -2533,10 +2513,15 @@ <&gcc GCC_MSS_GPLL0_DIV_CLK>, <&gcc GCC_MSS_SNOC_AXI_CLK>, <&gcc GCC_MSS_MNOC_BIMC_AXI_CLK>, - <&rpmcc RPM_SMD_PCNOC_CLK>, <&rpmcc RPM_SMD_QDSS_CLK>; - clock-names = "iface", "bus", "mem", "xo", "gpll0_mss", - "snoc_axi", "mnoc_axi", "pnoc", "qdss"; + clock-names = "iface", + "bus", + "mem", + "xo", + "gpll0_mss", + "snoc_axi", + "mnoc_axi", + "qdss"; resets = <&gcc GCC_MSS_RESTART>; reset-names = "mss_restart"; diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index bb591c6bf573..2793cc22d381 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -1605,9 +1605,8 @@ px-supply = <&vreg_lvs2a_1p8>; - clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - clock-names = "xo", "aggre2"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "xo"; memory-region = <&slpi_mem>; diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi index 6ac64ce9bb68..2f2eeaf2e945 100644 --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi @@ -558,9 +558,6 @@ reg = <0x00400000 0x80000>; compatible = "qcom,qcs404-bimc"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; tsens: thermal-sensor@4a9000 { @@ -601,18 +598,12 @@ reg = <0x00500000 0x15080>; compatible = "qcom,qcs404-pcnoc"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PNOC_CLK>, - <&rpmcc RPM_SMD_PNOC_A_CLK>; }; snoc: interconnect@580000 { reg = <0x00580000 0x23080>; compatible = "qcom,qcs404-snoc"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; remoteproc_cdsp: remoteproc@b00000 { diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index 043184557873..cd0db4f31d4a 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -1454,7 +1454,7 @@ altmodes { displayport { - svid = <0xff01>; + svid = /bits/ 16 <0xff01>; vdo = <0x00001c46>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index 775700f78e0f..513fe5e76b68 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -606,9 +606,6 @@ compatible = "qcom,sdm660-bimc"; reg = <0x01008000 0x78000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; restart@10ac000 { @@ -620,28 +617,17 @@ compatible = "qcom,sdm660-cnoc"; reg = <0x01500000 0x10000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_CNOC_CLK>, - <&rpmcc RPM_SMD_CNOC_A_CLK>; }; snoc: interconnect@1626000 { compatible = "qcom,sdm660-snoc"; reg = <0x01626000 0x7090>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; anoc2_smmu: iommu@16c0000 { compatible = "qcom,sdm630-smmu-v2", "qcom,smmu-v2"; reg = <0x016c0000 0x40000>; - - assigned-clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - assigned-clock-rates = <1000>; - clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - clock-names = "bus"; #global-interrupts = <2>; #iommu-cells = <1>; @@ -686,16 +672,12 @@ compatible = "qcom,sdm660-a2noc"; reg = <0x01704000 0xc100>; #interconnect-cells = <1>; - clock-names = "bus", - "bus_a", - "ipa", + clock-names = "ipa", "ufs_axi", "aggre2_ufs_axi", "aggre2_usb3_axi", "cfg_noc_usb2_axi"; - clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>, - <&rpmcc RPM_SMD_IPA_CLK>, + clocks = <&rpmcc RPM_SMD_IPA_CLK>, <&gcc GCC_UFS_AXI_CLK>, <&gcc GCC_AGGRE2_UFS_AXI_CLK>, <&gcc GCC_AGGRE2_USB3_AXI_CLK>, @@ -706,10 +688,8 @@ compatible = "qcom,sdm660-mnoc"; reg = <0x01745000 0xa010>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a", "iface"; - clocks = <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, - <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK_A>, - <&mmcc AHB_CLK_SRC>; + clock-names = "iface"; + clocks = <&mmcc AHB_CLK_SRC>; }; tsens: thermal-sensor@10ae000 { @@ -1186,7 +1166,9 @@ clocks = <&gcc GCC_GPU_CFG_AHB_CLK>, <&gcc GCC_BIMC_GFX_CLK>, <&gcc GCC_GPU_BIMC_GFX_CLK>; - clock-names = "iface", "mem", "mem_iface"; + clock-names = "iface", + "mem", + "mem_iface"; #global-interrupts = <2>; #iommu-cells = <1>; @@ -1288,20 +1270,16 @@ <&gcc GCC_USB30_MASTER_CLK>, <&gcc GCC_AGGRE2_USB3_AXI_CLK>, <&gcc GCC_USB30_SLEEP_CLK>, - <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; + <&gcc GCC_USB30_MOCK_UTMI_CLK>; clock-names = "cfg_noc", "core", "iface", "sleep", - "mock_utmi", - "bus"; + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_MASTER_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - assigned-clock-rates = <19200000>, <120000000>, - <19200000>; + <&gcc GCC_USB30_MASTER_CLK>; + assigned-clock-rates = <19200000>, <120000000>; interrupts = , ; @@ -2204,10 +2182,9 @@ clocks = <&mmcc MNOC_AHB_CLK>, <&mmcc BIMC_SMMU_AHB_CLK>, - <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, <&mmcc BIMC_SMMU_AXI_CLK>; clock-names = "iface-mm", "iface-smmu", - "bus-mm", "bus-smmu"; + "bus-smmu"; #global-interrupts = <2>; #iommu-cells = <1>; @@ -2324,12 +2301,6 @@ compatible = "qcom,sdm660-gnoc"; reg = <0x17900000 0xe000>; #interconnect-cells = <1>; - /* - * This one apparently features no clocks, - * so let's not mess with the driver needlessly - */ - clock-names = "bus", "bus_a"; - clocks = <&xo_board>, <&xo_board>; }; apcs_glb: mailbox@17911000 { diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c index 3a74d493eb3e..17b2987c2bf5 100644 --- a/arch/m68k/emu/nfcon.c +++ b/arch/m68k/emu/nfcon.c @@ -23,9 +23,9 @@ static int stderr_id; static struct tty_port nfcon_tty_port; static struct tty_driver *nfcon_tty_driver; -static void nfputs(const char *str, unsigned int count) +static void nfputs(const u8 *str, size_t count) { - char buf[68]; + u8 buf[68]; unsigned long phys = virt_to_phys(buf); buf[64] = 0; diff --git a/arch/powerpc/include/asm/hvconsole.h b/arch/powerpc/include/asm/hvconsole.h index ccb2034506f0..d841a97010a0 100644 --- a/arch/powerpc/include/asm/hvconsole.h +++ b/arch/powerpc/include/asm/hvconsole.h @@ -21,8 +21,8 @@ * Vio firmware always attempts to fetch MAX_VIO_GET_CHARS chars. The 'count' * parm is included to conform to put_chars() function pointer template */ -extern int hvc_get_chars(uint32_t vtermno, char *buf, int count); -extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count); +extern ssize_t hvc_get_chars(uint32_t vtermno, u8 *buf, size_t count); +extern ssize_t hvc_put_chars(uint32_t vtermno, const u8 *buf, size_t count); /* Provided by HVC VIO */ void hvc_vio_init_early(void); diff --git a/arch/powerpc/include/asm/hvsi.h b/arch/powerpc/include/asm/hvsi.h index 464a7519ed64..9058edcb632b 100644 --- a/arch/powerpc/include/asm/hvsi.h +++ b/arch/powerpc/include/asm/hvsi.h @@ -64,7 +64,7 @@ struct hvsi_priv { unsigned int inbuf_len; /* data in input buffer */ unsigned char inbuf[HVSI_INBUF_SIZE]; unsigned int inbuf_cur; /* Cursor in input buffer */ - unsigned int inbuf_pktlen; /* packet length from cursor */ + size_t inbuf_pktlen; /* packet length from cursor */ atomic_t seqno; /* packet sequence number */ unsigned int opened:1; /* driver opened */ unsigned int established:1; /* protocol established */ @@ -72,24 +72,26 @@ struct hvsi_priv { unsigned int mctrl_update:1; /* modem control updated */ unsigned short mctrl; /* modem control */ struct tty_struct *tty; /* tty structure */ - int (*get_chars)(uint32_t termno, char *buf, int count); - int (*put_chars)(uint32_t termno, const char *buf, int count); + ssize_t (*get_chars)(uint32_t termno, u8 *buf, size_t count); + ssize_t (*put_chars)(uint32_t termno, const u8 *buf, size_t count); uint32_t termno; }; /* hvsi lib functions */ struct hvc_struct; extern void hvsilib_init(struct hvsi_priv *pv, - int (*get_chars)(uint32_t termno, char *buf, int count), - int (*put_chars)(uint32_t termno, const char *buf, - int count), + ssize_t (*get_chars)(uint32_t termno, u8 *buf, + size_t count), + ssize_t (*put_chars)(uint32_t termno, const u8 *buf, + size_t count), int termno, int is_console); extern int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp); extern void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp); extern int hvsilib_read_mctrl(struct hvsi_priv *pv); extern int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr); extern void hvsilib_establish(struct hvsi_priv *pv); -extern int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count); -extern int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count); +extern ssize_t hvsilib_get_chars(struct hvsi_priv *pv, u8 *buf, size_t count); +extern ssize_t hvsilib_put_chars(struct hvsi_priv *pv, const u8 *buf, + size_t count); #endif /* _HVSI_H */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index b66b0c615f4f..af304e6cb486 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -313,9 +313,11 @@ extern int early_init_dt_scan_recoverable_ranges(unsigned long node, const char *uname, int depth, void *data); void __init opal_configure_cores(void); -extern int opal_get_chars(uint32_t vtermno, char *buf, int count); -extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); -extern int opal_put_chars_atomic(uint32_t vtermno, const char *buf, int total_len); +extern ssize_t opal_get_chars(uint32_t vtermno, u8 *buf, size_t count); +extern ssize_t opal_put_chars(uint32_t vtermno, const u8 *buf, + size_t total_len); +extern ssize_t opal_put_chars_atomic(uint32_t vtermno, const u8 *buf, + size_t total_len); extern int opal_flush_chars(uint32_t vtermno, bool wait); extern int opal_flush_console(uint32_t vtermno); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index cdf3838f08d3..45dd77e3ccf6 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -424,7 +424,7 @@ static int __init opal_message_init(struct device_node *opal_node) return 0; } -int opal_get_chars(uint32_t vtermno, char *buf, int count) +ssize_t opal_get_chars(uint32_t vtermno, u8 *buf, size_t count) { s64 rc; __be64 evt, len; @@ -441,10 +441,11 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) return 0; } -static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, bool atomic) +static ssize_t __opal_put_chars(uint32_t vtermno, const u8 *data, + size_t total_len, bool atomic) { unsigned long flags = 0 /* shut up gcc */; - int written; + ssize_t written; __be64 olen; s64 rc; @@ -484,7 +485,7 @@ static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, b if (atomic) { /* Should not happen */ pr_warn("atomic console write returned partial " - "len=%d written=%d\n", total_len, written); + "len=%zu written=%zd\n", total_len, written); } if (!written) written = -EAGAIN; @@ -497,7 +498,7 @@ out: return written; } -int opal_put_chars(uint32_t vtermno, const char *data, int total_len) +ssize_t opal_put_chars(uint32_t vtermno, const u8 *data, size_t total_len) { return __opal_put_chars(vtermno, data, total_len, false); } @@ -508,7 +509,8 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) * true at the moment because console space can race with OPAL's console * writes. */ -int opal_put_chars_atomic(uint32_t vtermno, const char *data, int total_len) +ssize_t opal_put_chars_atomic(uint32_t vtermno, const u8 *data, + size_t total_len) { return __opal_put_chars(vtermno, data, total_len, true); } diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c index 1ac52963e08b..8803c947998e 100644 --- a/arch/powerpc/platforms/pseries/hvconsole.c +++ b/arch/powerpc/platforms/pseries/hvconsole.c @@ -25,7 +25,7 @@ * firmware. * @count: not used? */ -int hvc_get_chars(uint32_t vtermno, char *buf, int count) +ssize_t hvc_get_chars(uint32_t vtermno, u8 *buf, size_t count) { long ret; unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; @@ -52,7 +52,7 @@ EXPORT_SYMBOL(hvc_get_chars); * firmware. Must be at least 16 bytes, even if count is less than 16. * @count: Send this number of characters. */ -int hvc_put_chars(uint32_t vtermno, const char *buf, int count) +ssize_t hvc_put_chars(uint32_t vtermno, const u8 *buf, size_t count) { unsigned long *lbuf = (unsigned long *) buf; long ret; diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h index 3fec3b8406e9..e14b9cdf7a33 100644 --- a/arch/um/drivers/chan.h +++ b/arch/um/drivers/chan.h @@ -30,7 +30,7 @@ struct chan { extern void chan_interrupt(struct line *line, int irq); extern int parse_chan_pair(char *str, struct line *line, int device, const struct chan_opts *opts, char **error_out); -extern int write_chan(struct chan *chan, const char *buf, int len, +extern int write_chan(struct chan *chan, const u8 *buf, size_t len, int write_irq); extern int console_write_chan(struct chan *chan, const char *buf, int len); diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 26a702a06515..37538b4168da 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -33,14 +33,14 @@ static void not_configged_close(int fd, void *data) "UML\n"); } -static int not_configged_read(int fd, char *c_out, void *data) +static int not_configged_read(int fd, u8 *c_out, void *data) { printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return -EIO; } -static int not_configged_write(int fd, const char *buf, int len, void *data) +static int not_configged_write(int fd, const u8 *buf, size_t len, void *data) { printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); @@ -247,8 +247,7 @@ void deactivate_chan(struct chan *chan, int irq) deactivate_fd(chan->fd, irq); } -int write_chan(struct chan *chan, const char *buf, int len, - int write_irq) +int write_chan(struct chan *chan, const u8 *buf, size_t len, int write_irq) { int n, ret = 0; @@ -540,7 +539,7 @@ void chan_interrupt(struct line *line, int irq) struct tty_port *port = &line->port; struct chan *chan = line->chan_in; int err; - char c; + u8 c; if (!chan || !chan->ops->read) goto out; diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index ed7cc830b3e7..ec04e47b9d79 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -19,7 +19,7 @@ void generic_close(int fd, void *unused) close(fd); } -int generic_read(int fd, char *c_out, void *unused) +int generic_read(int fd, __u8 *c_out, void *unused) { int n; @@ -35,7 +35,7 @@ int generic_read(int fd, char *c_out, void *unused) /* XXX Trivial wrapper around write */ -int generic_write(int fd, const char *buf, int n, void *unused) +int generic_write(int fd, const __u8 *buf, size_t n, void *unused) { int err; diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h index 4e51b85e2a23..e158e16fb3cc 100644 --- a/arch/um/drivers/chan_user.h +++ b/arch/um/drivers/chan_user.h @@ -7,6 +7,7 @@ #define __CHAN_USER_H__ #include +#include struct chan_opts { void (*const announce)(char *dev_name, int dev); @@ -19,8 +20,8 @@ struct chan_ops { void *(*init)(char *, int, const struct chan_opts *); int (*open)(int, int, int, void *, char **); void (*close)(int, void *); - int (*read)(int, char *, void *); - int (*write)(int, const char *, int, void *); + int (*read)(int, __u8 *, void *); + int (*write)(int, const __u8 *, size_t, void *); int (*console_write)(int, const char *, int); int (*window_size)(int, void *, unsigned short *, unsigned short *); void (*free)(void *); @@ -31,8 +32,8 @@ extern const struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops, xterm_ops; extern void generic_close(int fd, void *unused); -extern int generic_read(int fd, char *c_out, void *unused); -extern int generic_write(int fd, const char *buf, int n, void *unused); +extern int generic_read(int fd, __u8 *c_out, void *unused); +extern int generic_write(int fd, const __u8 *buf, size_t n, void *unused); extern int generic_console_write(int fd, const char *buf, int n); extern int generic_window_size(int fd, void *unused, unsigned short *rows_out, unsigned short *cols_out); diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 449d320c3f55..ffc5cb92fa36 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -83,7 +83,7 @@ unsigned int line_chars_in_buffer(struct tty_struct *tty) * * Must be called while holding line->lock! */ -static int buffer_data(struct line *line, const char *buf, int len) +static int buffer_data(struct line *line, const u8 *buf, size_t len) { int end, room; diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index e84fb9b4165e..e8bd6f3dfb50 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -47,9 +47,9 @@ struct line { * * buffer points to a buffer allocated on demand, of length * LINE_BUFSIZE, head to the start of the ring, tail to the end.*/ - char *buffer; - char *head; - char *tail; + u8 *buffer; + u8 *head; + u8 *tail; int sigio; struct delayed_work task; diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index 87087763a417..30d59b8481b4 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -28,7 +28,7 @@ static int null_open(int input, int output, int primary, void *d, return (fd < 0) ? -errno : fd; } -static int null_read(int fd, char *c_out, void *unused) +static int null_read(int fd, __u8 *c_out, void *unused) { return -ENODEV; } diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 7d1f8b398a46..8896e691c051 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -65,7 +65,7 @@ static void rs_poll(struct timer_list *unused) struct tty_port *port = &serial_port; int i = 0; int rd = 1; - unsigned char c; + u8 c; while (simc_poll(0)) { rd = simc_read(0, &c, 1); diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 203a000a84e3..3c84fcbda01a 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -383,8 +383,8 @@ static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) } } -static int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data, - size_t count) +static ssize_t btmtkuart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index b7c56be078f8..1d592ac413d1 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1264,8 +1264,8 @@ static const struct h4_recv_pkt nxp_recv_pkts[] = { { NXP_RECV_FW_REQ_V3, .recv = nxp_recv_fw_req_v3 }, }; -static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data, - size_t count) +static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7835170b1d66..d31edad7a056 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4796,10 +4796,8 @@ static struct usb_driver btusb_driver = { .disable_hub_initiated_lpm = 1, #ifdef CONFIG_DEV_COREDUMP - .drvwrap = { - .driver = { - .coredump = btusb_coredump, - }, + .driver = { + .coredump = btusb_coredump, }, #endif }; diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index f16fd79bc02b..39c8b567da3c 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -271,8 +271,8 @@ static void hci_uart_write_wakeup(struct serdev_device *serdev) * * Return: number of processed bytes */ -static int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data, - size_t count) +static ssize_t hci_uart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct hci_uart *hu = serdev_device_get_drvdata(serdev); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 5af804c17a75..4c806a189ee5 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -40,7 +40,7 @@ static struct ttyprintk_port tpk_port; static int tpk_curr; -static char tpk_buffer[TPK_STR_SIZE + 4]; +static u8 tpk_buffer[TPK_STR_SIZE + 4]; static void tpk_flush(void) { @@ -51,9 +51,9 @@ static void tpk_flush(void) } } -static int tpk_printk(const u8 *buf, int count) +static int tpk_printk(const u8 *buf, size_t count) { - int i; + size_t i; for (i = 0; i < count; i++) { if (tpk_curr >= TPK_STR_SIZE) { diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 431e9e5bf9c1..035f89f1a251 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -230,9 +230,6 @@ struct port { bool guest_connected; }; -/* This is the very early arch-specified put chars function. */ -static int (*early_put_chars)(u32, const char *, int); - static struct port *find_port_by_vtermno(u32 vtermno) { struct port *port; @@ -653,7 +650,7 @@ done: * Give out the data that's requested from the buffer that we have * queued up. */ -static ssize_t fill_readbuf(struct port *port, char __user *out_buf, +static ssize_t fill_readbuf(struct port *port, u8 __user *out_buf, size_t out_count, bool to_user) { struct port_buffer *buf; @@ -672,7 +669,7 @@ static ssize_t fill_readbuf(struct port *port, char __user *out_buf, if (ret) return -EFAULT; } else { - memcpy((__force char *)out_buf, buf->buf + buf->offset, + memcpy((__force u8 *)out_buf, buf->buf + buf->offset, out_count); } @@ -1107,16 +1104,13 @@ static const struct file_operations port_fops = { * it to finish: inefficient in theory, but in practice * implementations will do it immediately. */ -static int put_chars(u32 vtermno, const char *buf, int count) +static ssize_t put_chars(u32 vtermno, const u8 *buf, size_t count) { struct port *port; struct scatterlist sg[1]; void *data; int ret; - if (unlikely(early_put_chars)) - return early_put_chars(vtermno, buf, count); - port = find_port_by_vtermno(vtermno); if (!port) return -EPIPE; @@ -1138,14 +1132,10 @@ static int put_chars(u32 vtermno, const char *buf, int count) * We call out to fill_readbuf that gets us the required data from the * buffers that are queued up. */ -static int get_chars(u32 vtermno, char *buf, int count) +static ssize_t get_chars(u32 vtermno, u8 *buf, size_t count) { struct port *port; - /* If we've not set up the port yet, we have no input to give. */ - if (unlikely(early_put_chars)) - return 0; - port = find_port_by_vtermno(vtermno); if (!port) return -EPIPE; @@ -1153,7 +1143,7 @@ static int get_chars(u32 vtermno, char *buf, int count) /* If we don't have an input queue yet, we can't get input. */ BUG_ON(!port->in_vq); - return fill_readbuf(port, (__force char __user *)buf, count, false); + return fill_readbuf(port, (__force u8 __user *)buf, count, false); } static void resize_console(struct port *port) @@ -1201,21 +1191,6 @@ static const struct hv_ops hv_ops = { .notifier_hangup = notifier_del_vio, }; -/* - * Console drivers are initialized very early so boot messages can go - * out, so we do things slightly differently from the generic virtio - * initialization of the net and block drivers. - * - * At this stage, the console is output-only. It's too early to set - * up a virtqueue, so we let the drivers do some boutique early-output - * thing. - */ -int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) -{ - early_put_chars = put_chars; - return hvc_instantiate(0, 0, &hv_ops); -} - static int init_port_console(struct port *port) { int ret; @@ -1256,13 +1231,6 @@ static int init_port_console(struct port *port) spin_unlock_irq(&pdrvdata_lock); port->guest_connected = true; - /* - * Start using the new console output if this is the first - * console to come up. - */ - if (early_put_chars) - early_put_chars = NULL; - /* Notify host of port being opened */ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); @@ -1999,7 +1967,6 @@ static int virtcons_probe(struct virtio_device *vdev) struct ports_device *portdev; int err; bool multiport; - bool early = early_put_chars != NULL; /* We only need a config space if features are offered */ if (!vdev->config->get && @@ -2010,9 +1977,6 @@ static int virtcons_probe(struct virtio_device *vdev) return -EINVAL; } - /* Ensure to read early_put_chars now */ - barrier(); - portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); if (!portdev) { err = -ENOMEM; @@ -2100,18 +2064,6 @@ static int virtcons_probe(struct virtio_device *vdev) __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 1); - /* - * If there was an early virtio console, assume that there are no - * other consoles. We need to wait until the hvc_alloc matches the - * hvc_instantiate, otherwise tty_open will complain, resulting in - * a "Warning: unable to open an initial console" boot failure. - * Without multiport this is done in add_port above. With multiport - * this might take some host<->guest communication - thus we have to - * wait. - */ - if (multiport && early) - wait_for_completion(&early_console_added); - return 0; free_chrdev: diff --git a/drivers/gnss/serial.c b/drivers/gnss/serial.c index 5d8e9bfb24d0..baa956494e79 100644 --- a/drivers/gnss/serial.c +++ b/drivers/gnss/serial.c @@ -80,8 +80,8 @@ static const struct gnss_operations gnss_serial_gnss_ops = { .write_raw = gnss_serial_write_raw, }; -static int gnss_serial_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t count) +static ssize_t gnss_serial_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) { struct gnss_serial *gserial = serdev_device_get_drvdata(serdev); struct gnss_device *gdev = gserial->gdev; diff --git a/drivers/gnss/sirf.c b/drivers/gnss/sirf.c index bcb53ccfee4d..6801a8fb2040 100644 --- a/drivers/gnss/sirf.c +++ b/drivers/gnss/sirf.c @@ -160,8 +160,8 @@ static const struct gnss_operations sirf_gnss_ops = { .write_raw = sirf_write_raw, }; -static int sirf_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t count) +static ssize_t sirf_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) { struct sirf_data *data = serdev_device_get_drvdata(serdev); struct gnss_device *gdev = data->gdev; diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c index 7d98ae1a8263..c3e90025064b 100644 --- a/drivers/greybus/gb-beagleplay.c +++ b/drivers/greybus/gb-beagleplay.c @@ -271,7 +271,7 @@ static void hdlc_rx_frame(struct gb_beagleplay *bg) } } -static int hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count) +static ssize_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count) { size_t i; u8 c; @@ -331,7 +331,8 @@ static void hdlc_deinit(struct gb_beagleplay *bg) flush_work(&bg->tx_work); } -static int gb_tty_receive(struct serdev_device *sd, const unsigned char *data, size_t count) +static ssize_t gb_tty_receive(struct serdev_device *sd, const u8 *data, + size_t count) { struct gb_beagleplay *bg = serdev_device_get_drvdata(sd); diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c index e9857d93b307..b5cf15a515d2 100644 --- a/drivers/iio/chemical/pms7003.c +++ b/drivers/iio/chemical/pms7003.c @@ -211,13 +211,13 @@ static bool pms7003_frame_is_okay(struct pms7003_frame *frame) return checksum == pms7003_calc_checksum(frame); } -static int pms7003_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t size) +static ssize_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf, + size_t size) { struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev); struct pms7003_state *state = iio_priv(indio_dev); struct pms7003_frame *frame = &state->frame; - int num; + size_t num; if (!frame->expected_length) { u16 magic; diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c index 3c519103d30b..a47654591e55 100644 --- a/drivers/iio/chemical/scd30_serial.c +++ b/drivers/iio/chemical/scd30_serial.c @@ -174,13 +174,13 @@ static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u return 0; } -static int scd30_serdev_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t size) +static ssize_t scd30_serdev_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev); struct scd30_serdev_priv *priv; struct scd30_state *state; - int num; + size_t num; if (!indio_dev) return 0; diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c index 164f4b3e025c..3afa89f8acc3 100644 --- a/drivers/iio/chemical/sps30_serial.c +++ b/drivers/iio/chemical/sps30_serial.c @@ -74,8 +74,8 @@ static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf } static const struct { - unsigned char byte; - unsigned char byte2; + u8 byte; + u8 byte2; } sps30_serial_bytes[] = { { 0x11, 0x31 }, { 0x13, 0x33 }, @@ -83,7 +83,7 @@ static const struct { { 0x7d, 0x5d }, }; -static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte) +static int sps30_serial_put_byte(u8 *buf, u8 byte) { int i; @@ -102,7 +102,7 @@ static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte) return 1; } -static char sps30_serial_get_byte(bool escaped, unsigned char byte2) +static u8 sps30_serial_get_byte(bool escaped, u8 byte2) { int i; @@ -130,8 +130,8 @@ static unsigned char sps30_serial_calc_chksum(const unsigned char *buf, size_t n return ~chksum; } -static int sps30_serial_prep_frame(unsigned char *buf, unsigned char cmd, - const unsigned char *arg, size_t arg_size) +static int sps30_serial_prep_frame(u8 *buf, u8 cmd, const u8 *arg, + size_t arg_size) { unsigned char chksum; int num = 0; @@ -210,14 +210,14 @@ static int sps30_serial_command(struct sps30_state *state, unsigned char cmd, return rsp_size; } -static int sps30_serial_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t size) +static ssize_t sps30_serial_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); struct sps30_serial_priv *priv; struct sps30_state *state; - unsigned char byte; size_t i; + u8 byte; if (!indio_dev) return 0; diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c index 57728a568471..5677bdf4f846 100644 --- a/drivers/iio/imu/bno055/bno055_ser_core.c +++ b/drivers/iio/imu/bno055/bno055_ser_core.c @@ -378,12 +378,12 @@ static void bno055_ser_handle_rx(struct bno055_ser_priv *priv, int status) * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything * unless we require to AND we don't queue more than one request per time). */ -static int bno055_ser_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t size) +static ssize_t bno055_ser_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { int status; struct bno055_ser_priv *priv = serdev_device_get_drvdata(serdev); - int remaining = size; + size_t remaining = size; if (size == 0) return 0; diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c index da308be6c487..ba2e9e52d72b 100644 --- a/drivers/ipack/devices/ipoctal.c +++ b/drivers/ipack/devices/ipoctal.c @@ -158,9 +158,7 @@ static int ipoctal_get_icount(struct tty_struct *tty, static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr) { struct tty_port *port = &channel->tty_port; - unsigned char value; - unsigned char flag; - u8 isr; + u8 isr, value, flag; do { value = ioread8(&channel->regs->r.rhr); @@ -202,8 +200,8 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr) static void ipoctal_irq_tx(struct ipoctal_channel *channel) { - unsigned char value; unsigned int *pointer_write = &channel->pointer_write; + u8 value; if (channel->nb_bytes == 0) return; @@ -436,11 +434,11 @@ err_put_driver: return res; } -static inline int ipoctal_copy_write_buffer(struct ipoctal_channel *channel, - const u8 *buf, int count) +static inline size_t ipoctal_copy_write_buffer(struct ipoctal_channel *channel, + const u8 *buf, size_t count) { unsigned long flags; - int i; + size_t i; unsigned int *pointer_read = &channel->pointer_read; /* Copy the bytes from the user buffer to the internal one */ @@ -462,7 +460,7 @@ static ssize_t ipoctal_write_tty(struct tty_struct *tty, const u8 *buf, size_t count) { struct ipoctal_channel *channel = tty->driver_data; - unsigned int char_copied; + size_t char_copied; char_copied = ipoctal_copy_write_buffer(channel, buf, count); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 2f3789515445..6e80d7bd3c4d 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1231,9 +1231,9 @@ static void capinc_tty_hangup(struct tty_struct *tty) tty_port_hangup(&mp->port); } -static void capinc_tty_send_xchar(struct tty_struct *tty, char ch) +static void capinc_tty_send_xchar(struct tty_struct *tty, u8 ch) { - pr_debug("capinc_tty_send_xchar(%d)\n", ch); + pr_debug("capinc_tty_send_xchar(%u)\n", ch); } static const struct tty_operations capinc_ops = { diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index f62422740de2..6ff84b2600c5 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -471,17 +471,17 @@ static void rave_sp_receive_frame(struct rave_sp *sp, rave_sp_receive_reply(sp, data, length); } -static int rave_sp_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t size) +static ssize_t rave_sp_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { struct device *dev = &serdev->dev; struct rave_sp *sp = dev_get_drvdata(dev); struct rave_sp_deframer *deframer = &sp->deframer; - const unsigned char *src = buf; - const unsigned char *end = buf + size; + const u8 *src = buf; + const u8 *end = buf + size; while (src < end) { - const unsigned char byte = *src++; + const u8 byte = *src++; switch (deframer->state) { case RAVE_SP_EXPECT_SOF: diff --git a/drivers/misc/bcm-vk/bcm_vk_tty.c b/drivers/misc/bcm-vk/bcm_vk_tty.c index 2bce835ca43e..59bab76ff0a9 100644 --- a/drivers/misc/bcm-vk/bcm_vk_tty.c +++ b/drivers/misc/bcm-vk/bcm_vk_tty.c @@ -64,9 +64,9 @@ static void bcm_vk_tty_wq_handler(struct work_struct *work) struct bcm_vk_tty *vktty; int card_status; int count; - unsigned char c; int i; int wr; + u8 c; card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS); if (BCM_VK_INTF_IS_DOWN(card_status)) @@ -192,7 +192,7 @@ static ssize_t bcm_vk_tty_write(struct tty_struct *tty, const u8 *buffer, int index; struct bcm_vk *vk; struct bcm_vk_tty *vktty; - int i; + size_t i; index = tty->index; vk = dev_get_drvdata(tty->dev); diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c index ef38dcd3a887..575ebbce378e 100644 --- a/drivers/mmc/core/sdio_uart.c +++ b/drivers/mmc/core/sdio_uart.c @@ -178,11 +178,9 @@ static inline void sdio_uart_release_func(struct sdio_uart_port *port) sdio_release_host(port->func); } -static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset) +static inline u8 sdio_in(struct sdio_uart_port *port, int offset) { - unsigned char c; - c = sdio_readb(port->func, port->regs_offset + offset, NULL); - return c; + return sdio_readb(port->func, port->regs_offset + offset, NULL); } static inline void sdio_out(struct sdio_uart_port *port, int offset, int value) @@ -192,8 +190,8 @@ static inline void sdio_out(struct sdio_uart_port *port, int offset, int value) static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port) { - unsigned char status; unsigned int ret; + u8 status; /* FIXME: What stops this losing the delta bits and breaking sdio_uart_check_modem_status ? */ @@ -354,15 +352,13 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port) sdio_out(port, UART_IER, port->ier); } -static void sdio_uart_receive_chars(struct sdio_uart_port *port, - unsigned int *status) +static void sdio_uart_receive_chars(struct sdio_uart_port *port, u8 *status) { - unsigned int ch, flag; int max_count = 256; do { - ch = sdio_in(port, UART_RX); - flag = TTY_NORMAL; + u8 ch = sdio_in(port, UART_RX); + u8 flag = TTY_NORMAL; port->icount.rx++; if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | @@ -449,8 +445,8 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) static void sdio_uart_check_modem_status(struct sdio_uart_port *port) { - int status; struct tty_struct *tty; + u8 status; status = sdio_in(port, UART_MSR); @@ -499,7 +495,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) static void sdio_uart_irq(struct sdio_func *func) { struct sdio_uart_port *port = sdio_get_drvdata(func); - unsigned int iir, lsr; + u8 iir, lsr; /* * In a few places sdio_uart_irq() is called directly instead of @@ -795,7 +791,7 @@ static unsigned int sdio_uart_chars_in_buffer(struct tty_struct *tty) return kfifo_len(&port->xmit_fifo); } -static void sdio_uart_send_xchar(struct tty_struct *tty, char ch) +static void sdio_uart_send_xchar(struct tty_struct *tty, u8 ch) { struct sdio_uart_port *port = tty->driver_data; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 24ad9f593a77..1efa39e134f4 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -1143,7 +1143,7 @@ static void __exit peak_usb_exit(void) int err; /* last chance do send any synchronous commands here */ - err = driver_for_each_device(&peak_usb_driver.drvwrap.driver, NULL, + err = driver_for_each_device(&peak_usb_driver.driver, NULL, NULL, peak_usb_do_device_exit); if (err) pr_err("%s: failed to stop all can devices (err %d)\n", diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c index 9adec91f35e9..223321897b96 100644 --- a/drivers/net/ethernet/qualcomm/qca_uart.c +++ b/drivers/net/ethernet/qualcomm/qca_uart.c @@ -58,9 +58,8 @@ struct qcauart { unsigned char *tx_buffer; }; -static int -qca_tty_receive(struct serdev_device *serdev, const unsigned char *data, - size_t count) +static ssize_t +qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count) { struct qcauart *qca = serdev_device_get_drvdata(serdev); struct net_device *netdev = qca->net_dev; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 83b8452220ec..f088ea2ba6f3 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -363,7 +363,6 @@ static int disable_net; /* driver info */ static const char driver_name[] = "hso"; static const char tty_filename[] = "ttyHS"; -static const char *version = __FILE__ ": " MOD_AUTHOR; /* the usb driver itself (registered in hso_init) */ static struct usb_driver hso_driver; /* serial structures */ @@ -3228,16 +3227,8 @@ static struct usb_driver hso_driver = { static int __init hso_init(void) { - int i; int result; - /* put it in the log */ - pr_info("%s\n", version); - - /* Initialise the serial table semaphore and table */ - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) - serial_table[i] = NULL; - /* allocate our driver using the proper amount of supported minors */ tty_drv = tty_alloc_driver(HSO_SERIAL_TTY_MINORS, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); @@ -3285,8 +3276,6 @@ err_free_tty: static void __exit hso_exit(void) { - pr_info("unloaded\n"); - tty_unregister_driver(tty_drv); /* deregister the usb driver */ usb_deregister(&hso_driver); diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 9bf2140fd0a1..0d0672d2a654 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -10069,7 +10069,7 @@ static struct usb_driver rtl8152_driver = { .disable_hub_initiated_lpm = 1, }; -static int rtl8152_cfgselector_probe(struct usb_device *udev) +static int rtl8152_cfgselector_choose_configuration(struct usb_device *udev) { struct usb_host_config *c; int i, num_configs; @@ -10096,19 +10096,13 @@ static int rtl8152_cfgselector_probe(struct usb_device *udev) if (i == num_configs) return -ENODEV; - if (usb_set_configuration(udev, c->desc.bConfigurationValue)) { - dev_err(&udev->dev, "Failed to set configuration %d\n", - c->desc.bConfigurationValue); - return -ENODEV; - } - - return 0; + return c->desc.bConfigurationValue; } static struct usb_device_driver rtl8152_cfgselector_driver = { - .name = MODULENAME "-cfgselector", - .probe = rtl8152_cfgselector_probe, - .id_table = rtl8152_table, + .name = MODULENAME "-cfgselector", + .choose_configuration = rtl8152_cfgselector_choose_configuration, + .id_table = rtl8152_table, .generic_subclass = 1, .supports_autosuspend = 1, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 2178675ae1a4..0ccf735316c2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1581,7 +1581,7 @@ static int brcmf_usb_reset_device(struct device *dev, void *notused) void brcmf_usb_exit(void) { - struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver; + struct device_driver *drv = &brcmf_usbdrvr.driver; int ret; brcmf_dbg(USB, "Enter\n"); diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index d3ab9572e711..515e6db410f2 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -687,7 +687,7 @@ static struct usb_driver mwifiex_usb_driver = { .suspend = mwifiex_usb_suspend, .resume = mwifiex_usb_resume, .soft_unbind = 1, - .drvwrap.driver = { + .driver = { .coredump = mwifiex_usb_coredump, }, }; diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c index a556acdb947b..2eb5978bd79e 100644 --- a/drivers/nfc/pn533/uart.c +++ b/drivers/nfc/pn533/uart.c @@ -203,8 +203,8 @@ static int pn532_uart_rx_is_frame(struct sk_buff *skb) return 0; } -static int pn532_receive_buf(struct serdev_device *serdev, - const unsigned char *data, size_t count) +static ssize_t pn532_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev); size_t i; diff --git a/drivers/nfc/s3fwrn5/uart.c b/drivers/nfc/s3fwrn5/uart.c index 82ea35d748a5..456d3947116c 100644 --- a/drivers/nfc/s3fwrn5/uart.c +++ b/drivers/nfc/s3fwrn5/uart.c @@ -51,9 +51,8 @@ static const struct s3fwrn5_phy_ops uart_phy_ops = { .write = s3fwrn82_uart_write, }; -static int s3fwrn82_uart_read(struct serdev_device *serdev, - const unsigned char *data, - size_t count) +static ssize_t s3fwrn82_uart_read(struct serdev_device *serdev, + const u8 *data, size_t count) { struct s3fwrn82_uart_phy *phy = serdev_device_get_drvdata(serdev); size_t i; diff --git a/drivers/platform/chrome/cros_ec_uart.c b/drivers/platform/chrome/cros_ec_uart.c index 788246559bbb..68d80559fddc 100644 --- a/drivers/platform/chrome/cros_ec_uart.c +++ b/drivers/platform/chrome/cros_ec_uart.c @@ -81,9 +81,8 @@ struct cros_ec_uart { struct response_info response; }; -static int cros_ec_uart_rx_bytes(struct serdev_device *serdev, - const u8 *data, - size_t count) +static ssize_t cros_ec_uart_rx_bytes(struct serdev_device *serdev, + const u8 *data, size_t count) { struct ec_host_response *host_response; struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev); diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h index f0d987abc51e..f1638c2081e8 100644 --- a/drivers/platform/surface/aggregator/controller.h +++ b/drivers/platform/surface/aggregator/controller.h @@ -238,8 +238,8 @@ struct ssam_controller { * layer of the controller has been shut down, %-ESHUTDOWN. */ static inline -int ssam_controller_receive_buf(struct ssam_controller *ctrl, - const unsigned char *buf, size_t n) +ssize_t ssam_controller_receive_buf(struct ssam_controller *ctrl, const u8 *buf, + size_t n) { return ssh_ptl_rx_rcvbuf(&ctrl->rtl.ptl, buf, n); } diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index 6152be38398c..9591a28bc38a 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -227,8 +227,8 @@ EXPORT_SYMBOL_GPL(ssam_client_bind); /* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */ -static int ssam_receive_buf(struct serdev_device *dev, const unsigned char *buf, - size_t n) +static ssize_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf, + size_t n) { struct ssam_controller *ctrl; int ret; diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c index def8d7ac541f..d726b1a86319 100644 --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c @@ -1887,9 +1887,9 @@ int ssh_ptl_rx_stop(struct ssh_ptl *ptl) * Return: Returns the number of bytes transferred (positive or zero) on * success. Returns %-ESHUTDOWN if the packet layer has been shut down. */ -int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n) +ssize_t ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n) { - int used; + size_t used; if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state)) return -ESHUTDOWN; diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h index 64633522f971..c80e822070df 100644 --- a/drivers/platform/surface/aggregator/ssh_packet_layer.h +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h @@ -162,7 +162,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl); int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p); void ssh_ptl_cancel(struct ssh_packet *p); -int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n); +ssize_t ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n); /** * ssh_ptl_tx_wakeup_transfer() - Wake up packet transmitter thread for diff --git a/drivers/platform/x86/intel/chtwc_int33fe.c b/drivers/platform/x86/intel/chtwc_int33fe.c index 848baecc1bb0..93f75ba1dafd 100644 --- a/drivers/platform/x86/intel/chtwc_int33fe.c +++ b/drivers/platform/x86/intel/chtwc_int33fe.c @@ -136,7 +136,7 @@ static const struct software_node altmodes_node = { }; static const struct property_entry dp_altmode_properties[] = { - PROPERTY_ENTRY_U32("svid", 0xff01), + PROPERTY_ENTRY_U16("svid", 0xff01), PROPERTY_ENTRY_U32("vdo", 0x0c0086), { } }; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 99361618c31f..0b0324fe4aff 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -79,8 +79,8 @@ struct raw3215_info { struct ccw_device *cdev; /* device for tty driver */ spinlock_t *lock; /* pointer to irq lock */ int flags; /* state flags */ - char *buffer; /* pointer to output buffer */ - char *inbuf; /* pointer to input buffer */ + u8 *buffer; /* pointer to output buffer */ + u8 *inbuf; /* pointer to input buffer */ int head; /* first free byte in output buffer */ int count; /* number of bytes in output buffer */ int written; /* number of bytes in write requests */ @@ -89,7 +89,6 @@ struct raw3215_info { wait_queue_head_t empty_wait; /* wait queue for flushing */ struct timer_list timer; /* timer for delayed output */ int line_pos; /* position on the line (for tabs) */ - char ubuffer[80]; /* copy_from_user buffer */ }; /* array of 3215 devices structures */ @@ -523,12 +522,14 @@ static unsigned int raw3215_make_room(struct raw3215_info *raw, * string without blocking. * Return value is the number of bytes copied. */ -static unsigned int raw3215_addtext(const char *str, unsigned int length, +static unsigned int raw3215_addtext(const u8 *str, size_t length, struct raw3215_info *raw, int opmode, unsigned int todrop) { - unsigned int c, ch, i, blanks, expanded_size = 0; + unsigned int i, blanks, expanded_size = 0; unsigned int column = raw->line_pos; + size_t c; + u8 ch; if (opmode == RAW3215_COUNT) todrop = 0; @@ -559,7 +560,7 @@ static unsigned int raw3215_addtext(const char *str, unsigned int length, if (todrop && expanded_size < todrop) /* Drop head data */ continue; for (i = 0; i < blanks; i++) { - raw->buffer[raw->head] = (char)_ascebc[(int)ch]; + raw->buffer[raw->head] = _ascebc[ch]; raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); raw->count++; } @@ -571,8 +572,8 @@ static unsigned int raw3215_addtext(const char *str, unsigned int length, /* * String write routine for 3215 devices */ -static void raw3215_write(struct raw3215_info *raw, const char *str, - unsigned int length) +static void raw3215_write(struct raw3215_info *raw, const u8 *str, + size_t length) { unsigned int count, avail; unsigned long flags; @@ -597,7 +598,7 @@ static void raw3215_write(struct raw3215_info *raw, const char *str, /* * Put character routine for 3215 devices */ -static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) +static void raw3215_putchar(struct raw3215_info *raw, u8 ch) { raw3215_write(raw, &ch, 1); } @@ -824,12 +825,10 @@ static struct ccw_driver raw3215_ccw_driver = { .int_class = IRQIO_C15, }; -static void handle_write(struct raw3215_info *raw, const char *str, int count) +static void handle_write(struct raw3215_info *raw, const u8 *str, size_t count) { - int i; - while (count > 0) { - i = min_t(int, count, RAW3215_BUFFER_SIZE - 1); + size_t i = min_t(size_t, count, RAW3215_BUFFER_SIZE - 1); raw3215_write(raw, str, i); count -= i; str += i; diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 363315fa1666..251d2a1c3eef 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -54,7 +54,7 @@ struct tty3270_attribute { }; struct tty3270_cell { - unsigned char character; + u8 character; struct tty3270_attribute attributes; }; @@ -123,7 +123,7 @@ struct tty3270 { /* Character array for put_char/flush_chars. */ unsigned int char_count; - char char_buf[TTY3270_CHAR_BUF_SIZE]; + u8 char_buf[TTY3270_CHAR_BUF_SIZE]; }; /* tty3270->update_flags. See tty3270_update for details. */ @@ -1255,7 +1255,7 @@ static unsigned int tty3270_write_room(struct tty_struct *tty) * Insert character into the screen at the current position with the * current color and highlight. This function does NOT do cursor movement. */ -static void tty3270_put_character(struct tty3270 *tp, char ch) +static void tty3270_put_character(struct tty3270 *tp, u8 ch) { struct tty3270_line *line; struct tty3270_cell *cell; @@ -1561,7 +1561,7 @@ static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy) * Pn is a numeric parameter, a string of zero or more decimal digits. * Ps is a selective parameter. */ -static void tty3270_escape_sequence(struct tty3270 *tp, char ch) +static void tty3270_escape_sequence(struct tty3270 *tp, u8 ch) { enum { ES_NORMAL, ES_ESC, ES_SQUARE, ES_PAREN, ES_GETPARS }; @@ -1726,7 +1726,7 @@ static void tty3270_escape_sequence(struct tty3270 *tp, char ch) * String write routine for 3270 ttys */ static void tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty, - const unsigned char *buf, int count) + const u8 *buf, size_t count) { int i_msg, i; @@ -2052,7 +2052,7 @@ con3270_write(struct console *co, const char *str, unsigned int count) { struct tty3270 *tp = co->data; unsigned long flags; - char c; + u8 c; spin_lock_irqsave(&tp->view.lock, flags); while (count--) { diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index ec7b5f65804e..9fb1a64f3300 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -307,7 +307,7 @@ static const struct attribute_group *domain_attr_groups[] = { NULL, }; -struct bus_type tb_bus_type = { +const struct bus_type tb_bus_type = { .name = "thunderbolt", .match = tb_service_match, .probe = tb_service_probe, diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index d8b9c734abd3..56790d50f9e3 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -1020,7 +1020,7 @@ icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level, memset(&reply, 0, sizeof(reply)); ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply), - 1, 10, 2000); + 1, 10, 250); if (ret) return ret; diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 4b7bec74e89f..fb4f46e51753 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -1517,6 +1517,10 @@ static struct pci_device_id nhi_ids[] = { .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI1), .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_LNL_NHI0), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_LNL_NHI1), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_80G_NHI) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_40G_NHI) }, diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h index 0f029ce75882..7a07c7c1a9c2 100644 --- a/drivers/thunderbolt/nhi.h +++ b/drivers/thunderbolt/nhi.h @@ -90,6 +90,8 @@ extern const struct tb_nhi_ops icl_nhi_ops; #define PCI_DEVICE_ID_INTEL_TGL_H_NHI1 0x9a21 #define PCI_DEVICE_ID_INTEL_RPL_NHI0 0xa73e #define PCI_DEVICE_ID_INTEL_RPL_NHI1 0xa76d +#define PCI_DEVICE_ID_INTEL_LNL_NHI0 0xa833 +#define PCI_DEVICE_ID_INTEL_LNL_NHI1 0xa834 #define PCI_CLASS_SERIAL_USB_USB4 0x0c0340 diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 44e9b09de47a..900114ba4371 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -941,22 +941,6 @@ int tb_port_get_link_generation(struct tb_port *port) } } -static const char *width_name(enum tb_link_width width) -{ - switch (width) { - case TB_LINK_WIDTH_SINGLE: - return "symmetric, single lane"; - case TB_LINK_WIDTH_DUAL: - return "symmetric, dual lanes"; - case TB_LINK_WIDTH_ASYM_TX: - return "asymmetric, 3 transmitters, 1 receiver"; - case TB_LINK_WIDTH_ASYM_RX: - return "asymmetric, 3 receivers, 1 transmitter"; - default: - return "unknown"; - } -} - /** * tb_port_get_link_width() - Get current link width * @port: Port to check (USB4 or CIO) @@ -2769,7 +2753,7 @@ static void tb_switch_link_init(struct tb_switch *sw) return; tb_sw_dbg(sw, "current link speed %u.0 Gb/s\n", sw->link_speed); - tb_sw_dbg(sw, "current link width %s\n", width_name(sw->link_width)); + tb_sw_dbg(sw, "current link width %s\n", tb_width_name(sw->link_width)); bonded = sw->link_width >= TB_LINK_WIDTH_DUAL; @@ -2789,6 +2773,19 @@ static void tb_switch_link_init(struct tb_switch *sw) if (down->dual_link_port) down->dual_link_port->bonded = bonded; tb_port_update_credits(down); + + if (tb_port_get_link_generation(up) < 4) + return; + + /* + * Set the Gen 4 preferred link width. This is what the router + * prefers when the link is brought up. If the router does not + * support asymmetric link configuration, this also will be set + * to TB_LINK_WIDTH_DUAL. + */ + sw->preferred_link_width = sw->link_width; + tb_sw_dbg(sw, "preferred link width %s\n", + tb_width_name(sw->preferred_link_width)); } /** @@ -3029,7 +3026,7 @@ int tb_switch_set_link_width(struct tb_switch *sw, enum tb_link_width width) tb_switch_update_link_attributes(sw); - tb_sw_dbg(sw, "link width set to %s\n", width_name(width)); + tb_sw_dbg(sw, "link width set to %s\n", tb_width_name(width)); return ret; } diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index fd49f86e0353..846d2813bb1a 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -513,8 +513,6 @@ static void tb_port_unconfigure_xdomain(struct tb_port *port) usb4_port_unconfigure_xdomain(port); else tb_lc_unconfigure_xdomain(port); - - tb_port_enable(port->dual_link_port); } static void tb_scan_xdomain(struct tb_port *port) @@ -1087,15 +1085,14 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port, struct tb_port *dst_port, int requested_up, int requested_down) { + bool clx = false, clx_disabled = false, downstream; struct tb_switch *sw; - bool clx, downstream; struct tb_port *up; int ret = 0; if (!asym_threshold) return 0; - /* Disable CL states before doing any transitions */ downstream = tb_port_path_direction_downstream(src_port, dst_port); /* Pick up router deepest in the hierarchy */ if (downstream) @@ -1103,11 +1100,10 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port, else sw = src_port->sw; - clx = tb_disable_clx(sw); - tb_for_each_upstream_port_on_path(src_port, dst_port, up) { + struct tb_port *down = tb_switch_downstream_port(up->sw); + enum tb_link_width width_up, width_down; int consumed_up, consumed_down; - enum tb_link_width width; ret = tb_consumed_dp_bandwidth(tb, src_port, dst_port, up, &consumed_up, &consumed_down); @@ -1128,7 +1124,8 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port, if (consumed_down + requested_down < asym_threshold) continue; - width = TB_LINK_WIDTH_ASYM_RX; + width_up = TB_LINK_WIDTH_ASYM_RX; + width_down = TB_LINK_WIDTH_ASYM_TX; } else { /* Upstream, the opposite of above */ if (consumed_down + requested_down >= TB_ASYM_MIN) { @@ -1138,22 +1135,34 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port, if (consumed_up + requested_up < asym_threshold) continue; - width = TB_LINK_WIDTH_ASYM_TX; + width_up = TB_LINK_WIDTH_ASYM_TX; + width_down = TB_LINK_WIDTH_ASYM_RX; } - if (up->sw->link_width == width) + if (up->sw->link_width == width_up) continue; - if (!tb_port_width_supported(up, width)) + if (!tb_port_width_supported(up, width_up) || + !tb_port_width_supported(down, width_down)) continue; + /* + * Disable CL states before doing any transitions. We + * delayed it until now that we know there is a real + * transition taking place. + */ + if (!clx_disabled) { + clx = tb_disable_clx(sw); + clx_disabled = true; + } + tb_sw_dbg(up->sw, "configuring asymmetric link\n"); /* * Here requested + consumed > threshold so we need to * transtion the link into asymmetric now. */ - ret = tb_switch_set_link_width(up->sw, width); + ret = tb_switch_set_link_width(up->sw, width_up); if (ret) { tb_sw_warn(up->sw, "failed to set link width\n"); break; @@ -1174,24 +1183,24 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port, * @dst_port: Destination adapter * @requested_up: New lower bandwidth request upstream (Mb/s) * @requested_down: New lower bandwidth request downstream (Mb/s) + * @keep_asym: Keep asymmetric link if preferred * * Goes over each link from @src_port to @dst_port and tries to * transition the link to symmetric if the currently consumed bandwidth - * allows. + * allows and link asymmetric preference is ignored (if @keep_asym is %false). */ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port, struct tb_port *dst_port, int requested_up, - int requested_down) + int requested_down, bool keep_asym) { + bool clx = false, clx_disabled = false, downstream; struct tb_switch *sw; - bool clx, downstream; struct tb_port *up; int ret = 0; if (!asym_threshold) return 0; - /* Disable CL states before doing any transitions */ downstream = tb_port_path_direction_downstream(src_port, dst_port); /* Pick up router deepest in the hierarchy */ if (downstream) @@ -1199,8 +1208,6 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port, else sw = src_port->sw; - clx = tb_disable_clx(sw); - tb_for_each_upstream_port_on_path(src_port, dst_port, up) { int consumed_up, consumed_down; @@ -1233,6 +1240,25 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port, if (up->sw->link_width == TB_LINK_WIDTH_DUAL) continue; + /* + * Here consumed < threshold so we can transition the + * link to symmetric. + * + * However, if the router prefers asymmetric link we + * honor that (unless @keep_asym is %false). + */ + if (keep_asym && + up->sw->preferred_link_width > TB_LINK_WIDTH_DUAL) { + tb_sw_dbg(up->sw, "keeping preferred asymmetric link\n"); + continue; + } + + /* Disable CL states before doing any transitions */ + if (!clx_disabled) { + clx = tb_disable_clx(sw); + clx_disabled = true; + } + tb_sw_dbg(up->sw, "configuring symmetric link\n"); ret = tb_switch_set_link_width(up->sw, TB_LINK_WIDTH_DUAL); @@ -1280,7 +1306,7 @@ static void tb_configure_link(struct tb_port *down, struct tb_port *up, struct tb_port *host_port; host_port = tb_port_at(tb_route(sw), tb->root_switch); - tb_configure_sym(tb, host_port, up, 0, 0); + tb_configure_sym(tb, host_port, up, 0, 0, false); } /* Set the link configured */ @@ -1465,7 +1491,7 @@ static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel) * If bandwidth on a link is < asym_threshold * transition the link to symmetric. */ - tb_configure_sym(tb, src_port, dst_port, 0, 0); + tb_configure_sym(tb, src_port, dst_port, 0, 0, true); /* Now we can allow the domain to runtime suspend again */ pm_runtime_mark_last_busy(&dst_port->sw->dev); pm_runtime_put_autosuspend(&dst_port->sw->dev); @@ -1901,7 +1927,7 @@ static void tb_dp_resource_available(struct tb *tb, struct tb_port *port) return; } - tb_port_dbg(port, "DP %s resource available\n", + tb_port_dbg(port, "DP %s resource available after hotplug\n", tb_port_is_dpin(port) ? "IN" : "OUT"); list_add_tail(&port->list, &tcm->dp_resources); @@ -2287,7 +2313,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up, * If bandwidth on a link is < asym_threshold transition * the link to symmetric. */ - tb_configure_sym(tb, in, out, *requested_up, *requested_down); + tb_configure_sym(tb, in, out, *requested_up, *requested_down, true); /* * If requested bandwidth is less or equal than what is * currently allocated to that tunnel we simply change @@ -2330,7 +2356,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up, ret = tb_configure_asym(tb, in, out, *requested_up, *requested_down); if (ret) { - tb_configure_sym(tb, in, out, 0, 0); + tb_configure_sym(tb, in, out, 0, 0, true); return ret; } @@ -2338,7 +2364,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up, requested_down); if (ret) { tb_tunnel_warn(tunnel, "failed to allocate bandwidth\n"); - tb_configure_sym(tb, in, out, 0, 0); + tb_configure_sym(tb, in, out, 0, 0, true); } } else { ret = -ENOBUFS; diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index e299e53473ae..997c5a536905 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -125,6 +125,7 @@ struct tb_switch_tmu { * @device_name: Name of the device (or %NULL if not known) * @link_speed: Speed of the link in Gb/s * @link_width: Width of the upstream facing link + * @preferred_link_width: Router preferred link width (only set for Gen 4 links) * @link_usb4: Upstream link is USB4 * @generation: Switch Thunderbolt generation * @cap_plug_events: Offset to the plug events capability (%0 if not found) @@ -178,6 +179,7 @@ struct tb_switch { const char *device_name; unsigned int link_speed; enum tb_link_width link_width; + enum tb_link_width preferred_link_width; bool link_usb4; unsigned int generation; int cap_plug_events; @@ -568,6 +570,22 @@ static inline struct tb_port *tb_port_at(u64 route, struct tb_switch *sw) return &sw->ports[port]; } +static inline const char *tb_width_name(enum tb_link_width width) +{ + switch (width) { + case TB_LINK_WIDTH_SINGLE: + return "symmetric, single lane"; + case TB_LINK_WIDTH_DUAL: + return "symmetric, dual lanes"; + case TB_LINK_WIDTH_ASYM_TX: + return "asymmetric, 3 transmitters, 1 receiver"; + case TB_LINK_WIDTH_ASYM_RX: + return "asymmetric, 3 receivers, 1 transmitter"; + default: + return "unknown"; + } +} + /** * tb_port_has_remote() - Does the port have switch connected downstream * @port: Port to check diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c index 11f2aec2a5d3..9a259c72e5a7 100644 --- a/drivers/thunderbolt/tmu.c +++ b/drivers/thunderbolt/tmu.c @@ -894,7 +894,7 @@ static int tb_switch_tmu_change_mode(struct tb_switch *sw) ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.mode_request); if (ret) - return ret; + goto out; /* Program the new mode and the downstream router lane adapter */ switch (sw->tmu.mode_request) { diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 7534cd3a81f4..6fffb2c82d3d 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -173,16 +173,28 @@ static int tb_pci_set_ext_encapsulation(struct tb_tunnel *tunnel, bool enable) int ret; /* Only supported of both routers are at least USB4 v2 */ - if (tb_port_get_link_generation(port) < 4) + if ((usb4_switch_version(tunnel->src_port->sw) < 2) || + (usb4_switch_version(tunnel->dst_port->sw) < 2)) + return 0; + + if (enable && tb_port_get_link_generation(port) < 4) return 0; ret = usb4_pci_port_set_ext_encapsulation(tunnel->src_port, enable); if (ret) return ret; + /* + * Downstream router could be unplugged so disable of encapsulation + * in upstream router is still possible. + */ ret = usb4_pci_port_set_ext_encapsulation(tunnel->dst_port, enable); - if (ret) - return ret; + if (ret) { + if (enable) + return ret; + if (ret != -ENODEV) + return ret; + } tb_tunnel_dbg(tunnel, "extended encapsulation %s\n", str_enabled_disabled(enable)); @@ -199,14 +211,21 @@ static int tb_pci_activate(struct tb_tunnel *tunnel, bool activate) return res; } - res = tb_pci_port_enable(tunnel->src_port, activate); + if (activate) + res = tb_pci_port_enable(tunnel->dst_port, activate); + else + res = tb_pci_port_enable(tunnel->src_port, activate); if (res) return res; - if (tb_port_is_pcie_up(tunnel->dst_port)) { - res = tb_pci_port_enable(tunnel->dst_port, activate); + + if (activate) { + res = tb_pci_port_enable(tunnel->src_port, activate); if (res) return res; + } else { + /* Downstream router could be unplugged */ + tb_pci_port_enable(tunnel->dst_port, activate); } return activate ? 0 : tb_pci_set_ext_encapsulation(tunnel, activate); @@ -1067,8 +1086,7 @@ static int tb_dp_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up, return 0; } -static int tb_dp_read_dprx(struct tb_tunnel *tunnel, u32 *rate, u32 *lanes, - int timeout_msec) +static int tb_dp_wait_dprx(struct tb_tunnel *tunnel, int timeout_msec) { ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec); struct tb_port *in = tunnel->src_port; @@ -1087,15 +1105,13 @@ static int tb_dp_read_dprx(struct tb_tunnel *tunnel, u32 *rate, u32 *lanes, return ret; if (val & DP_COMMON_CAP_DPRX_DONE) { - *rate = tb_dp_cap_get_rate(val); - *lanes = tb_dp_cap_get_lanes(val); - tb_tunnel_dbg(tunnel, "DPRX read done\n"); return 0; } usleep_range(100, 150); } while (ktime_before(ktime_get(), timeout)); + tb_tunnel_dbg(tunnel, "DPRX read timeout\n"); return -ETIMEDOUT; } @@ -1110,6 +1126,7 @@ static int tb_dp_read_cap(struct tb_tunnel *tunnel, unsigned int cap, u32 *rate, switch (cap) { case DP_LOCAL_CAP: case DP_REMOTE_CAP: + case DP_COMMON_CAP: break; default: @@ -1182,7 +1199,7 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up, * reduced one). Otherwise return the remote (possibly * reduced) caps. */ - ret = tb_dp_read_dprx(tunnel, &rate, &lanes, 150); + ret = tb_dp_wait_dprx(tunnel, 150); if (ret) { if (ret == -ETIMEDOUT) ret = tb_dp_read_cap(tunnel, DP_REMOTE_CAP, @@ -1190,6 +1207,9 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up, if (ret) return ret; } + ret = tb_dp_read_cap(tunnel, DP_COMMON_CAP, &rate, &lanes); + if (ret) + return ret; } else if (sw->generation >= 2) { ret = tb_dp_read_cap(tunnel, DP_REMOTE_CAP, &rate, &lanes); if (ret) @@ -1313,8 +1333,6 @@ static void tb_dp_dump(struct tb_tunnel *tunnel) "DP IN maximum supported bandwidth %u Mb/s x%u = %u Mb/s\n", rate, lanes, tb_dp_bandwidth(rate, lanes)); - out = tunnel->dst_port; - if (tb_port_read(out, &dp_cap, TB_CFG_PORT, out->cap_adap + DP_LOCAL_CAP, 1)) return; diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index 9803f0bbf20d..9495742913d5 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -1462,6 +1462,11 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd) tb_port_disable(port->dual_link_port); } + dev_dbg(&xd->dev, "current link speed %u.0 Gb/s\n", + xd->link_speed); + dev_dbg(&xd->dev, "current link width %s\n", + tb_width_name(xd->link_width)); + if (device_add(&xd->dev)) { dev_err(&xd->dev, "failed to add XDomain device\n"); return -ENODEV; @@ -1895,6 +1900,50 @@ struct device_type tb_xdomain_type = { }; EXPORT_SYMBOL_GPL(tb_xdomain_type); +static void tb_xdomain_link_init(struct tb_xdomain *xd, struct tb_port *down) +{ + if (!down->dual_link_port) + return; + + /* + * Gen 4 links come up already as bonded so only update the port + * structures here. + */ + if (tb_port_get_link_generation(down) >= 4) { + down->bonded = true; + down->dual_link_port->bonded = true; + } else { + xd->bonding_possible = true; + } +} + +static void tb_xdomain_link_exit(struct tb_xdomain *xd) +{ + struct tb_port *down = tb_xdomain_downstream_port(xd); + + if (!down->dual_link_port) + return; + + if (tb_port_get_link_generation(down) >= 4) { + down->bonded = false; + down->dual_link_port->bonded = false; + } else if (xd->link_width > TB_LINK_WIDTH_SINGLE) { + /* + * Just return port structures back to way they were and + * update credits. No need to update userspace because + * the XDomain is removed soon anyway. + */ + tb_port_lane_bonding_disable(down); + tb_port_update_credits(down); + } else if (down->dual_link_port) { + /* + * Re-enable the lane 1 adapter we disabled at the end + * of tb_xdomain_get_properties(). + */ + tb_port_enable(down->dual_link_port); + } +} + /** * tb_xdomain_alloc() - Allocate new XDomain object * @tb: Domain where the XDomain belongs @@ -1945,7 +1994,8 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, goto err_free_local_uuid; } else { xd->needs_uuid = true; - xd->bonding_possible = !!down->dual_link_port; + + tb_xdomain_link_init(xd, down); } device_initialize(&xd->dev); @@ -2014,6 +2064,8 @@ void tb_xdomain_remove(struct tb_xdomain *xd) device_for_each_child_reverse(&xd->dev, xd, unregister_service); + tb_xdomain_link_exit(xd); + /* * Undo runtime PM here explicitly because it is possible that * the XDomain was never added to the bus and thus device_del() diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 785558c65ae8..7716ce0d35bc 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -81,7 +81,7 @@ struct serial_state { int quot; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ - int x_char; /* xon/xoff character */ + u8 x_char; /* xon/xoff character */ }; static struct tty_driver *serial_driver; @@ -178,9 +178,9 @@ static void receive_chars(struct serial_state *info) { int status; int serdatr; - unsigned char ch, flag; + u8 ch, flag; struct async_icount *icount; - int oe = 0; + bool overrun = false; icount = &info->icount; @@ -230,7 +230,7 @@ static void receive_chars(struct serial_state *info) * should be ignored. */ if (status & info->ignore_status_mask) - goto out; + return; status &= info->read_status_mask; @@ -251,15 +251,13 @@ static void receive_chars(struct serial_state *info) * reported immediately, and doesn't * affect the current character */ - oe = 1; + overrun = true; } } tty_insert_flip_char(&info->tport, ch, flag); - if (oe == 1) + if (overrun) tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN); tty_flip_buffer_push(&info->tport); -out: - return; } static void transmit_chars(struct serial_state *info) @@ -813,7 +811,7 @@ static void rs_flush_buffer(struct tty_struct *tty) * This function is used to send a high-priority XON/XOFF character to * the device */ -static void rs_send_xchar(struct tty_struct *tty, char ch) +static void rs_send_xchar(struct tty_struct *tty, u8 ch) { struct serial_state *info = tty->driver_data; unsigned long flags; diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index a067628e01c8..69508d7a4135 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -49,7 +49,7 @@ struct ehv_bc_data { unsigned int tx_irq; spinlock_t lock; /* lock for transmit buffer */ - unsigned char buf[BUF_SIZE]; /* transmit circular buffer */ + u8 buf[BUF_SIZE]; /* transmit circular buffer */ unsigned int head; /* circular buffer head */ unsigned int tail; /* circular buffer tail */ @@ -138,14 +138,17 @@ static int find_console_handle(void) static unsigned int local_ev_byte_channel_send(unsigned int handle, unsigned int *count, - const char *p) + const u8 *p) { - char buffer[EV_BYTE_CHANNEL_MAX_BYTES]; + u8 buffer[EV_BYTE_CHANNEL_MAX_BYTES]; unsigned int c = *count; + /* + * ev_byte_channel_send() expects at least EV_BYTE_CHANNEL_MAX_BYTES + * (16 B) in the buffer. Fake it using a local buffer if needed. + */ if (c < sizeof(buffer)) { - memcpy(buffer, p, c); - memset(&buffer[c], 0, sizeof(buffer) - c); + memcpy_and_pad(buffer, sizeof(buffer), p, c, 0); p = buffer; } return ev_byte_channel_send(handle, count, p); @@ -163,7 +166,7 @@ static unsigned int local_ev_byte_channel_send(unsigned int handle, * has been sent, or if some error has occurred. * */ -static void byte_channel_spin_send(const char data) +static void byte_channel_spin_send(const u8 data) { int ret, count; @@ -471,8 +474,7 @@ static ssize_t ehv_bc_tty_write(struct tty_struct *ttys, const u8 *s, { struct ehv_bc_data *bc = ttys->driver_data; unsigned long flags; - unsigned int len; - unsigned int written = 0; + size_t len, written = 0; while (1) { spin_lock_irqsave(&bc->lock, flags); diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 4591f940b7a1..d27979eabfdf 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -50,10 +50,8 @@ static u32 goldfish_tty_line_count = 8; static u32 goldfish_tty_current_line_count; static struct goldfish_tty *goldfish_ttys; -static void do_rw_io(struct goldfish_tty *qtty, - unsigned long address, - unsigned int count, - int is_write) +static void do_rw_io(struct goldfish_tty *qtty, unsigned long address, + size_t count, bool is_write) { unsigned long irq_flags; void __iomem *base = qtty->base; @@ -73,10 +71,8 @@ static void do_rw_io(struct goldfish_tty *qtty, spin_unlock_irqrestore(&qtty->lock, irq_flags); } -static void goldfish_tty_rw(struct goldfish_tty *qtty, - unsigned long addr, - unsigned int count, - int is_write) +static void goldfish_tty_rw(struct goldfish_tty *qtty, unsigned long addr, + size_t count, bool is_write) { dma_addr_t dma_handle; enum dma_data_direction dma_dir; @@ -125,20 +121,18 @@ static void goldfish_tty_rw(struct goldfish_tty *qtty, } } -static void goldfish_tty_do_write(int line, const u8 *buf, unsigned int count) +static void goldfish_tty_do_write(int line, const u8 *buf, size_t count) { struct goldfish_tty *qtty = &goldfish_ttys[line]; - unsigned long address = (unsigned long)(void *)buf; - goldfish_tty_rw(qtty, address, count, 1); + goldfish_tty_rw(qtty, (unsigned long)buf, count, true); } static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) { struct goldfish_tty *qtty = dev_id; void __iomem *base = qtty->base; - unsigned long address; - unsigned char *buf; + u8 *buf; u32 count; count = gf_ioread32(base + GOLDFISH_TTY_REG_BYTES_READY); @@ -147,8 +141,7 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) count = tty_prepare_flip_string(&qtty->port, &buf, count); - address = (unsigned long)(void *)buf; - goldfish_tty_rw(qtty, address, count, 0); + goldfish_tty_rw(qtty, (unsigned long)buf, count, false); tty_flip_buffer_push(&qtty->port); return IRQ_HANDLED; diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 959fae54ca39..cd1f657f782d 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -922,8 +922,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, return ERR_PTR(err); } - hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, - GFP_KERNEL); + hp = kzalloc(struct_size(hp, outbuf, outbuf_size), GFP_KERNEL); if (!hp) return ERR_PTR(-ENOMEM); @@ -931,7 +930,6 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, hp->data = data; hp->ops = ops; hp->outbuf_size = outbuf_size; - hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; tty_port_init(&hp->port); hp->port.ops = &hvc_port_ops; @@ -976,7 +974,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, } EXPORT_SYMBOL_GPL(hvc_alloc); -int hvc_remove(struct hvc_struct *hp) +void hvc_remove(struct hvc_struct *hp) { unsigned long flags; struct tty_struct *tty; @@ -1010,7 +1008,6 @@ int hvc_remove(struct hvc_struct *hp) tty_vhangup(tty); tty_kref_put(tty); } - return 0; } EXPORT_SYMBOL_GPL(hvc_remove); diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index f990c5094d20..d2aa2a56b566 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -37,7 +37,6 @@ struct hvc_struct { spinlock_t lock; int index; int do_wakeup; - char *outbuf; int outbuf_size; int n_outbuf; uint32_t vtermno; @@ -48,12 +47,13 @@ struct hvc_struct { struct work_struct tty_resize; struct list_head next; unsigned long flags; + u8 outbuf[] __aligned(sizeof(long)); }; /* implemented by a low level driver */ struct hv_ops { - int (*get_chars)(uint32_t vtermno, char *buf, int count); - int (*put_chars)(uint32_t vtermno, const char *buf, int count); + ssize_t (*get_chars)(uint32_t vtermno, u8 *buf, size_t count); + ssize_t (*put_chars)(uint32_t vtermno, const u8 *buf, size_t count); int (*flush)(uint32_t vtermno, bool wait); /* Callbacks for notification. Called in open, close and hangup */ @@ -77,7 +77,7 @@ extern int hvc_instantiate(uint32_t vtermno, int index, extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data, const struct hv_ops *ops, int outbuf_size); /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ -extern int hvc_remove(struct hvc_struct *hp); +extern void hvc_remove(struct hvc_struct *hp); /* data available */ int hvc_poll(struct hvc_struct *hp); diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c index 3cbd441af88f..831d4be23e80 100644 --- a/drivers/tty/hvc/hvc_dcc.c +++ b/drivers/tty/hvc/hvc_dcc.c @@ -34,10 +34,10 @@ module_param(enable, bool, 0444); /* Lock to serialize access to DCC fifo */ static DEFINE_SPINLOCK(dcc_lock); -static DEFINE_KFIFO(inbuf, unsigned char, DCC_INBUF_SIZE); -static DEFINE_KFIFO(outbuf, unsigned char, DCC_OUTBUF_SIZE); +static DEFINE_KFIFO(inbuf, u8, DCC_INBUF_SIZE); +static DEFINE_KFIFO(outbuf, u8, DCC_OUTBUF_SIZE); -static void dcc_uart_console_putchar(struct uart_port *port, unsigned char ch) +static void dcc_uart_console_putchar(struct uart_port *port, u8 ch) { while (__dcc_getstatus() & DCC_STATUS_TX) cpu_relax(); @@ -55,6 +55,14 @@ static void dcc_early_write(struct console *con, const char *s, unsigned n) static int __init dcc_early_console_setup(struct earlycon_device *device, const char *opt) { + unsigned int count = 0x4000000; + + while (--count && (__dcc_getstatus() & DCC_STATUS_TX)) + cpu_relax(); + + if (__dcc_getstatus() & DCC_STATUS_TX) + return -ENODEV; + device->con->write = dcc_early_write; return 0; @@ -62,9 +70,9 @@ static int __init dcc_early_console_setup(struct earlycon_device *device, EARLYCON_DECLARE(dcc, dcc_early_console_setup); -static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) +static ssize_t hvc_dcc_put_chars(uint32_t vt, const u8 *buf, size_t count) { - int i; + size_t i; for (i = 0; i < count; i++) { while (__dcc_getstatus() & DCC_STATUS_TX) @@ -76,9 +84,9 @@ static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) return count; } -static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count) +static ssize_t hvc_dcc_get_chars(uint32_t vt, u8 *buf, size_t count) { - int i; + size_t i; for (i = 0; i < count; ++i) if (__dcc_getstatus() & DCC_STATUS_RX) @@ -157,8 +165,8 @@ static DECLARE_WORK(dcc_pwork, dcc_put_work); */ static void dcc_get_work(struct work_struct *work) { - unsigned char ch; unsigned long irqflags; + u8 ch; /* * Read characters from DCC and put them into the input FIFO, as @@ -180,10 +188,10 @@ static DECLARE_WORK(dcc_gwork, dcc_get_work); * Write characters directly to the DCC if we're on core 0 and the FIFO * is empty, or write them to the FIFO if we're not. */ -static int hvc_dcc0_put_chars(u32 vt, const char *buf, int count) +static ssize_t hvc_dcc0_put_chars(u32 vt, const u8 *buf, size_t count) { - int len; unsigned long irqflags; + ssize_t len; if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP)) return hvc_dcc_put_chars(vt, buf, count); @@ -219,10 +227,10 @@ static int hvc_dcc0_put_chars(u32 vt, const char *buf, int count) * Read characters directly from the DCC if we're on core 0 and the FIFO * is empty, or read them from the FIFO if we're not. */ -static int hvc_dcc0_get_chars(u32 vt, char *buf, int count) +static ssize_t hvc_dcc0_get_chars(u32 vt, u8 *buf, size_t count) { - int len; unsigned long irqflags; + ssize_t len; if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP)) return hvc_dcc_get_chars(vt, buf, count); diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 543f35ddf523..fdecc0d63731 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -215,11 +215,11 @@ static void destroy_tty_buffer_list(struct list_head *list) * If the IUCV path has been severed, then -EPIPE is returned to cause a * hang up (that is issued by the HVC layer). */ -static int hvc_iucv_write(struct hvc_iucv_private *priv, - char *buf, int count, int *has_more_data) +static ssize_t hvc_iucv_write(struct hvc_iucv_private *priv, + u8 *buf, size_t count, int *has_more_data) { struct iucv_tty_buffer *rb; - int written; + ssize_t written; int rc; /* immediately return if there is no IUCV connection */ @@ -312,10 +312,10 @@ out_written: * the routine locks the struct hvc_iucv_private->lock to call * helper functions. */ -static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count) +static ssize_t hvc_iucv_get_chars(uint32_t vtermno, u8 *buf, size_t count) { struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); - int written; + ssize_t written; int has_more_data; if (count <= 0) @@ -352,8 +352,8 @@ static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count) * If an existing IUCV communicaton path has been severed, -EPIPE is returned * (that can be passed to HVC layer to cause a tty hangup). */ -static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf, - int count) +static ssize_t hvc_iucv_queue(struct hvc_iucv_private *priv, const u8 *buf, + size_t count) { size_t len; @@ -455,12 +455,12 @@ static void hvc_iucv_sndbuf_work(struct work_struct *work) * Locking: The method gets called under an irqsave() spinlock; and * locks struct hvc_iucv_private->lock. */ -static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) +static ssize_t hvc_iucv_put_chars(uint32_t vtermno, const u8 *buf, size_t count) { struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); int queued; - if (count <= 0) + if (!count) return 0; if (!priv) diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 992e199e0ea8..095c33ad10f8 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -58,7 +58,7 @@ static const struct hv_ops hvc_opal_raw_ops = { .notifier_hangup = notifier_hangup_irq, }; -static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count) +static ssize_t hvc_opal_hvsi_get_chars(uint32_t vtermno, u8 *buf, size_t count) { struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; @@ -68,7 +68,8 @@ static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count) return hvsilib_get_chars(&pv->hvsi, buf, count); } -static int hvc_opal_hvsi_put_chars(uint32_t vtermno, const char *buf, int count) +static ssize_t hvc_opal_hvsi_put_chars(uint32_t vtermno, const u8 *buf, + size_t count) { struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; @@ -232,24 +233,21 @@ static int hvc_opal_probe(struct platform_device *dev) return 0; } -static int hvc_opal_remove(struct platform_device *dev) +static void hvc_opal_remove(struct platform_device *dev) { struct hvc_struct *hp = dev_get_drvdata(&dev->dev); - int rc, termno; + int termno; termno = hp->vtermno; - rc = hvc_remove(hp); - if (rc == 0) { - if (hvc_opal_privs[termno] != &hvc_opal_boot_priv) - kfree(hvc_opal_privs[termno]); - hvc_opal_privs[termno] = NULL; - } - return rc; + hvc_remove(hp); + if (hvc_opal_privs[termno] != &hvc_opal_boot_priv) + kfree(hvc_opal_privs[termno]); + hvc_opal_privs[termno] = NULL; } static struct platform_driver hvc_opal_driver = { .probe = hvc_opal_probe, - .remove = hvc_opal_remove, + .remove_new = hvc_opal_remove, .driver = { .name = hvc_opal_name, .of_match_table = hvc_opal_match, diff --git a/drivers/tty/hvc/hvc_riscv_sbi.c b/drivers/tty/hvc/hvc_riscv_sbi.c index 31f53fa77e4a..a72591279f86 100644 --- a/drivers/tty/hvc/hvc_riscv_sbi.c +++ b/drivers/tty/hvc/hvc_riscv_sbi.c @@ -15,9 +15,9 @@ #include "hvc_console.h" -static int hvc_sbi_tty_put(uint32_t vtermno, const char *buf, int count) +static ssize_t hvc_sbi_tty_put(uint32_t vtermno, const u8 *buf, size_t count) { - int i; + size_t i; for (i = 0; i < count; i++) sbi_console_putchar(buf[i]); @@ -25,9 +25,10 @@ static int hvc_sbi_tty_put(uint32_t vtermno, const char *buf, int count) return i; } -static int hvc_sbi_tty_get(uint32_t vtermno, char *buf, int count) +static ssize_t hvc_sbi_tty_get(uint32_t vtermno, u8 *buf, size_t count) { - int i, c; + size_t i; + int c; for (i = 0; i < count; i++) { c = sbi_console_getchar(); diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c index 184d325abeed..a0b90275b37f 100644 --- a/drivers/tty/hvc/hvc_rtas.c +++ b/drivers/tty/hvc/hvc_rtas.c @@ -31,10 +31,10 @@ static struct hvc_struct *hvc_rtas_dev; static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE; static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE; -static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, - int count) +static ssize_t hvc_rtas_write_console(uint32_t vtermno, const u8 *buf, + size_t count) { - int i; + size_t i; for (i = 0; i < count; i++) { if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i])) @@ -44,9 +44,10 @@ static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, return i; } -static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) +static ssize_t hvc_rtas_read_console(uint32_t vtermno, u8 *buf, size_t count) { - int i, c; + size_t i; + int c; for (i = 0; i < count; i++) { if (rtas_call(rtascons_get_char_token, 0, 2, &c)) diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index ff0dcc56413c..fdc2699b78dc 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/drivers/tty/hvc/hvc_udbg.c @@ -19,9 +19,9 @@ static struct hvc_struct *hvc_udbg_dev; -static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) +static ssize_t hvc_udbg_put(uint32_t vtermno, const u8 *buf, size_t count) { - int i; + size_t i; for (i = 0; i < count && udbg_putc; i++) udbg_putc(buf[i]); @@ -29,9 +29,10 @@ static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) return i; } -static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) +static ssize_t hvc_udbg_get(uint32_t vtermno, u8 *buf, size_t count) { - int i, c; + size_t i; + int c; if (!udbg_getc_poll) return 0; diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 736b230f5ec0..47930601a26a 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -58,20 +58,20 @@ struct hvterm_priv { hv_protocol_t proto; /* Raw data or HVSI packets */ struct hvsi_priv hvsi; /* HVSI specific data */ spinlock_t buf_lock; - char buf[SIZE_VIO_GET_CHARS]; - int left; - int offset; + u8 buf[SIZE_VIO_GET_CHARS]; + size_t left; + size_t offset; }; static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES]; /* For early boot console */ static struct hvterm_priv hvterm_priv0; -static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count) +static ssize_t hvterm_raw_get_chars(uint32_t vtermno, u8 *buf, size_t count) { struct hvterm_priv *pv = hvterm_privs[vtermno]; unsigned long i; unsigned long flags; - int got; + size_t got; if (WARN_ON(!pv)) return 0; @@ -115,7 +115,8 @@ static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count) * you are sending fewer chars. * @count: number of chars to send. */ -static int hvterm_raw_put_chars(uint32_t vtermno, const char *buf, int count) +static ssize_t hvterm_raw_put_chars(uint32_t vtermno, const u8 *buf, + size_t count) { struct hvterm_priv *pv = hvterm_privs[vtermno]; @@ -133,7 +134,7 @@ static const struct hv_ops hvterm_raw_ops = { .notifier_hangup = notifier_hangup_irq, }; -static int hvterm_hvsi_get_chars(uint32_t vtermno, char *buf, int count) +static ssize_t hvterm_hvsi_get_chars(uint32_t vtermno, u8 *buf, size_t count) { struct hvterm_priv *pv = hvterm_privs[vtermno]; @@ -143,7 +144,8 @@ static int hvterm_hvsi_get_chars(uint32_t vtermno, char *buf, int count) return hvsilib_get_chars(&pv->hvsi, buf, count); } -static int hvterm_hvsi_put_chars(uint32_t vtermno, const char *buf, int count) +static ssize_t hvterm_hvsi_put_chars(uint32_t vtermno, const u8 *buf, + size_t count) { struct hvterm_priv *pv = hvterm_privs[vtermno]; diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 34c01874f45b..0e497501f8e3 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -84,13 +84,13 @@ static inline void notify_daemon(struct xencons_info *cons) notify_remote_via_evtchn(cons->evtchn); } -static int __write_console(struct xencons_info *xencons, - const char *data, int len) +static ssize_t __write_console(struct xencons_info *xencons, + const u8 *data, size_t len) { XENCONS_RING_IDX cons, prod; struct xencons_interface *intf = xencons->intf; - int sent = 0; unsigned long flags; + size_t sent = 0; spin_lock_irqsave(&xencons->ring_lock, flags); cons = intf->out_cons; @@ -115,10 +115,11 @@ static int __write_console(struct xencons_info *xencons, return sent; } -static int domU_write_console(uint32_t vtermno, const char *data, int len) +static ssize_t domU_write_console(uint32_t vtermno, const u8 *data, size_t len) { - int ret = len; struct xencons_info *cons = vtermno_to_xencons(vtermno); + size_t ret = len; + if (cons == NULL) return -EINVAL; @@ -129,7 +130,7 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len) * kernel is crippled. */ while (len) { - int sent = __write_console(cons, data, len); + ssize_t sent = __write_console(cons, data, len); if (sent < 0) return sent; @@ -144,14 +145,14 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len) return ret; } -static int domU_read_console(uint32_t vtermno, char *buf, int len) +static ssize_t domU_read_console(uint32_t vtermno, u8 *buf, size_t len) { struct xencons_interface *intf; XENCONS_RING_IDX cons, prod; - int recv = 0; struct xencons_info *xencons = vtermno_to_xencons(vtermno); unsigned int eoiflag = 0; unsigned long flags; + size_t recv = 0; if (xencons == NULL) return -EINVAL; @@ -209,7 +210,7 @@ static const struct hv_ops domU_hvc_ops = { .notifier_hangup = notifier_hangup_irq, }; -static int dom0_read_console(uint32_t vtermno, char *buf, int len) +static ssize_t dom0_read_console(uint32_t vtermno, u8 *buf, size_t len) { return HYPERVISOR_console_io(CONSOLEIO_read, len, buf); } @@ -218,9 +219,9 @@ static int dom0_read_console(uint32_t vtermno, char *buf, int len) * Either for a dom0 to write to the system console, or a domU with a * debug version of Xen */ -static int dom0_write_console(uint32_t vtermno, const char *str, int len) +static ssize_t dom0_write_console(uint32_t vtermno, const u8 *str, size_t len) { - int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); + int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (u8 *)str); if (rc < 0) return rc; diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 09289c8154ae..22e1bc4d8a66 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -12,7 +12,7 @@ static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet) packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno)); /* Assumes that always succeeds, works in practice */ - return pv->put_chars(pv->termno, (char *)packet, packet->len); + return pv->put_chars(pv->termno, (u8 *)packet, packet->len); } static void hvsi_start_handshake(struct hvsi_priv *pv) @@ -178,9 +178,10 @@ static int hvsi_get_packet(struct hvsi_priv *pv) return 0; } -int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) +ssize_t hvsilib_get_chars(struct hvsi_priv *pv, u8 *buf, size_t count) { - unsigned int tries, read = 0; + unsigned int tries; + size_t read = 0; if (WARN_ON(!pv)) return -ENXIO; @@ -199,7 +200,7 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) for (tries = 1; count && tries < 2; tries++) { /* Consume existing data packet */ if (pv->inbuf_pktlen) { - unsigned int l = min(count, (int)pv->inbuf_pktlen); + size_t l = min(count, pv->inbuf_pktlen); memcpy(&buf[read], &pv->inbuf[pv->inbuf_cur], l); pv->inbuf_cur += l; pv->inbuf_pktlen -= l; @@ -228,10 +229,11 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) return read; } -int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count) +ssize_t hvsilib_put_chars(struct hvsi_priv *pv, const u8 *buf, size_t count) { struct hvsi_data dp; - int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA); + size_t adjcount = min_t(size_t, count, HVSI_MAX_OUTGOING_DATA); + int rc; if (WARN_ON(!pv)) return -ENODEV; @@ -411,9 +413,9 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp) } void hvsilib_init(struct hvsi_priv *pv, - int (*get_chars)(uint32_t termno, char *buf, int count), - int (*put_chars)(uint32_t termno, const char *buf, - int count), + ssize_t (*get_chars)(uint32_t termno, u8 *buf, size_t count), + ssize_t (*put_chars)(uint32_t termno, const u8 *buf, + size_t count), int termno, int is_console) { memset(pv, 0, sizeof(*pv)); diff --git a/drivers/tty/ipwireless/main.h b/drivers/tty/ipwireless/main.h index 73818bb64416..a5728a5b3f83 100644 --- a/drivers/tty/ipwireless/main.h +++ b/drivers/tty/ipwireless/main.h @@ -49,9 +49,6 @@ struct ipw_dev { void __iomem *common_memory; - /* Reference to attribute memory, containing CIS data */ - void *attribute_memory; - /* Hardware context */ struct ipw_hardware *hardware; /* Network layer context */ diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 369ec71c24ef..aac80b69a069 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -213,16 +213,16 @@ struct fdc_word { */ /* ranges >= 1 && sizes[0] >= 1 */ -static struct fdc_word mips_ejtag_fdc_encode(const char **ptrs, +static struct fdc_word mips_ejtag_fdc_encode(const u8 **ptrs, unsigned int *sizes, unsigned int ranges) { struct fdc_word word = { 0, 0 }; - const char **ptrs_end = ptrs + ranges; + const u8 **ptrs_end = ptrs + ranges; for (; ptrs < ptrs_end; ++ptrs) { - const char *ptr = *(ptrs++); - const char *end = ptr + *(sizes++); + const u8 *ptr = *(ptrs++); + const u8 *end = ptr + *(sizes++); for (; ptr < end; ++ptr) { word.word |= (u8)*ptr << (8*word.bytes); @@ -417,7 +417,7 @@ static unsigned int mips_ejtag_fdc_put_chan(struct mips_ejtag_fdc_tty *priv, { struct mips_ejtag_fdc_tty_port *dport; struct tty_struct *tty; - const char *ptrs[2]; + const u8 *ptrs[2]; unsigned int sizes[2] = { 0 }; struct fdc_word word = { .bytes = 0 }; unsigned long flags; diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index bf3f87ba3a92..ebaada8db929 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -514,7 +514,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, bool, bool); static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); static int MoxaPortLineStatus(struct moxa_port *); static void MoxaPortFlushData(struct moxa_port *, int); -static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); +static ssize_t MoxaPortWriteData(struct tty_struct *, const u8 *, size_t); static int MoxaPortReadData(struct moxa_port *); static unsigned int MoxaPortTxQueue(struct moxa_port *); static int MoxaPortRxQueue(struct moxa_port *); @@ -1933,10 +1933,10 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode) * * Function 20: Write data. * Syntax: - * int MoxaPortWriteData(int port, unsigned char * buffer, int length); + * ssize_t MoxaPortWriteData(int port, u8 *buffer, size_t length); * int port : port number (0 - 127) - * unsigned char * buffer : pointer to write data buffer. - * int length : write data length + * u8 *buffer : pointer to write data buffer. + * size_t length : write data length * * return: 0 - length : real write data length * @@ -2163,11 +2163,12 @@ static int MoxaPortLineStatus(struct moxa_port *port) return val; } -static int MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer, int len) +static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer, + size_t len) { struct moxa_port *port = tty->driver_data; void __iomem *baseAddr, *ofsAddr, *ofs; - unsigned int c, total; + size_t c, total; u16 head, tail, tx_mask, spage, epage; u16 pageno, pageofs, bufhead; @@ -2224,8 +2225,8 @@ static int MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer, int len) static int MoxaPortReadData(struct moxa_port *port) { struct tty_struct *tty = port->port.tty; - unsigned char *dst; void __iomem *baseAddr, *ofsAddr, *ofs; + u8 *dst; unsigned int count, len, total; u16 tail, rx_mask, spage, epage; u16 pageno, pageofs, bufhead, head; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 6ce7f259968f..458bb1280ebf 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -264,7 +264,7 @@ struct mxser_port { u8 rx_low_water; int type; /* UART type */ - unsigned char x_char; /* xon/xoff character */ + u8 x_char; /* xon/xoff character */ u8 IER; /* Interrupt Enable Register */ u8 MCR; /* Modem control register */ u8 FCR; /* FIFO control register */ @@ -905,7 +905,7 @@ static ssize_t mxser_write(struct tty_struct *tty, const u8 *buf, size_t count) { struct mxser_port *info = tty->driver_data; unsigned long flags; - int written; + size_t written; bool is_empty; spin_lock_irqsave(&info->slock, flags); @@ -1521,7 +1521,7 @@ static u8 mxser_receive_chars_old(struct tty_struct *tty, if (++ignored > 100) break; } else { - char flag = 0; + u8 flag = 0; if (status & UART_LSR_BRK_ERROR_BITS) { if (status & UART_LSR_BI) { flag = TTY_BREAK; @@ -1585,7 +1585,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port count = port->xmit_fifo_size; do { - unsigned char c; + u8 c; if (!kfifo_get(&port->port.xmit_fifo, &c)) break; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index a3ab3946e4ad..4036566febcb 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -124,8 +124,8 @@ struct gsm_msg { u8 addr; /* DLCI address + flags */ u8 ctrl; /* Control byte + flags */ unsigned int len; /* Length of data block (can be zero) */ - unsigned char *data; /* Points into buffer but not at the start */ - unsigned char buffer[]; + u8 *data; /* Points into buffer but not at the start */ + u8 buffer[]; }; enum gsm_dlci_state { @@ -283,7 +283,7 @@ struct gsm_mux { /* Bits for GSM mode decoding */ /* Framing Layer */ - unsigned char *buf; + u8 *buf; enum gsm_mux_state state; unsigned int len; unsigned int address; @@ -2856,7 +2856,7 @@ invalid: * Receive bytes in gsm mode 0 */ -static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) +static void gsm0_receive(struct gsm_mux *gsm, u8 c) { unsigned int len; @@ -2947,7 +2947,7 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) * Receive bytes in mode 1 (Advanced option) */ -static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) +static void gsm1_receive(struct gsm_mux *gsm, u8 c) { /* handle XON/XOFF */ if ((c & ISO_IEC_646_MASK) == XON) { @@ -3541,7 +3541,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp, size_t count) { struct gsm_mux *gsm = tty->disc_data; - char flags = TTY_NORMAL; + u8 flags = TTY_NORMAL; if (debug & DBG_DATA) gsm_hex_dump_bytes(__func__, cp, count); @@ -3711,7 +3711,7 @@ static ssize_t gsmld_write(struct tty_struct *tty, struct file *file, { struct gsm_mux *gsm = tty->disc_data; unsigned long flags; - int space; + size_t space; int ret; if (!gsm) @@ -3909,8 +3909,7 @@ static void gsm_mux_net_tx_timeout(struct net_device *net, unsigned int txqueue) net->stats.tx_errors++; } -static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, - const unsigned char *in_buf, int size) +static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, const u8 *in_buf, int size) { struct net_device *net = dlci->net; struct sk_buff *skb; diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index a670419efe79..1615f074ab86 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -109,8 +109,8 @@ struct n_hdlc_buf { struct list_head list_item; - int count; - char buf[]; + size_t count; + u8 buf[]; }; struct n_hdlc_buf_list { @@ -263,9 +263,9 @@ static int n_hdlc_tty_open(struct tty_struct *tty) */ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) { - register int actual; unsigned long flags; struct n_hdlc_buf *tbuf; + ssize_t actual; check_again: @@ -281,7 +281,7 @@ check_again: tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); while (tbuf) { - pr_debug("sending frame %p, count=%d\n", tbuf, tbuf->count); + pr_debug("sending frame %p, count=%zu\n", tbuf, tbuf->count); /* Send the next block of data to device */ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); @@ -521,9 +521,9 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, const u8 *data, size_t count) { struct n_hdlc *n_hdlc = tty->disc_data; - int error = 0; DECLARE_WAITQUEUE(wait, current); struct n_hdlc_buf *tbuf; + ssize_t error = 0; pr_debug("%s() called count=%zd\n", __func__, count); diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 02cd40147b3a..e28a921c1637 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -65,24 +65,8 @@ do { \ #define DBG3(args...) DBG_(0x04, ##args) #define DBG4(args...) DBG_(0x08, ##args) -/* TODO: rewrite to optimize macros... */ - #define TMP_BUF_MAX 256 -#define DUMP(buf__, len__) \ - do { \ - char tbuf[TMP_BUF_MAX] = {0}; \ - if (len__ > 1) { \ - u32 data_len = min_t(u32, len__, TMP_BUF_MAX); \ - strscpy(tbuf, buf__, data_len); \ - if (tbuf[data_len - 2] == '\r') \ - tbuf[data_len - 2] = 'r'; \ - DBG1("SENDING: '%s' (%d+n)", tbuf, len__); \ - } else { \ - DBG1("SENDING: '%s' (%d)", tbuf, len__); \ - } \ - } while (0) - /* Defines */ #define NOZOMI_NAME "nozomi" #define NOZOMI_NAME_TTY "nozomi_tty" @@ -754,8 +738,6 @@ static int send_data(enum port_type index, struct nozomi *dc) return 0; } - /* DUMP(buf, size); */ - /* Write length + data */ write_mem32(addr, (u32 *) &size, 4); write_mem32(addr + 4, (u32 *) dc->send_buf, size); @@ -801,11 +783,10 @@ static int receive_data(enum port_type index, struct nozomi *dc) tty_insert_flip_char(&port->port, buf[0], TTY_NORMAL); size = 0; } else if (size < RECEIVE_BUF_MAX) { - size -= tty_insert_flip_string(&port->port, - (char *)buf, size); + size -= tty_insert_flip_string(&port->port, buf, size); } else { - i = tty_insert_flip_string(&port->port, - (char *)buf, RECEIVE_BUF_MAX); + i = tty_insert_flip_string(&port->port, buf, + RECEIVE_BUF_MAX); size -= i; offset += i; } @@ -1602,10 +1583,10 @@ static void ntty_hangup(struct tty_struct *tty) static ssize_t ntty_write(struct tty_struct *tty, const u8 *buffer, size_t count) { - int rval = -EINVAL; struct nozomi *dc = get_dc_by_tty(tty); struct port *port = tty->driver_data; unsigned long flags; + size_t rval; if (!dc || !port) return -ENODEV; diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index a5fdaf5e148e..822a5cd05566 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -77,7 +77,7 @@ static bool is_serdev_device(const struct device *dev) static void serdev_ctrl_release(struct device *dev) { struct serdev_controller *ctrl = to_serdev_controller(dev); - ida_simple_remove(&ctrl_ida, ctrl->nr); + ida_free(&ctrl_ida, ctrl->nr); kfree(ctrl); } @@ -225,8 +225,7 @@ EXPORT_SYMBOL_GPL(serdev_device_write_wakeup); * Return: The number of bytes written (less than count if not enough room in * the write buffer), or a negative errno on errors. */ -int serdev_device_write_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t count) +int serdev_device_write_buf(struct serdev_device *serdev, const u8 *buf, size_t count) { struct serdev_controller *ctrl = serdev->ctrl; @@ -259,13 +258,12 @@ EXPORT_SYMBOL_GPL(serdev_device_write_buf); * -ETIMEDOUT or -ERESTARTSYS if interrupted before any bytes were written, or * a negative errno on errors. */ -int serdev_device_write(struct serdev_device *serdev, - const unsigned char *buf, size_t count, - long timeout) +ssize_t serdev_device_write(struct serdev_device *serdev, const u8 *buf, + size_t count, long timeout) { struct serdev_controller *ctrl = serdev->ctrl; - int written = 0; - int ret; + size_t written = 0; + ssize_t ret; if (!ctrl || !ctrl->ops->write_buf || !serdev->ops->write_wakeup) return -EINVAL; @@ -468,6 +466,7 @@ EXPORT_SYMBOL_GPL(serdev_device_alloc); /** * serdev_controller_alloc() - Allocate a new serdev controller + * @host: serial port hardware controller device * @parent: parent device * @size: size of private data * @@ -476,8 +475,9 @@ EXPORT_SYMBOL_GPL(serdev_device_alloc); * The allocated private data region may be accessed via * serdev_controller_get_drvdata() */ -struct serdev_controller *serdev_controller_alloc(struct device *parent, - size_t size) +struct serdev_controller *serdev_controller_alloc(struct device *host, + struct device *parent, + size_t size) { struct serdev_controller *ctrl; int id; @@ -489,7 +489,7 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent, if (!ctrl) return NULL; - id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL); + id = ida_alloc(&ctrl_ida, GFP_KERNEL); if (id < 0) { dev_err(parent, "unable to allocate serdev controller identifier.\n"); @@ -502,7 +502,8 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent, ctrl->dev.type = &serdev_ctrl_type; ctrl->dev.bus = &serdev_bus_type; ctrl->dev.parent = parent; - device_set_node(&ctrl->dev, dev_fwnode(parent)); + ctrl->host = host; + device_set_node(&ctrl->dev, dev_fwnode(host)); serdev_controller_set_drvdata(ctrl, &ctrl[1]); dev_set_name(&ctrl->dev, "serial%d", id); @@ -665,7 +666,7 @@ static int acpi_serdev_check_resources(struct serdev_controller *ctrl, acpi_get_parent(adev->handle, &lookup.controller_handle); /* Make sure controller and ResourceSource handle match */ - if (!device_match_acpi_handle(ctrl->dev.parent, lookup.controller_handle)) + if (!device_match_acpi_handle(ctrl->host, lookup.controller_handle)) return -ENODEV; return 0; @@ -730,7 +731,7 @@ static int acpi_serdev_register_devices(struct serdev_controller *ctrl) bool skip; int ret; - if (!has_acpi_companion(ctrl->dev.parent)) + if (!has_acpi_companion(ctrl->host)) return -ENODEV; /* @@ -739,7 +740,7 @@ static int acpi_serdev_register_devices(struct serdev_controller *ctrl) * succeed in this case, so that the proper serdev devices can be * added "manually" later. */ - ret = acpi_quirk_skip_serdev_enumeration(ctrl->dev.parent, &skip); + ret = acpi_quirk_skip_serdev_enumeration(ctrl->host, &skip); if (ret) return ret; if (skip) diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index e3856814ce77..e94e090cf0a1 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -74,7 +74,7 @@ static const struct tty_port_client_operations client_ops = { * Callback functions from the serdev core. */ -static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len) +static ssize_t ttyport_write_buf(struct serdev_controller *ctrl, const u8 *data, size_t len) { struct serport *serport = serdev_controller_get_drvdata(ctrl); struct tty_struct *tty = serport->tty; @@ -274,6 +274,7 @@ static const struct serdev_controller_ops ctrl_ops = { }; struct device *serdev_tty_port_register(struct tty_port *port, + struct device *host, struct device *parent, struct tty_driver *drv, int idx) { @@ -284,7 +285,7 @@ struct device *serdev_tty_port_register(struct tty_port *port, if (!port || !drv || !parent) return ERR_PTR(-ENODEV); - ctrl = serdev_controller_alloc(parent, sizeof(struct serport)); + ctrl = serdev_controller_alloc(host, parent, sizeof(struct serport)); if (!ctrl) return ERR_PTR(-ENOMEM); serport = serdev_controller_get_drvdata(ctrl); diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index d7482ae33a1c..8c2aaf7af7b7 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -566,7 +566,7 @@ err_sysfs_remove: return rc; } -static int aspeed_vuart_remove(struct platform_device *pdev) +static void aspeed_vuart_remove(struct platform_device *pdev) { struct aspeed_vuart *vuart = platform_get_drvdata(pdev); @@ -574,8 +574,6 @@ static int aspeed_vuart_remove(struct platform_device *pdev) aspeed_vuart_set_enabled(vuart, false); serial8250_unregister_port(vuart->line); sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); - - return 0; } static const struct of_device_id aspeed_vuart_table[] = { @@ -590,7 +588,7 @@ static struct platform_driver aspeed_vuart_driver = { .of_match_table = aspeed_vuart_table, }, .probe = aspeed_vuart_probe, - .remove = aspeed_vuart_remove, + .remove_new = aspeed_vuart_remove, }; module_platform_driver(aspeed_vuart_driver); diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index 15a2387a5b25..beac6b340ace 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -119,6 +119,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) /* get the clock - this also enables the HW */ data->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(data->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n"); /* get the interrupt */ ret = platform_get_irq(pdev, 0); @@ -195,14 +197,12 @@ dis_clk: return ret; } -static int bcm2835aux_serial_remove(struct platform_device *pdev) +static void bcm2835aux_serial_remove(struct platform_device *pdev) { struct bcm2835aux_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk); - - return 0; } static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = { @@ -228,7 +228,7 @@ static struct platform_driver bcm2835aux_serial_driver = { .acpi_match_table = bcm2835aux_serial_acpi_match, }, .probe = bcm2835aux_serial_probe, - .remove = bcm2835aux_serial_remove, + .remove_new = bcm2835aux_serial_remove, }; module_platform_driver(bcm2835aux_serial_driver); diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 55dea2539c47..504c4c020857 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -1121,7 +1121,7 @@ release_dma: return ret; } -static int brcmuart_remove(struct platform_device *pdev) +static void brcmuart_remove(struct platform_device *pdev) { struct brcmuart_priv *priv = platform_get_drvdata(pdev); @@ -1131,7 +1131,6 @@ static int brcmuart_remove(struct platform_device *pdev) brcmuart_free_bufs(&pdev->dev, priv); if (priv->dma_enabled) brcmuart_arbitration(priv, 0); - return 0; } static int __maybe_unused brcmuart_suspend(struct device *dev) @@ -1207,7 +1206,7 @@ static struct platform_driver brcmuart_platform_driver = { .of_match_table = brcmuart_dt_ids, }, .probe = brcmuart_probe, - .remove = brcmuart_remove, + .remove_new = brcmuart_remove, }; static int __init brcmuart_init(void) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 912733151858..b62ad9006780 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -883,7 +883,7 @@ static int serial8250_probe(struct platform_device *dev) /* * Remove serial ports registered against a platform device. */ -static int serial8250_remove(struct platform_device *dev) +static void serial8250_remove(struct platform_device *dev) { int i; @@ -893,7 +893,6 @@ static int serial8250_remove(struct platform_device *dev) if (up->port.dev == &dev->dev) serial8250_unregister_port(i); } - return 0; } static int serial8250_suspend(struct platform_device *dev, pm_message_t state) @@ -926,7 +925,7 @@ static int serial8250_resume(struct platform_device *dev) static struct platform_driver serial8250_isa_driver = { .probe = serial8250_probe, - .remove = serial8250_remove, + .remove_new = serial8250_remove, .suspend = serial8250_suspend, .resume = serial8250_resume, .driver = { diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index e6218766d0c8..2d1f350a4bea 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -663,7 +663,7 @@ static int dw8250_probe(struct platform_device *pdev) return 0; } -static int dw8250_remove(struct platform_device *pdev) +static void dw8250_remove(struct platform_device *pdev) { struct dw8250_data *data = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -680,8 +680,6 @@ static int dw8250_remove(struct platform_device *pdev) pm_runtime_disable(dev); pm_runtime_put_noidle(dev); - - return 0; } static int dw8250_suspend(struct device *dev) @@ -790,7 +788,7 @@ static struct platform_driver dw8250_platform_driver = { .acpi_match_table = dw8250_acpi_match, }, .probe = dw8250_probe, - .remove = dw8250_remove, + .remove_new = dw8250_remove, }; module_platform_driver(dw8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index 84843e204a5e..3e33ddf7bc80 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -259,17 +259,6 @@ void dw8250_setup_port(struct uart_port *p) } up->capabilities |= UART_CAP_NOTEMT; - /* - * If the Component Version Register returns zero, we know that - * ADDITIONAL_FEATURES are not enabled. No need to go any further. - */ - reg = dw8250_readl_ext(p, DW_UART_UCV); - if (!reg) - return; - - dev_dbg(p->dev, "Designware UART version %c.%c%c\n", - (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); - /* Preserve value written by firmware or bootloader */ old_dlf = dw8250_readl_ext(p, DW_UART_DLF); dw8250_writel_ext(p, DW_UART_DLF, ~0U); @@ -282,6 +271,11 @@ void dw8250_setup_port(struct uart_port *p) p->set_divisor = dw8250_set_divisor; } + reg = dw8250_readl_ext(p, DW_UART_UCV); + if (reg) + dev_dbg(p->dev, "Designware UART version %c.%c%c\n", + (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); + reg = dw8250_readl_ext(p, DW_UART_CPR); if (!reg) { reg = data->pdata->cpr_val; diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index ef5019e944ea..a754755100ff 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -200,12 +200,11 @@ static int serial8250_em_probe(struct platform_device *pdev) return 0; } -static int serial8250_em_remove(struct platform_device *pdev) +static void serial8250_em_remove(struct platform_device *pdev) { struct serial8250_em_priv *priv = platform_get_drvdata(pdev); serial8250_unregister_port(priv->line); - return 0; } static const struct of_device_id serial8250_em_dt_ids[] = { @@ -220,7 +219,7 @@ static struct platform_driver serial8250_em_platform_driver = { .of_match_table = serial8250_em_dt_ids, }, .probe = serial8250_em_probe, - .remove = serial8250_em_remove, + .remove_new = serial8250_em_remove, }; module_platform_driver(serial8250_em_platform_driver); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 6085d356ad86..23366f868ae3 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -480,7 +480,7 @@ static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termio } static const struct serial_rs485 generic_rs485_supported = { - .flags = SER_RS485_ENABLED, + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, }; static const struct exar8250_platform exar8250_default_platform = { @@ -524,7 +524,8 @@ static int iot2040_rs485_config(struct uart_port *port, struct ktermios *termios } static const struct serial_rs485 iot2040_rs485_supported = { - .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS, + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS, }; static const struct property_entry iot2040_gpio_properties[] = { diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index f522eb5026c9..b4ed442082a8 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -51,7 +51,8 @@ int fsl8250_handle_irq(struct uart_port *port) * immediately and interrupt the CPU again. The hardware clears LSR.BI * when the next valid char is read.) */ - if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) { + if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI && + (up->lsr_saved_flags & UART_LSR_BI))) { up->lsr_saved_flags &= ~UART_LSR_BI; port->serial_in(port, UART_RX); uart_port_unlock_irqrestore(&up->port, flags); @@ -159,12 +160,11 @@ static int fsl8250_acpi_probe(struct platform_device *pdev) return 0; } -static int fsl8250_acpi_remove(struct platform_device *pdev) +static void fsl8250_acpi_remove(struct platform_device *pdev) { struct fsl8250_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); - return 0; } static const struct acpi_device_id fsl_8250_acpi_id[] = { @@ -179,7 +179,7 @@ static struct platform_driver fsl8250_platform_driver = { .acpi_match_table = ACPI_PTR(fsl_8250_acpi_id), }, .probe = fsl8250_acpi_probe, - .remove = fsl8250_acpi_remove, + .remove_new = fsl8250_acpi_remove, }; module_platform_driver(fsl8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 4c4c4da73ad0..a12f737924c0 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -320,14 +320,13 @@ out: return err; } -static int ingenic_uart_remove(struct platform_device *pdev) +static void ingenic_uart_remove(struct platform_device *pdev) { struct ingenic_uart_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk_module); clk_disable_unprepare(data->clk_baud); - return 0; } static const struct ingenic_uart_config jz4740_uart_config = { @@ -368,7 +367,7 @@ static struct platform_driver ingenic_uart_platform_driver = { .of_match_table = of_match, }, .probe = ingenic_uart_probe, - .remove = ingenic_uart_remove, + .remove_new = ingenic_uart_remove, }; module_platform_driver(ingenic_uart_platform_driver); diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c index d5a39e105a76..50c77c3dacf2 100644 --- a/drivers/tty/serial/8250/8250_ioc3.c +++ b/drivers/tty/serial/8250/8250_ioc3.c @@ -75,17 +75,16 @@ static int serial8250_ioc3_probe(struct platform_device *pdev) return 0; } -static int serial8250_ioc3_remove(struct platform_device *pdev) +static void serial8250_ioc3_remove(struct platform_device *pdev) { struct ioc3_8250_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); - return 0; } static struct platform_driver serial8250_ioc3_driver = { .probe = serial8250_ioc3_probe, - .remove = serial8250_ioc3_remove, + .remove_new = serial8250_ioc3_remove, .driver = { .name = "ioc3-serial8250", } diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index 6dc85aaba5d0..8d728a6a5991 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -182,15 +182,13 @@ dis_clk_reg: return ret; } -static int lpc18xx_serial_remove(struct platform_device *pdev) +static void lpc18xx_serial_remove(struct platform_device *pdev) { struct lpc18xx_uart_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk_uart); clk_disable_unprepare(data->clk_reg); - - return 0; } static const struct of_device_id lpc18xx_serial_match[] = { @@ -201,7 +199,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_serial_match); static struct platform_driver lpc18xx_serial_driver = { .probe = lpc18xx_serial_probe, - .remove = lpc18xx_serial_remove, + .remove_new = lpc18xx_serial_remove, .driver = { .name = "lpc18xx-uart", .of_match_table = lpc18xx_serial_match, diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 0e43bdfb7459..776ec1ef29d6 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -287,17 +287,14 @@ static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port return 0; } - rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + rx_param = devm_kmemdup(dev, &lpss->dma_param, sizeof(*rx_param), GFP_KERNEL); if (!rx_param) return -ENOMEM; - tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + tx_param = devm_kmemdup(dev, &lpss->dma_param, sizeof(*tx_param), GFP_KERNEL); if (!tx_param) return -ENOMEM; - *rx_param = lpss->dma_param; - *tx_param = lpss->dma_param; - dma->fn = lpss8250_dma_filter; dma->rx_param = rx_param; dma->tx_param = tx_param; diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 23457daae8a1..9ff6bbe9c086 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -581,7 +581,7 @@ static int mtk8250_probe(struct platform_device *pdev) return 0; } -static int mtk8250_remove(struct platform_device *pdev) +static void mtk8250_remove(struct platform_device *pdev) { struct mtk8250_data *data = platform_get_drvdata(pdev); @@ -591,8 +591,6 @@ static int mtk8250_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } static int __maybe_unused mtk8250_suspend(struct device *dev) @@ -652,7 +650,7 @@ static struct platform_driver mtk8250_platform_driver = { .of_match_table = mtk8250_of_match, }, .probe = mtk8250_probe, - .remove = mtk8250_remove, + .remove_new = mtk8250_remove, }; module_platform_driver(mtk8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index ef3e745bd09c..34f17a9785e7 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -251,7 +251,7 @@ err_free: /* * Release a line */ -static int of_platform_serial_remove(struct platform_device *ofdev) +static void of_platform_serial_remove(struct platform_device *ofdev) { struct of_serial_info *info = platform_get_drvdata(ofdev); @@ -261,7 +261,6 @@ static int of_platform_serial_remove(struct platform_device *ofdev) pm_runtime_put_sync(&ofdev->dev); pm_runtime_disable(&ofdev->dev); kfree(info); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -337,7 +336,7 @@ static struct platform_driver of_platform_serial_driver = { .pm = &of_serial_pm_ops, }, .probe = of_platform_serial_probe, - .remove = of_platform_serial_remove, + .remove_new = of_platform_serial_remove, }; module_platform_driver(of_platform_serial_driver); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 578f35895b27..6942990a333c 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1586,7 +1586,7 @@ err: return ret; } -static int omap8250_remove(struct platform_device *pdev) +static void omap8250_remove(struct platform_device *pdev) { struct omap8250_priv *priv = platform_get_drvdata(pdev); struct uart_8250_port *up; @@ -1594,7 +1594,7 @@ static int omap8250_remove(struct platform_device *pdev) err = pm_runtime_resume_and_get(&pdev->dev); if (err) - return err; + dev_err(&pdev->dev, "Failed to resume hardware\n"); up = serial8250_get_port(priv->line); omap_8250_shutdown(&up->port); @@ -1606,7 +1606,6 @@ static int omap8250_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); cpu_latency_qos_remove_request(&priv->pm_qos_request); device_init_wakeup(&pdev->dev, false); - return 0; } static int omap8250_prepare(struct device *dev) @@ -1865,7 +1864,7 @@ static struct platform_driver omap8250_platform_driver = { .of_match_table = omap8250_dt_ids, }, .probe = omap8250_probe, - .remove = omap8250_remove, + .remove_new = omap8250_remove, }; module_platform_driver(omap8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 614be0f13a31..0d35c77fad9e 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1970,6 +1971,20 @@ pci_sunix_setup(struct serial_private *priv, #define MOXA_GPIO_PIN2 BIT(2) +#define MOXA_RS232 0x00 +#define MOXA_RS422 0x01 +#define MOXA_RS485_4W 0x0B +#define MOXA_RS485_2W 0x0F +#define MOXA_UIR_OFFSET 0x04 +#define MOXA_EVEN_RS_MASK GENMASK(3, 0) +#define MOXA_ODD_RS_MASK GENMASK(7, 4) + +enum { + MOXA_SUPP_RS232 = BIT(0), + MOXA_SUPP_RS422 = BIT(1), + MOXA_SUPP_RS485 = BIT(2), +}; + static bool pci_moxa_is_mini_pcie(unsigned short device) { if (device == PCI_DEVICE_ID_MOXA_CP102N || @@ -1983,12 +1998,54 @@ static bool pci_moxa_is_mini_pcie(unsigned short device) return false; } +static unsigned int pci_moxa_supported_rs(struct pci_dev *dev) +{ + switch (dev->device & 0x0F00) { + case 0x0000: + case 0x0600: + return MOXA_SUPP_RS232; + case 0x0100: + return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485; + case 0x0300: + return MOXA_SUPP_RS422 | MOXA_SUPP_RS485; + } + return 0; +} + +static int pci_moxa_set_interface(const struct pci_dev *dev, + unsigned int port_idx, + u8 mode) +{ + resource_size_t iobar_addr = pci_resource_start(dev, 2); + resource_size_t UIR_addr = iobar_addr + MOXA_UIR_OFFSET + port_idx / 2; + u8 val; + + val = inb(UIR_addr); + + if (port_idx % 2) { + val &= ~MOXA_ODD_RS_MASK; + val |= FIELD_PREP(MOXA_ODD_RS_MASK, mode); + } else { + val &= ~MOXA_EVEN_RS_MASK; + val |= FIELD_PREP(MOXA_EVEN_RS_MASK, mode); + } + outb(val, UIR_addr); + + return 0; +} + static int pci_moxa_init(struct pci_dev *dev) { unsigned short device = dev->device; resource_size_t iobar_addr = pci_resource_start(dev, 2); - unsigned int num_ports = (device & 0x00F0) >> 4; - u8 val; + unsigned int num_ports = (device & 0x00F0) >> 4, i; + u8 val, init_mode = MOXA_RS232; + + if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) { + init_mode = MOXA_RS422; + } + for (i = 0; i < num_ports; ++i) + pci_moxa_set_interface(dev, i, init_mode); /* * Enable hardware buffer to prevent break signal output when system boots up. diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index 9f9e21981929..558c4c7f3104 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -9,15 +9,21 @@ #include #include +#include #include +#include #include #include #include #include +#include +#include #include #include #include #include +#include +#include #include @@ -52,6 +58,17 @@ #define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400 #define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414 +#define UART_SYSTEM_ADDR_BASE 0x1000 +#define UART_DEV_REV_REG (UART_SYSTEM_ADDR_BASE + 0x00) +#define UART_DEV_REV_MASK GENMASK(7, 0) +#define UART_SYSLOCK_REG (UART_SYSTEM_ADDR_BASE + 0xA0) +#define UART_SYSLOCK BIT(2) +#define SYSLOCK_SLEEP_TIMEOUT 100 +#define SYSLOCK_RETRY_CNT 1000 + +#define UART_RX_BYTE_FIFO 0x00 +#define UART_FIFO_CTL 0x02 + #define UART_ACTV_REG 0x11 #define UART_BLOCK_SET_ACTIVE BIT(0) @@ -82,8 +99,59 @@ #define UART_RESET_REG 0x94 #define UART_RESET_D3_RESET_DISABLE BIT(16) +#define UART_BURST_STATUS_REG 0x9C +#define UART_RX_BURST_FIFO 0xA4 + #define MAX_PORTS 4 #define PORT_OFFSET 0x100 +#define RX_BUF_SIZE 512 +#define UART_BYTE_SIZE 1 +#define UART_BURST_SIZE 4 + +#define UART_BST_STAT_RX_COUNT_MASK 0x00FF +#define UART_BST_STAT_IIR_INT_PEND 0x100000 +#define UART_LSR_OVERRUN_ERR_CLR 0x43 +#define UART_BST_STAT_LSR_RX_MASK 0x9F000000 +#define UART_BST_STAT_LSR_RX_ERR_MASK 0x9E000000 +#define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000 +#define UART_BST_STAT_LSR_PARITY_ERR 0x4000000 +#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000 + +struct pci1xxxx_8250 { + unsigned int nr; + u8 dev_rev; + u8 pad[3]; + void __iomem *membase; + int line[] __counted_by(nr); +}; + +static const struct serial_rs485 pci1xxxx_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND, + .delay_rts_after_send = 1, + /* Delay RTS before send is not supported */ +}; + +static int pci1xxxx_set_sys_lock(struct pci1xxxx_8250 *port) +{ + writel(UART_SYSLOCK, port->membase + UART_SYSLOCK_REG); + return readl(port->membase + UART_SYSLOCK_REG); +} + +static int pci1xxxx_acquire_sys_lock(struct pci1xxxx_8250 *port) +{ + u32 regval; + + return readx_poll_timeout(pci1xxxx_set_sys_lock, port, regval, + (regval & UART_SYSLOCK), + SYSLOCK_SLEEP_TIMEOUT, + SYSLOCK_RETRY_CNT * SYSLOCK_SLEEP_TIMEOUT); +} + +static void pci1xxxx_release_sys_lock(struct pci1xxxx_8250 *port) +{ + writel(0x0, port->membase + UART_SYSLOCK_REG); +} static const int logical_to_physical_port_idx[][MAX_PORTS] = { {0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */ @@ -104,12 +172,6 @@ static const int logical_to_physical_port_idx[][MAX_PORTS] = { {3, -1, -1, -1}, /* PCI1p3 */ }; -struct pci1xxxx_8250 { - unsigned int nr; - void __iomem *membase; - int line[] __counted_by(nr); -}; - static int pci1xxxx_get_num_ports(struct pci_dev *dev) { switch (dev->subsystem_device) { @@ -205,12 +267,102 @@ static int pci1xxxx_rs485_config(struct uart_port *port, return 0; } -static const struct serial_rs485 pci1xxxx_rs485_supported = { - .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | - SER_RS485_RTS_AFTER_SEND, - .delay_rts_after_send = 1, - /* Delay RTS before send is not supported */ -}; +static u32 pci1xxxx_read_burst_status(struct uart_port *port) +{ + u32 status; + + status = readl(port->membase + UART_BURST_STATUS_REG); + if (status & UART_BST_STAT_LSR_RX_ERR_MASK) { + if (status & UART_BST_STAT_LSR_OVERRUN_ERR) { + writeb(UART_LSR_OVERRUN_ERR_CLR, + port->membase + UART_FIFO_CTL); + port->icount.overrun++; + } + + if (status & UART_BST_STAT_LSR_FRAME_ERR) + port->icount.frame++; + + if (status & UART_BST_STAT_LSR_PARITY_ERR) + port->icount.parity++; + } + return status; +} + +static void pci1xxxx_process_read_data(struct uart_port *port, + unsigned char *rx_buff, u32 *buff_index, + u32 *valid_byte_count) +{ + u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE; + u32 *burst_buf; + + /* + * Depending on the RX Trigger Level the number of bytes that can be + * stored in RX FIFO at a time varies. Each transaction reads data + * in DWORDs. If there are less than four remaining valid_byte_count + * to read, the data is received one byte at a time. + */ + while (valid_burst_count--) { + if (*buff_index > (RX_BUF_SIZE - UART_BURST_SIZE)) + break; + burst_buf = (u32 *)&rx_buff[*buff_index]; + *burst_buf = readl(port->membase + UART_RX_BURST_FIFO); + *buff_index += UART_BURST_SIZE; + *valid_byte_count -= UART_BURST_SIZE; + } + + while (*valid_byte_count) { + if (*buff_index > RX_BUF_SIZE) + break; + rx_buff[*buff_index] = readb(port->membase + + UART_RX_BYTE_FIFO); + *buff_index += UART_BYTE_SIZE; + *valid_byte_count -= UART_BYTE_SIZE; + } +} + +static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status) +{ + u32 valid_byte_count = uart_status & UART_BST_STAT_RX_COUNT_MASK; + struct tty_port *tty_port = &port->state->port; + unsigned char rx_buff[RX_BUF_SIZE]; + u32 buff_index = 0; + u32 copied_len; + + if (valid_byte_count != 0 && + valid_byte_count < RX_BUF_SIZE) { + pci1xxxx_process_read_data(port, rx_buff, &buff_index, + &valid_byte_count); + + copied_len = (u32)tty_insert_flip_string(tty_port, rx_buff, + buff_index); + + if (copied_len != buff_index) + port->icount.overrun += buff_index - copied_len; + + port->icount.rx += buff_index; + tty_flip_buffer_push(tty_port); + } +} + +static int pci1xxxx_handle_irq(struct uart_port *port) +{ + unsigned long flags; + u32 status; + + status = pci1xxxx_read_burst_status(port); + + if (status & UART_BST_STAT_IIR_INT_PEND) + return 0; + + spin_lock_irqsave(&port->lock, flags); + + if (status & UART_BST_STAT_LSR_RX_MASK) + pci1xxxx_rx_burst(port, status); + + spin_unlock_irqrestore(&port->lock, flags); + + return 1; +} static bool pci1xxxx_port_suspend(int line) { @@ -323,7 +475,7 @@ static int pci1xxxx_resume(struct device *dev) } static int pci1xxxx_setup(struct pci_dev *pdev, - struct uart_8250_port *port, int port_idx) + struct uart_8250_port *port, int port_idx, int rev) { int ret; @@ -335,6 +487,10 @@ static int pci1xxxx_setup(struct pci_dev *pdev, port->port.rs485_config = pci1xxxx_rs485_config; port->port.rs485_supported = pci1xxxx_rs485_supported; + /* From C0 rev Burst operation is supported */ + if (rev >= 0xC0) + port->port.handle_irq = pci1xxxx_handle_irq; + ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0); if (ret < 0) return ret; @@ -370,6 +526,27 @@ static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port) return logical_to_physical_port_idx[0][port]; } +static int pci1xxxx_get_device_revision(struct pci1xxxx_8250 *priv) +{ + u32 regval; + int ret; + + /* + * DEV REV is a system register, HW Syslock bit + * should be acquired before accessing the register + */ + ret = pci1xxxx_acquire_sys_lock(priv); + if (ret) + return ret; + + regval = readl(priv->membase + UART_DEV_REV_REG); + priv->dev_rev = regval & UART_DEV_REV_MASK; + + pci1xxxx_release_sys_lock(priv); + + return 0; +} + static int pci1xxxx_serial_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -381,6 +558,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev, int num_vectors; int subsys_dev; int port_idx; + int ret; int rc; rc = pcim_enable_device(pdev); @@ -397,6 +575,10 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev, if (!priv->membase) return -ENOMEM; + ret = pci1xxxx_get_device_revision(priv); + if (ret) + return ret; + pci_set_master(pdev); priv->nr = nr_ports; @@ -428,7 +610,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev, else uart.port.irq = pci_irq_vector(pdev, 0); - rc = pci1xxxx_setup(pdev, &uart, port_idx); + rc = pci1xxxx_setup(pdev, &uart, port_idx, priv->dev_rev); if (rc) { dev_warn(dev, "Failed to setup port %u\n", i); continue; diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c index a5b3ea27fc90..77686da42ce8 100644 --- a/drivers/tty/serial/8250/8250_pxa.c +++ b/drivers/tty/serial/8250/8250_pxa.c @@ -146,20 +146,18 @@ static int serial_pxa_probe(struct platform_device *pdev) return ret; } -static int serial_pxa_remove(struct platform_device *pdev) +static void serial_pxa_remove(struct platform_device *pdev) { struct pxa8250_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_unprepare(data->clk); - - return 0; } static struct platform_driver serial_pxa_driver = { .probe = serial_pxa_probe, - .remove = serial_pxa_remove, + .remove_new = serial_pxa_remove, .driver = { .name = "pxa2xx-uart", diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c index 89956bbf34d9..ba352262df75 100644 --- a/drivers/tty/serial/8250/8250_tegra.c +++ b/drivers/tty/serial/8250/8250_tegra.c @@ -128,15 +128,13 @@ err_clkdisable: return ret; } -static int tegra_uart_remove(struct platform_device *pdev) +static void tegra_uart_remove(struct platform_device *pdev) { struct tegra_uart *uart = platform_get_drvdata(pdev); serial8250_unregister_port(uart->line); reset_control_assert(uart->rst); clk_disable_unprepare(uart->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -192,7 +190,7 @@ static struct platform_driver tegra_uart_driver = { .acpi_match_table = ACPI_PTR(tegra_uart_acpi_match), }, .probe = tegra_uart_probe, - .remove = tegra_uart_remove, + .remove_new = tegra_uart_remove, }; module_platform_driver(tegra_uart_driver); diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index a405155264b1..6399a38ecce2 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -241,14 +241,12 @@ static int uniphier_uart_probe(struct platform_device *pdev) return 0; } -static int uniphier_uart_remove(struct platform_device *pdev) +static void uniphier_uart_remove(struct platform_device *pdev) { struct uniphier8250_priv *priv = platform_get_drvdata(pdev); serial8250_unregister_port(priv->line); clk_disable_unprepare(priv->clk); - - return 0; } static int __maybe_unused uniphier_uart_suspend(struct device *dev) @@ -293,7 +291,7 @@ MODULE_DEVICE_TABLE(of, uniphier_uart_match); static struct platform_driver uniphier_uart_platform_driver = { .probe = uniphier_uart_probe, - .remove = uniphier_uart_remove, + .remove_new = uniphier_uart_remove, .driver = { .name = "uniphier-uart", .of_match_table = uniphier_uart_match, diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index dc2ef05a10eb..2056aed46688 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -90,12 +90,6 @@ struct serial_info { const struct serial_quirk *quirk; }; -struct serial_cfg_mem { - tuple_t tuple; - cisparse_t parse; - u_char buf[256]; -}; - /* * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6" * manfid 0x0160, 0x0104 diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a6cc020f25e6..63a4b75ff264 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -531,6 +531,9 @@ config SERIAL_UARTLITE_NR_UARTS help Set this to the number of uartlites in your system, or the number you think you might implement. + If maximum number of uartlite serial ports is more than 4, then the + driver uses dynamic allocation instead of static allocation for major + number. config SERIAL_SUNCORE bool diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 7090b251dd4d..effcba71ea77 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -425,7 +425,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev) return 0; } -static int altera_jtaguart_remove(struct platform_device *pdev) +static void altera_jtaguart_remove(struct platform_device *pdev) { struct uart_port *port; int i = pdev->id; @@ -436,8 +436,6 @@ static int altera_jtaguart_remove(struct platform_device *pdev) port = &altera_jtaguart_ports[i]; uart_remove_one_port(&altera_jtaguart_driver, port); iounmap(port->membase); - - return 0; } #ifdef CONFIG_OF @@ -451,7 +449,7 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match); static struct platform_driver altera_jtaguart_platform_driver = { .probe = altera_jtaguart_probe, - .remove = altera_jtaguart_remove, + .remove_new = altera_jtaguart_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(altera_jtaguart_match), diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 77835ac68df2..897f0995b2fe 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -305,7 +305,7 @@ static int altera_uart_startup(struct uart_port *port) int ret; ret = request_irq(port->irq, altera_uart_interrupt, 0, - DRV_NAME, port); + dev_name(port->dev), port); if (ret) { pr_err(DRV_NAME ": unable to attach Altera UART %d " "interrupt vector=%d\n", port->line, port->irq); @@ -595,7 +595,7 @@ static int altera_uart_probe(struct platform_device *pdev) return 0; } -static int altera_uart_remove(struct platform_device *pdev) +static void altera_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); @@ -604,8 +604,6 @@ static int altera_uart_remove(struct platform_device *pdev) port->mapbase = 0; iounmap(port->membase); } - - return 0; } #ifdef CONFIG_OF @@ -619,7 +617,7 @@ MODULE_DEVICE_TABLE(of, altera_uart_match); static struct platform_driver altera_uart_platform_driver = { .probe = altera_uart_probe, - .remove = altera_uart_remove, + .remove_new = altera_uart_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(altera_uart_match), diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index b7635363373e..fccec1698a54 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -50,8 +50,8 @@ #define AMBA_ISR_PASS_LIMIT 256 -#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) -#define UART_DUMMY_DR_RX (1 << 16) +#define UART_DR_ERROR (UART011_DR_OE | UART011_DR_BE | UART011_DR_PE | UART011_DR_FE) +#define UART_DUMMY_DR_RX BIT(16) enum { REG_DR, @@ -125,7 +125,7 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .reg_offset = pl011_std_offsets, - .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8, .fr_busy = UART01x_FR_BUSY, .fr_dsr = UART01x_FR_DSR, .fr_cts = UART01x_FR_CTS, @@ -203,7 +203,7 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .reg_offset = pl011_st_offsets, - .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .ifls = UART011_IFLS_RX_HALF | UART011_IFLS_TX_HALF, .fr_busy = UART01x_FR_BUSY, .fr_dsr = UART01x_FR_DSR, .fr_cts = UART01x_FR_CTS, @@ -277,13 +277,13 @@ struct uart_amba_port { static unsigned int pl011_tx_empty(struct uart_port *port); static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap, - unsigned int reg) + unsigned int reg) { return uap->reg_offset[reg]; } static unsigned int pl011_read(const struct uart_amba_port *uap, - unsigned int reg) + unsigned int reg) { void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg); @@ -292,7 +292,7 @@ static unsigned int pl011_read(const struct uart_amba_port *uap, } static void pl011_write(unsigned int val, const struct uart_amba_port *uap, - unsigned int reg) + unsigned int reg) { void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg); @@ -330,10 +330,11 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) uap->port.icount.brk++; if (uart_handle_break(&uap->port)) continue; - } else if (ch & UART011_DR_PE) + } else if (ch & UART011_DR_PE) { uap->port.icount.parity++; - else if (ch & UART011_DR_FE) + } else if (ch & UART011_DR_FE) { uap->port.icount.frame++; + } if (ch & UART011_DR_OE) uap->port.icount.overrun++; @@ -358,7 +359,6 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) return fifotaken; } - /* * All the DMA operation mode stuff goes inside this ifdef. * This assumes that you have a generic DMA device interface, @@ -369,7 +369,7 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) #define PL011_DMA_BUFFER_SIZE PAGE_SIZE static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db, - enum dma_data_direction dir) + enum dma_data_direction dir) { db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE, &db->dma, GFP_KERNEL); @@ -381,7 +381,7 @@ static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db, } static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db, - enum dma_data_direction dir) + enum dma_data_direction dir) { if (db->buf) { dma_free_coherent(chan->device->dev, @@ -424,7 +424,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) dma_cap_set(DMA_SLAVE, mask); chan = dma_request_channel(mask, plat->dma_filter, - plat->dma_tx_param); + plat->dma_tx_param); if (!chan) { dev_err(uap->port.dev, "no TX DMA channel!\n"); return; @@ -438,9 +438,9 @@ static void pl011_dma_probe(struct uart_amba_port *uap) dma_chan_name(uap->dmatx.chan)); /* Optionally make use of an RX channel as well */ - chan = dma_request_slave_channel(dev, "rx"); + chan = dma_request_chan(dev, "rx"); - if (!chan && plat && plat->dma_rx_param) { + if (IS_ERR(chan) && plat && plat->dma_rx_param) { chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); if (!chan) { @@ -449,7 +449,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) } } - if (chan) { + if (!IS_ERR(chan)) { struct dma_slave_config rx_conf = { .src_addr = uap->port.mapbase + pl011_reg_to_offset(uap, REG_DR), @@ -465,12 +465,12 @@ static void pl011_dma_probe(struct uart_amba_port *uap) * If the controller does, check for suitable residue processing * otherwise assime all is well. */ - if (0 == dma_get_slave_caps(chan, &caps)) { + if (dma_get_slave_caps(chan, &caps) == 0) { if (caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) { dma_release_channel(chan); dev_info(uap->port.dev, - "RX DMA disabled - no residue processing\n"); + "RX DMA disabled - no residue processing\n"); return; } } @@ -499,18 +499,16 @@ static void pl011_dma_probe(struct uart_amba_port *uap) else uap->dmarx.poll_timeout = 3000; } else if (!plat && dev->of_node) { - uap->dmarx.auto_poll_rate = of_property_read_bool( - dev->of_node, "auto-poll"); + uap->dmarx.auto_poll_rate = + of_property_read_bool(dev->of_node, "auto-poll"); if (uap->dmarx.auto_poll_rate) { u32 x; - if (0 == of_property_read_u32(dev->of_node, - "poll-rate-ms", &x)) + if (of_property_read_u32(dev->of_node, "poll-rate-ms", &x) == 0) uap->dmarx.poll_rate = x; else uap->dmarx.poll_rate = 100; - if (0 == of_property_read_u32(dev->of_node, - "poll-timeout-ms", &x)) + if (of_property_read_u32(dev->of_node, "poll-timeout-ms", &x) == 0) uap->dmarx.poll_timeout = x; else uap->dmarx.poll_timeout = 3000; @@ -547,7 +545,7 @@ static void pl011_dma_tx_callback(void *data) uart_port_lock_irqsave(&uap->port, &flags); if (uap->dmatx.queued) dma_unmap_single(dmatx->chan->device->dev, dmatx->dma, - dmatx->len, DMA_TO_DEVICE); + dmatx->len, DMA_TO_DEVICE); dmacr = uap->dmacr; uap->dmacr = dmacr & ~UART011_TXDMAE; @@ -618,9 +616,9 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) if (count > PL011_DMA_BUFFER_SIZE) count = PL011_DMA_BUFFER_SIZE; - if (xmit->tail < xmit->head) + if (xmit->tail < xmit->head) { memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); - else { + } else { size_t first = UART_XMIT_SIZE - xmit->tail; size_t second; @@ -643,7 +641,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) } desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE); uap->dmatx.queued = false; @@ -754,8 +752,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; pl011_write(uap->im, uap, REG_IMSC); - } else + } else { ret = false; + } } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; pl011_write(uap->dmacr, uap, REG_DMACR); @@ -832,8 +831,8 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) dbuf = uap->dmarx.use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a; desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); /* * If the DMA engine is busy and cannot prepare a * channel, no big deal, the driver will fall back @@ -889,14 +888,12 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, /* Pick the remain data from the DMA */ if (pending) { - /* * First take all chars in the DMA pipe, then look in the FIFO. * Note that tty_insert_flip_buf() tries to take as many chars * as it can. */ - dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, - pending); + dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, pending); uap->port.icount.rx += dma_count; if (dma_count < pending) @@ -978,8 +975,8 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) /* Switch buffer & re-trigger DMA job */ dmarx->use_buf_b = !dmarx->use_buf_b; if (pl011_dma_rx_trigger_dma(uap)) { - dev_dbg(uap->port.dev, "could not retrigger RX DMA job " - "fall back to interrupt mode\n"); + dev_dbg(uap->port.dev, + "could not retrigger RX DMA job fall back to interrupt mode\n"); uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); } @@ -1026,8 +1023,8 @@ static void pl011_dma_rx_callback(void *data) * get some IRQ immediately from RX. */ if (ret) { - dev_dbg(uap->port.dev, "could not retrigger RX DMA job " - "fall back to interrupt mode\n"); + dev_dbg(uap->port.dev, + "could not retrigger RX DMA job fall back to interrupt mode\n"); uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); } @@ -1072,7 +1069,7 @@ static void pl011_dma_rx_poll(struct timer_list *t) dmataken = dbuf->len - dmarx->last_residue; size = dmarx->last_residue - state.residue; dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, - size); + size); if (dma_count == size) dmarx->last_residue = state.residue; dmarx->last_jiffies = jiffies; @@ -1085,7 +1082,6 @@ static void pl011_dma_rx_poll(struct timer_list *t) */ if (jiffies_to_msecs(jiffies - dmarx->last_jiffies) > uap->dmarx.poll_timeout) { - uart_port_lock_irqsave(&uap->port, &flags); pl011_dma_rx_stop(uap); uap->im |= UART011_RXIM; @@ -1097,7 +1093,7 @@ static void pl011_dma_rx_poll(struct timer_list *t) del_timer(&uap->dmarx.timer); } else { mod_timer(&uap->dmarx.timer, - jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); + jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); } } @@ -1113,7 +1109,6 @@ static void pl011_dma_startup(struct uart_amba_port *uap) uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA); if (!uap->dmatx.buf) { - dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); uap->port.fifosize = uap->fifosize; return; } @@ -1129,7 +1124,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap) /* Allocate and map DMA RX buffers */ ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a, - DMA_FROM_DEVICE); + DMA_FROM_DEVICE); if (ret) { dev_err(uap->port.dev, "failed to init DMA %s: %d\n", "RX buffer A", ret); @@ -1137,12 +1132,12 @@ static void pl011_dma_startup(struct uart_amba_port *uap) } ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b, - DMA_FROM_DEVICE); + DMA_FROM_DEVICE); if (ret) { dev_err(uap->port.dev, "failed to init DMA %s: %d\n", "RX buffer B", ret); pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, - DMA_FROM_DEVICE); + DMA_FROM_DEVICE); goto skip_rx; } @@ -1164,13 +1159,12 @@ skip_rx: if (uap->using_rx_dma) { if (pl011_dma_rx_trigger_dma(uap)) - dev_dbg(uap->port.dev, "could not trigger initial " - "RX DMA job, fall back to interrupt mode\n"); + dev_dbg(uap->port.dev, + "could not trigger initial RX DMA job, fall back to interrupt mode\n"); if (uap->dmarx.poll_rate) { timer_setup(&uap->dmarx.timer, pl011_dma_rx_poll, 0); mod_timer(&uap->dmarx.timer, - jiffies + - msecs_to_jiffies(uap->dmarx.poll_rate)); + jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE; uap->dmarx.last_jiffies = jiffies; } @@ -1359,8 +1353,8 @@ static void pl011_stop_rx(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| - UART011_PEIM|UART011_BEIM|UART011_OEIM); + uap->im &= ~(UART011_RXIM | UART011_RTIM | UART011_FEIM | + UART011_PEIM | UART011_BEIM | UART011_OEIM); pl011_write(uap->im, uap, REG_IMSC); pl011_dma_rx_stop(uap); @@ -1380,7 +1374,7 @@ static void pl011_enable_ms(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; + uap->im |= UART011_RIMIM | UART011_CTSMIM | UART011_DCDMIM | UART011_DSRMIM; pl011_write(uap->im, uap, REG_IMSC); } @@ -1398,8 +1392,8 @@ __acquires(&uap->port.lock) */ if (pl011_dma_rx_available(uap)) { if (pl011_dma_rx_trigger_dma(uap)) { - dev_dbg(uap->port.dev, "could not trigger RX DMA job " - "fall back to interrupt mode again\n"); + dev_dbg(uap->port.dev, + "could not trigger RX DMA job fall back to interrupt mode again\n"); uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); } else { @@ -1409,8 +1403,7 @@ __acquires(&uap->port.lock) uap->dmarx.last_jiffies = jiffies; uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE; mod_timer(&uap->dmarx.timer, - jiffies + - msecs_to_jiffies(uap->dmarx.poll_rate)); + jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); } #endif } @@ -1557,18 +1550,17 @@ static irqreturn_t pl011_int(int irq, void *dev_id) do { check_apply_cts_event_workaround(uap); - pl011_write(status & ~(UART011_TXIS|UART011_RTIS| - UART011_RXIS), + pl011_write(status & ~(UART011_TXIS | UART011_RTIS | UART011_RXIS), uap, REG_ICR); - if (status & (UART011_RTIS|UART011_RXIS)) { + if (status & (UART011_RTIS | UART011_RXIS)) { if (pl011_dma_rx_running(uap)) pl011_dma_rx_irq(uap); else pl011_rx_chars(uap); } - if (status & (UART011_DSRMIS|UART011_DCDMIS| - UART011_CTSMIS|UART011_RIMIS)) + if (status & (UART011_DSRMIS | UART011_DCDMIS | + UART011_CTSMIS | UART011_RIMIS)) pl011_modem_status(uap); if (status & UART011_TXIS) pl011_tx_chars(uap, true); @@ -1598,6 +1590,12 @@ static unsigned int pl011_tx_empty(struct uart_port *port) 0 : TIOCSER_TEMT; } +static void pl011_maybe_set_bit(bool cond, unsigned int *ptr, unsigned int mask) +{ + if (cond) + *ptr |= mask; +} + static unsigned int pl011_get_mctrl(struct uart_port *port) { struct uart_amba_port *uap = @@ -1605,18 +1603,22 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) unsigned int result = 0; unsigned int status = pl011_read(uap, REG_FR); -#define TIOCMBIT(uartbit, tiocmbit) \ - if (status & uartbit) \ - result |= tiocmbit + pl011_maybe_set_bit(status & UART01x_FR_DCD, &result, TIOCM_CAR); + pl011_maybe_set_bit(status & uap->vendor->fr_dsr, &result, TIOCM_DSR); + pl011_maybe_set_bit(status & uap->vendor->fr_cts, &result, TIOCM_CTS); + pl011_maybe_set_bit(status & uap->vendor->fr_ri, &result, TIOCM_RNG); - TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); - TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR); - TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS); - TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG); -#undef TIOCMBIT return result; } +static void pl011_assign_bit(bool cond, unsigned int *ptr, unsigned int mask) +{ + if (cond) + *ptr |= mask; + else + *ptr &= ~mask; +} + static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct uart_amba_port *uap = @@ -1625,23 +1627,16 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) cr = pl011_read(uap, REG_CR); -#define TIOCMBIT(tiocmbit, uartbit) \ - if (mctrl & tiocmbit) \ - cr |= uartbit; \ - else \ - cr &= ~uartbit - - TIOCMBIT(TIOCM_RTS, UART011_CR_RTS); - TIOCMBIT(TIOCM_DTR, UART011_CR_DTR); - TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1); - TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2); - TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE); + pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTS); + pl011_assign_bit(mctrl & TIOCM_DTR, &cr, UART011_CR_DTR); + pl011_assign_bit(mctrl & TIOCM_OUT1, &cr, UART011_CR_OUT1); + pl011_assign_bit(mctrl & TIOCM_OUT2, &cr, UART011_CR_OUT2); + pl011_assign_bit(mctrl & TIOCM_LOOP, &cr, UART011_CR_LBE); if (port->status & UPSTAT_AUTORTS) { /* We need to disable auto-RTS if we want to turn RTS off */ - TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN); + pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTSEN); } -#undef TIOCMBIT pl011_write(cr, uap, REG_CR); } @@ -1707,8 +1702,7 @@ static int pl011_get_poll_char(struct uart_port *port) return pl011_read(uap, REG_DR); } -static void pl011_put_poll_char(struct uart_port *port, - unsigned char ch) +static void pl011_put_poll_char(struct uart_port *port, unsigned char ch) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); @@ -1909,14 +1903,13 @@ static int sbsa_uart_startup(struct uart_port *port) return 0; } -static void pl011_shutdown_channel(struct uart_amba_port *uap, - unsigned int lcrh) +static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh) { - unsigned long val; + unsigned long val; - val = pl011_read(uap, lcrh); - val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); - pl011_write(val, uap, lcrh); + val = pl011_read(uap, lcrh); + val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); + pl011_write(val, uap, lcrh); } /* @@ -2065,7 +2058,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud); #endif - if (baud > port->uartclk/16) + if (baud > port->uartclk / 16) quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); else quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); @@ -2147,9 +2140,9 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, * else we see data corruption. */ if (uap->vendor->oversampling) { - if ((baud >= 3000000) && (baud < 3250000) && (quot > 1)) + if (baud >= 3000000 && baud < 3250000 && quot > 1) quot -= 1; - else if ((baud > 3250000) && (quot > 2)) + else if (baud > 3250000 && quot > 2) quot -= 2; } /* Set baud rate */ @@ -2218,13 +2211,14 @@ static void pl011_config_port(struct uart_port *port, int flags) static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) ret = -EINVAL; if (ser->irq < 0 || ser->irq >= nr_irqs) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; - if (port->mapbase != (unsigned long) ser->iomem_base) + if (port->mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; return ret; } @@ -2369,35 +2363,34 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) static void pl011_console_get_options(struct uart_amba_port *uap, int *baud, int *parity, int *bits) { - if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) { - unsigned int lcr_h, ibrd, fbrd; + unsigned int lcr_h, ibrd, fbrd; - lcr_h = pl011_read(uap, REG_LCRH_TX); + if (!(pl011_read(uap, REG_CR) & UART01x_CR_UARTEN)) + return; - *parity = 'n'; - if (lcr_h & UART01x_LCRH_PEN) { - if (lcr_h & UART01x_LCRH_EPS) - *parity = 'e'; - else - *parity = 'o'; - } + lcr_h = pl011_read(uap, REG_LCRH_TX); - if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) - *bits = 7; + *parity = 'n'; + if (lcr_h & UART01x_LCRH_PEN) { + if (lcr_h & UART01x_LCRH_EPS) + *parity = 'e'; else - *bits = 8; - - ibrd = pl011_read(uap, REG_IBRD); - fbrd = pl011_read(uap, REG_FBRD); - - *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); - - if (uap->vendor->oversampling) { - if (pl011_read(uap, REG_CR) - & ST_UART011_CR_OVSFACT) - *baud *= 2; - } + *parity = 'o'; } + + if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) + *bits = 7; + else + *bits = 8; + + ibrd = pl011_read(uap, REG_IBRD); + fbrd = pl011_read(uap, REG_FBRD); + + *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); + + if (uap->vendor->oversampling && + (pl011_read(uap, REG_CR) & ST_UART011_CR_OVSFACT)) + *baud *= 2; } static int pl011_console_setup(struct console *co, char *options) @@ -2533,7 +2526,7 @@ static void qdf2400_e44_putc(struct uart_port *port, unsigned char c) cpu_relax(); } -static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned n) +static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned int n) { struct earlycon_device *dev = con->data; @@ -2552,7 +2545,7 @@ static void pl011_putc(struct uart_port *port, unsigned char c) cpu_relax(); } -static void pl011_early_write(struct console *con, const char *s, unsigned n) +static void pl011_early_write(struct console *con, const char *s, unsigned int n) { struct earlycon_device *dev = con->data; @@ -2613,7 +2606,9 @@ static int __init pl011_early_console_setup(struct earlycon_device *device, return 0; } + OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); + OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup); /* @@ -2636,6 +2631,7 @@ qdf2400_e44_early_console_setup(struct earlycon_device *device, device->con->write = qdf2400_e44_early_write; return 0; } + EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup); #else @@ -2655,8 +2651,8 @@ static struct uart_driver amba_reg = { static int pl011_probe_dt_alias(int index, struct device *dev) { struct device_node *np; - static bool seen_dev_with_alias = false; - static bool seen_dev_without_alias = false; + static bool seen_dev_with_alias; + static bool seen_dev_without_alias; int ret = index; if (!IS_ENABLED(CONFIG_OF)) @@ -2672,7 +2668,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev) ret = index; } else { seen_dev_with_alias = true; - if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) { + if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret]) { dev_warn(dev, "requested serial port %d not available.\n", ret); ret = index; } @@ -2706,7 +2702,7 @@ static int pl011_find_free_port(void) int i; for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == NULL) + if (!amba_ports[i]) return i; return -EBUSY; @@ -2873,6 +2869,22 @@ static int pl011_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); +#ifdef CONFIG_ACPI_SPCR_TABLE +static void qpdf2400_erratum44_workaround(struct device *dev, + struct uart_amba_port *uap) +{ + if (!qdf2400_e44_present) + return; + + dev_info(dev, "working around QDF2400 SoC erratum 44\n"); + uap->vendor = &vendor_qdt_qdf2400_e44; +} +#else +static void qpdf2400_erratum44_workaround(struct device *dev, + struct uart_amba_port *uap) +{ /* empty */ } +#endif + static int sbsa_uart_probe(struct platform_device *pdev) { struct uart_amba_port *uap; @@ -2908,13 +2920,8 @@ static int sbsa_uart_probe(struct platform_device *pdev) return ret; uap->port.irq = ret; -#ifdef CONFIG_ACPI_SPCR_TABLE - if (qdf2400_e44_present) { - dev_info(&pdev->dev, "working around QDF2400 SoC erratum 44\n"); - uap->vendor = &vendor_qdt_qdf2400_e44; - } else -#endif - uap->vendor = &vendor_sbsa; + uap->vendor = &vendor_sbsa; + qpdf2400_erratum44_workaround(&pdev->dev, uap); uap->reg_offset = uap->vendor->reg_offset; uap->fifosize = 32; @@ -2935,13 +2942,12 @@ static int sbsa_uart_probe(struct platform_device *pdev) return pl011_register_port(uap); } -static int sbsa_uart_remove(struct platform_device *pdev) +static void sbsa_uart_remove(struct platform_device *pdev) { struct uart_amba_port *uap = platform_get_drvdata(pdev); uart_remove_one_port(&amba_reg, &uap->port); pl011_unregister_port(uap); - return 0; } static const struct of_device_id sbsa_uart_of_match[] = { @@ -2959,7 +2965,7 @@ MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match); static struct platform_driver arm_sbsa_uart_platform_driver = { .probe = sbsa_uart_probe, - .remove = sbsa_uart_remove, + .remove_new = sbsa_uart_remove, .driver = { .name = "sbsa-uart", .pm = &pl011_dev_pm_ops, @@ -2998,7 +3004,7 @@ static struct amba_driver pl011_driver = { static int __init pl011_init(void) { - printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); + pr_info("Serial: AMBA PL011 UART driver\n"); if (platform_driver_register(&arm_sbsa_uart_platform_driver)) pr_warn("could not register SBSA UART platform driver\n"); diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 716cb014c028..364599f256db 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -122,7 +122,7 @@ static void apbuart_tx_chars(struct uart_port *port) { u8 ch; - uart_port_tx_limited(port, ch, port->fifosize >> 1, + uart_port_tx_limited(port, ch, port->fifosize, true, UART_PUT_CHAR(port, ch), ({})); diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index ffd234673177..8d09ace062e5 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -818,7 +818,7 @@ err_disable_clk: return ret; } -static int ar933x_uart_remove(struct platform_device *pdev) +static void ar933x_uart_remove(struct platform_device *pdev) { struct ar933x_uart_port *up; @@ -828,8 +828,6 @@ static int ar933x_uart_remove(struct platform_device *pdev) uart_remove_one_port(&ar933x_uart_driver, &up->port); clk_disable_unprepare(up->clk); } - - return 0; } #ifdef CONFIG_OF @@ -842,7 +840,7 @@ MODULE_DEVICE_TABLE(of, ar933x_uart_of_ids); static struct platform_driver ar933x_uart_platform_driver = { .probe = ar933x_uart_probe, - .remove = ar933x_uart_remove, + .remove_new = ar933x_uart_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ar933x_uart_of_ids), diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 1946fafc3f3e..85667f709515 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1013,14 +1013,18 @@ static int atmel_prepare_tx_dma(struct uart_port *port) struct device *mfd_dev = port->dev->parent; dma_cap_mask_t mask; struct dma_slave_config config; + struct dma_chan *chan; int ret, nent; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx"); - if (atmel_port->chan_tx == NULL) + chan = dma_request_chan(mfd_dev, "tx"); + if (IS_ERR(chan)) { + atmel_port->chan_tx = NULL; goto chan_err; + } + atmel_port->chan_tx = chan; dev_info(port->dev, "using %s for tx DMA transfers\n", dma_chan_name(atmel_port->chan_tx)); @@ -1188,6 +1192,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dma_cap_mask_t mask; struct dma_slave_config config; struct circ_buf *ring; + struct dma_chan *chan; int ret, nent; ring = &atmel_port->rx_ring; @@ -1195,9 +1200,12 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dma_cap_zero(mask); dma_cap_set(DMA_CYCLIC, mask); - atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx"); - if (atmel_port->chan_rx == NULL) + chan = dma_request_chan(mfd_dev, "rx"); + if (IS_ERR(chan)) { + atmel_port->chan_rx = NULL; goto chan_err; + } + atmel_port->chan_rx = chan; dev_info(port->dev, "using %s for rx DMA transfers\n", dma_chan_name(atmel_port->chan_rx)); @@ -3001,7 +3009,7 @@ err: * protocol that needs bitbanging on IO lines, but use the regular serial * port in the normal case. */ -static int atmel_serial_remove(struct platform_device *pdev) +static void atmel_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -3020,8 +3028,6 @@ static int atmel_serial_remove(struct platform_device *pdev) clear_bit(port->line, atmel_ports_in_use); pdev->dev.of_node = NULL; - - return 0; } static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend, @@ -3029,7 +3035,7 @@ static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend, static struct platform_driver atmel_serial_driver = { .probe = atmel_serial_probe, - .remove = atmel_serial_remove, + .remove_new = atmel_serial_remove, .driver = { .name = "atmel_usart_serial", .of_match_table = of_match_ptr(atmel_serial_dt_ids), diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 4a08fd5ee61b..a3cefa153456 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -868,7 +868,7 @@ static int bcm_uart_probe(struct platform_device *pdev) return 0; } -static int bcm_uart_remove(struct platform_device *pdev) +static void bcm_uart_remove(struct platform_device *pdev) { struct uart_port *port; @@ -876,7 +876,6 @@ static int bcm_uart_remove(struct platform_device *pdev) uart_remove_one_port(&bcm_uart_driver, port); /* mark port as free */ ports[pdev->id].membase = NULL; - return 0; } static const struct of_device_id bcm63xx_of_match[] = { @@ -890,7 +889,7 @@ MODULE_DEVICE_TABLE(of, bcm63xx_of_match); */ static struct platform_driver bcm_uart_platform_driver = { .probe = bcm_uart_probe, - .remove = bcm_uart_remove, + .remove_new = bcm_uart_remove, .driver = { .name = "bcm63xx_uart", .of_match_table = bcm63xx_of_match, diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 55d19937efbd..7927725b8957 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -510,13 +510,11 @@ static int uart_clps711x_probe(struct platform_device *pdev) return ret; } -static int uart_clps711x_remove(struct platform_device *pdev) +static void uart_clps711x_remove(struct platform_device *pdev) { struct clps711x_port *s = platform_get_drvdata(pdev); uart_remove_one_port(&clps711x_uart, &s->port); - - return 0; } static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = { @@ -531,7 +529,7 @@ static struct platform_driver clps711x_uart_platform = { .of_match_table = of_match_ptr(clps711x_uart_dt_ids), }, .probe = uart_clps711x_probe, - .remove = uart_clps711x_remove, + .remove_new = uart_clps711x_remove, }; static int __init uart_clps711x_init(void) diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c index be4af6eda4c2..df56c6c5afd0 100644 --- a/drivers/tty/serial/cpm_uart.c +++ b/drivers/tty/serial/cpm_uart.c @@ -1549,13 +1549,11 @@ static int cpm_uart_probe(struct platform_device *ofdev) return ret; } -static int cpm_uart_remove(struct platform_device *ofdev) +static void cpm_uart_remove(struct platform_device *ofdev) { struct uart_cpm_port *pinfo = platform_get_drvdata(ofdev); uart_remove_one_port(&cpm_reg, &pinfo->port); - - return 0; } static const struct of_device_id cpm_uart_match[] = { @@ -1581,7 +1579,7 @@ static struct platform_driver cpm_uart_driver = { .of_match_table = cpm_uart_match, }, .probe = cpm_uart_probe, - .remove = cpm_uart_remove, + .remove_new = cpm_uart_remove, }; static int __init cpm_uart_init(void) diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c index 5004125f3045..e419c4bde8b7 100644 --- a/drivers/tty/serial/digicolor-usart.c +++ b/drivers/tty/serial/digicolor-usart.c @@ -503,13 +503,11 @@ static int digicolor_uart_probe(struct platform_device *pdev) return uart_add_one_port(&digicolor_uart, &dp->port); } -static int digicolor_uart_remove(struct platform_device *pdev) +static void digicolor_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&digicolor_uart, port); - - return 0; } static const struct of_device_id digicolor_uart_dt_ids[] = { @@ -524,7 +522,7 @@ static struct platform_driver digicolor_uart_platform = { .of_match_table = of_match_ptr(digicolor_uart_dt_ids), }, .probe = digicolor_uart_probe, - .remove = digicolor_uart_remove, + .remove_new = digicolor_uart_remove, }; static int __init digicolor_uart_init(void) diff --git a/drivers/tty/serial/esp32_acm.c b/drivers/tty/serial/esp32_acm.c index cb28a87736aa..d4e8bdb1cdef 100644 --- a/drivers/tty/serial/esp32_acm.c +++ b/drivers/tty/serial/esp32_acm.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -413,18 +413,17 @@ static int esp32s3_acm_probe(struct platform_device *pdev) return uart_add_one_port(&esp32s3_acm_reg, port); } -static int esp32s3_acm_remove(struct platform_device *pdev) +static void esp32s3_acm_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&esp32s3_acm_reg, port); - return 0; } static struct platform_driver esp32s3_acm_driver = { .probe = esp32s3_acm_probe, - .remove = esp32s3_acm_remove, + .remove_new = esp32s3_acm_remove, .driver = { .name = DRIVER_NAME, .of_match_table = esp32s3_acm_dt_ids, diff --git a/drivers/tty/serial/esp32_uart.c b/drivers/tty/serial/esp32_uart.c index 85c9c5ad7cc5..6fc61f323355 100644 --- a/drivers/tty/serial/esp32_uart.c +++ b/drivers/tty/serial/esp32_uart.c @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -678,16 +679,11 @@ static struct uart_driver esp32_uart_reg = { static int esp32_uart_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - static const struct of_device_id *match; struct uart_port *port; struct esp32_port *sport; struct resource *res; int ret; - match = of_match_device(esp32_uart_dt_ids, &pdev->dev); - if (!match) - return -ENODEV; - sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); if (!sport) return -ENOMEM; @@ -728,7 +724,7 @@ static int esp32_uart_probe(struct platform_device *pdev) port->flags = UPF_BOOT_AUTOCONF; port->has_sysrq = 1; port->fifosize = ESP32_UART_TX_FIFO_SIZE; - port->private_data = (void *)match->data; + port->private_data = (void *)device_get_match_data(&pdev->dev); esp32_uart_ports[port->line] = sport; @@ -737,19 +733,17 @@ static int esp32_uart_probe(struct platform_device *pdev) return uart_add_one_port(&esp32_uart_reg, port); } -static int esp32_uart_remove(struct platform_device *pdev) +static void esp32_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&esp32_uart_reg, port); - - return 0; } static struct platform_driver esp32_uart_driver = { .probe = esp32_uart_probe, - .remove = esp32_uart_remove, + .remove_new = esp32_uart_remove, .driver = { .name = DRIVER_NAME, .of_match_table = esp32_uart_dt_ids, diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 3bdaf1ddc309..52c87876a88d 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -851,13 +851,11 @@ static int linflex_probe(struct platform_device *pdev) return uart_add_one_port(&linflex_reg, sport); } -static int linflex_remove(struct platform_device *pdev) +static void linflex_remove(struct platform_device *pdev) { struct uart_port *sport = platform_get_drvdata(pdev); uart_remove_one_port(&linflex_reg, sport); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -884,7 +882,7 @@ static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume); static struct platform_driver linflex_driver = { .probe = linflex_probe, - .remove = linflex_remove, + .remove_new = linflex_remove, .driver = { .name = DRIVER_NAME, .of_match_table = linflex_dt_ids, diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 6d0cfb2e86b4..5ddf110aedbe 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2959,7 +2959,7 @@ failed_reset: return ret; } -static int lpuart_remove(struct platform_device *pdev) +static void lpuart_remove(struct platform_device *pdev) { struct lpuart_port *sport = platform_get_drvdata(pdev); @@ -2976,7 +2976,6 @@ static int lpuart_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - return 0; } static int lpuart_runtime_suspend(struct device *dev) @@ -3210,7 +3209,7 @@ static const struct dev_pm_ops lpuart_pm_ops = { static struct platform_driver lpuart_driver = { .probe = lpuart_probe, - .remove = lpuart_remove, + .remove_new = lpuart_remove, .driver = { .name = "fsl-lpuart", .of_match_table = lpuart_dt_ids, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 708b9852a575..4aa72d5aeafb 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -415,13 +415,13 @@ static void imx_uart_stop_tx(struct uart_port *port) ucr1 = imx_uart_readl(sport, UCR1); imx_uart_writel(sport, ucr1 & ~UCR1_TRDYEN, UCR1); + ucr4 = imx_uart_readl(sport, UCR4); usr2 = imx_uart_readl(sport, USR2); - if (!(usr2 & USR2_TXDC)) { + if ((!(usr2 & USR2_TXDC)) && (ucr4 & UCR4_TCEN)) { /* The shifter is still busy, so retry once TC triggers */ return; } - ucr4 = imx_uart_readl(sport, UCR4); ucr4 &= ~UCR4_TCEN; imx_uart_writel(sport, ucr4, UCR4); @@ -1336,15 +1336,18 @@ static int imx_uart_dma_init(struct imx_port *sport) { struct dma_slave_config slave_config = {}; struct device *dev = sport->port.dev; + struct dma_chan *chan; int ret; /* Prepare for RX : */ - sport->dma_chan_rx = dma_request_slave_channel(dev, "rx"); - if (!sport->dma_chan_rx) { + chan = dma_request_chan(dev, "rx"); + if (IS_ERR(chan)) { dev_dbg(dev, "cannot get the DMA channel.\n"); - ret = -EINVAL; + sport->dma_chan_rx = NULL; + ret = PTR_ERR(chan); goto err; } + sport->dma_chan_rx = chan; slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = sport->port.mapbase + URXD0; @@ -1366,12 +1369,14 @@ static int imx_uart_dma_init(struct imx_port *sport) sport->rx_ring.buf = sport->rx_buf; /* Prepare for TX : */ - sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); - if (!sport->dma_chan_tx) { + chan = dma_request_chan(dev, "tx"); + if (IS_ERR(chan)) { dev_err(dev, "cannot get the TX DMA channel!\n"); - ret = -EINVAL; + sport->dma_chan_tx = NULL; + ret = PTR_ERR(chan); goto err; } + sport->dma_chan_tx = chan; slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = sport->port.mapbase + URTX0; @@ -1943,10 +1948,6 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio rs485conf->flags & SER_RS485_RX_DURING_TX) imx_uart_start_rx(port); - if (port->rs485_rx_during_tx_gpio) - gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, - !!(rs485conf->flags & SER_RS485_RX_DURING_TX)); - return 0; } @@ -2210,7 +2211,6 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t) return HRTIMER_NORESTART; } -static const struct serial_rs485 imx_no_rs485 = {}; /* No RS485 if no RTS */ static const struct serial_rs485 imx_rs485_supported = { .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX, @@ -2294,8 +2294,6 @@ static int imx_uart_probe(struct platform_device *pdev) /* RTS is required to control the RS485 transmitter */ if (sport->have_rtscts || sport->have_rtsgpio) sport->port.rs485_supported = imx_rs485_supported; - else - sport->port.rs485_supported = imx_no_rs485; sport->port.flags = UPF_BOOT_AUTOCONF; timer_setup(&sport->timer, imx_uart_timeout, 0); @@ -2322,19 +2320,13 @@ static int imx_uart_probe(struct platform_device *pdev) /* For register access, we only need to enable the ipg clock. */ ret = clk_prepare_enable(sport->clk_ipg); if (ret) { - dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret); + dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret); return ret; } ret = uart_get_rs485_mode(&sport->port); - if (ret) { - clk_disable_unprepare(sport->clk_ipg); - return ret; - } - - if (sport->port.rs485.flags & SER_RS485_ENABLED && - (!sport->have_rtscts && !sport->have_rtsgpio)) - dev_err(&pdev->dev, "no RTS control, disabling rs485\n"); + if (ret) + goto err_clk; /* * If using the i.MX UART RTS/CTS control then the RTS (CTS_B) @@ -2414,8 +2406,6 @@ static int imx_uart_probe(struct platform_device *pdev) imx_uart_writel(sport, ucr3, UCR3); } - clk_disable_unprepare(sport->clk_ipg); - hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); sport->trigger_start_tx.function = imx_trigger_start_tx; @@ -2431,7 +2421,7 @@ static int imx_uart_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request rx irq: %d\n", ret); - return ret; + goto err_clk; } ret = devm_request_irq(&pdev->dev, txirq, imx_uart_txint, 0, @@ -2439,7 +2429,7 @@ static int imx_uart_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request tx irq: %d\n", ret); - return ret; + goto err_clk; } ret = devm_request_irq(&pdev->dev, rtsirq, imx_uart_rtsint, 0, @@ -2447,14 +2437,14 @@ static int imx_uart_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request rts irq: %d\n", ret); - return ret; + goto err_clk; } } else { ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_int, 0, dev_name(&pdev->dev), sport); if (ret) { dev_err(&pdev->dev, "failed to request irq: %d\n", ret); - return ret; + goto err_clk; } } @@ -2462,16 +2452,19 @@ static int imx_uart_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sport); - return uart_add_one_port(&imx_uart_uart_driver, &sport->port); + ret = uart_add_one_port(&imx_uart_uart_driver, &sport->port); + +err_clk: + clk_disable_unprepare(sport->clk_ipg); + + return ret; } -static int imx_uart_remove(struct platform_device *pdev) +static void imx_uart_remove(struct platform_device *pdev) { struct imx_port *sport = platform_get_drvdata(pdev); uart_remove_one_port(&imx_uart_uart_driver, &sport->port); - - return 0; } static void imx_uart_restore_context(struct imx_port *sport) @@ -2640,7 +2633,7 @@ static const struct dev_pm_ops imx_uart_pm_ops = { static struct platform_driver imx_uart_platform_driver = { .probe = imx_uart_probe, - .remove = imx_uart_remove, + .remove_new = imx_uart_remove, .driver = { .name = "imx-uart", diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index 8489c07f4cd5..df55e5dc5afc 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -115,8 +115,6 @@ struct board_ops { void (*send_start_character)(struct jsm_channel *ch); void (*send_stop_character)(struct jsm_channel *ch); void (*copy_data_from_queue_to_uart)(struct jsm_channel *ch); - u32 (*get_uart_bytes_left)(struct jsm_channel *ch); - void (*send_immediate_char)(struct jsm_channel *ch, unsigned char); }; @@ -127,7 +125,6 @@ struct jsm_board { int boardnum; /* Board number: 0-32 */ - int type; /* Type of board */ u8 rev; /* PCI revision ID */ struct pci_dev *pci_dev; u32 maxports; /* MAX ports this board can handle */ @@ -155,8 +152,6 @@ struct jsm_board u32 bd_dividend; /* Board/UARTs specific dividend */ struct board_ops *bd_ops; - - struct list_head jsm_board_entry; }; /************************************************************************ diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index 3fd57ac3ad81..1eda48964c0b 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -877,28 +877,6 @@ static void cls_uart_off(struct jsm_channel *ch) writeb(0, &ch->ch_cls_uart->ier); } -/* - * cls_get_uarts_bytes_left. - * Returns 0 is nothing left in the FIFO, returns 1 otherwise. - * - * The channel lock MUST be held by the calling function. - */ -static u32 cls_get_uart_bytes_left(struct jsm_channel *ch) -{ - u8 left = 0; - u8 lsr = readb(&ch->ch_cls_uart->lsr); - - /* Determine whether the Transmitter is empty or not */ - if (!(lsr & UART_LSR_TEMT)) - left = 1; - else { - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - left = 0; - } - - return left; -} - /* * cls_send_break. * Starts sending a break thru the UART. @@ -916,18 +894,6 @@ static void cls_send_break(struct jsm_channel *ch) } } -/* - * cls_send_immediate_char. - * Sends a specific character as soon as possible to the UART, - * jumping over any bytes that might be in the write queue. - * - * The channel lock MUST be held by the calling function. - */ -static void cls_send_immediate_char(struct jsm_channel *ch, unsigned char c) -{ - writeb(c, &ch->ch_cls_uart->txrx); -} - struct board_ops jsm_cls_ops = { .intr = cls_intr, .uart_init = cls_uart_init, @@ -943,7 +909,5 @@ struct board_ops jsm_cls_ops = { .send_start_character = cls_send_start_character, .send_stop_character = cls_send_stop_character, .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart, - .get_uart_bytes_left = cls_get_uart_bytes_left, - .send_immediate_char = cls_send_immediate_char }; diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 2bd640428970..1fa10f19368f 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -1309,25 +1309,6 @@ static void neo_uart_off(struct jsm_channel *ch) writeb(0, &ch->ch_neo_uart->ier); } -static u32 neo_get_uart_bytes_left(struct jsm_channel *ch) -{ - u8 left = 0; - u8 lsr = readb(&ch->ch_neo_uart->lsr); - - /* We must cache the LSR as some of the bits get reset once read... */ - ch->ch_cached_lsr |= lsr; - - /* Determine whether the Transmitter is empty or not */ - if (!(lsr & UART_LSR_TEMT)) - left = 1; - else { - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - left = 0; - } - - return left; -} - /* Channel lock MUST be held by the calling function! */ static void neo_send_break(struct jsm_channel *ch) { @@ -1348,25 +1329,6 @@ static void neo_send_break(struct jsm_channel *ch) } } -/* - * neo_send_immediate_char. - * - * Sends a specific character as soon as possible to the UART, - * jumping over any bytes that might be in the write queue. - * - * The channel lock MUST be held by the calling function. - */ -static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c) -{ - if (!ch) - return; - - writeb(c, &ch->ch_neo_uart->txrx); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); -} - struct board_ops jsm_neo_ops = { .intr = neo_intr, .uart_init = neo_uart_init, @@ -1382,6 +1344,4 @@ struct board_ops jsm_neo_ops = { .send_start_character = neo_send_start_character, .send_stop_character = neo_send_stop_character, .copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart, - .get_uart_bytes_left = neo_get_uart_bytes_left, - .send_immediate_char = neo_send_immediate_char }; diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 3adb60c683f7..a0731773ce75 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -887,13 +887,11 @@ static int lqasc_probe(struct platform_device *pdev) return ret; } -static int lqasc_remove(struct platform_device *pdev) +static void lqasc_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&lqasc_reg, port); - - return 0; } static const struct ltq_soc_data soc_data_lantiq = { @@ -917,7 +915,7 @@ MODULE_DEVICE_TABLE(of, ltq_asc_match); static struct platform_driver lqasc_driver = { .probe = lqasc_probe, - .remove = lqasc_remove, + .remove_new = lqasc_remove, .driver = { .name = DRVNAME, .of_match_table = ltq_asc_match, diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index a25ab1efe38f..3ce369f76349 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -336,15 +336,13 @@ err_erase_id: return ret; } -static int liteuart_remove(struct platform_device *pdev) +static void liteuart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); unsigned int line = port->line; uart_remove_one_port(&liteuart_driver, port); xa_erase(&liteuart_array, line); - - return 0; } static const struct of_device_id liteuart_of_match[] = { @@ -355,7 +353,7 @@ MODULE_DEVICE_TABLE(of, liteuart_of_match); static struct platform_driver liteuart_platform_driver = { .probe = liteuart_probe, - .remove = liteuart_remove, + .remove_new = liteuart_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = liteuart_of_match, diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 5149a947b7fe..ec20329f0603 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -659,13 +659,11 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev) /* * Remove serial ports registered against a platform device. */ -static int serial_hs_lpc32xx_remove(struct platform_device *pdev) +static void serial_hs_lpc32xx_remove(struct platform_device *pdev) { struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); uart_remove_one_port(&lpc32xx_hs_reg, &p->port); - - return 0; } @@ -702,7 +700,7 @@ MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids); static struct platform_driver serial_hs_lpc32xx_driver = { .probe = serial_hs_lpc32xx_probe, - .remove = serial_hs_lpc32xx_remove, + .remove_new = serial_hs_lpc32xx_remove, .suspend = serial_hs_lpc32xx_suspend, .resume = serial_hs_lpc32xx_resume, .driver = { diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c index 21b574f78b86..19f0a305cc43 100644 --- a/drivers/tty/serial/ma35d1_serial.c +++ b/drivers/tty/serial/ma35d1_serial.c @@ -558,7 +558,7 @@ static void ma35d1serial_console_write(struct console *co, const char *s, u32 co u32 ier; if ((co->index < 0) || (co->index >= MA35_UART_NR)) { - pr_warn("Failed to write on ononsole port %x, out of range\n", + pr_warn("Failed to write on console port %x, out of range\n", co->index); return; } @@ -754,14 +754,13 @@ err_iounmap: /* * Remove serial ports registered against a platform device. */ -static int ma35d1serial_remove(struct platform_device *dev) +static void ma35d1serial_remove(struct platform_device *dev) { struct uart_port *port = platform_get_drvdata(dev); struct uart_ma35d1_port *up = to_ma35d1_uart_port(port); uart_remove_one_port(&ma35d1serial_reg, port); clk_disable_unprepare(up->clk); - return 0; } static int ma35d1serial_suspend(struct platform_device *dev, pm_message_t state) @@ -794,7 +793,7 @@ static int ma35d1serial_resume(struct platform_device *dev) static struct platform_driver ma35d1serial_driver = { .probe = ma35d1serial_probe, - .remove = ma35d1serial_remove, + .remove_new = ma35d1serial_remove, .suspend = ma35d1serial_suspend, .resume = ma35d1serial_resume, .driver = { diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 97e4965b73d4..f3a99daebdaa 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -780,7 +780,7 @@ static void max310x_handle_tx(struct uart_port *port) to_send = uart_circ_chars_pending(xmit); until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (likely(to_send)) { - /* Limit to size of TX FIFO */ + /* Limit to space available in TX FIFO */ txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); txlen = port->fifosize - txlen; to_send = (to_send > txlen) ? txlen : to_send; diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 91b15243f6c6..8690a45239e0 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -627,7 +627,7 @@ static int mcf_probe(struct platform_device *pdev) /****************************************************************************/ -static int mcf_remove(struct platform_device *pdev) +static void mcf_remove(struct platform_device *pdev) { struct uart_port *port; int i; @@ -637,15 +637,13 @@ static int mcf_remove(struct platform_device *pdev) if (port) uart_remove_one_port(&mcf_driver, port); } - - return 0; } /****************************************************************************/ static struct platform_driver mcf_platform_driver = { .probe = mcf_probe, - .remove = mcf_remove, + .remove_new = mcf_remove, .driver = { .name = "mcfuart", }, diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 8dd84617e715..8395688f5ee9 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -795,7 +795,7 @@ static int meson_uart_probe(struct platform_device *pdev) return ret; } -static int meson_uart_remove(struct platform_device *pdev) +static void meson_uart_remove(struct platform_device *pdev) { struct uart_driver *uart_driver; struct uart_port *port; @@ -807,12 +807,10 @@ static int meson_uart_remove(struct platform_device *pdev) for (int id = 0; id < AML_UART_PORT_NUM; id++) if (meson_ports[id]) - return 0; + return; /* No more available uart ports, unregister uart driver */ uart_unregister_driver(uart_driver); - - return 0; } static struct meson_uart_data meson_g12a_uart_data = { @@ -852,7 +850,7 @@ MODULE_DEVICE_TABLE(of, meson_uart_dt_match); static struct platform_driver meson_uart_platform_driver = { .probe = meson_uart_probe, - .remove = meson_uart_remove, + .remove_new = meson_uart_remove, .driver = { .name = "meson_uart", .of_match_table = meson_uart_dt_match, diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c index db3b81f2aa57..da4c6f7e2a30 100644 --- a/drivers/tty/serial/milbeaut_usio.c +++ b/drivers/tty/serial/milbeaut_usio.c @@ -552,15 +552,13 @@ failed: return ret; } -static int mlb_usio_remove(struct platform_device *pdev) +static void mlb_usio_remove(struct platform_device *pdev) { struct uart_port *port = &mlb_usio_ports[pdev->id]; struct clk *clk = port->private_data; uart_remove_one_port(&mlb_usio_uart_driver, port); clk_disable_unprepare(clk); - - return 0; } static const struct of_device_id mlb_usio_dt_ids[] = { @@ -571,7 +569,7 @@ MODULE_DEVICE_TABLE(of, mlb_usio_dt_ids); static struct platform_driver mlb_usio_driver = { .probe = mlb_usio_probe, - .remove = mlb_usio_remove, + .remove_new = mlb_usio_remove, .driver = { .name = USIO_NAME, .of_match_table = mlb_usio_dt_ids, diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index a252465e745f..95dae5e27b28 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1765,15 +1765,12 @@ static int mpc52xx_uart_of_probe(struct platform_device *op) return 0; } -static int -mpc52xx_uart_of_remove(struct platform_device *op) +static void mpc52xx_uart_of_remove(struct platform_device *op) { struct uart_port *port = platform_get_drvdata(op); if (port) uart_remove_one_port(&mpc52xx_uart_driver, port); - - return 0; } #ifdef CONFIG_PM @@ -1846,7 +1843,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); static struct platform_driver mpc52xx_uart_of_driver = { .probe = mpc52xx_uart_of_probe, - .remove = mpc52xx_uart_of_remove, + .remove_new = mpc52xx_uart_of_remove, #ifdef CONFIG_PM .suspend = mpc52xx_uart_of_suspend, .resume = mpc52xx_uart_of_resume, diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 597264b546fd..e24204ad35de 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1131,7 +1132,7 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, uart_port_unlock_irqrestore(port, flags); entry = msm_find_best_baud(port, baud, &rate); - clk_set_rate(msm_port->clk, rate); + dev_pm_opp_set_rate(port->dev, rate); baud = rate / 16 / entry->divisor; uart_port_lock_irqsave(port, &flags); @@ -1186,6 +1187,7 @@ static void msm_init_clock(struct uart_port *port) { struct msm_port *msm_port = to_msm_port(port); + dev_pm_opp_set_rate(port->dev, port->uartclk); clk_prepare_enable(msm_port->clk); clk_prepare_enable(msm_port->pclk); msm_serial_set_mnd_regs(port); @@ -1239,6 +1241,7 @@ err_irq: clk_disable_unprepare(msm_port->pclk); clk_disable_unprepare(msm_port->clk); + dev_pm_opp_set_rate(port->dev, 0); return ret; } @@ -1254,6 +1257,7 @@ static void msm_shutdown(struct uart_port *port) msm_release_dma(msm_port); clk_disable_unprepare(msm_port->clk); + dev_pm_opp_set_rate(port->dev, 0); free_irq(port->irq, port); } @@ -1419,11 +1423,13 @@ static void msm_power(struct uart_port *port, unsigned int state, switch (state) { case 0: + dev_pm_opp_set_rate(port->dev, port->uartclk); clk_prepare_enable(msm_port->clk); clk_prepare_enable(msm_port->pclk); break; case 3: clk_disable_unprepare(msm_port->clk); + dev_pm_opp_set_rate(port->dev, 0); clk_disable_unprepare(msm_port->pclk); break; default: @@ -1789,7 +1795,7 @@ static int msm_serial_probe(struct platform_device *pdev) struct resource *resource; struct uart_port *port; const struct of_device_id *id; - int irq, line; + int irq, line, ret; if (pdev->dev.of_node) line = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -1824,6 +1830,15 @@ static int msm_serial_probe(struct platform_device *pdev) return PTR_ERR(msm_port->pclk); } + ret = devm_pm_opp_set_clkname(&pdev->dev, "core"); + if (ret) + return ret; + + /* OPP table is optional */ + ret = devm_pm_opp_of_add_table(&pdev->dev); + if (ret && ret != -ENODEV) + return dev_err_probe(&pdev->dev, ret, "invalid OPP table\n"); + port->uartclk = clk_get_rate(msm_port->clk); dev_info(&pdev->dev, "uartclk = %d\n", port->uartclk); @@ -1843,13 +1858,11 @@ static int msm_serial_probe(struct platform_device *pdev) return uart_add_one_port(&msm_uart_driver, port); } -static int msm_serial_remove(struct platform_device *pdev) +static void msm_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&msm_uart_driver, port); - - return 0; } static const struct of_device_id msm_match_table[] = { @@ -1882,7 +1895,7 @@ static const struct dev_pm_ops msm_serial_dev_pm_ops = { }; static struct platform_driver msm_platform_driver = { - .remove = msm_serial_remove, + .remove_new = msm_serial_remove, .probe = msm_serial_probe, .driver = { .name = "msm_serial", diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 8eeecf8ad359..3ec725555bcc 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -904,21 +904,27 @@ static void mxs_auart_dma_exit(struct mxs_auart_port *s) static int mxs_auart_dma_init(struct mxs_auart_port *s) { + struct dma_chan *chan; + if (auart_dma_enabled(s)) return 0; /* init for RX */ - s->rx_dma_chan = dma_request_slave_channel(s->dev, "rx"); - if (!s->rx_dma_chan) + chan = dma_request_chan(s->dev, "rx"); + if (IS_ERR(chan)) goto err_out; + s->rx_dma_chan = chan; + s->rx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA); if (!s->rx_dma_buf) goto err_out; /* init for TX */ - s->tx_dma_chan = dma_request_slave_channel(s->dev, "tx"); - if (!s->tx_dma_chan) + chan = dma_request_chan(s->dev, "tx"); + if (IS_ERR(chan)) goto err_out; + s->tx_dma_chan = chan; + s->tx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA); if (!s->tx_dma_buf) goto err_out; @@ -1686,7 +1692,7 @@ out_disable_clks: return ret; } -static int mxs_auart_remove(struct platform_device *pdev) +static void mxs_auart_remove(struct platform_device *pdev) { struct mxs_auart_port *s = platform_get_drvdata(pdev); @@ -1698,13 +1704,11 @@ static int mxs_auart_remove(struct platform_device *pdev) clk_disable_unprepare(s->clk); clk_disable_unprepare(s->clk_ahb); } - - return 0; } static struct platform_driver mxs_auart_driver = { .probe = mxs_auart_probe, - .remove = mxs_auart_remove, + .remove_new = mxs_auart_remove, .driver = { .name = "mxs-auart", .of_match_table = mxs_auart_dt_ids, diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index ad4c1c5d0a7f..f5a0b401af63 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1483,6 +1483,13 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) return omap_up_info; } +static const struct serial_rs485 serial_omap_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | + SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + static int serial_omap_probe_rs485(struct uart_omap_port *up, struct device *dev) { @@ -1497,6 +1504,9 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, if (!np) return 0; + up->port.rs485_config = serial_omap_config_rs485; + up->port.rs485_supported = serial_omap_rs485_supported; + ret = uart_get_rs485_mode(&up->port); if (ret) return ret; @@ -1531,13 +1541,6 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, return 0; } -static const struct serial_rs485 serial_omap_rs485_supported = { - .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND | - SER_RS485_RX_DURING_TX, - .delay_rts_before_send = 1, - .delay_rts_after_send = 1, -}; - static int serial_omap_probe(struct platform_device *pdev) { struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); @@ -1604,17 +1607,11 @@ static int serial_omap_probe(struct platform_device *pdev) dev_info(up->port.dev, "no wakeirq for uart%d\n", up->port.line); - ret = serial_omap_probe_rs485(up, &pdev->dev); - if (ret < 0) - goto err_rs485; - sprintf(up->name, "OMAP UART%d", up->port.line); up->port.mapbase = mem->start; up->port.membase = base; up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; - up->port.rs485_config = serial_omap_config_rs485; - up->port.rs485_supported = serial_omap_rs485_supported; if (!up->port.uartclk) { up->port.uartclk = DEFAULT_CLK_SPEED; dev_warn(&pdev->dev, @@ -1622,6 +1619,10 @@ static int serial_omap_probe(struct platform_device *pdev) DEFAULT_CLK_SPEED); } + ret = serial_omap_probe_rs485(up, &pdev->dev); + if (ret < 0) + goto err_rs485; + up->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE; up->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE; cpu_latency_qos_add_request(&up->pm_qos_request, up->latency); @@ -1658,7 +1659,7 @@ err_port_line: return ret; } -static int serial_omap_remove(struct platform_device *dev) +static void serial_omap_remove(struct platform_device *dev) { struct uart_omap_port *up = platform_get_drvdata(dev); @@ -1670,8 +1671,6 @@ static int serial_omap_remove(struct platform_device *dev) pm_runtime_disable(up->dev); cpu_latency_qos_remove_request(&up->pm_qos_request); device_init_wakeup(&dev->dev, false); - - return 0; } /* @@ -1808,7 +1807,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match); static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, - .remove = serial_omap_remove, + .remove_new = serial_omap_remove, .driver = { .name = OMAP_SERIAL_DRIVER_NAME, .pm = &serial_omap_dev_pm_ops, diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index 919f5e5aa0f1..d9fe85397741 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -725,20 +725,18 @@ static int owl_uart_probe(struct platform_device *pdev) return ret; } -static int owl_uart_remove(struct platform_device *pdev) +static void owl_uart_remove(struct platform_device *pdev) { struct owl_uart_port *owl_port = platform_get_drvdata(pdev); uart_remove_one_port(&owl_uart_driver, &owl_port->port); owl_uart_ports[pdev->id] = NULL; clk_disable_unprepare(owl_port->clk); - - return 0; } static struct platform_driver owl_uart_platform_driver = { .probe = owl_uart_probe, - .remove = owl_uart_remove, + .remove_new = owl_uart_remove, .driver = { .name = "owl-uart", .of_match_table = owl_uart_dt_matches, diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index 3a95bf5d55d3..bbb46e6e98a2 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -938,7 +938,7 @@ err: return ret; } -static int pic32_uart_remove(struct platform_device *pdev) +static void pic32_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct pic32_sport *sport = to_pic32_sport(port); @@ -947,9 +947,6 @@ static int pic32_uart_remove(struct platform_device *pdev) clk_disable_unprepare(sport->clk); platform_set_drvdata(pdev, NULL); pic32_sports[sport->idx] = NULL; - - /* automatic unroll of sport and gpios */ - return 0; } static const struct of_device_id pic32_serial_dt_ids[] = { @@ -960,7 +957,7 @@ MODULE_DEVICE_TABLE(of, pic32_serial_dt_ids); static struct platform_driver pic32_uart_platform_driver = { .probe = pic32_uart_probe, - .remove = pic32_uart_remove, + .remove_new = pic32_uart_remove, .driver = { .name = PIC32_DEV_NAME, .of_match_table = of_match_ptr(pic32_serial_dt_ids), diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 7e78f97e8f43..e63a8fbe63bd 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1696,7 +1696,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) return 0; } -static int qcom_geni_serial_remove(struct platform_device *pdev) +static void qcom_geni_serial_remove(struct platform_device *pdev) { struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); struct uart_driver *drv = port->private_data.drv; @@ -1704,8 +1704,6 @@ static int qcom_geni_serial_remove(struct platform_device *pdev) dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); uart_remove_one_port(drv, &port->uport); - - return 0; } static int qcom_geni_serial_sys_suspend(struct device *dev) @@ -1805,7 +1803,7 @@ static const struct of_device_id qcom_geni_serial_match_table[] = { MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); static struct platform_driver qcom_geni_serial_platform_driver = { - .remove = qcom_geni_serial_remove, + .remove_new = qcom_geni_serial_remove, .probe = qcom_geni_serial_probe, .driver = { .name = "qcom_geni_serial", diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index d824c8318f33..13deb355cf1b 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -780,19 +780,17 @@ static int rda_uart_probe(struct platform_device *pdev) return ret; } -static int rda_uart_remove(struct platform_device *pdev) +static void rda_uart_remove(struct platform_device *pdev) { struct rda_uart_port *rda_port = platform_get_drvdata(pdev); uart_remove_one_port(&rda_uart_driver, &rda_port->port); rda_uart_ports[pdev->id] = NULL; - - return 0; } static struct platform_driver rda_uart_platform_driver = { .probe = rda_uart_probe, - .remove = rda_uart_remove, + .remove_new = rda_uart_remove, .driver = { .name = "rda-uart", .of_match_table = rda_uart_dt_matches, diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index d46a81cddfcd..4132fcff7d4e 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -178,7 +178,6 @@ struct rp2_card; struct rp2_uart_port { struct uart_port port; int idx; - int ignore_rx; struct rp2_card *card; void __iomem *asic_base; void __iomem *base; diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index be7bcd75d9f4..79c794fa6545 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -870,19 +870,17 @@ static int sa1100_serial_probe(struct platform_device *dev) return 0; } -static int sa1100_serial_remove(struct platform_device *pdev) +static void sa1100_serial_remove(struct platform_device *pdev) { struct sa1100_port *sport = platform_get_drvdata(pdev); if (sport) uart_remove_one_port(&sa1100_reg, &sport->port); - - return 0; } static struct platform_driver sa11x0_serial_driver = { .probe = sa1100_serial_probe, - .remove = sa1100_serial_remove, + .remove_new = sa1100_serial_remove, .suspend = sa1100_serial_suspend, .resume = sa1100_serial_resume, .driver = { diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 66bd6c090ace..71d17d804fda 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2054,7 +2054,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) return 0; } -static int s3c24xx_serial_remove(struct platform_device *dev) +static void s3c24xx_serial_remove(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); @@ -2063,8 +2063,6 @@ static int s3c24xx_serial_remove(struct platform_device *dev) } uart_unregister_driver(&s3c24xx_uart_drv); - - return 0; } /* UART power management code */ @@ -2627,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); static struct platform_driver samsung_serial_driver = { .probe = s3c24xx_serial_probe, - .remove = s3c24xx_serial_remove, + .remove_new = s3c24xx_serial_remove, .id_table = s3c24xx_serial_driver_ids, .driver = { .name = "samsung-uart", diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index cf0c6120d30e..929206a9a6e1 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -24,10 +24,12 @@ #include #include #include +#include #include #define SC16IS7XX_NAME "sc16is7xx" #define SC16IS7XX_MAX_DEVS 8 +#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */ /* SC16IS7XX register definitions */ #define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */ @@ -300,8 +302,8 @@ /* Misc definitions */ +#define SC16IS7XX_SPI_READ_BIT BIT(7) #define SC16IS7XX_FIFO_SIZE (64) -#define SC16IS7XX_REG_SHIFT 2 #define SC16IS7XX_GPIOS_PER_BANK 4 struct sc16is7xx_devtype { @@ -322,18 +324,19 @@ struct sc16is7xx_one_config { struct sc16is7xx_one { struct uart_port port; - u8 line; + struct regmap *regmap; + struct mutex efr_lock; /* EFR registers access */ struct kthread_work tx_work; struct kthread_work reg_work; struct kthread_delayed_work ms_work; struct sc16is7xx_one_config config; - bool irda_mode; unsigned int old_mctrl; + u8 old_lcr; /* Value before EFR access. */ + bool irda_mode; }; struct sc16is7xx_port { const struct sc16is7xx_devtype *devtype; - struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; @@ -343,65 +346,47 @@ struct sc16is7xx_port { unsigned char buf[SC16IS7XX_FIFO_SIZE]; struct kthread_worker kworker; struct task_struct *kworker_task; - struct mutex efr_lock; struct sc16is7xx_one p[]; }; -static unsigned long sc16is7xx_lines; +static DECLARE_BITMAP(sc16is7xx_lines, SC16IS7XX_MAX_DEVS); static struct uart_driver sc16is7xx_uart = { .owner = THIS_MODULE, + .driver_name = SC16IS7XX_NAME, .dev_name = "ttySC", .nr = SC16IS7XX_MAX_DEVS, }; -static void sc16is7xx_ier_set(struct uart_port *port, u8 bit); -static void sc16is7xx_stop_tx(struct uart_port *port); - #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) -static int sc16is7xx_line(struct uart_port *port) -{ - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - - return one->line; -} - static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); unsigned int val = 0; - const u8 line = sc16is7xx_line(port); - regmap_read(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, &val); + regmap_read(one->regmap, reg, &val); return val; } static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - regmap_write(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, val); + regmap_write(one->regmap, reg, val); } -static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen) +static void sc16is7xx_fifo_read(struct uart_port *port, u8 *rxbuf, unsigned int rxlen) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); - u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | line; + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - regcache_cache_bypass(s->regmap, true); - regmap_raw_read(s->regmap, addr, s->buf, rxlen); - regcache_cache_bypass(s->regmap, false); + regmap_noinc_read(one->regmap, SC16IS7XX_RHR_REG, rxbuf, rxlen); } -static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send) +static void sc16is7xx_fifo_write(struct uart_port *port, u8 *txbuf, u8 to_send) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); - u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line; + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); /* * Don't send zero-length data, at least on SPI it confuses the chip @@ -410,32 +395,15 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send) if (unlikely(!to_send)) return; - regcache_cache_bypass(s->regmap, true); - regmap_raw_write(s->regmap, addr, s->buf, to_send); - regcache_cache_bypass(s->regmap, false); + regmap_noinc_write(one->regmap, SC16IS7XX_THR_REG, txbuf, to_send); } static void sc16is7xx_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - const u8 line = sc16is7xx_line(port); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - regmap_update_bits(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, - mask, val); -} - -static int sc16is7xx_alloc_line(void) -{ - int i; - - BUILD_BUG_ON(SC16IS7XX_MAX_DEVS > BITS_PER_LONG); - - for (i = 0; i < SC16IS7XX_MAX_DEVS; i++) - if (!test_and_set_bit(i, &sc16is7xx_lines)) - break; - - return i; + regmap_update_bits(one->regmap, reg, mask, val); } static void sc16is7xx_power(struct uart_port *port, int on) @@ -445,6 +413,85 @@ static void sc16is7xx_power(struct uart_port *port, int on) on ? 0 : SC16IS7XX_IER_SLEEP_BIT); } +/* + * In an amazing feat of design, the Enhanced Features Register (EFR) + * shares the address of the Interrupt Identification Register (IIR). + * Access to EFR is switched on by writing a magic value (0xbf) to the + * Line Control Register (LCR). Any interrupt firing during this time will + * see the EFR where it expects the IIR to be, leading to + * "Unexpected interrupt" messages. + * + * Prevent this possibility by claiming a mutex while accessing the EFR, + * and claiming the same mutex from within the interrupt handler. This is + * similar to disabling the interrupt, but that doesn't work because the + * bulk of the interrupt processing is run as a workqueue job in thread + * context. + */ +static void sc16is7xx_efr_lock(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + mutex_lock(&one->efr_lock); + + /* Backup content of LCR. */ + one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); + + /* Enable access to Enhanced register set */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B); + + /* Disable cache updates when writing to EFR registers */ + regcache_cache_bypass(one->regmap, true); +} + +static void sc16is7xx_efr_unlock(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + /* Re-enable cache updates when writing to normal registers */ + regcache_cache_bypass(one->regmap, false); + + /* Restore original content of LCR */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, one->old_lcr); + + mutex_unlock(&one->efr_lock); +} + +static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + lockdep_assert_held_once(&port->lock); + + one->config.flags |= SC16IS7XX_RECONF_IER; + one->config.ier_mask |= bit; + one->config.ier_val &= ~bit; + kthread_queue_work(&s->kworker, &one->reg_work); +} + +static void sc16is7xx_ier_set(struct uart_port *port, u8 bit) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + lockdep_assert_held_once(&port->lock); + + one->config.flags |= SC16IS7XX_RECONF_IER; + one->config.ier_mask |= bit; + one->config.ier_val |= bit; + kthread_queue_work(&s->kworker, &one->reg_work); +} + +static void sc16is7xx_stop_tx(struct uart_port *port) +{ + sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT); +} + +static void sc16is7xx_stop_rx(struct uart_port *port) +{ + sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); +} + static const struct sc16is7xx_devtype sc16is74x_devtype = { .name = "SC16IS74X", .nr_gpio = 0, @@ -477,7 +524,7 @@ static const struct sc16is7xx_devtype sc16is762_devtype = { static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) { - switch (reg >> SC16IS7XX_REG_SHIFT) { + switch (reg) { case SC16IS7XX_RHR_REG: case SC16IS7XX_IIR_REG: case SC16IS7XX_LSR_REG: @@ -488,85 +535,60 @@ static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) case SC16IS7XX_IOCONTROL_REG: return true; default: - break; + return false; } - - return false; } static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg) { - switch (reg >> SC16IS7XX_REG_SHIFT) { + switch (reg) { case SC16IS7XX_RHR_REG: return true; default: - break; + return false; } +} - return false; +static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) +{ + return reg == SC16IS7XX_RHR_REG; } static int sc16is7xx_set_baud(struct uart_port *port, int baud) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); u8 lcr; u8 prescaler = 0; unsigned long clk = port->uartclk, div = clk / 16 / baud; - if (div > 0xffff) { + if (div >= BIT(16)) { prescaler = SC16IS7XX_MCR_CLKSEL_BIT; div /= 4; } - /* In an amazing feat of design, the Enhanced Features Register shares - * the address of the Interrupt Identification Register, and is - * switched in by writing a magic value (0xbf) to the Line Control - * Register. Any interrupt firing during this time will see the EFR - * where it expects the IIR to be, leading to "Unexpected interrupt" - * messages. - * - * Prevent this possibility by claiming a mutex while accessing the - * EFR, and claiming the same mutex from within the interrupt handler. - * This is similar to disabling the interrupt, but that doesn't work - * because the bulk of the interrupt processing is run as a workqueue - * job in thread context. - */ - mutex_lock(&s->efr_lock); - - lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); - - /* Open the LCR divisors for configuration */ - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, - SC16IS7XX_LCR_CONF_MODE_B); - /* Enable enhanced features */ - regcache_cache_bypass(s->regmap, true); + sc16is7xx_efr_lock(port); sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, SC16IS7XX_EFR_ENABLE_BIT, SC16IS7XX_EFR_ENABLE_BIT); - - regcache_cache_bypass(s->regmap, false); - - /* Put LCR back to the normal mode */ - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); - - mutex_unlock(&s->efr_lock); + sc16is7xx_efr_unlock(port); sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_CLKSEL_BIT, prescaler); - /* Open the LCR divisors for configuration */ + /* Backup LCR and access special register set (DLL/DLH) */ + lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_A); /* Write the new divisor */ - regcache_cache_bypass(s->regmap, true); + regcache_cache_bypass(one->regmap, true); sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); - regcache_cache_bypass(s->regmap, false); + regcache_cache_bypass(one->regmap, false); - /* Put LCR back to the normal mode */ + /* Restore LCR and access to general register set */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); return DIV_ROUND_CLOSEST(clk / 16, div); @@ -602,7 +624,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG); bytes_read = 1; } else { - sc16is7xx_fifo_read(port, rxlen); + sc16is7xx_fifo_read(port, s->buf, rxlen); bytes_read = rxlen; } @@ -675,7 +697,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port) /* Get length of data pending in circular buffer */ to_send = uart_circ_chars_pending(xmit); if (likely(to_send)) { - /* Limit to size of TX FIFO */ + /* Limit to space available in TX FIFO */ txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); if (txlen > SC16IS7XX_FIFO_SIZE) { dev_err_ratelimited(port->dev, @@ -691,7 +713,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port) uart_xmit_advance(port, 1); } - sc16is7xx_fifo_write(port, to_send); + sc16is7xx_fifo_write(port, s->buf, to_send); } uart_port_lock_irqsave(port, &flags); @@ -700,6 +722,8 @@ static void sc16is7xx_handle_tx(struct uart_port *port) if (uart_circ_empty(xmit)) sc16is7xx_stop_tx(port); + else + sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); uart_port_unlock_irqrestore(port, flags); } @@ -718,11 +742,10 @@ static unsigned int sc16is7xx_get_hwmctrl(struct uart_port *port) static void sc16is7xx_update_mlines(struct sc16is7xx_one *one) { struct uart_port *port = &one->port; - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned long flags; unsigned int status, changed; - lockdep_assert_held_once(&s->efr_lock); + lockdep_assert_held_once(&one->efr_lock); status = sc16is7xx_get_hwmctrl(port); changed = status ^ one->old_mctrl; @@ -748,74 +771,77 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one) static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) { + bool rc = true; + unsigned int iir, rxlen; struct uart_port *port = &s->p[portno].port; + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - do { - unsigned int iir, rxlen; - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + mutex_lock(&one->efr_lock); - iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); - if (iir & SC16IS7XX_IIR_NO_INT_BIT) - return false; + iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); + if (iir & SC16IS7XX_IIR_NO_INT_BIT) { + rc = false; + goto out_port_irq; + } - iir &= SC16IS7XX_IIR_ID_MASK; + iir &= SC16IS7XX_IIR_ID_MASK; - switch (iir) { - case SC16IS7XX_IIR_RDI_SRC: - case SC16IS7XX_IIR_RLSE_SRC: - case SC16IS7XX_IIR_RTOI_SRC: - case SC16IS7XX_IIR_XOFFI_SRC: - rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); + switch (iir) { + case SC16IS7XX_IIR_RDI_SRC: + case SC16IS7XX_IIR_RLSE_SRC: + case SC16IS7XX_IIR_RTOI_SRC: + case SC16IS7XX_IIR_XOFFI_SRC: + rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); - /* - * There is a silicon bug that makes the chip report a - * time-out interrupt but no data in the FIFO. This is - * described in errata section 18.1.4. - * - * When this happens, read one byte from the FIFO to - * clear the interrupt. - */ - if (iir == SC16IS7XX_IIR_RTOI_SRC && !rxlen) - rxlen = 1; + /* + * There is a silicon bug that makes the chip report a + * time-out interrupt but no data in the FIFO. This is + * described in errata section 18.1.4. + * + * When this happens, read one byte from the FIFO to + * clear the interrupt. + */ + if (iir == SC16IS7XX_IIR_RTOI_SRC && !rxlen) + rxlen = 1; - if (rxlen) - sc16is7xx_handle_rx(port, rxlen, iir); - break; + if (rxlen) + sc16is7xx_handle_rx(port, rxlen, iir); + break; /* CTSRTS interrupt comes only when CTS goes inactive */ - case SC16IS7XX_IIR_CTSRTS_SRC: - case SC16IS7XX_IIR_MSI_SRC: - sc16is7xx_update_mlines(one); - break; - case SC16IS7XX_IIR_THRI_SRC: - sc16is7xx_handle_tx(port); - break; - default: - dev_err_ratelimited(port->dev, - "ttySC%i: Unexpected interrupt: %x", - port->line, iir); - break; - } - } while (0); - return true; + case SC16IS7XX_IIR_CTSRTS_SRC: + case SC16IS7XX_IIR_MSI_SRC: + sc16is7xx_update_mlines(one); + break; + case SC16IS7XX_IIR_THRI_SRC: + sc16is7xx_handle_tx(port); + break; + default: + dev_err_ratelimited(port->dev, + "ttySC%i: Unexpected interrupt: %x", + port->line, iir); + break; + } + +out_port_irq: + mutex_unlock(&one->efr_lock); + + return rc; } static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) { + bool keep_polling; + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; - mutex_lock(&s->efr_lock); - - while (1) { - bool keep_polling = false; + do { int i; + keep_polling = false; + for (i = 0; i < s->devtype->nr_uart; ++i) keep_polling |= sc16is7xx_port_irq(s, i); - if (!keep_polling) - break; - } - - mutex_unlock(&s->efr_lock); + } while (keep_polling); return IRQ_HANDLED; } @@ -823,20 +849,15 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) static void sc16is7xx_tx_proc(struct kthread_work *ws) { struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - unsigned long flags; + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); if ((port->rs485.flags & SER_RS485_ENABLED) && (port->rs485.delay_rts_before_send > 0)) msleep(port->rs485.delay_rts_before_send); - mutex_lock(&s->efr_lock); + mutex_lock(&one->efr_lock); sc16is7xx_handle_tx(port); - mutex_unlock(&s->efr_lock); - - uart_port_lock_irqsave(port, &flags); - sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); - uart_port_unlock_irqrestore(port, flags); + mutex_unlock(&one->efr_lock); } static void sc16is7xx_reconf_rs485(struct uart_port *port) @@ -897,51 +918,15 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws) sc16is7xx_reconf_rs485(&one->port); } -static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) -{ - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - - lockdep_assert_held_once(&port->lock); - - one->config.flags |= SC16IS7XX_RECONF_IER; - one->config.ier_mask |= bit; - one->config.ier_val &= ~bit; - kthread_queue_work(&s->kworker, &one->reg_work); -} - -static void sc16is7xx_ier_set(struct uart_port *port, u8 bit) -{ - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - - lockdep_assert_held_once(&port->lock); - - one->config.flags |= SC16IS7XX_RECONF_IER; - one->config.ier_mask |= bit; - one->config.ier_val |= bit; - kthread_queue_work(&s->kworker, &one->reg_work); -} - -static void sc16is7xx_stop_tx(struct uart_port *port) -{ - sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT); -} - -static void sc16is7xx_stop_rx(struct uart_port *port) -{ - sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); -} - static void sc16is7xx_ms_proc(struct kthread_work *ws) { struct sc16is7xx_one *one = to_sc16is7xx_one(ws, ms_work.work); struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); if (one->port.state) { - mutex_lock(&s->efr_lock); + mutex_lock(&one->efr_lock); sc16is7xx_update_mlines(one); - mutex_unlock(&s->efr_lock); + mutex_unlock(&one->efr_lock); kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ); } @@ -1025,7 +1010,6 @@ static void sc16is7xx_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); unsigned int lcr, flow = 0; int baud; @@ -1083,17 +1067,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, if (!(termios->c_cflag & CREAD)) port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; - /* As above, claim the mutex while accessing the EFR. */ - mutex_lock(&s->efr_lock); - - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, - SC16IS7XX_LCR_CONF_MODE_B); - /* Configure flow control */ - regcache_cache_bypass(s->regmap, true); - sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); - sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); - port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); if (termios->c_cflag & CRTSCTS) { flow |= SC16IS7XX_EFR_AUTOCTS_BIT | @@ -1105,16 +1079,16 @@ static void sc16is7xx_set_termios(struct uart_port *port, if (termios->c_iflag & IXOFF) flow |= SC16IS7XX_EFR_SWFLOW1_BIT; - sc16is7xx_port_update(port, - SC16IS7XX_EFR_REG, - SC16IS7XX_EFR_FLOWCTRL_BITS, - flow); - regcache_cache_bypass(s->regmap, false); - /* Update LCR register */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); - mutex_unlock(&s->efr_lock); + /* Update EFR registers */ + sc16is7xx_efr_lock(port); + sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); + sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); + sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_FLOWCTRL_BITS, flow); + sc16is7xx_efr_unlock(port); /* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old, @@ -1160,7 +1134,6 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi static int sc16is7xx_startup(struct uart_port *port) { struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val; unsigned long flags; @@ -1177,7 +1150,7 @@ static int sc16is7xx_startup(struct uart_port *port) sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B); - regcache_cache_bypass(s->regmap, true); + regcache_cache_bypass(one->regmap, true); /* Enable write access to enhanced features and internal clock div */ sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, @@ -1195,7 +1168,7 @@ static int sc16is7xx_startup(struct uart_port *port) SC16IS7XX_TCR_RX_RESUME(24) | SC16IS7XX_TCR_RX_HALT(48)); - regcache_cache_bypass(s->regmap, false); + regcache_cache_bypass(one->regmap, false); /* Now, initialize the UART */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); @@ -1425,7 +1398,7 @@ static void sc16is7xx_setup_irda_ports(struct sc16is7xx_port *s) int i; int ret; int count; - u32 irda_port[2]; + u32 irda_port[SC16IS7XX_MAX_PORTS]; struct device *dev = s->p[0].port.dev; count = device_property_count_u32(dev, "irda-mode-ports"); @@ -1446,12 +1419,13 @@ static void sc16is7xx_setup_irda_ports(struct sc16is7xx_port *s) /* * Configure ports designated to operate as modem control lines. */ -static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s) +static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s, + struct regmap *regmap) { int i; int ret; int count; - u32 mctrl_port[2]; + u32 mctrl_port[SC16IS7XX_MAX_PORTS]; struct device *dev = s->p[0].port.dev; count = device_property_count_u32(dev, "nxp,modem-control-line-ports"); @@ -1475,8 +1449,8 @@ static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s) if (s->mctrl_mask) regmap_update_bits( - s->regmap, - SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT, + regmap, + SC16IS7XX_IOCONTROL_REG, SC16IS7XX_IOCONTROL_MODEM_A_BIT | SC16IS7XX_IOCONTROL_MODEM_B_BIT, s->mctrl_mask); @@ -1491,7 +1465,7 @@ static const struct serial_rs485 sc16is7xx_rs485_supported = { static int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, - struct regmap *regmap, int irq) + struct regmap *regmaps[], int irq) { unsigned long freq = 0, *pfreq = dev_get_platdata(dev); unsigned int val; @@ -1499,16 +1473,20 @@ static int sc16is7xx_probe(struct device *dev, int i, ret; struct sc16is7xx_port *s; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + for (i = 0; i < devtype->nr_uart; i++) + if (IS_ERR(regmaps[i])) + return PTR_ERR(regmaps[i]); /* * This device does not have an identification register that would * tell us if we are really connected to the correct device. * The best we can do is to check if communication is at all possible. + * + * Note: regmap[0] is used in the probe function to access registers + * common to all channels/ports, as it is guaranteed to be present on + * all variants. */ - ret = regmap_read(regmap, - SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val); + ret = regmap_read(regmaps[0], SC16IS7XX_LSR_REG, &val); if (ret < 0) return -EPROBE_DEFER; @@ -1542,10 +1520,8 @@ static int sc16is7xx_probe(struct device *dev, return -EINVAL; } - s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); - mutex_init(&s->efr_lock); kthread_init_worker(&s->kworker); s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, @@ -1557,11 +1533,17 @@ static int sc16is7xx_probe(struct device *dev, sched_set_fifo(s->kworker_task); /* reset device, purging any pending irq / data */ - regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT, - SC16IS7XX_IOCONTROL_SRESET_BIT); + regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG, + SC16IS7XX_IOCONTROL_SRESET_BIT); for (i = 0; i < devtype->nr_uart; ++i) { - s->p[i].line = i; + s->p[i].port.line = find_first_zero_bit(sc16is7xx_lines, + SC16IS7XX_MAX_DEVS); + if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { + ret = -ERANGE; + goto out_ports; + } + /* Initialize port data */ s->p[i].port.dev = dev; s->p[i].port.irq = irq; @@ -1581,12 +1563,9 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.rs485_supported = sc16is7xx_rs485_supported; s->p[i].port.ops = &sc16is7xx_ops; s->p[i].old_mctrl = 0; - s->p[i].port.line = sc16is7xx_alloc_line(); + s->p[i].regmap = regmaps[i]; - if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { - ret = -ENOMEM; - goto out_ports; - } + mutex_init(&s->p[i].efr_lock); ret = uart_get_rs485_mode(&s->p[i].port); if (ret) @@ -1603,20 +1582,25 @@ static int sc16is7xx_probe(struct device *dev, kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc); kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc); kthread_init_delayed_work(&s->p[i].ms_work, sc16is7xx_ms_proc); + /* Register port */ - uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); + ret = uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); + if (ret) + goto out_ports; + + set_bit(s->p[i].port.line, sc16is7xx_lines); /* Enable EFR */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B); - regcache_cache_bypass(s->regmap, true); + regcache_cache_bypass(regmaps[i], true); /* Enable write access to enhanced features */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG, SC16IS7XX_EFR_ENABLE_BIT); - regcache_cache_bypass(s->regmap, false); + regcache_cache_bypass(regmaps[i], false); /* Restore access to general registers */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00); @@ -1627,7 +1611,7 @@ static int sc16is7xx_probe(struct device *dev, sc16is7xx_setup_irda_ports(s); - ret = sc16is7xx_setup_mctrl_ports(s); + ret = sc16is7xx_setup_mctrl_ports(s, regmaps[0]); if (ret) goto out_ports; @@ -1662,10 +1646,9 @@ static int sc16is7xx_probe(struct device *dev, #endif out_ports: - for (i--; i >= 0; i--) { - uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, &sc16is7xx_lines); - } + for (i = 0; i < devtype->nr_uart; i++) + if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines)) + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); kthread_stop(s->kworker_task); @@ -1687,8 +1670,8 @@ static void sc16is7xx_remove(struct device *dev) for (i = 0; i < s->devtype->nr_uart; i++) { kthread_cancel_delayed_work_sync(&s->p[i].ms_work); - uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, &sc16is7xx_lines); + if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines)) + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); sc16is7xx_power(&s->p[i].port, 0); } @@ -1710,45 +1693,74 @@ static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); static struct regmap_config regcfg = { - .reg_bits = 7, - .pad_bits = 1, + .reg_bits = 5, + .pad_bits = 3, .val_bits = 8, .cache_type = REGCACHE_RBTREE, .volatile_reg = sc16is7xx_regmap_volatile, .precious_reg = sc16is7xx_regmap_precious, + .writeable_noinc_reg = sc16is7xx_regmap_noinc, + .readable_noinc_reg = sc16is7xx_regmap_noinc, + .max_raw_read = SC16IS7XX_FIFO_SIZE, + .max_raw_write = SC16IS7XX_FIFO_SIZE, + .max_register = SC16IS7XX_EFCR_REG, }; +static const char *sc16is7xx_regmap_name(u8 port_id) +{ + switch (port_id) { + case 0: return "port0"; + case 1: return "port1"; + default: + WARN_ON(true); + return NULL; + } +} + +static unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id) +{ + /* CH1,CH0 are at bits 2:1. */ + return port_id << 1; +} + #ifdef CONFIG_SERIAL_SC16IS7XX_SPI static int sc16is7xx_spi_probe(struct spi_device *spi) { const struct sc16is7xx_devtype *devtype; - struct regmap *regmap; + struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + unsigned int i; int ret; /* Setup SPI bus */ spi->bits_per_word = 8; - /* only supports mode 0 on SC16IS762 */ + /* For all variants, only mode 0 is supported */ + if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0) + return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n"); + spi->mode = spi->mode ? : SPI_MODE_0; - spi->max_speed_hz = spi->max_speed_hz ? : 15000000; + spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ; ret = spi_setup(spi); if (ret) return ret; - if (spi->dev.of_node) { - devtype = device_get_match_data(&spi->dev); - if (!devtype) - return -ENODEV; - } else { - const struct spi_device_id *id_entry = spi_get_device_id(spi); + devtype = spi_get_device_match_data(spi); + if (!devtype) + return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n"); - devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; + for (i = 0; i < devtype->nr_uart; i++) { + regcfg.name = sc16is7xx_regmap_name(i); + /* + * If read_flag_mask is 0, the regmap code sets it to a default + * of 0x80. Since we specify our own mask, we must add the READ + * bit ourselves: + */ + regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) | + SC16IS7XX_SPI_READ_BIT; + regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_spi(spi, ®cfg); } - regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | - (devtype->nr_uart - 1); - regmap = devm_regmap_init_spi(spi, ®cfg); - - return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq); + return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq); } static void sc16is7xx_spi_remove(struct spi_device *spi) @@ -1778,30 +1790,27 @@ static struct spi_driver sc16is7xx_spi_uart_driver = { .remove = sc16is7xx_spi_remove, .id_table = sc16is7xx_spi_id_table, }; - -MODULE_ALIAS("spi:sc16is7xx"); #endif #ifdef CONFIG_SERIAL_SC16IS7XX_I2C static int sc16is7xx_i2c_probe(struct i2c_client *i2c) { - const struct i2c_device_id *id = i2c_client_get_device_id(i2c); const struct sc16is7xx_devtype *devtype; - struct regmap *regmap; + struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + unsigned int i; - if (i2c->dev.of_node) { - devtype = device_get_match_data(&i2c->dev); - if (!devtype) - return -ENODEV; - } else { - devtype = (struct sc16is7xx_devtype *)id->driver_data; + devtype = i2c_get_match_data(i2c); + if (!devtype) + return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n"); + + for (i = 0; i < devtype->nr_uart; i++) { + regcfg.name = sc16is7xx_regmap_name(i); + regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i); + regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_i2c(i2c, ®cfg); } - regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | - (devtype->nr_uart - 1); - regmap = devm_regmap_init_i2c(i2c, ®cfg); - - return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq); + return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq); } static void sc16is7xx_i2c_remove(struct i2c_client *client) diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 2be2c1098025..f24217a560d7 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -1021,7 +1021,7 @@ err_out: return ret; } -static int sccnxp_remove(struct platform_device *pdev) +static void sccnxp_remove(struct platform_device *pdev) { int i; struct sccnxp_port *s = platform_get_drvdata(pdev); @@ -1036,10 +1036,11 @@ static int sccnxp_remove(struct platform_device *pdev) uart_unregister_driver(&s->uart); - if (!IS_ERR(s->regulator)) - return regulator_disable(s->regulator); - - return 0; + if (!IS_ERR(s->regulator)) { + int ret = regulator_disable(s->regulator); + if (ret) + dev_err(&pdev->dev, "Failed to disable regulator\n"); + } } static struct platform_driver sccnxp_uart_driver = { @@ -1047,7 +1048,7 @@ static struct platform_driver sccnxp_uart_driver = { .name = SCCNXP_NAME, }, .probe = sccnxp_probe, - .remove = sccnxp_remove, + .remove_new = sccnxp_remove, .id_table = sccnxp_id_table, }; module_platform_driver(sccnxp_uart_driver); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 6d4006b41975..525f3a2f7bd4 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1611,13 +1611,12 @@ static int tegra_uart_probe(struct platform_device *pdev) return ret; } -static int tegra_uart_remove(struct platform_device *pdev) +static void tegra_uart_remove(struct platform_device *pdev) { struct tegra_uart_port *tup = platform_get_drvdata(pdev); struct uart_port *u = &tup->uport; uart_remove_one_port(&tegra_uart_driver, u); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1644,7 +1643,7 @@ static const struct dev_pm_ops tegra_uart_pm_ops = { static struct platform_driver tegra_uart_platform_driver = { .probe = tegra_uart_probe, - .remove = tegra_uart_remove, + .remove_new = tegra_uart_remove, .driver = { .name = "serial-tegra", .of_match_table = tegra_uart_of_match, diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f1348a509552..b56ed8c376b2 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -156,7 +156,7 @@ static void __uart_start(struct uart_state *state) * enabled, serial_port_runtime_resume() calls start_tx() again * after enabling the device. */ - if (!pm_runtime_enabled(port->dev) || pm_runtime_active(port->dev)) + if (pm_runtime_active(&port_dev->dev)) port->ops->start_tx(port); pm_runtime_mark_last_busy(&port_dev->dev); pm_runtime_put_autosuspend(&port_dev->dev); @@ -410,11 +410,10 @@ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud) { - unsigned int size = tty_get_frame_size(cflag); - u64 frame_time; + u64 temp = tty_get_frame_size(cflag); - frame_time = (u64)size * NSEC_PER_SEC; - port->frame_time = DIV64_U64_ROUND_UP(frame_time, baud); + temp *= NSEC_PER_SEC; + port->frame_time = (unsigned int)DIV64_U64_ROUND_UP(temp, baud); } EXPORT_SYMBOL(uart_update_timeout); @@ -687,7 +686,7 @@ EXPORT_SYMBOL_GPL(uart_xchar_out); * This function is used to send a high-priority XON/XOFF character to * the device */ -static void uart_send_xchar(struct tty_struct *tty, char ch) +static void uart_send_xchar(struct tty_struct *tty, u8 ch) { struct uart_state *state = tty->driver_data; struct uart_port *port; @@ -1371,20 +1370,34 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4 return; } - /* Pick sane settings if the user hasn't */ - if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) && - !(rs485->flags & SER_RS485_RTS_ON_SEND) == - !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { - dev_warn_ratelimited(port->dev, - "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", - port->name, port->line); - rs485->flags |= SER_RS485_RTS_ON_SEND; - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND; + /* Clear other RS485 flags but SER_RS485_TERMINATE_BUS and return if enabling RS422 */ + if (rs485->flags & SER_RS485_MODE_RS422) { + rs485->flags &= (SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_TERMINATE_BUS); + return; } rs485->flags &= supported_flags; + /* Pick sane settings if the user hasn't */ + if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == + !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { + if (supported_flags & SER_RS485_RTS_ON_SEND) { + rs485->flags |= SER_RS485_RTS_ON_SEND; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + + dev_warn_ratelimited(port->dev, + "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", + port->name, port->line); + } else { + rs485->flags |= SER_RS485_RTS_AFTER_SEND; + rs485->flags &= ~SER_RS485_RTS_ON_SEND; + + dev_warn_ratelimited(port->dev, + "%s (%d): invalid RTS setting, using RTS_AFTER_SEND instead\n", + port->name, port->line); + } + } + uart_sanitize_serial_rs485_delays(port, rs485); /* Return clean padding area to userspace */ @@ -1402,6 +1415,16 @@ static void uart_set_rs485_termination(struct uart_port *port, !!(rs485->flags & SER_RS485_TERMINATE_BUS)); } +static void uart_set_rs485_rx_during_tx(struct uart_port *port, + const struct serial_rs485 *rs485) +{ + if (!(rs485->flags & SER_RS485_ENABLED)) + return; + + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, + !!(rs485->flags & SER_RS485_RX_DURING_TX)); +} + static int uart_rs485_config(struct uart_port *port) { struct serial_rs485 *rs485 = &port->rs485; @@ -1413,12 +1436,17 @@ static int uart_rs485_config(struct uart_port *port) uart_sanitize_serial_rs485(port, rs485); uart_set_rs485_termination(port, rs485); + uart_set_rs485_rx_during_tx(port, rs485); uart_port_lock_irqsave(port, &flags); ret = port->rs485_config(port, NULL, rs485); uart_port_unlock_irqrestore(port, flags); - if (ret) + if (ret) { memset(rs485, 0, sizeof(*rs485)); + /* unset GPIOs */ + gpiod_set_value_cansleep(port->rs485_term_gpio, 0); + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, 0); + } return ret; } @@ -1446,7 +1474,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, int ret; unsigned long flags; - if (!port->rs485_config) + if (!(port->rs485_supported.flags & SER_RS485_ENABLED)) return -ENOTTY; if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) @@ -1457,6 +1485,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, return ret; uart_sanitize_serial_rs485(port, &rs485); uart_set_rs485_termination(port, &rs485); + uart_set_rs485_rx_during_tx(port, &rs485); uart_port_lock_irqsave(port, &flags); ret = port->rs485_config(port, &tty->termios, &rs485); @@ -1468,8 +1497,14 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, port->ops->set_mctrl(port, port->mctrl); } uart_port_unlock_irqrestore(port, flags); - if (ret) + if (ret) { + /* restore old GPIO settings */ + gpiod_set_value_cansleep(port->rs485_term_gpio, + !!(port->rs485.flags & SER_RS485_TERMINATE_BUS)); + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, + !!(port->rs485.flags & SER_RS485_RX_DURING_TX)); return ret; + } if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485))) return -EFAULT; @@ -2342,7 +2377,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) mutex_lock(&port->mutex); - tty_dev = device_find_child(uport->dev, &match, serial_match_port); + tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port); if (tty_dev && device_may_wakeup(tty_dev)) { enable_irq_wake(uport->irq); put_device(tty_dev); @@ -2423,7 +2458,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) mutex_lock(&port->mutex); - tty_dev = device_find_child(uport->dev, &match, serial_match_port); + tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port); if (!uport->suspended && device_may_wakeup(tty_dev)) { if (irqd_is_wakeup_set(irq_get_irq_data((uport->irq)))) disable_irq_wake(uport->irq); @@ -2633,7 +2668,8 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) mutex_lock(&tport->mutex); port = uart_port_check(state); - if (!port || !(port->ops->poll_get_char && port->ops->poll_put_char)) { + if (!port || port->type == PORT_UNKNOWN || + !(port->ops->poll_get_char && port->ops->poll_put_char)) { ret = -1; goto out; } @@ -3153,7 +3189,8 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u * setserial to be used to alter this port's parameters. */ tty_dev = tty_port_register_device_attr_serdev(port, drv->tty_driver, - uport->line, uport->dev, port, uport->tty_groups); + uport->line, uport->dev, &uport->port_dev->dev, port, + uport->tty_groups); if (!IS_ERR(tty_dev)) { device_set_wakeup_capable(tty_dev, 1); } else { @@ -3570,6 +3607,9 @@ int uart_get_rs485_mode(struct uart_port *port) u32 rs485_delay[2]; int ret; + if (!(port->rs485_supported.flags & SER_RS485_ENABLED)) + return 0; + ret = device_property_read_u32_array(dev, "rs485-rts-delay", rs485_delay, 2); if (!ret) { @@ -3620,6 +3660,8 @@ int uart_get_rs485_mode(struct uart_port *port) if (IS_ERR(desc)) return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-rx-during-tx-gpios\n"); port->rs485_rx_during_tx_gpio = desc; + if (port->rs485_rx_during_tx_gpio) + port->rs485_supported.flags |= SER_RS485_RX_DURING_TX; return 0; } diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index eaa980722455..e1897894a4ef 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -1052,7 +1052,7 @@ static int serial_txx9_probe(struct platform_device *dev) /* * Remove serial ports registered against a platform device. */ -static int serial_txx9_remove(struct platform_device *dev) +static void serial_txx9_remove(struct platform_device *dev) { int i; @@ -1062,7 +1062,6 @@ static int serial_txx9_remove(struct platform_device *dev) if (up->dev == &dev->dev) serial_txx9_unregister_port(i); } - return 0; } #ifdef CONFIG_PM @@ -1097,7 +1096,7 @@ static int serial_txx9_resume(struct platform_device *dev) static struct platform_driver serial_txx9_plat_driver = { .probe = serial_txx9_probe, - .remove = serial_txx9_remove, + .remove_new = serial_txx9_remove, #ifdef CONFIG_PM .suspend = serial_txx9_suspend, .resume = serial_txx9_resume, diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 84ab434c94ba..a85e7b9a2e49 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1558,10 +1558,9 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port, struct dma_slave_config cfg; int ret; - chan = dma_request_slave_channel(port->dev, - dir == DMA_MEM_TO_DEV ? "tx" : "rx"); - if (!chan) { - dev_dbg(port->dev, "dma_request_slave_channel failed\n"); + chan = dma_request_chan(port->dev, dir == DMA_MEM_TO_DEV ? "tx" : "rx"); + if (IS_ERR(chan)) { + dev_dbg(port->dev, "dma_request_chan failed\n"); return NULL; } @@ -3190,7 +3189,7 @@ static struct uart_driver sci_uart_driver = { .cons = SCI_CONSOLE, }; -static int sci_remove(struct platform_device *dev) +static void sci_remove(struct platform_device *dev) { struct sci_port *port = platform_get_drvdata(dev); unsigned int type = port->port.type; /* uart_remove_... clears it */ @@ -3204,8 +3203,6 @@ static int sci_remove(struct platform_device *dev) device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger); if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF) device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout); - - return 0; } @@ -3470,7 +3467,7 @@ static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume); static struct platform_driver sci_driver = { .probe = sci_probe, - .remove = sci_remove, + .remove_new = sci_remove, .driver = { .name = "sh-sci", .pm = &sci_dev_pm_ops, diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index b296e57a9dee..a4cc569a78a2 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -1007,7 +1007,7 @@ probe_out1: return r; } -static int sifive_serial_remove(struct platform_device *dev) +static void sifive_serial_remove(struct platform_device *dev) { struct sifive_serial_port *ssp = platform_get_drvdata(dev); @@ -1015,8 +1015,6 @@ static int sifive_serial_remove(struct platform_device *dev) uart_remove_one_port(&sifive_serial_uart_driver, &ssp->port); free_irq(ssp->port.irq, ssp); clk_notifier_unregister(ssp->clk, &ssp->clk_notifier); - - return 0; } static int sifive_serial_suspend(struct device *dev) @@ -1033,8 +1031,8 @@ static int sifive_serial_resume(struct device *dev) return uart_resume_port(&sifive_serial_uart_driver, &ssp->port); } -DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend, - sifive_serial_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend, + sifive_serial_resume); static const struct of_device_id sifive_serial_of_match[] = { { .compatible = "sifive,fu540-c000-uart0" }, @@ -1045,7 +1043,7 @@ MODULE_DEVICE_TABLE(of, sifive_serial_of_match); static struct platform_driver sifive_serial_platform_driver = { .probe = sifive_serial_probe, - .remove = sifive_serial_remove, + .remove_new = sifive_serial_remove, .driver = { .name = SIFIVE_SERIAL_NAME, .pm = pm_sleep_ptr(&sifive_uart_pm_ops), diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index f257525f9299..15f14fa593da 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1076,7 +1076,7 @@ static struct uart_driver sprd_uart_driver = { .cons = SPRD_CONSOLE, }; -static int sprd_remove(struct platform_device *dev) +static void sprd_remove(struct platform_device *dev) { struct sprd_uart_port *sup = platform_get_drvdata(dev); @@ -1089,8 +1089,6 @@ static int sprd_remove(struct platform_device *dev) if (!sprd_ports_num) uart_unregister_driver(&sprd_uart_driver); - - return 0; } static bool sprd_uart_is_console(struct uart_port *uport) @@ -1257,7 +1255,7 @@ MODULE_DEVICE_TABLE(of, serial_ids); static struct platform_driver sprd_platform_driver = { .probe = sprd_probe, - .remove = sprd_remove, + .remove_new = sprd_remove, .driver = { .name = "sprd_serial", .of_match_table = serial_ids, diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index a821f5d76a26..bbb5595d7e24 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -793,13 +793,11 @@ static int asc_serial_probe(struct platform_device *pdev) return 0; } -static int asc_serial_remove(struct platform_device *pdev) +static void asc_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); uart_remove_one_port(&asc_uart_driver, port); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -932,7 +930,7 @@ static const struct dev_pm_ops asc_serial_pm_ops = { static struct platform_driver asc_serial_driver = { .probe = asc_serial_probe, - .remove = asc_serial_remove, + .remove_new = asc_serial_remove, .driver = { .name = DRIVER_NAME, .pm = &asc_serial_pm_ops, diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 3048620315d6..794b77512740 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -226,12 +226,6 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - if (port->rs485_rx_during_tx_gpio) - gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, - !!(rs485conf->flags & SER_RS485_RX_DURING_TX)); - else - rs485conf->flags |= SER_RS485_RX_DURING_TX; - if (rs485conf->flags & SER_RS485_ENABLED) { cr1 = readl_relaxed(port->membase + ofs->cr1); cr3 = readl_relaxed(port->membase + ofs->cr3); @@ -256,6 +250,8 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr1, port->membase + ofs->cr1); + + rs485conf->flags |= SER_RS485_RX_DURING_TX; } else { stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP); @@ -1822,7 +1818,7 @@ err_dma_rx: return ret; } -static int stm32_usart_serial_remove(struct platform_device *pdev) +static void stm32_usart_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct stm32_port *stm32_port = to_stm32_port(port); @@ -1861,8 +1857,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) } stm32_usart_deinit_port(stm32_port); - - return 0; } static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch) @@ -2146,7 +2140,7 @@ static const struct dev_pm_ops stm32_serial_pm_ops = { static struct platform_driver stm32_serial_driver = { .probe = stm32_usart_serial_probe, - .remove = stm32_usart_serial_remove, + .remove_new = stm32_usart_serial_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_serial_pm_ops, diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 5bfc0040f17b..8d612ab80680 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -595,7 +595,7 @@ out_free_port: return err; } -static int hv_remove(struct platform_device *dev) +static void hv_remove(struct platform_device *dev) { struct uart_port *port = platform_get_drvdata(dev); @@ -608,8 +608,6 @@ static int hv_remove(struct platform_device *dev) kfree(con_write_page); kfree(port); sunhv_port = NULL; - - return 0; } static const struct of_device_id hv_match[] = { @@ -630,7 +628,7 @@ static struct platform_driver hv_driver = { .of_match_table = hv_match, }, .probe = hv_probe, - .remove = hv_remove, + .remove_new = hv_remove, }; static int __init sunhv_init(void) diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c index 4251f4e1ba99..99f5285819d4 100644 --- a/drivers/tty/serial/sunplus-uart.c +++ b/drivers/tty/serial/sunplus-uart.c @@ -662,13 +662,11 @@ static int sunplus_uart_probe(struct platform_device *pdev) return ret; } -static int sunplus_uart_remove(struct platform_device *pdev) +static void sunplus_uart_remove(struct platform_device *pdev) { struct sunplus_uart_port *sup = platform_get_drvdata(pdev); uart_remove_one_port(&sunplus_uart_driver, &sup->port); - - return 0; } static int __maybe_unused sunplus_uart_suspend(struct device *dev) @@ -703,7 +701,7 @@ MODULE_DEVICE_TABLE(of, sp_uart_of_match); static struct platform_driver sunplus_uart_platform_driver = { .probe = sunplus_uart_probe, - .remove = sunplus_uart_remove, + .remove_new = sunplus_uart_remove, .driver = { .name = "sunplus_uart", .of_match_table = sp_uart_of_match, diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 6aa51a6f8063..1ea2f33a07a7 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -443,7 +443,7 @@ static void sunsab_start_tx(struct uart_port *port) up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); writeb(up->interrupt_mask1, &up->regs->w.imr1); - + if (!test_bit(SAB82532_XPR, &up->irqflags)) return; @@ -549,7 +549,7 @@ static int sunsab_startup(struct uart_port *port) (void) readb(&up->regs->r.isr1); /* - * Now, initialize the UART + * Now, initialize the UART */ writeb(0, &up->regs->w.ccr0); /* power-down */ writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | @@ -563,7 +563,7 @@ static int sunsab_startup(struct uart_port *port) SAB82532_MODE_RAC); writeb(up->cached_mode, &up->regs->w.mode); writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); - + tmp = readb(&up->regs->rw.ccr0); tmp |= SAB82532_CCR0_PU; /* power-up */ writeb(tmp, &up->regs->rw.ccr0); @@ -607,7 +607,7 @@ static void sunsab_shutdown(struct uart_port *port) up->cached_dafo &= ~SAB82532_DAFO_XBRK; writeb(up->cached_dafo, &up->regs->rw.dafo); - /* Disable Receiver */ + /* Disable Receiver */ up->cached_mode &= ~SAB82532_MODE_RAC; writeb(up->cached_mode, &up->regs->rw.mode); @@ -622,7 +622,7 @@ static void sunsab_shutdown(struct uart_port *port) * speed the chip was configured for when the port was open). */ #if 0 - /* Power Down */ + /* Power Down */ tmp = readb(&up->regs->rw.ccr0); tmp &= ~SAB82532_CCR0_PU; writeb(tmp, &up->regs->rw.ccr0); @@ -649,7 +649,7 @@ static void calc_ebrg(int baud, int *n_ret, int *m_ret) *m_ret = 0; return; } - + /* * We scale numbers by 10 so that we get better accuracy * without having to use floating point. Here we increment m @@ -788,7 +788,7 @@ static const char *sunsab_type(struct uart_port *port) { struct uart_sunsab_port *up = (void *)port; static char buf[36]; - + sprintf(buf, "SAB82532 %s", sab82532_version[up->type]); return buf; } @@ -933,7 +933,7 @@ static int sunsab_console_setup(struct console *con, char *options) sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); uart_port_unlock_irqrestore(&up->port, flags); - + return 0; } @@ -1066,7 +1066,7 @@ out: return err; } -static int sab_remove(struct platform_device *op) +static void sab_remove(struct platform_device *op) { struct uart_sunsab_port *up = platform_get_drvdata(op); @@ -1078,8 +1078,6 @@ static int sab_remove(struct platform_device *op) of_iounmap(&op->resource[0], up[0].port.membase, sizeof(union sab82532_async_regs)); - - return 0; } static const struct of_device_id sab_match[] = { @@ -1100,7 +1098,7 @@ static struct platform_driver sab_driver = { .of_match_table = sab_match, }, .probe = sab_probe, - .remove = sab_remove, + .remove_new = sab_remove, }; static int __init sunsab_init(void) diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 1e051cc2591c..c8b65f4b2710 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1515,7 +1515,7 @@ out_unmap: return err; } -static int su_remove(struct platform_device *op) +static void su_remove(struct platform_device *op) { struct uart_sunsu_port *up = platform_get_drvdata(op); bool kbdms = false; @@ -1536,8 +1536,6 @@ static int su_remove(struct platform_device *op) if (kbdms) kfree(up); - - return 0; } static const struct of_device_id su_match[] = { @@ -1565,7 +1563,7 @@ static struct platform_driver su_driver = { .of_match_table = su_match, }, .probe = su_probe, - .remove = su_remove, + .remove_new = su_remove, }; static int __init sunsu_init(void) diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index d3b5e864b727..c99289c6c8f8 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1513,7 +1513,7 @@ static void zs_remove_one(struct uart_sunzilog_port *up) uart_remove_one_port(&sunzilog_reg, &up->port); } -static int zs_remove(struct platform_device *op) +static void zs_remove(struct platform_device *op) { struct uart_sunzilog_port *up = platform_get_drvdata(op); struct zilog_layout __iomem *regs; @@ -1523,8 +1523,6 @@ static int zs_remove(struct platform_device *op) regs = sunzilog_chip_regs[up[0].port.line / 2]; of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout)); - - return 0; } static const struct of_device_id zs_match[] = { @@ -1541,7 +1539,7 @@ static struct platform_driver zs_driver = { .of_match_table = zs_match, }, .probe = zs_probe, - .remove = zs_remove, + .remove_new = zs_remove, }; static int __init sunzilog_init(void) diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c index 65069daf36ec..d9c78320eb02 100644 --- a/drivers/tty/serial/tegra-tcu.c +++ b/drivers/tty/serial/tegra-tcu.c @@ -266,7 +266,7 @@ free_tx: return err; } -static int tegra_tcu_remove(struct platform_device *pdev) +static void tegra_tcu_remove(struct platform_device *pdev) { struct tegra_tcu *tcu = platform_get_drvdata(pdev); @@ -277,8 +277,6 @@ static int tegra_tcu_remove(struct platform_device *pdev) uart_remove_one_port(&tcu->driver, &tcu->port); uart_unregister_driver(&tcu->driver); mbox_free_channel(tcu->tx); - - return 0; } static const struct of_device_id tegra_tcu_match[] = { @@ -293,7 +291,7 @@ static struct platform_driver tegra_tcu_driver = { .of_match_table = tegra_tcu_match, }, .probe = tegra_tcu_probe, - .remove = tegra_tcu_remove, + .remove_new = tegra_tcu_remove, }; module_platform_driver(tegra_tcu_driver); diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 0cc6524f5e8b..4bc89a9b380a 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -473,7 +473,7 @@ err_mem: return err; } -static int timbuart_remove(struct platform_device *dev) +static void timbuart_remove(struct platform_device *dev) { struct timbuart_port *uart = platform_get_drvdata(dev); @@ -481,8 +481,6 @@ static int timbuart_remove(struct platform_device *dev) uart_remove_one_port(&timbuart_driver, &uart->port); uart_unregister_driver(&timbuart_driver); kfree(uart); - - return 0; } static struct platform_driver timbuart_platform_driver = { @@ -490,7 +488,7 @@ static struct platform_driver timbuart_platform_driver = { .name = "timb-uart", }, .probe = timbuart_probe, - .remove = timbuart_remove, + .remove_new = timbuart_remove, }; module_platform_driver(timbuart_platform_driver); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 404c14acafa5..10ba41b7be99 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -24,8 +24,13 @@ #include #define ULITE_NAME "ttyUL" +#if CONFIG_SERIAL_UARTLITE_NR_UARTS > 4 +#define ULITE_MAJOR 0 /* use dynamic node allocation */ +#define ULITE_MINOR 0 +#else #define ULITE_MAJOR 204 #define ULITE_MINOR 187 +#endif #define ULITE_NR_UARTS CONFIG_SERIAL_UARTLITE_NR_UARTS /* --------------------------------------------------------------------- @@ -62,11 +67,11 @@ static struct uart_port *console_port; #endif /** - * struct uartlite_data: Driver private data - * reg_ops: Functions to read/write registers - * clk: Our parent clock, if present - * baud: The baud rate configured when this device was synthesized - * cflags: The cflags for parity and data bits + * struct uartlite_data - Driver private data + * @reg_ops: Functions to read/write registers + * @clk: Our parent clock, if present + * @baud: The baud rate configured when this device was synthesized + * @cflags: The cflags for parity and data bits */ struct uartlite_data { const struct uartlite_reg_ops *reg_ops; @@ -890,7 +895,7 @@ of_err: return ret; } -static int ulite_remove(struct platform_device *pdev) +static void ulite_remove(struct platform_device *pdev) { struct uart_port *port = dev_get_drvdata(&pdev->dev); struct uartlite_data *pdata = port->private_data; @@ -900,7 +905,6 @@ static int ulite_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - return 0; } /* work with hotplug and coldplug */ @@ -908,7 +912,7 @@ MODULE_ALIAS("platform:uartlite"); static struct platform_driver ulite_platform_driver = { .probe = ulite_probe, - .remove = ulite_remove, + .remove_new = ulite_remove, .driver = { .name = "uartlite", .of_match_table = of_match_ptr(ulite_of_match), diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index ed7a6bb5596a..397b95dff7ed 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -189,10 +189,10 @@ struct uart_qe_port { u16 tx_fifosize; int wait_closing; u32 flags; - struct qe_bd *rx_bd_base; - struct qe_bd *rx_cur; - struct qe_bd *tx_bd_base; - struct qe_bd *tx_cur; + struct qe_bd __iomem *rx_bd_base; + struct qe_bd __iomem *rx_cur; + struct qe_bd __iomem *tx_bd_base; + struct qe_bd __iomem *tx_cur; unsigned char *tx_buf; unsigned char *rx_buf; void *bd_virt; /* virtual address of the BD buffers */ @@ -258,7 +258,7 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port) { struct uart_qe_port *qe_port = container_of(port, struct uart_qe_port, port); - struct qe_bd *bdp = qe_port->tx_bd_base; + struct qe_bd __iomem *bdp = qe_port->tx_bd_base; while (1) { if (ioread16be(&bdp->status) & BD_SC_READY) @@ -330,7 +330,7 @@ static void qe_uart_stop_tx(struct uart_port *port) */ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) { - struct qe_bd *bdp; + struct qe_bd __iomem *bdp; unsigned char *p; unsigned int count; struct uart_port *port = &qe_port->port; @@ -341,7 +341,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) /* Pick next descriptor and fill from buffer */ bdp = qe_port->tx_cur; - p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); + p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port); *p++ = port->x_char; iowrite16be(1, &bdp->length); @@ -368,7 +368,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) while (!(ioread16be(&bdp->status) & BD_SC_READY) && !uart_circ_empty(xmit)) { count = 0; - p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); + p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port); while (count < qe_port->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; uart_xmit_advance(port, 1); @@ -460,7 +460,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) unsigned char ch, *cp; struct uart_port *port = &qe_port->port; struct tty_port *tport = &port->state->port; - struct qe_bd *bdp; + struct qe_bd __iomem *bdp; u16 status; unsigned int flg; @@ -487,7 +487,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) } /* get pointer */ - cp = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); + cp = qe2cpu_addr(ioread32be(&bdp->buf), qe_port); /* loop through the buffer */ while (i-- > 0) { @@ -590,7 +590,7 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port) { int i; void *bd_virt; - struct qe_bd *bdp; + struct qe_bd __iomem *bdp; /* Set the physical address of the host memory buffers in the buffer * descriptors, and the virtual address for us to work with. @@ -648,7 +648,7 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) { u32 cecr_subblock; struct ucc_slow __iomem *uccp = qe_port->uccp; - struct ucc_uart_pram *uccup = qe_port->uccup; + struct ucc_uart_pram __iomem *uccup = qe_port->uccup; unsigned int i; @@ -983,7 +983,7 @@ static int qe_uart_request_port(struct uart_port *port) qe_port->us_private = uccs; qe_port->uccp = uccs->us_regs; - qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram; + qe_port->uccup = (struct ucc_uart_pram __iomem *)uccs->us_pram; qe_port->rx_bd_base = uccs->rx_bd; qe_port->tx_bd_base = uccs->tx_bd; @@ -1156,7 +1156,7 @@ static void uart_firmware_cont(const struct firmware *fw, void *context) firmware = (struct qe_firmware *) fw->data; - if (firmware->header.length != fw->size) { + if (be32_to_cpu(firmware->header.length) != fw->size) { dev_err(dev, "invalid firmware\n"); goto out; } @@ -1459,7 +1459,7 @@ out_free: return ret; } -static int ucc_uart_remove(struct platform_device *ofdev) +static void ucc_uart_remove(struct platform_device *ofdev) { struct uart_qe_port *qe_port = platform_get_drvdata(ofdev); @@ -1470,8 +1470,6 @@ static int ucc_uart_remove(struct platform_device *ofdev) of_node_put(qe_port->np); kfree(qe_port); - - return 0; } static const struct of_device_id ucc_uart_match[] = { @@ -1492,7 +1490,7 @@ static struct platform_driver ucc_uart_of_driver = { .of_match_table = ucc_uart_match, }, .probe = ucc_uart_probe, - .remove = ucc_uart_remove, + .remove_new = ucc_uart_remove, }; static int __init ucc_uart_init(void) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 66a45a634158..920762d7b4a4 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1663,10 +1663,8 @@ err_out_unregister_driver: /** * cdns_uart_remove - called when the platform driver is unregistered * @pdev: Pointer to the platform device structure - * - * Return: 0 on success, negative errno otherwise */ -static int cdns_uart_remove(struct platform_device *pdev) +static void cdns_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct cdns_uart *cdns_uart_data = port->private_data; @@ -1692,12 +1690,11 @@ static int cdns_uart_remove(struct platform_device *pdev) if (!--instances) uart_unregister_driver(cdns_uart_data->cdns_uart_driver); - return 0; } static struct platform_driver cdns_uart_platform_driver = { .probe = cdns_uart_probe, - .remove = cdns_uart_remove, + .remove_new = cdns_uart_remove, .driver = { .name = CDNS_UART_NAME, .of_match_table = cdns_uart_of_match, diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index dcf2e1ebf9c5..4a17070d7402 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -1154,16 +1154,29 @@ EXPORT_SYMBOL(unregister_sysrq_key); #ifdef CONFIG_PROC_FS /* * writing 'C' to /proc/sysrq-trigger is like sysrq-C + * Normally, only the first character written is processed. + * However, if the first character is an underscore, + * all characters are processed. */ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - if (count) { + bool bulk = false; + size_t i; + + for (i = 0; i < count; i++) { char c; - if (get_user(c, buf)) + if (get_user(c, buf + i)) return -EFAULT; - __handle_sysrq(c, false); + + if (c == '_') + bulk = true; + else + __handle_sysrq(c, false); + + if (!bulk) + break; } return count; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index e2e93404133e..407b0d87b7c1 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -852,9 +852,9 @@ static ssize_t iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, { void *cookie = NULL; unsigned long offset = 0; - char kernel_buf[64]; ssize_t retval = 0; size_t copied, count = iov_iter_count(to); + u8 kernel_buf[64]; do { ssize_t size = min(count, sizeof(kernel_buf)); @@ -995,7 +995,7 @@ static ssize_t iterate_tty_write(struct tty_ldisc *ld, struct tty_struct *tty, /* write_buf/write_cnt is protected by the atomic_write_lock mutex */ if (tty->write_cnt < chunk) { - unsigned char *buf_chunk; + u8 *buf_chunk; if (chunk < 1024) chunk = 1024; @@ -1047,6 +1047,7 @@ out: return ret; } +#ifdef CONFIG_PRINT_QUOTA_WARNING /** * tty_write_message - write a message to a certain tty, not just the console. * @tty: the destination tty_struct @@ -1057,6 +1058,8 @@ out: * needed. * * We must still hold the BTM and test the CLOSING flag for the moment. + * + * This function is DEPRECATED, do not use in new code. */ void tty_write_message(struct tty_struct *tty, char *msg) { @@ -1069,6 +1072,7 @@ void tty_write_message(struct tty_struct *tty, char *msg) tty_write_unlock(tty); } } +#endif static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_iter *from) { @@ -1145,7 +1149,7 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter) * * Locking: none for xchar method, write ordering for write method. */ -int tty_send_xchar(struct tty_struct *tty, char ch) +int tty_send_xchar(struct tty_struct *tty, u8 ch) { bool was_stopped = tty->flow.stopped; @@ -2274,10 +2278,10 @@ static bool tty_legacy_tiocsti __read_mostly = IS_ENABLED(CONFIG_LEGACY_TIOCSTI) * * Called functions take tty_ldiscs_lock * * current->signal->tty check is safe without locks */ -static int tiocsti(struct tty_struct *tty, char __user *p) +static int tiocsti(struct tty_struct *tty, u8 __user *p) { - char ch, mbz = 0; struct tty_ldisc *ld; + u8 ch; if (!tty_legacy_tiocsti && !capable(CAP_SYS_ADMIN)) return -EIO; @@ -2292,7 +2296,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) return -EIO; tty_buffer_lock_exclusive(tty->port); if (ld->ops->receive_buf) - ld->ops->receive_buf(tty, &ch, &mbz, 1); + ld->ops->receive_buf(tty, &ch, NULL, 1); tty_buffer_unlock_exclusive(tty->port); tty_ldisc_deref(ld); return 0; @@ -2489,6 +2493,9 @@ static int send_break(struct tty_struct *tty, unsigned int duration) if (!retval) { msleep_interruptible(duration); retval = tty->ops->break_ctl(tty, 0); + } else if (retval == -EOPNOTSUPP) { + /* some drivers can tell only dynamically */ + retval = 0; } tty_write_unlock(tty); @@ -3154,7 +3161,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) * * Return: the number of characters successfully output. */ -int tty_put_char(struct tty_struct *tty, unsigned char ch) +int tty_put_char(struct tty_struct *tty, u8 ch) { if (tty->ops->put_char) return tty->ops->put_char(tty, ch); diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 4b499301a3db..85de90eebc7b 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -844,7 +844,7 @@ int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) ret = -EFAULT; return ret; case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) + if (!checkpoint_restore_ns_capable(&init_user_ns)) return -EPERM; copy_termios_locked(real_tty, &kterm); if (user_termios_to_kernel_termios(&kterm, @@ -861,7 +861,7 @@ int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) ret = -EFAULT; return ret; case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) + if (!checkpoint_restore_ns_capable(&init_user_ns)) return -EPERM; copy_termios_locked(real_tty, &kterm); if (user_termios_to_kernel_termios_1(&kterm, diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 63c125250961..14cca33d2269 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -171,7 +171,8 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr); * @port: tty_port of the device * @driver: tty_driver for this device * @index: index of the tty - * @device: parent if exists, otherwise NULL + * @host: serial port hardware device + * @parent: parent if exists, otherwise NULL * @drvdata: driver data for the device * @attr_grp: attribute group for the device * @@ -180,20 +181,20 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr); */ struct device *tty_port_register_device_attr_serdev(struct tty_port *port, struct tty_driver *driver, unsigned index, - struct device *device, void *drvdata, + struct device *host, struct device *parent, void *drvdata, const struct attribute_group **attr_grp) { struct device *dev; tty_port_link_device(port, driver, index); - dev = serdev_tty_port_register(port, device, driver, index); + dev = serdev_tty_port_register(port, host, parent, driver, index); if (PTR_ERR(dev) != -ENODEV) { /* Skip creating cdev if we registered a serdev device */ return dev; } - return tty_register_device_attr(driver, index, device, drvdata, + return tty_register_device_attr(driver, index, parent, drvdata, attr_grp); } EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev); @@ -203,17 +204,18 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev); * @port: tty_port of the device * @driver: tty_driver for this device * @index: index of the tty - * @device: parent if exists, otherwise NULL + * @host: serial port hardware controller device + * @parent: parent if exists, otherwise NULL * * Register a serdev or tty device depending on if the parent device has any * defined serdev clients or not. */ struct device *tty_port_register_device_serdev(struct tty_port *port, struct tty_driver *driver, unsigned index, - struct device *device) + struct device *host, struct device *parent) { return tty_port_register_device_attr_serdev(port, driver, index, - device, NULL, NULL); + host, parent, NULL, NULL); } EXPORT_SYMBOL_GPL(tty_port_register_device_serdev); @@ -245,7 +247,7 @@ int tty_port_alloc_xmit_buf(struct tty_port *port) /* We may sleep in get_zeroed_page() */ mutex_lock(&port->buf_mutex); if (port->xmit_buf == NULL) { - port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL); if (port->xmit_buf) kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE); } diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 5e39a4f430ee..82d70083fead 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -644,7 +644,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) if (!ct) return 0; - unilist = vmemdup_user(list, array_size(sizeof(*unilist), ct)); + unilist = vmemdup_array_user(list, ct, sizeof(*unilist)); if (IS_ERR(unilist)) return PTR_ERR(unilist); diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 12a192e1196b..a2116e135a82 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1772,12 +1772,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) return -EINVAL; if (ct) { - - dia = memdup_user(a->kbdiacr, - sizeof(struct kbdiacr) * ct); + dia = memdup_array_user(a->kbdiacr, + ct, sizeof(struct kbdiacr)); if (IS_ERR(dia)) return PTR_ERR(dia); - } spin_lock_irqsave(&kbd_event_lock, flags); @@ -1811,8 +1809,8 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) return -EINVAL; if (ct) { - buf = memdup_user(a->kbdiacruc, - ct * sizeof(struct kbdiacruc)); + buf = memdup_array_user(a->kbdiacruc, + ct, sizeof(struct kbdiacruc)); if (IS_ERR(buf)) return PTR_ERR(buf); } diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 5812f7ea7f90..16703815be0c 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -546,7 +546,7 @@ MODULE_PARM_DESC(annex, #define uea_wait(sc, cond, timeo) \ ({ \ - int _r = wait_event_interruptible_timeout(sc->sync_q, \ + int _r = wait_event_freezable_timeout(sc->sync_q, \ (cond) || kthread_should_stop(), timeo); \ if (kthread_should_stop()) \ _r = -ENODEV; \ @@ -1896,7 +1896,6 @@ static int uea_kthread(void *data) ret = sc->stat(sc); if (ret != -EAGAIN) uea_wait(sc, 0, msecs_to_jiffies(1000)); - try_to_freeze(); } uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -2252,7 +2251,7 @@ static ssize_t stat_status_show(struct device *dev, struct device_attribute *att sc = dev_to_uea(dev); if (!sc) goto out; - ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.state); + ret = sysfs_emit(buf, "%08x\n", sc->stats.phy.state); out: mutex_unlock(&uea_mutex); return ret; @@ -2318,19 +2317,19 @@ static ssize_t stat_human_status_show(struct device *dev, switch (modem_state) { case 0: - ret = sprintf(buf, "Modem is booting\n"); + ret = sysfs_emit(buf, "Modem is booting\n"); break; case 1: - ret = sprintf(buf, "Modem is initializing\n"); + ret = sysfs_emit(buf, "Modem is initializing\n"); break; case 2: - ret = sprintf(buf, "Modem is operational\n"); + ret = sysfs_emit(buf, "Modem is operational\n"); break; case 3: - ret = sprintf(buf, "Modem synchronization failed\n"); + ret = sysfs_emit(buf, "Modem synchronization failed\n"); break; default: - ret = sprintf(buf, "Modem state is unknown\n"); + ret = sysfs_emit(buf, "Modem state is unknown\n"); break; } out: @@ -2364,7 +2363,7 @@ static ssize_t stat_delin_show(struct device *dev, struct device_attribute *attr delin = "LOSS"; } - ret = sprintf(buf, "%s\n", delin); + ret = sysfs_emit(buf, "%s\n", delin); out: mutex_unlock(&uea_mutex); return ret; @@ -2384,7 +2383,7 @@ static ssize_t stat_##name##_show(struct device *dev, \ sc = dev_to_uea(dev); \ if (!sc) \ goto out; \ - ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.name); \ + ret = sysfs_emit(buf, "%08x\n", sc->stats.phy.name); \ if (reset) \ sc->stats.phy.name = 0; \ out: \ diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 11a5b3437c32..aeca902ab6cc 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -1119,6 +1119,8 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, dma_addr_t trb_dma; u32 togle_pcs = 1; int sg_iter = 0; + int num_trb_req; + int trb_burst; int num_trb; int address; u32 control; @@ -1126,16 +1128,15 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, u16 total_tdl = 0; struct scatterlist *s = NULL; bool sg_supported = !!(request->num_mapped_sgs); + u32 ioc = request->no_interrupt ? 0 : TRB_IOC; + num_trb_req = sg_supported ? request->num_mapped_sgs : 1; + + /* ISO transfer require each SOF have a TD, each TD include some TRBs */ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) - num_trb = priv_ep->interval; + num_trb = priv_ep->interval * num_trb_req; else - num_trb = sg_supported ? request->num_mapped_sgs : 1; - - if (num_trb > priv_ep->free_trbs) { - priv_ep->flags |= EP_RING_FULL; - return -ENOBUFS; - } + num_trb = num_trb_req; priv_req = to_cdns3_request(request); address = priv_ep->endpoint.desc->bEndpointAddress; @@ -1184,14 +1185,31 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, link_trb->control = cpu_to_le32(((priv_ep->pcs) ? TRB_CYCLE : 0) | TRB_TYPE(TRB_LINK) | TRB_TOGGLE | ch_bit); + + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) { + /* + * ISO require LINK TRB must be first one of TD. + * Fill LINK TRBs for left trb space to simply software process logic. + */ + while (priv_ep->enqueue) { + *trb = *link_trb; + trace_cdns3_prepare_trb(priv_ep, trb); + + cdns3_ep_inc_enq(priv_ep); + trb = priv_ep->trb_pool + priv_ep->enqueue; + priv_req->trb = trb; + } + } + } + + if (num_trb > priv_ep->free_trbs) { + priv_ep->flags |= EP_RING_FULL; + return -ENOBUFS; } if (priv_dev->dev_ver <= DEV_VER_V2) togle_pcs = cdns3_wa1_update_guard(priv_ep, trb); - if (sg_supported) - s = request->sg; - /* set incorrect Cycle Bit for first trb*/ control = priv_ep->pcs ? 0 : TRB_CYCLE; trb->length = 0; @@ -1209,6 +1227,9 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, do { u32 length; + if (!(sg_iter % num_trb_req) && sg_supported) + s = request->sg; + /* fill TRB */ control |= TRB_TYPE(TRB_NORMAL); if (sg_supported) { @@ -1223,7 +1244,36 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, total_tdl += DIV_ROUND_UP(length, priv_ep->endpoint.maxpacket); - trb->length |= cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) | + trb_burst = priv_ep->trb_burst_size; + + /* + * Supposed DMA cross 4k bounder problem should be fixed at DEV_VER_V2, but still + * met problem when do ISO transfer if sg enabled. + * + * Data pattern likes below when sg enabled, package size is 1k and mult is 2 + * [UVC Header(8B) ] [data(3k - 8)] ... + * + * The received data at offset 0xd000 will get 0xc000 data, len 0x70. Error happen + * as below pattern: + * 0xd000: wrong + * 0xe000: wrong + * 0xf000: correct + * 0x10000: wrong + * 0x11000: wrong + * 0x12000: correct + * ... + * + * But it is still unclear about why error have not happen below 0xd000, it should + * cross 4k bounder. But anyway, the below code can fix this problem. + * + * To avoid DMA cross 4k bounder at ISO transfer, reduce burst len according to 16. + */ + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && priv_dev->dev_ver <= DEV_VER_V2) + if (ALIGN_DOWN(trb->buffer, SZ_4K) != + ALIGN_DOWN(trb->buffer + length, SZ_4K)) + trb_burst = 16; + + trb->length |= cpu_to_le32(TRB_BURST_LEN(trb_burst) | TRB_LEN(length)); pcs = priv_ep->pcs ? TRB_CYCLE : 0; @@ -1235,11 +1285,11 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, control |= pcs; if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && !priv_ep->dir) { - control |= TRB_IOC | TRB_ISP; + control |= ioc | TRB_ISP; } else { /* for last element in TD or in SG list */ if (sg_iter == (num_trb - 1) && sg_iter != 0) - control |= pcs | TRB_IOC | TRB_ISP; + control |= pcs | ioc | TRB_ISP; } if (sg_iter) @@ -1250,7 +1300,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, if (sg_supported) { trb->control |= cpu_to_le32(TRB_ISP); /* Don't set chain bit for last TRB */ - if (sg_iter < num_trb - 1) + if ((sg_iter % num_trb_req) < num_trb_req - 1) trb->control |= cpu_to_le32(TRB_CHAIN); s = sg_next(s); @@ -1270,7 +1320,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, priv_req->num_of_trb = num_trb; if (sg_iter == 1) - trb->control |= cpu_to_le32(TRB_IOC | TRB_ISP); + trb->control |= cpu_to_le32(ioc | TRB_ISP); if (priv_dev->dev_ver < DEV_VER_V2 && (priv_ep->flags & EP_TDLCHK_EN)) { @@ -1508,6 +1558,12 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, /* The TRB was changed as link TRB, and the request was handled at ep_dequeue */ while (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) { + + /* ISO ep_traddr may stop at LINK TRB */ + if (priv_ep->dequeue == cdns3_get_dma_pos(priv_dev, priv_ep) && + priv_ep->type == USB_ENDPOINT_XFER_ISOC) + break; + trace_cdns3_complete_trb(priv_ep, trb); cdns3_ep_inc_deq(priv_ep); trb = priv_ep->trb_pool + priv_ep->dequeue; @@ -1540,6 +1596,10 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, } if (request_handled) { + /* TRBs are duplicated by priv_ep->interval time for ISO IN */ + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && priv_ep->dir) + request->actual /= priv_ep->interval; + cdns3_gadget_giveback(priv_ep, priv_req, 0); request_handled = false; transfer_end = false; @@ -2035,11 +2095,10 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC); struct cdns3_device *priv_dev = priv_ep->cdns3_dev; u32 bEndpointAddress = priv_ep->num | priv_ep->dir; - u32 max_packet_size = 0; - u8 maxburst = 0; + u32 max_packet_size = priv_ep->wMaxPacketSize; + u8 maxburst = priv_ep->bMaxBurst; u32 ep_cfg = 0; u8 buffering; - u8 mult = 0; int ret; buffering = priv_dev->ep_buf_size - 1; @@ -2061,8 +2120,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) break; default: ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC); - mult = priv_dev->ep_iso_burst - 1; - buffering = mult + 1; + buffering = (priv_ep->bMaxBurst + 1) * (priv_ep->mult + 1) - 1; } switch (priv_dev->gadget.speed) { @@ -2073,17 +2131,8 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) max_packet_size = is_iso_ep ? 1024 : 512; break; case USB_SPEED_SUPER: - /* It's limitation that driver assumes in driver. */ - mult = 0; - max_packet_size = 1024; - if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) { - maxburst = priv_dev->ep_iso_burst - 1; - buffering = (mult + 1) * - (maxburst + 1); - - if (priv_ep->interval > 1) - buffering++; - } else { + if (priv_ep->type != USB_ENDPOINT_XFER_ISOC) { + max_packet_size = 1024; maxburst = priv_dev->ep_buf_size - 1; } break; @@ -2112,7 +2161,6 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) if (priv_dev->dev_ver < DEV_VER_V2) priv_ep->trb_burst_size = 16; - mult = min_t(u8, mult, EP_CFG_MULT_MAX); buffering = min_t(u8, buffering, EP_CFG_BUFFERING_MAX); maxburst = min_t(u8, maxburst, EP_CFG_MAXBURST_MAX); @@ -2146,7 +2194,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) } ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) | - EP_CFG_MULT(mult) | + EP_CFG_MULT(priv_ep->mult) | /* must match EP setting */ EP_CFG_BUFFERING(buffering) | EP_CFG_MAXBURST(maxburst); @@ -2236,6 +2284,13 @@ usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, priv_ep->type = usb_endpoint_type(desc); priv_ep->flags |= EP_CLAIMED; priv_ep->interval = desc->bInterval ? BIT(desc->bInterval - 1) : 0; + priv_ep->wMaxPacketSize = usb_endpoint_maxp(desc); + priv_ep->mult = USB_EP_MAXP_MULT(priv_ep->wMaxPacketSize); + priv_ep->wMaxPacketSize &= USB_ENDPOINT_MAXP_MASK; + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && comp_desc) { + priv_ep->mult = USB_SS_MULT(comp_desc->bmAttributes) - 1; + priv_ep->bMaxBurst = comp_desc->bMaxBurst; + } spin_unlock_irqrestore(&priv_dev->lock, flags); return &priv_ep->endpoint; @@ -3019,22 +3074,40 @@ static int cdns3_gadget_check_config(struct usb_gadget *gadget) struct cdns3_endpoint *priv_ep; struct usb_ep *ep; int n_in = 0; + int iso = 0; + int out = 1; int total; + int n; list_for_each_entry(ep, &gadget->ep_list, ep_list) { priv_ep = ep_to_cdns3_ep(ep); - if ((priv_ep->flags & EP_CLAIMED) && (ep->address & USB_DIR_IN)) - n_in++; + if (!(priv_ep->flags & EP_CLAIMED)) + continue; + + n = (priv_ep->mult + 1) * (priv_ep->bMaxBurst + 1); + if (ep->address & USB_DIR_IN) { + /* + * ISO transfer: DMA start move data when get ISO, only transfer + * data as min(TD size, iso). No benefit for allocate bigger + * internal memory than 'iso'. + */ + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) + iso += n; + else + n_in++; + } else { + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) + out = max_t(int, out, n); + } } /* 2KB are reserved for EP0, 1KB for out*/ - total = 2 + n_in + 1; + total = 2 + n_in + out + iso; if (total > priv_dev->onchip_buffers) return -ENOMEM; - priv_dev->ep_buf_size = priv_dev->ep_iso_burst = - (priv_dev->onchip_buffers - 2) / (n_in + 1); + priv_dev->ep_buf_size = (priv_dev->onchip_buffers - 2 - iso) / (n_in + out); return 0; } diff --git a/drivers/usb/cdns3/cdns3-gadget.h b/drivers/usb/cdns3/cdns3-gadget.h index fbe4a8e3aa89..086a7bb83897 100644 --- a/drivers/usb/cdns3/cdns3-gadget.h +++ b/drivers/usb/cdns3/cdns3-gadget.h @@ -1168,6 +1168,9 @@ struct cdns3_endpoint { u8 dir; u8 num; u8 type; + u8 mult; + u8 bMaxBurst; + u16 wMaxPacketSize; int interval; int free_trbs; diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c index 2c1aca84f226..3ef8e3c872a3 100644 --- a/drivers/usb/cdns3/cdns3-plat.c +++ b/drivers/usb/cdns3/cdns3-plat.c @@ -87,16 +87,20 @@ static int cdns3_plat_probe(struct platform_device *pdev) cdns->dev_irq = platform_get_irq_byname(pdev, "peripheral"); if (cdns->dev_irq < 0) - return cdns->dev_irq; + return dev_err_probe(dev, cdns->dev_irq, + "Failed to get peripheral IRQ\n"); regs = devm_platform_ioremap_resource_byname(pdev, "dev"); if (IS_ERR(regs)) - return PTR_ERR(regs); + return dev_err_probe(dev, PTR_ERR(regs), + "Failed to get dev base\n"); + cdns->dev_regs = regs; cdns->otg_irq = platform_get_irq_byname(pdev, "otg"); if (cdns->otg_irq < 0) - return cdns->otg_irq; + return dev_err_probe(dev, cdns->otg_irq, + "Failed to get otg IRQ\n"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg"); if (!res) { @@ -119,7 +123,8 @@ static int cdns3_plat_probe(struct platform_device *pdev) cdns->usb2_phy = devm_phy_optional_get(dev, "cdns3,usb2-phy"); if (IS_ERR(cdns->usb2_phy)) - return PTR_ERR(cdns->usb2_phy); + return dev_err_probe(dev, PTR_ERR(cdns->usb2_phy), + "Failed to get cdn3,usb2-phy\n"); ret = phy_init(cdns->usb2_phy); if (ret) @@ -127,7 +132,8 @@ static int cdns3_plat_probe(struct platform_device *pdev) cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy"); if (IS_ERR(cdns->usb3_phy)) - return PTR_ERR(cdns->usb3_phy); + return dev_err_probe(dev, PTR_ERR(cdns->usb3_phy), + "Failed to get cdn3,usb3-phy\n"); ret = phy_init(cdns->usb3_phy); if (ret) diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c index a7265b86e427..c04d196abd87 100644 --- a/drivers/usb/cdns3/cdns3-starfive.c +++ b/drivers/usb/cdns3/cdns3-starfive.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * cdns3-starfive.c - StarFive specific Glue layer for Cadence USB Controller * * Copyright (C) 2023 StarFive Technology Co., Ltd. diff --git a/drivers/usb/cdns3/cdnsp-debug.h b/drivers/usb/cdns3/cdnsp-debug.h index ad617b7455b9..cd138acdcce1 100644 --- a/drivers/usb/cdns3/cdnsp-debug.h +++ b/drivers/usb/cdns3/cdnsp-debug.h @@ -187,202 +187,202 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0, switch (type) { case TRB_LINK: - ret = snprintf(str, size, - "LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c", - field1, field0, GET_INTR_TARGET(field2), - cdnsp_trb_type_string(type), - field3 & TRB_IOC ? 'I' : 'i', - field3 & TRB_CHAIN ? 'C' : 'c', - field3 & TRB_TC ? 'T' : 't', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c", + field1, field0, GET_INTR_TARGET(field2), + cdnsp_trb_type_string(type), + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_TC ? 'T' : 't', + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_TRANSFER: case TRB_COMPLETION: case TRB_PORT_STATUS: case TRB_HC_EVENT: - ret = snprintf(str, size, - "ep%d%s(%d) type '%s' TRB %08x%08x status '%s'" - " len %ld slot %ld flags %c:%c", - ep_num, ep_id % 2 ? "out" : "in", - TRB_TO_EP_INDEX(field3), - cdnsp_trb_type_string(type), field1, field0, - cdnsp_trb_comp_code_string(GET_COMP_CODE(field2)), - EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), - field3 & EVENT_DATA ? 'E' : 'e', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "ep%d%s(%d) type '%s' TRB %08x%08x status '%s'" + " len %ld slot %ld flags %c:%c", + ep_num, ep_id % 2 ? "out" : "in", + TRB_TO_EP_INDEX(field3), + cdnsp_trb_type_string(type), field1, field0, + cdnsp_trb_comp_code_string(GET_COMP_CODE(field2)), + EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), + field3 & EVENT_DATA ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_MFINDEX_WRAP: - ret = snprintf(str, size, "%s: flags %c", - cdnsp_trb_type_string(type), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, "%s: flags %c", + cdnsp_trb_type_string(type), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_SETUP: - ret = snprintf(str, size, - "type '%s' bRequestType %02x bRequest %02x " - "wValue %02x%02x wIndex %02x%02x wLength %d " - "length %ld TD size %ld intr %ld Setup ID %ld " - "flags %c:%c:%c", - cdnsp_trb_type_string(type), - field0 & 0xff, - (field0 & 0xff00) >> 8, - (field0 & 0xff000000) >> 24, - (field0 & 0xff0000) >> 16, - (field1 & 0xff00) >> 8, - field1 & 0xff, - (field1 & 0xff000000) >> 16 | - (field1 & 0xff0000) >> 16, - TRB_LEN(field2), GET_TD_SIZE(field2), - GET_INTR_TARGET(field2), - TRB_SETUPID_TO_TYPE(field3), - field3 & TRB_IDT ? 'D' : 'd', - field3 & TRB_IOC ? 'I' : 'i', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "type '%s' bRequestType %02x bRequest %02x " + "wValue %02x%02x wIndex %02x%02x wLength %d " + "length %ld TD size %ld intr %ld Setup ID %ld " + "flags %c:%c:%c", + cdnsp_trb_type_string(type), + field0 & 0xff, + (field0 & 0xff00) >> 8, + (field0 & 0xff000000) >> 24, + (field0 & 0xff0000) >> 16, + (field1 & 0xff00) >> 8, + field1 & 0xff, + (field1 & 0xff000000) >> 16 | + (field1 & 0xff0000) >> 16, + TRB_LEN(field2), GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + TRB_SETUPID_TO_TYPE(field3), + field3 & TRB_IDT ? 'D' : 'd', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_DATA: - ret = snprintf(str, size, - "type '%s' Buffer %08x%08x length %ld TD size %ld " - "intr %ld flags %c:%c:%c:%c:%c:%c:%c", - cdnsp_trb_type_string(type), - field1, field0, TRB_LEN(field2), - GET_TD_SIZE(field2), - GET_INTR_TARGET(field2), - field3 & TRB_IDT ? 'D' : 'i', - field3 & TRB_IOC ? 'I' : 'i', - field3 & TRB_CHAIN ? 'C' : 'c', - field3 & TRB_NO_SNOOP ? 'S' : 's', - field3 & TRB_ISP ? 'I' : 'i', - field3 & TRB_ENT ? 'E' : 'e', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "type '%s' Buffer %08x%08x length %ld TD size %ld " + "intr %ld flags %c:%c:%c:%c:%c:%c:%c", + cdnsp_trb_type_string(type), + field1, field0, TRB_LEN(field2), + GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + field3 & TRB_IDT ? 'D' : 'i', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_NO_SNOOP ? 'S' : 's', + field3 & TRB_ISP ? 'I' : 'i', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_STATUS: - ret = snprintf(str, size, - "Buffer %08x%08x length %ld TD size %ld intr" - "%ld type '%s' flags %c:%c:%c:%c", - field1, field0, TRB_LEN(field2), - GET_TD_SIZE(field2), - GET_INTR_TARGET(field2), - cdnsp_trb_type_string(type), - field3 & TRB_IOC ? 'I' : 'i', - field3 & TRB_CHAIN ? 'C' : 'c', - field3 & TRB_ENT ? 'E' : 'e', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "Buffer %08x%08x length %ld TD size %ld intr" + "%ld type '%s' flags %c:%c:%c:%c", + field1, field0, TRB_LEN(field2), + GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + cdnsp_trb_type_string(type), + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_NORMAL: case TRB_ISOC: case TRB_EVENT_DATA: case TRB_TR_NOOP: - ret = snprintf(str, size, - "type '%s' Buffer %08x%08x length %ld " - "TD size %ld intr %ld " - "flags %c:%c:%c:%c:%c:%c:%c:%c:%c", - cdnsp_trb_type_string(type), - field1, field0, TRB_LEN(field2), - GET_TD_SIZE(field2), - GET_INTR_TARGET(field2), - field3 & TRB_BEI ? 'B' : 'b', - field3 & TRB_IDT ? 'T' : 't', - field3 & TRB_IOC ? 'I' : 'i', - field3 & TRB_CHAIN ? 'C' : 'c', - field3 & TRB_NO_SNOOP ? 'S' : 's', - field3 & TRB_ISP ? 'I' : 'i', - field3 & TRB_ENT ? 'E' : 'e', - field3 & TRB_CYCLE ? 'C' : 'c', - !(field3 & TRB_EVENT_INVALIDATE) ? 'V' : 'v'); + ret = scnprintf(str, size, + "type '%s' Buffer %08x%08x length %ld " + "TD size %ld intr %ld " + "flags %c:%c:%c:%c:%c:%c:%c:%c:%c", + cdnsp_trb_type_string(type), + field1, field0, TRB_LEN(field2), + GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + field3 & TRB_BEI ? 'B' : 'b', + field3 & TRB_IDT ? 'T' : 't', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_NO_SNOOP ? 'S' : 's', + field3 & TRB_ISP ? 'I' : 'i', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c', + !(field3 & TRB_EVENT_INVALIDATE) ? 'V' : 'v'); break; case TRB_CMD_NOOP: case TRB_ENABLE_SLOT: - ret = snprintf(str, size, "%s: flags %c", - cdnsp_trb_type_string(type), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, "%s: flags %c", + cdnsp_trb_type_string(type), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_DISABLE_SLOT: - ret = snprintf(str, size, "%s: slot %ld flags %c", - cdnsp_trb_type_string(type), - TRB_TO_SLOT_ID(field3), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, "%s: slot %ld flags %c", + cdnsp_trb_type_string(type), + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_ADDR_DEV: - ret = snprintf(str, size, - "%s: ctx %08x%08x slot %ld flags %c:%c", - cdnsp_trb_type_string(type), field1, field0, - TRB_TO_SLOT_ID(field3), - field3 & TRB_BSR ? 'B' : 'b', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "%s: ctx %08x%08x slot %ld flags %c:%c", + cdnsp_trb_type_string(type), field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_BSR ? 'B' : 'b', + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_CONFIG_EP: - ret = snprintf(str, size, - "%s: ctx %08x%08x slot %ld flags %c:%c", - cdnsp_trb_type_string(type), field1, field0, - TRB_TO_SLOT_ID(field3), - field3 & TRB_DC ? 'D' : 'd', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "%s: ctx %08x%08x slot %ld flags %c:%c", + cdnsp_trb_type_string(type), field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_DC ? 'D' : 'd', + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_EVAL_CONTEXT: - ret = snprintf(str, size, - "%s: ctx %08x%08x slot %ld flags %c", - cdnsp_trb_type_string(type), field1, field0, - TRB_TO_SLOT_ID(field3), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "%s: ctx %08x%08x slot %ld flags %c", + cdnsp_trb_type_string(type), field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_RESET_EP: case TRB_HALT_ENDPOINT: - ret = snprintf(str, size, - "%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c", - cdnsp_trb_type_string(type), - ep_num, ep_id % 2 ? "out" : "in", - TRB_TO_EP_INDEX(field3), field1, field0, - TRB_TO_SLOT_ID(field3), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c", + cdnsp_trb_type_string(type), + ep_num, ep_id % 2 ? "out" : "in", + TRB_TO_EP_INDEX(field3), field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_STOP_RING: - ret = snprintf(str, size, - "%s: ep%d%s(%d) slot %ld sp %d flags %c", - cdnsp_trb_type_string(type), - ep_num, ep_id % 2 ? "out" : "in", - TRB_TO_EP_INDEX(field3), - TRB_TO_SLOT_ID(field3), - TRB_TO_SUSPEND_PORT(field3), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "%s: ep%d%s(%d) slot %ld sp %d flags %c", + cdnsp_trb_type_string(type), + ep_num, ep_id % 2 ? "out" : "in", + TRB_TO_EP_INDEX(field3), + TRB_TO_SLOT_ID(field3), + TRB_TO_SUSPEND_PORT(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_SET_DEQ: - ret = snprintf(str, size, - "%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c", - cdnsp_trb_type_string(type), - ep_num, ep_id % 2 ? "out" : "in", - TRB_TO_EP_INDEX(field3), field1, field0, - TRB_TO_STREAM_ID(field2), - TRB_TO_SLOT_ID(field3), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c", + cdnsp_trb_type_string(type), + ep_num, ep_id % 2 ? "out" : "in", + TRB_TO_EP_INDEX(field3), field1, field0, + TRB_TO_STREAM_ID(field2), + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_RESET_DEV: - ret = snprintf(str, size, "%s: slot %ld flags %c", - cdnsp_trb_type_string(type), - TRB_TO_SLOT_ID(field3), - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, "%s: slot %ld flags %c", + cdnsp_trb_type_string(type), + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_ENDPOINT_NRDY: temp = TRB_TO_HOST_STREAM(field2); - ret = snprintf(str, size, - "%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c", - cdnsp_trb_type_string(type), - ep_num, ep_id % 2 ? "out" : "in", - TRB_TO_EP_INDEX(field3), temp, - temp == STREAM_PRIME_ACK ? "(PRIME)" : "", - temp == STREAM_REJECTED ? "(REJECTED)" : "", - TRB_TO_DEV_STREAM(field0), - field3 & TRB_STAT ? 'S' : 's', - field3 & TRB_CYCLE ? 'C' : 'c'); + ret = scnprintf(str, size, + "%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c", + cdnsp_trb_type_string(type), + ep_num, ep_id % 2 ? "out" : "in", + TRB_TO_EP_INDEX(field3), temp, + temp == STREAM_PRIME_ACK ? "(PRIME)" : "", + temp == STREAM_REJECTED ? "(REJECTED)" : "", + TRB_TO_DEV_STREAM(field0), + field3 & TRB_STAT ? 'S' : 's', + field3 & TRB_CYCLE ? 'C' : 'c'); break; default: - ret = snprintf(str, size, - "type '%s' -> raw %08x %08x %08x %08x", - cdnsp_trb_type_string(type), - field0, field1, field2, field3); + ret = scnprintf(str, size, + "type '%s' -> raw %08x %08x %08x %08x", + cdnsp_trb_type_string(type), + field0, field1, field2, field3); } - if (ret >= size) - pr_info("CDNSP: buffer overflowed.\n"); + if (ret == size - 1) + pr_info("CDNSP: buffer may be truncated.\n"); return str; } @@ -465,32 +465,32 @@ static inline const char *cdnsp_decode_portsc(char *str, size_t size, { int ret; - ret = snprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ", - portsc & PORT_POWER ? "Powered" : "Powered-off", - portsc & PORT_CONNECT ? "Connected" : "Not-connected", - portsc & PORT_PED ? "Enabled" : "Disabled", - cdnsp_portsc_link_state_string(portsc), - DEV_PORT_SPEED(portsc)); + ret = scnprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ", + portsc & PORT_POWER ? "Powered" : "Powered-off", + portsc & PORT_CONNECT ? "Connected" : "Not-connected", + portsc & PORT_PED ? "Enabled" : "Disabled", + cdnsp_portsc_link_state_string(portsc), + DEV_PORT_SPEED(portsc)); if (portsc & PORT_RESET) - ret += snprintf(str + ret, size - ret, "In-Reset "); + ret += scnprintf(str + ret, size - ret, "In-Reset "); - ret += snprintf(str + ret, size - ret, "Change: "); + ret += scnprintf(str + ret, size - ret, "Change: "); if (portsc & PORT_CSC) - ret += snprintf(str + ret, size - ret, "CSC "); + ret += scnprintf(str + ret, size - ret, "CSC "); if (portsc & PORT_WRC) - ret += snprintf(str + ret, size - ret, "WRC "); + ret += scnprintf(str + ret, size - ret, "WRC "); if (portsc & PORT_RC) - ret += snprintf(str + ret, size - ret, "PRC "); + ret += scnprintf(str + ret, size - ret, "PRC "); if (portsc & PORT_PLC) - ret += snprintf(str + ret, size - ret, "PLC "); + ret += scnprintf(str + ret, size - ret, "PLC "); if (portsc & PORT_CEC) - ret += snprintf(str + ret, size - ret, "CEC "); - ret += snprintf(str + ret, size - ret, "Wake: "); + ret += scnprintf(str + ret, size - ret, "CEC "); + ret += scnprintf(str + ret, size - ret, "Wake: "); if (portsc & PORT_WKCONN_E) - ret += snprintf(str + ret, size - ret, "WCE "); + ret += scnprintf(str + ret, size - ret, "WCE "); if (portsc & PORT_WKDISC_E) - ret += snprintf(str + ret, size - ret, "WDE "); + ret += scnprintf(str + ret, size - ret, "WDE "); return str; } @@ -562,20 +562,20 @@ static inline const char *cdnsp_decode_ep_context(char *str, size_t size, avg = EP_AVG_TRB_LENGTH(tx_info); - ret = snprintf(str, size, "State %s mult %d max P. Streams %d %s", - cdnsp_ep_state_string(ep_state), mult, - max_pstr, lsa ? "LSA " : ""); + ret = scnprintf(str, size, "State %s mult %d max P. Streams %d %s", + cdnsp_ep_state_string(ep_state), mult, + max_pstr, lsa ? "LSA " : ""); - ret += snprintf(str + ret, size - ret, - "interval %d us max ESIT payload %d CErr %d ", - (1 << interval) * 125, esit, cerr); + ret += scnprintf(str + ret, size - ret, + "interval %d us max ESIT payload %d CErr %d ", + (1 << interval) * 125, esit, cerr); - ret += snprintf(str + ret, size - ret, - "Type %s %sburst %d maxp %d deq %016llx ", - cdnsp_ep_type_string(ep_type), hid ? "HID" : "", - burst, maxp, deq); + ret += scnprintf(str + ret, size - ret, + "Type %s %sburst %d maxp %d deq %016llx ", + cdnsp_ep_type_string(ep_type), hid ? "HID" : "", + burst, maxp, deq); - ret += snprintf(str + ret, size - ret, "avg trb len %d", avg); + ret += scnprintf(str + ret, size - ret, "avg trb len %d", avg); return str; } diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index e28bb2f2612d..ae9a6a17ec6e 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -96,6 +96,7 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; + struct clk *clk_wakeup; struct imx_usbmisc_data *usbmisc_data; bool supports_runtime_pm; bool override_phy_control; @@ -199,7 +200,7 @@ static int imx_get_clks(struct device *dev) data->clk_ipg = devm_clk_get(dev, "ipg"); if (IS_ERR(data->clk_ipg)) { - /* If the platform only needs one clocks */ + /* If the platform only needs one primary clock */ data->clk = devm_clk_get(dev, NULL); if (IS_ERR(data->clk)) { ret = PTR_ERR(data->clk); @@ -208,6 +209,13 @@ static int imx_get_clks(struct device *dev) PTR_ERR(data->clk), PTR_ERR(data->clk_ipg)); return ret; } + /* Get wakeup clock. Not all of the platforms need to + * handle this clock. So make it optional. + */ + data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup_clk"); + if (IS_ERR(data->clk_wakeup)) + ret = dev_err_probe(dev, PTR_ERR(data->clk_wakeup), + "Failed to get wakeup clk\n"); return ret; } @@ -423,6 +431,10 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) goto disable_hsic_regulator; + ret = clk_prepare_enable(data->clk_wakeup); + if (ret) + goto err_wakeup_clk; + data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0); if (IS_ERR(data->phy)) { ret = PTR_ERR(data->phy); @@ -504,6 +516,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data->ci_pdev); err_clk: + clk_disable_unprepare(data->clk_wakeup); +err_wakeup_clk: imx_disable_unprepare_clks(dev); disable_hsic_regulator: if (data->hsic_pad_regulator) @@ -530,6 +544,7 @@ static void ci_hdrc_imx_remove(struct platform_device *pdev) usb_phy_shutdown(data->phy); if (data->ci_pdev) { imx_disable_unprepare_clks(&pdev->dev); + clk_disable_unprepare(data->clk_wakeup); if (data->plat_data->flags & CI_HDRC_PMQOS) cpu_latency_qos_remove_request(&data->pm_qos_req); if (data->hsic_pad_regulator) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 7ac39a281b8c..41014f93cfdf 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -523,6 +523,13 @@ static irqreturn_t ci_irq_handler(int irq, void *data) u32 otgsc = 0; if (ci->in_lpm) { + /* + * If we already have a wakeup irq pending there, + * let's just return to wait resume finished firstly. + */ + if (ci->wakeup_int) + return IRQ_HANDLED; + disable_irq_nosync(irq); ci->wakeup_int = true; pm_runtime_get(ci->dev); @@ -862,7 +869,7 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, if (ret) return ERR_PTR(ret); - id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL); + id = ida_alloc(&ci_ida, GFP_KERNEL); if (id < 0) return ERR_PTR(id); @@ -892,7 +899,7 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, err: platform_device_put(pdev); put_id: - ida_simple_remove(&ci_ida, id); + ida_free(&ci_ida, id); return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(ci_hdrc_add_device); @@ -901,7 +908,7 @@ void ci_hdrc_remove_device(struct platform_device *pdev) { int id = pdev->id; platform_device_unregister(pdev); - ida_simple_remove(&ci_ida, id); + ida_free(&ci_ida, id); } EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 0b7bd3c643c3..2d7f616270c1 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -688,7 +688,8 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) if ((TD_STATUS_ACTIVE & tmptoken) != 0) { int n = hw_ep_bit(hwep->num, hwep->dir); - if (ci->rev == CI_REVISION_24) + if (ci->rev == CI_REVISION_24 || + ci->rev == CI_REVISION_22) if (!hw_read(ci, OP_ENDPTSTAT, BIT(n))) reprime_dtd(ci, hwep, node); hwreq->req.status = -EALREADY; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a1f4e1ead97f..0e7439dba8fe 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -916,6 +916,9 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state) struct acm *acm = tty->driver_data; int retval; + if (!(acm->ctrl_caps & USB_CDC_CAP_BRK)) + return -EOPNOTSUPP; + retval = acm_send_break(acm, state ? 0xffff : 0); if (retval < 0) dev_dbg(&acm->control->dev, diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index f58a0299fb3b..e01b1913d02b 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -189,13 +189,13 @@ static int usb_create_newid_files(struct usb_driver *usb_drv) goto exit; if (usb_drv->probe != NULL) { - error = driver_create_file(&usb_drv->drvwrap.driver, + error = driver_create_file(&usb_drv->driver, &driver_attr_new_id); if (error == 0) { - error = driver_create_file(&usb_drv->drvwrap.driver, + error = driver_create_file(&usb_drv->driver, &driver_attr_remove_id); if (error) - driver_remove_file(&usb_drv->drvwrap.driver, + driver_remove_file(&usb_drv->driver, &driver_attr_new_id); } } @@ -209,9 +209,9 @@ static void usb_remove_newid_files(struct usb_driver *usb_drv) return; if (usb_drv->probe != NULL) { - driver_remove_file(&usb_drv->drvwrap.driver, + driver_remove_file(&usb_drv->driver, &driver_attr_remove_id); - driver_remove_file(&usb_drv->drvwrap.driver, + driver_remove_file(&usb_drv->driver, &driver_attr_new_id); } } @@ -290,7 +290,10 @@ static int usb_probe_device(struct device *dev) * specialised device drivers prior to setting the * use_generic_driver bit. */ - error = udriver->probe(udev); + if (udriver->probe) + error = udriver->probe(udev); + else if (!udriver->generic_subclass) + error = -EINVAL; if (error == -ENODEV && udriver != &usb_generic_driver && (udriver->id_table || udriver->match)) { udev->use_generic_driver = 1; @@ -549,7 +552,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (!iface->authorized) return -ENODEV; - dev->driver = &driver->drvwrap.driver; + dev->driver = &driver->driver; usb_set_intfdata(iface, data); iface->needs_binding = 0; @@ -612,7 +615,7 @@ void usb_driver_release_interface(struct usb_driver *driver, struct device *dev = &iface->dev; /* this should never happen, don't release something that's not ours */ - if (!dev->driver || dev->driver != &driver->drvwrap.driver) + if (!dev->driver || dev->driver != &driver->driver) return; /* don't release from within disconnect() */ @@ -947,7 +950,7 @@ static int __usb_bus_reprobe_drivers(struct device *dev, void *data) int ret; /* Don't reprobe if current driver isn't usb_generic_driver */ - if (dev->driver != &usb_generic_driver.drvwrap.driver) + if (dev->driver != &usb_generic_driver.driver) return 0; udev = to_usb_device(dev); @@ -961,6 +964,11 @@ static int __usb_bus_reprobe_drivers(struct device *dev, void *data) return 0; } +bool is_usb_device_driver(const struct device_driver *drv) +{ + return drv->probe == usb_probe_device; +} + /** * usb_register_device_driver - register a USB device (not interface) driver * @new_udriver: USB operations for the device driver @@ -980,15 +988,14 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver, if (usb_disabled()) return -ENODEV; - new_udriver->drvwrap.for_devices = 1; - new_udriver->drvwrap.driver.name = new_udriver->name; - new_udriver->drvwrap.driver.bus = &usb_bus_type; - new_udriver->drvwrap.driver.probe = usb_probe_device; - new_udriver->drvwrap.driver.remove = usb_unbind_device; - new_udriver->drvwrap.driver.owner = owner; - new_udriver->drvwrap.driver.dev_groups = new_udriver->dev_groups; + new_udriver->driver.name = new_udriver->name; + new_udriver->driver.bus = &usb_bus_type; + new_udriver->driver.probe = usb_probe_device; + new_udriver->driver.remove = usb_unbind_device; + new_udriver->driver.owner = owner; + new_udriver->driver.dev_groups = new_udriver->dev_groups; - retval = driver_register(&new_udriver->drvwrap.driver); + retval = driver_register(&new_udriver->driver); if (!retval) { pr_info("%s: registered new device driver %s\n", @@ -1020,7 +1027,7 @@ void usb_deregister_device_driver(struct usb_device_driver *udriver) pr_info("%s: deregistering device driver %s\n", usbcore_name, udriver->name); - driver_unregister(&udriver->drvwrap.driver); + driver_unregister(&udriver->driver); } EXPORT_SYMBOL_GPL(usb_deregister_device_driver); @@ -1048,18 +1055,17 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, if (usb_disabled()) return -ENODEV; - new_driver->drvwrap.for_devices = 0; - new_driver->drvwrap.driver.name = new_driver->name; - new_driver->drvwrap.driver.bus = &usb_bus_type; - new_driver->drvwrap.driver.probe = usb_probe_interface; - new_driver->drvwrap.driver.remove = usb_unbind_interface; - new_driver->drvwrap.driver.owner = owner; - new_driver->drvwrap.driver.mod_name = mod_name; - new_driver->drvwrap.driver.dev_groups = new_driver->dev_groups; + new_driver->driver.name = new_driver->name; + new_driver->driver.bus = &usb_bus_type; + new_driver->driver.probe = usb_probe_interface; + new_driver->driver.remove = usb_unbind_interface; + new_driver->driver.owner = owner; + new_driver->driver.mod_name = mod_name; + new_driver->driver.dev_groups = new_driver->dev_groups; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); - retval = driver_register(&new_driver->drvwrap.driver); + retval = driver_register(&new_driver->driver); if (retval) goto out; @@ -1074,7 +1080,7 @@ out: return retval; out_newid: - driver_unregister(&new_driver->drvwrap.driver); + driver_unregister(&new_driver->driver); pr_err("%s: error %d registering interface driver %s\n", usbcore_name, retval, new_driver->name); @@ -1099,7 +1105,7 @@ void usb_deregister(struct usb_driver *driver) usbcore_name, driver->name); usb_remove_newid_files(driver); - driver_unregister(&driver->drvwrap.driver); + driver_unregister(&driver->driver); usb_free_dynids(driver); } EXPORT_SYMBOL_GPL(usb_deregister); diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 740342a2812a..b134bff5c3fe 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -59,10 +59,26 @@ int usb_choose_configuration(struct usb_device *udev) int num_configs; int insufficient_power = 0; struct usb_host_config *c, *best; + struct usb_device_driver *udriver; + + /* + * If a USB device (not an interface) doesn't have a driver then the + * kernel has no business trying to select or install a configuration + * for it. + */ + if (!udev->dev.driver) + return -1; + udriver = to_usb_device_driver(udev->dev.driver); if (usb_device_is_owned(udev)) return 0; + if (udriver->choose_configuration) { + i = udriver->choose_configuration(udev); + if (i >= 0) + return i; + } + best = NULL; c = udev->config; num_configs = udev->descriptor.bNumConfigurations; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 87480a6e6d93..ffd7c99e24a3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -47,12 +47,24 @@ #define USB_VENDOR_TEXAS_INSTRUMENTS 0x0451 #define USB_PRODUCT_TUSB8041_USB3 0x8140 #define USB_PRODUCT_TUSB8041_USB2 0x8142 -#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 -#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02 +#define USB_VENDOR_MICROCHIP 0x0424 +#define USB_PRODUCT_USB4913 0x4913 +#define USB_PRODUCT_USB4914 0x4914 +#define USB_PRODUCT_USB4915 0x4915 +#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND BIT(0) +#define HUB_QUIRK_DISABLE_AUTOSUSPEND BIT(1) +#define HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL BIT(2) #define USB_TP_TRANSMISSION_DELAY 40 /* ns */ #define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ #define USB_PING_RESPONSE_TIME 400 /* ns */ +#define USB_REDUCE_FRAME_INTR_BINTERVAL 9 + +/* + * The SET_ADDRESS request timeout will be 500 ms when + * USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT quirk flag is set. + */ +#define USB_SHORT_SET_ADDRESS_REQ_TIMEOUT 500 /* ms */ /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can @@ -1904,6 +1916,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) usb_autopm_get_interface_no_resume(intf); } + if ((id->driver_info & HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL) && + desc->endpoint[0].desc.bInterval > USB_REDUCE_FRAME_INTR_BINTERVAL) { + desc->endpoint[0].desc.bInterval = + USB_REDUCE_FRAME_INTR_BINTERVAL; + /* Tell the HCD about the interrupt ep's new bInterval */ + usb_set_interface(hdev, 0, 0); + } + if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) { onboard_hub_create_pdevs(hdev, &hub->onboard_hub_devs); @@ -4626,7 +4646,12 @@ EXPORT_SYMBOL_GPL(usb_ep0_reinit); static int hub_set_address(struct usb_device *udev, int devnum) { int retval; + unsigned int timeout_ms = USB_CTRL_SET_TIMEOUT; struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + + if (hub->hdev->quirks & USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT) + timeout_ms = USB_SHORT_SET_ADDRESS_REQ_TIMEOUT; /* * The host controller will choose the device address, @@ -4639,11 +4664,11 @@ static int hub_set_address(struct usb_device *udev, int devnum) if (udev->state != USB_STATE_DEFAULT) return -EINVAL; if (hcd->driver->address_device) - retval = hcd->driver->address_device(hcd, udev); + retval = hcd->driver->address_device(hcd, udev, timeout_ms); else retval = usb_control_msg(udev, usb_sndaddr0pipe(), USB_REQ_SET_ADDRESS, 0, devnum, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); + NULL, 0, timeout_ms); if (retval == 0) { update_devnum(udev, devnum); /* Device now using proper address. */ @@ -5895,6 +5920,21 @@ static const struct usb_device_id hub_id_table[] = { .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS, .idProduct = USB_PRODUCT_TUSB8041_USB3, .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND}, + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT, + .idVendor = USB_VENDOR_MICROCHIP, + .idProduct = USB_PRODUCT_USB4913, + .driver_info = HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL}, + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT, + .idVendor = USB_VENDOR_MICROCHIP, + .idProduct = USB_PRODUCT_USB4914, + .driver_info = HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL}, + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT, + .idVendor = USB_VENDOR_MICROCHIP, + .idProduct = USB_PRODUCT_USB4915, + .driver_info = HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL}, { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, .bDeviceClass = USB_CLASS_HUB}, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 15e9bd180a1d..b4783574b8e6 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -138,6 +138,9 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp) case 'o': flags |= USB_QUIRK_HUB_SLOW_RESET; break; + case 'p': + flags |= USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT; + break; /* Ignore unrecognized flag characters */ } } @@ -527,6 +530,10 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM }, + /* APTIV AUTOMOTIVE HUB */ + { USB_DEVICE(0x2c48, 0x0132), .driver_info = + USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT }, + /* DJI CineSSD */ { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 2a938cf47ccd..dc8d9228a5e7 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -431,7 +431,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) struct device *dev; argb.minor = minor; - argb.drv = &drv->drvwrap.driver; + argb.drv = &drv->driver; dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 60363153fc3f..bfecb50773b6 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -175,13 +175,7 @@ static inline int is_root_hub(struct usb_device *udev) return (udev->parent == NULL); } -/* Do the same for device drivers and interface drivers. */ - -static inline int is_usb_device_driver(struct device_driver *drv) -{ - return container_of(drv, struct usbdrv_wrap, driver)-> - for_devices; -} +extern bool is_usb_device_driver(const struct device_driver *drv); /* for labeling diagnostics */ extern const char *usbcore_name; diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index fb03162ae9b7..eb677c3cfd0b 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -130,6 +130,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) p->lpm_clock_gating = false; p->besl = false; p->hird_threshold_en = false; + p->no_clock_gating = true; } static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b101dbf8c5dc..3e55838c0001 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -277,48 +277,11 @@ int dwc3_core_soft_reset(struct dwc3 *dwc) /* * We're resetting only the device side because, if we're in host mode, * XHCI driver will reset the host block. If dwc3 was configured for - * host-only mode or current role is host, then we can return early. + * host-only mode, then we can return early. */ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) return 0; - /* - * If the dr_mode is host and the dwc->current_dr_role is not the - * corresponding DWC3_GCTL_PRTCAP_HOST, then the dwc3_core_init_mode - * isn't executed yet. Ensure the phy is ready before the controller - * updates the GCTL.PRTCAPDIR or other settings by soft-resetting - * the phy. - * - * Note: GUSB3PIPECTL[n] and GUSB2PHYCFG[n] are port settings where n - * is port index. If this is a multiport host, then we need to reset - * all active ports. - */ - if (dwc->dr_mode == USB_DR_MODE_HOST) { - u32 usb3_port; - u32 usb2_port; - - usb3_port = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - usb3_port |= DWC3_GUSB3PIPECTL_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port); - - usb2_port = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - usb2_port |= DWC3_GUSB2PHYCFG_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port); - - /* Small delay for phy reset assertion */ - usleep_range(1000, 2000); - - usb3_port &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port); - - usb2_port &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port); - - /* Wait for clock synchronization */ - msleep(50); - return 0; - } - reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= DWC3_DCTL_CSFTRST; reg &= ~DWC3_DCTL_RUN_STOP; @@ -1367,6 +1330,18 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_config_threshold(dwc); + /* + * Modify this for all supported Super Speed ports when + * multiport support is added. + */ + if (hw_mode != DWC3_GHWPARAMS0_MODE_GADGET && + (DWC3_IP_IS(DWC31)) && + dwc->maximum_speed == USB_SPEED_SUPER) { + reg = dwc3_readl(dwc->regs, DWC3_LLUCTL); + reg |= DWC3_LLUCTL_FORCE_GEN1; + dwc3_writel(dwc->regs, DWC3_LLUCTL, reg); + } + return 0; err_power_off_phy: @@ -2340,12 +2315,15 @@ static int dwc3_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - ret = dwc3_resume_common(dwc, PMSG_RESUME); - if (ret) - return ret; - pm_runtime_disable(dev); pm_runtime_set_active(dev); + + ret = dwc3_resume_common(dwc, PMSG_RESUME); + if (ret) { + pm_runtime_set_suspended(dev); + return ret; + } + pm_runtime_enable(dev); return 0; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index efe6caf4d0e8..e3eea965e57b 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -172,6 +172,8 @@ #define DWC3_OEVTEN 0xcc0C #define DWC3_OSTS 0xcc10 +#define DWC3_LLUCTL 0xd024 + /* Bit fields */ /* Global SoC Bus Configuration INCRx Register 0 */ @@ -374,6 +376,7 @@ /* Global HWPARAMS4 Register */ #define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13) #define DWC3_MAX_HIBER_SCRATCHBUFS 15 +#define DWC3_EXT_BUFF_CONTROL BIT(21) /* Global HWPARAMS6 Register */ #define DWC3_GHWPARAMS6_BCSUPPORT BIT(14) @@ -657,6 +660,9 @@ #define DWC3_OSTS_VBUSVLD BIT(1) #define DWC3_OSTS_CONIDSTS BIT(0) +/* Force Gen1 speed on Gen2 link */ +#define DWC3_LLUCTL_FORCE_GEN1 BIT(10) + /* Structures */ struct dwc3_trb; diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index a1e15f2fffdb..8ee448068503 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -363,8 +363,10 @@ static int __maybe_unused dwc3_imx8mp_pm_resume(struct device *dev) } ret = clk_prepare_enable(dwc3_imx->hsio_clk); - if (ret) + if (ret) { + clk_disable_unprepare(dwc3_imx->suspend_clk); return ret; + } ret = dwc3_imx8mp_resume(dwc3_imx, PMSG_RESUME); diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index fdf6d5d3c2ad..dbd6a5b2b289 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -57,7 +57,7 @@ struct dwc3_acpi_pdata { u32 qscratch_base_offset; u32 qscratch_base_size; u32 dwc3_core_base_size; - int hs_phy_irq_index; + int qusb2_phy_irq_index; int dp_hs_phy_irq_index; int dm_hs_phy_irq_index; int ss_phy_irq_index; @@ -73,7 +73,7 @@ struct dwc3_qcom { int num_clocks; struct reset_control *resets; - int hs_phy_irq; + int qusb2_phy_irq; int dp_hs_phy_irq; int dm_hs_phy_irq; int ss_phy_irq; @@ -372,7 +372,7 @@ static void dwc3_qcom_disable_wakeup_irq(int irq) static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) { - dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->qusb2_phy_irq); if (qcom->usb2_speed == USB_SPEED_LOW) { dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); @@ -389,7 +389,7 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) { - dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq, 0); + dwc3_qcom_enable_wakeup_irq(qcom->qusb2_phy_irq, 0); /* * Configure DP/DM line interrupts based on the USB2 device attached to @@ -542,19 +542,19 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) int irq; int ret; - irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq", - pdata ? pdata->hs_phy_irq_index : -1); + irq = dwc3_qcom_get_irq(pdev, "qusb2_phy", + pdata ? pdata->qusb2_phy_irq_index : -1); if (irq > 0) { /* Keep wakeup interrupts disabled until suspend */ ret = devm_request_threaded_irq(qcom->dev, irq, NULL, qcom_dwc3_resume_irq, IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 HS", qcom); + "qcom_dwc3 QUSB2", qcom); if (ret) { - dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret); + dev_err(qcom->dev, "qusb2_phy_irq failed: %d\n", ret); return ret; } - qcom->hs_phy_irq = irq; + qcom->qusb2_phy_irq = irq; } irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq", @@ -1058,7 +1058,7 @@ static const struct dwc3_acpi_pdata sdm845_acpi_pdata = { .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET, .qscratch_base_size = SDM845_QSCRATCH_SIZE, .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE, - .hs_phy_irq_index = 1, + .qusb2_phy_irq_index = 1, .dp_hs_phy_irq_index = 4, .dm_hs_phy_irq_index = 3, .ss_phy_irq_index = 2 @@ -1068,7 +1068,7 @@ static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = { .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET, .qscratch_base_size = SDM845_QSCRATCH_SIZE, .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE, - .hs_phy_irq_index = 1, + .qusb2_phy_irq_index = 1, .dp_hs_phy_irq_index = 4, .dm_hs_phy_irq_index = 3, .ss_phy_irq_index = 2, diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c index 5b7e92f476de..6095f4dee6ce 100644 --- a/drivers/usb/dwc3/dwc3-xilinx.c +++ b/drivers/usb/dwc3/dwc3-xilinx.c @@ -293,11 +293,15 @@ static int dwc3_xlnx_probe(struct platform_device *pdev) goto err_clk_put; pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_suspend_ignore_children(dev, false); - pm_runtime_get_sync(dev); + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + goto err_pm_set_suspended; - return 0; + pm_suspend_ignore_children(dev, false); + return pm_runtime_resume_and_get(dev); + +err_pm_set_suspended: + pm_runtime_set_suspended(dev); err_clk_put: clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks); @@ -315,7 +319,6 @@ static void dwc3_xlnx_remove(struct platform_device *pdev) clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks); priv_data->num_clocks = 0; - pm_runtime_disable(dev); pm_runtime_put_noidle(dev); pm_runtime_set_suspended(dev); } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index b94243237293..6ae8a36f21cf 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -238,7 +238,10 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) struct dwc3_request *req; req = next_request(&dep->pending_list); - dwc3_gadget_giveback(dep, req, -ECONNRESET); + if (!dwc->connected) + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + else + dwc3_gadget_giveback(dep, req, -ECONNRESET); } dwc->eps[0]->trb_enqueue = 0; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 858fe4c299b7..019368f8e9c4 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -673,6 +673,12 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action) params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1); } + if (dep->endpoint.fifo_mode) { + if (!(dwc->hwparams.hwparams4 & DWC3_EXT_BUFF_CONTROL)) + return -EINVAL; + params.param1 |= DWC3_DEPCFG_EBC_HWO_NOWB | DWC3_DEPCFG_USE_EBC; + } + return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, ¶ms); } @@ -2103,7 +2109,17 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, list_for_each_entry(r, &dep->pending_list, list) { if (r == req) { - dwc3_gadget_giveback(dep, req, -ECONNRESET); + /* + * Explicitly check for EP0/1 as dequeue for those + * EPs need to be handled differently. Control EP + * only deals with one USB req, and giveback will + * occur during dwc3_ep0_stall_and_restart(). EP0 + * requests are never added to started_list. + */ + if (dep->number > 1) + dwc3_gadget_giveback(dep, req, -ECONNRESET); + else + dwc3_ep0_reset_state(dwc); goto out; } } @@ -3973,6 +3989,13 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); dwc3_ep0_reset_state(dwc); + + /* + * Request PM idle to address condition where usage count is + * already decremented to zero, but waiting for the disconnect + * interrupt to set dwc->connected to FALSE. + */ + pm_request_idle(dwc->dev); } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 55a56cf67d73..fd7a4e94397e 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -26,6 +26,8 @@ struct dwc3; #define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10) #define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11) #define DWC3_DEPCFG_STREAM_EVENT_EN BIT(13) +#define DWC3_DEPCFG_EBC_HWO_NOWB BIT(14) +#define DWC3_DEPCFG_USE_EBC BIT(15) #define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16) #define DWC3_DEPCFG_STREAM_CAPABLE BIT(24) #define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25) diff --git a/drivers/usb/fotg210/fotg210-hcd.c b/drivers/usb/fotg210/fotg210-hcd.c index 7bf810a0c98a..8c5aaf860635 100644 --- a/drivers/usb/fotg210/fotg210-hcd.c +++ b/drivers/usb/fotg210/fotg210-hcd.c @@ -404,9 +404,9 @@ static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, else if (td->hw_alt_next != list_end) mark = '/'; } - temp = snprintf(next, size, - "\n\t%p%c%s len=%d %08x urb %p", - td, mark, ({ char *tmp; + temp = scnprintf(next, size, + "\n\t%p%c%s len=%d %08x urb %p", + td, mark, ({ char *tmp; switch ((scratch>>8)&0x03) { case 0: tmp = "out"; @@ -424,15 +424,11 @@ static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, (scratch >> 16) & 0x7fff, scratch, td->urb); - if (size < temp) - temp = size; size -= temp; next += temp; } - temp = snprintf(next, size, "\n"); - if (size < temp) - temp = size; + temp = scnprintf(next, size, "\n"); size -= temp; next += temp; diff --git a/drivers/usb/fotg210/fotg210-udc.c b/drivers/usb/fotg210/fotg210-udc.c index f7ea84070554..0bae12e34f9a 100644 --- a/drivers/usb/fotg210/fotg210-udc.c +++ b/drivers/usb/fotg210/fotg210-udc.c @@ -1094,10 +1094,10 @@ static int fotg210_udc_stop(struct usb_gadget *g) /** * fotg210_vbus_session - Called by external transceiver to enable/disable udc - * @_gadget: usb gadget + * @g: usb gadget * @is_active: 0 if should disable UDC VBUS, 1 if should enable * - * Returns 0 + * Returns: %0 */ static int fotg210_vbus_session(struct usb_gadget *g, int is_active) { @@ -1122,7 +1122,7 @@ static const struct usb_gadget_ops fotg210_gadget_ops = { * * Called by the USB Phy when a cable connect or disconnect is sensed. * - * Returns NOTIFY_OK or NOTIFY_DONE + * Returns: NOTIFY_OK or NOTIFY_DONE */ static int fotg210_phy_event(struct notifier_block *nb, unsigned long action, void *data) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 4c639e9ddedc..ce3cfa1f36f5 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -606,10 +606,11 @@ static struct config_group *function_make( char *instance_name; int ret; - ret = snprintf(buf, MAX_NAME_LEN, "%s", name); - if (ret >= MAX_NAME_LEN) + if (strlen(name) >= MAX_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); + scnprintf(buf, MAX_NAME_LEN, "%s", name); + func_name = buf; instance_name = strchr(func_name, '.'); if (!instance_name) { @@ -701,10 +702,12 @@ static struct config_group *config_desc_make( int ret; gi = container_of(group, struct gadget_info, configs_group); - ret = snprintf(buf, MAX_NAME_LEN, "%s", name); - if (ret >= MAX_NAME_LEN) + + if (strlen(name) >= MAX_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); + scnprintf(buf, MAX_NAME_LEN, "%s", name); + num_str = strchr(buf, '.'); if (!num_str) { pr_err("Unable to locate . in name.bConfigurationValue\n"); @@ -812,7 +815,7 @@ static ssize_t gadget_string_s_show(struct config_item *item, char *page) struct gadget_string *string = to_gadget_string(item); int ret; - ret = snprintf(page, sizeof(string->string), "%s\n", string->string); + ret = sysfs_emit(page, "%s\n", string->string); return ret; } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index fdd0fc7b8f25..6bff6cb93789 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2931,9 +2931,8 @@ static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type, t = &func->function.os_desc_table[desc->bFirstInterfaceNumber]; t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber]; - memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID, - ARRAY_SIZE(desc->CompatibleID) + - ARRAY_SIZE(desc->SubCompatibleID)); + memcpy(t->os_desc->ext_compat_id, &desc->IDs, + sizeof_field(struct usb_ext_compat_desc, IDs)); length = sizeof(*desc); } break; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 5335845d697b..20c6fbd94f32 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1177,11 +1177,11 @@ F_MIDI_OPT(out_ports, true, MAX_PORTS); static ssize_t f_midi_opts_id_show(struct config_item *item, char *page) { struct f_midi_opts *opts = to_f_midi_opts(item); - int result; + ssize_t result; mutex_lock(&opts->lock); if (opts->id) { - result = strlcpy(page, opts->id, PAGE_SIZE); + result = strscpy(page, opts->id, PAGE_SIZE); } else { page[0] = 0; result = 0; diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index cc0ed29a4adc..a1575a0ca568 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -103,6 +103,16 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) /* Delay for the transmit to wait before sending an unfilled NTB frame. */ #define TX_TIMEOUT_NSECS 300000 +/* + * Although max mtu as dictated by u_ether is 15412 bytes, setting + * max_segment_sizeto 15426 would not be efficient. If user chooses segment + * size to be (>= 8192), then we can't aggregate more than one buffer in each + * NTB (assuming each packet coming from network layer is >= 8192 bytes) as ep + * maxpacket limit is 16384. So let max_segment_size be limited to 8000 to allow + * at least 2 packets to be aggregated reducing wastage of NTB buffer space + */ +#define MAX_DATAGRAM_SIZE 8000 + #define FORMATS_SUPPORTED (USB_CDC_NCM_NTB16_SUPPORTED | \ USB_CDC_NCM_NTB32_SUPPORTED) @@ -179,7 +189,6 @@ static struct usb_cdc_ether_desc ecm_desc = { /* this descriptor actually adds value, surprise! */ /* .iMACAddress = DYNAMIC */ .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */ - .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN), .wNumberMCFilters = cpu_to_le16(0), .bNumberPowerFilters = 0, }; @@ -1166,11 +1175,15 @@ static int ncm_unwrap_ntb(struct gether *port, struct sk_buff *skb2; int ret = -EINVAL; unsigned ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize); - unsigned frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize); + unsigned frame_max; const struct ndp_parser_opts *opts = ncm->parser_opts; unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; int dgram_counter; int to_process = skb->len; + struct f_ncm_opts *ncm_opts; + + ncm_opts = container_of(port->func.fi, struct f_ncm_opts, func_inst); + frame_max = ncm_opts->max_segment_size; parse_ntb: tmp = (__le16 *)ntb_ptr; @@ -1430,8 +1443,10 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) mutex_lock(&ncm_opts->lock); gether_set_gadget(ncm_opts->net, cdev->gadget); - if (!ncm_opts->bound) + if (!ncm_opts->bound) { + ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); status = gether_register_netdev(ncm_opts->net); + } mutex_unlock(&ncm_opts->lock); if (status) @@ -1474,6 +1489,8 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm_data_intf.bInterfaceNumber = status; ncm_union_desc.bSlaveInterface0 = status; + ecm_desc.wMaxSegmentSize = ncm_opts->max_segment_size; + status = -ENODEV; /* allocate instance-specific endpoints */ @@ -1576,11 +1593,56 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm); /* f_ncm_opts_ifname */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm); +static ssize_t ncm_opts_max_segment_size_show(struct config_item *item, + char *page) +{ + struct f_ncm_opts *opts = to_f_ncm_opts(item); + u16 segment_size; + + mutex_lock(&opts->lock); + segment_size = opts->max_segment_size; + mutex_unlock(&opts->lock); + + return sysfs_emit(page, "%u\n", segment_size); +} + +static ssize_t ncm_opts_max_segment_size_store(struct config_item *item, + const char *page, size_t len) +{ + struct f_ncm_opts *opts = to_f_ncm_opts(item); + u16 segment_size; + int ret; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto out; + } + + ret = kstrtou16(page, 0, &segment_size); + if (ret) + goto out; + + if (segment_size > MAX_DATAGRAM_SIZE) { + ret = -EINVAL; + goto out; + } + + opts->max_segment_size = segment_size; + ret = len; +out: + mutex_unlock(&opts->lock); + return ret; +} + +CONFIGFS_ATTR(ncm_opts_, max_segment_size); + static struct configfs_attribute *ncm_attrs[] = { &ncm_opts_attr_dev_addr, &ncm_opts_attr_host_addr, &ncm_opts_attr_qmult, &ncm_opts_attr_ifname, + &ncm_opts_attr_max_segment_size, NULL, }; @@ -1623,6 +1685,7 @@ static struct usb_function_instance *ncm_alloc_inst(void) kfree(opts); return ERR_CAST(net); } + opts->max_segment_size = cpu_to_le16(ETH_FRAME_LEN); INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); descs[0] = &opts->ncm_os_desc; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index ff33f31bcdf6..37befd6db001 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1504,8 +1504,8 @@ static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page) ret = -ENODEV; goto out; } - ret = snprintf(page, PAGE_SIZE, "%s\n", - tv_nexus->tvn_se_sess->se_node_acl->initiatorname); + ret = sysfs_emit(page, "%s\n", + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); out: mutex_unlock(&tpg->tpg_mutex); return ret; diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 6f0e1d803dc2..7de74a3dd392 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -292,6 +292,77 @@ static struct usb_descriptor_header *f_audio_desc[] = { NULL, }; +/* Standard ISO OUT Endpoint Descriptor */ +static struct usb_endpoint_descriptor ss_as_out_ep_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE + | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(UAC1_OUT_EP_MAX_PACKET_SIZE), + .bInterval = 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_as_out_ep_desc_comp = { + .bLength = sizeof(ss_as_out_ep_desc_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + /* wBytesPerInterval = DYNAMIC */ +}; + +/* Standard ISO OUT Endpoint Descriptor */ +static struct usb_endpoint_descriptor ss_as_in_ep_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_SYNC_ASYNC + | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(UAC1_OUT_EP_MAX_PACKET_SIZE), + .bInterval = 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_as_in_ep_desc_comp = { + .bLength = sizeof(ss_as_in_ep_desc_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + /* wBytesPerInterval = DYNAMIC */ +}; + +static struct usb_descriptor_header *f_audio_ss_desc[] = { + (struct usb_descriptor_header *)&ac_interface_desc, + (struct usb_descriptor_header *)&ac_header_desc, + + (struct usb_descriptor_header *)&usb_out_it_desc, + (struct usb_descriptor_header *)&io_out_ot_desc, + (struct usb_descriptor_header *)&io_in_it_desc, + (struct usb_descriptor_header *)&usb_in_ot_desc, + + (struct usb_descriptor_header *)&as_out_interface_alt_0_desc, + (struct usb_descriptor_header *)&as_out_interface_alt_1_desc, + (struct usb_descriptor_header *)&as_out_header_desc, + + (struct usb_descriptor_header *)&as_out_type_i_desc, + + //(struct usb_descriptor_header *)&as_out_ep_desc, + (struct usb_descriptor_header *)&ss_as_out_ep_desc, + (struct usb_descriptor_header *)&ss_as_out_ep_desc_comp, + (struct usb_descriptor_header *)&as_iso_out_desc, + + (struct usb_descriptor_header *)&as_in_interface_alt_0_desc, + (struct usb_descriptor_header *)&as_in_interface_alt_1_desc, + (struct usb_descriptor_header *)&as_in_header_desc, + + (struct usb_descriptor_header *)&as_in_type_i_desc, + + //(struct usb_descriptor_header *)&as_in_ep_desc, + (struct usb_descriptor_header *)&ss_as_in_ep_desc, + (struct usb_descriptor_header *)&ss_as_in_ep_desc_comp, + (struct usb_descriptor_header *)&as_iso_in_desc, + NULL, +}; + enum { STR_AC_IF, STR_USB_OUT_IT, @@ -1352,6 +1423,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); if (!ep) goto err_free_fu; + ss_as_out_ep_desc.bEndpointAddress = as_out_ep_desc.bEndpointAddress; audio->out_ep = ep; audio->out_ep->desc = &as_out_ep_desc; } @@ -1360,6 +1432,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); if (!ep) goto err_free_fu; + ss_as_in_ep_desc.bEndpointAddress = as_in_ep_desc.bEndpointAddress; audio->in_ep = ep; audio->in_ep->desc = &as_in_ep_desc; } @@ -1367,8 +1440,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) setup_descriptor(audio_opts); /* copy descriptors, and track endpoint copies */ - status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, - NULL); + status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, f_audio_ss_desc, + f_audio_ss_desc); if (status) goto err_free_fu; @@ -1561,7 +1634,7 @@ static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \ int result; \ \ mutex_lock(&opts->lock); \ - result = snprintf(page, sizeof(opts->name), "%s", opts->name); \ + result = scnprintf(page, sizeof(opts->name), "%s", opts->name); \ mutex_unlock(&opts->lock); \ \ return result; \ @@ -1579,7 +1652,7 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \ goto end; \ } \ \ - ret = snprintf(opts->name, min(sizeof(opts->name), len), \ + ret = scnprintf(opts->name, min(sizeof(opts->name), len), \ "%s", page); \ \ end: \ @@ -1685,7 +1758,7 @@ static struct usb_function_instance *f_audio_alloc_inst(void) opts->req_number = UAC1_DEF_REQ_NUM; - snprintf(opts->function_name, sizeof(opts->function_name), "AC Interface"); + scnprintf(opts->function_name, sizeof(opts->function_name), "AC Interface"); return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index f9a0f07a7476..383f6854cfec 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -2045,7 +2045,7 @@ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ int result; \ \ mutex_lock(&opts->lock); \ - result = snprintf(page, sizeof(opts->name), "%s", opts->name); \ + result = scnprintf(page, sizeof(opts->name), "%s", opts->name); \ mutex_unlock(&opts->lock); \ \ return result; \ @@ -2063,7 +2063,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ goto end; \ } \ \ - ret = snprintf(opts->name, min(sizeof(opts->name), len), \ + ret = scnprintf(opts->name, min(sizeof(opts->name), len), \ "%s", page); \ \ end: \ @@ -2187,7 +2187,7 @@ static struct usb_function_instance *afunc_alloc_inst(void) opts->req_number = UAC2_DEF_REQ_NUM; opts->fb_max = FBACK_FAST_MAX; - snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink"); + scnprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink"); opts->p_terminal_type = UAC2_DEF_P_TERM_TYPE; opts->c_terminal_type = UAC2_DEF_C_TERM_TYPE; diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 786379f1b7b7..929666805bd2 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -263,10 +263,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) return 0; } -void uvc_function_setup_continue(struct uvc_device *uvc) +void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep) { struct usb_composite_dev *cdev = uvc->func.config->cdev; + if (disable_ep && uvc->video.ep) + usb_ep_disable(uvc->video.ep); + usb_composite_setup_continue(cdev); } @@ -337,15 +340,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (uvc->state != UVC_STATE_STREAMING) return 0; - if (uvc->video.ep) - usb_ep_disable(uvc->video.ep); - memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMOFF; v4l2_event_queue(&uvc->vdev, &v4l2_event); - uvc->state = UVC_STATE_CONNECTED; - return 0; + return USB_GADGET_DELAYED_STATUS; case 1: if (uvc->state != UVC_STATE_CONNECTED) @@ -722,13 +721,29 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) } uvc->enable_interrupt_ep = opts->enable_interrupt_ep; - ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); + /* + * gadget_is_{super|dual}speed() API check UDC controller capitblity. It should pass down + * highest speed endpoint descriptor to UDC controller. So UDC controller driver can reserve + * enough resource at check_config(), especially mult and maxburst. So UDC driver (such as + * cdns3) can know need at least (mult + 1) * (maxburst + 1) * wMaxPacketSize internal + * memory for this uvc functions. This is the only straightforward method to resolve the UDC + * resource allocation issue in the current gadget framework. + */ + if (gadget_is_superspeed(c->cdev->gadget)) + ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep, + &uvc_ss_streaming_comp); + else if (gadget_is_dualspeed(cdev->gadget)) + ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep); + else + ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); + if (!ep) { uvcg_info(f, "Unable to allocate streaming EP\n"); goto error; } uvc->video.ep = ep; + uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address; uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address; uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; @@ -960,7 +975,8 @@ static void uvc_free(struct usb_function *f) struct uvc_device *uvc = to_uvc(f); struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts, func_inst); - config_item_put(&uvc->header->item); + if (!opts->header) + config_item_put(&uvc->header->item); --opts->refcnt; kfree(uvc); } @@ -1052,25 +1068,29 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->desc.hs_streaming = opts->hs_streaming; uvc->desc.ss_streaming = opts->ss_streaming; - streaming = config_group_find_item(&opts->func_inst.group, "streaming"); - if (!streaming) - goto err_config; + if (opts->header) { + uvc->header = opts->header; + } else { + streaming = config_group_find_item(&opts->func_inst.group, "streaming"); + if (!streaming) + goto err_config; - header = config_group_find_item(to_config_group(streaming), "header"); - config_item_put(streaming); - if (!header) - goto err_config; + header = config_group_find_item(to_config_group(streaming), "header"); + config_item_put(streaming); + if (!header) + goto err_config; - h = config_group_find_item(to_config_group(header), "h"); - config_item_put(header); - if (!h) - goto err_config; + h = config_group_find_item(to_config_group(header), "h"); + config_item_put(header); + if (!h) + goto err_config; - uvc->header = to_uvcg_streaming_header(h); - if (!uvc->header->linked) { - mutex_unlock(&opts->lock); - kfree(uvc); - return ERR_PTR(-EBUSY); + uvc->header = to_uvcg_streaming_header(h); + if (!uvc->header->linked) { + mutex_unlock(&opts->lock); + kfree(uvc); + return ERR_PTR(-EBUSY); + } } uvc->desc.extension_units = &opts->extension_units; diff --git a/drivers/usb/gadget/function/f_uvc.h b/drivers/usb/gadget/function/f_uvc.h index 1db972d4beeb..083aef0c65c6 100644 --- a/drivers/usb/gadget/function/f_uvc.h +++ b/drivers/usb/gadget/function/f_uvc.h @@ -11,7 +11,7 @@ struct uvc_device; -void uvc_function_setup_continue(struct uvc_device *uvc); +void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep); void uvc_function_connect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 9d1c40c152d8..3c5a6f6ac341 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1163,6 +1163,8 @@ struct net_device *gether_connect(struct gether *link) if (netif_running(dev->net)) eth_start(dev, GFP_ATOMIC); + netif_device_attach(dev->net); + /* on error, disable any endpoints */ } else { (void) usb_ep_disable(link->out_ep); diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index 5408854d8407..49ec095cdb4b 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -31,6 +31,8 @@ struct f_ncm_opts { */ struct mutex lock; int refcnt; + + u16 max_segment_size; }; #endif /* U_NCM_H */ diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 1ce58f61253c..3ac392cbb779 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -98,6 +98,12 @@ struct f_uvc_opts { */ struct mutex lock; int refcnt; + + /* + * Only for legacy gadget. Shall be NULL for configfs-composed gadgets, + * which is guaranteed by alloc_inst implementation of f_uvc doing kzalloc. + */ + struct uvcg_streaming_header *header; }; #endif /* U_UVC_H */ diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 6751de8b63ad..cb35687b11e7 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -81,6 +81,7 @@ struct uvc_request { struct sg_table sgt; u8 header[UVCG_REQUEST_HEADER_LEN]; struct uvc_buffer *last_buf; + struct list_head list; }; struct uvc_video { @@ -101,9 +102,18 @@ struct uvc_video { unsigned int uvc_num_requests; /* Requests */ + bool is_enabled; /* tracks whether video stream is enabled */ unsigned int req_size; - struct uvc_request *ureq; + struct list_head ureqs; /* all uvc_requests allocated by uvc_video */ + + /* USB requests that the video pump thread can encode into */ struct list_head req_free; + + /* + * USB requests video pump thread has already encoded into. These are + * ready to be queued to the endpoint. + */ + struct list_head req_ready; spinlock_t req_lock; unsigned int req_int_count; @@ -177,7 +187,7 @@ struct uvc_file_handle { * Functions */ -extern void uvc_function_setup_continue(struct uvc_device *uvc); +extern void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep); extern void uvc_function_connect(struct uvc_device *uvc); extern void uvc_function_disconnect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 9bf0e985acfa..7e704b2bcfd1 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -3414,7 +3414,7 @@ static ssize_t f_uvc_opts_string_##cname##_show(struct config_item *item,\ int result; \ \ mutex_lock(&opts->lock); \ - result = snprintf(page, sizeof(opts->aname), "%s", opts->aname);\ + result = scnprintf(page, sizeof(opts->aname), "%s", opts->aname);\ mutex_unlock(&opts->lock); \ \ return result; \ diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 3f0a9795c0d4..c7e5fa4f29e0 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -443,7 +443,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return -EINVAL; /* Enable UVC video. */ - ret = uvcg_video_enable(video, 1); + ret = uvcg_video_enable(video); if (ret < 0) return ret; @@ -451,7 +451,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) * Complete the alternate setting selection setup phase now that * userspace is ready to provide video frames. */ - uvc_function_setup_continue(uvc); + uvc_function_setup_continue(uvc, 0); uvc->state = UVC_STATE_STREAMING; return 0; @@ -463,11 +463,18 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) struct video_device *vdev = video_devdata(file); struct uvc_device *uvc = video_get_drvdata(vdev); struct uvc_video *video = &uvc->video; + int ret = 0; if (type != video->queue.queue.type) return -EINVAL; - return uvcg_video_enable(video, 0); + ret = uvcg_video_disable(video); + if (ret < 0) + return ret; + + uvc->state = UVC_STATE_CONNECTED; + uvc_function_setup_continue(uvc, 1); + return 0; } static int @@ -500,7 +507,7 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh, static void uvc_v4l2_disable(struct uvc_device *uvc) { uvc_function_disconnect(uvc); - uvcg_video_enable(&uvc->video, 0); + uvcg_video_disable(&uvc->video); uvcg_free_buffers(&uvc->video.queue); uvc->func_connected = false; wake_up_interruptible(&uvc->func_connected_queue); @@ -647,4 +654,3 @@ const struct v4l2_file_operations uvc_v4l2_fops = { .get_unmapped_area = uvcg_v4l2_get_unmapped_area, #endif }; - diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 91af3b1ef0d4..dd3241fc6939 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -227,6 +227,28 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, * Request handling */ +/* + * Callers must take care to hold req_lock when this function may be called + * from multiple threads. For example, when frames are streaming to the host. + */ +static void +uvc_video_free_request(struct uvc_request *ureq, struct usb_ep *ep) +{ + sg_free_table(&ureq->sgt); + if (ureq->req && ep) { + usb_ep_free_request(ep, ureq->req); + ureq->req = NULL; + } + + kfree(ureq->req_buffer); + ureq->req_buffer = NULL; + + if (!list_empty(&ureq->list)) + list_del_init(&ureq->list); + + kfree(ureq); +} + static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) { int ret; @@ -247,14 +269,127 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) return ret; } +/* This function must be called with video->req_lock held. */ +static int uvcg_video_usb_req_queue(struct uvc_video *video, + struct usb_request *req, bool queue_to_ep) +{ + bool is_bulk = video->max_payload_size; + struct list_head *list = NULL; + + if (!video->is_enabled) + return -ENODEV; + + if (queue_to_ep) { + struct uvc_request *ureq = req->context; + /* + * With USB3 handling more requests at a higher speed, we can't + * afford to generate an interrupt for every request. Decide to + * interrupt: + * + * - When no more requests are available in the free queue, as + * this may be our last chance to refill the endpoint's + * request queue. + * + * - When this is request is the last request for the video + * buffer, as we want to start sending the next video buffer + * ASAP in case it doesn't get started already in the next + * iteration of this loop. + * + * - Four times over the length of the requests queue (as + * indicated by video->uvc_num_requests), as a trade-off + * between latency and interrupt load. + */ + if (list_empty(&video->req_free) || ureq->last_buf || + !(video->req_int_count % + DIV_ROUND_UP(video->uvc_num_requests, 4))) { + video->req_int_count = 0; + req->no_interrupt = 0; + } else { + req->no_interrupt = 1; + } + video->req_int_count++; + return uvcg_video_ep_queue(video, req); + } + /* + * If we're not queuing to the ep, for isoc we're queuing + * to the req_ready list, otherwise req_free. + */ + list = is_bulk ? &video->req_free : &video->req_ready; + list_add_tail(&req->list, list); + return 0; +} + +/* + * Must only be called from uvcg_video_enable - since after that we only want to + * queue requests to the endpoint from the uvc_video_complete complete handler. + * This function is needed in order to 'kick start' the flow of requests from + * gadget driver to the usb controller. + */ +static void uvc_video_ep_queue_initial_requests(struct uvc_video *video) +{ + struct usb_request *req = NULL; + unsigned long flags = 0; + unsigned int count = 0; + int ret = 0; + + /* + * We only queue half of the free list since we still want to have + * some free usb_requests in the free list for the video_pump async_wq + * thread to encode uvc buffers into. Otherwise we could get into a + * situation where the free list does not have any usb requests to + * encode into - we always end up queueing 0 length requests to the + * end point. + */ + unsigned int half_list_size = video->uvc_num_requests / 2; + + spin_lock_irqsave(&video->req_lock, flags); + /* + * Take these requests off the free list and queue them all to the + * endpoint. Since we queue 0 length requests with the req_lock held, + * there isn't any 'data' race involved here with the complete handler. + */ + while (count < half_list_size) { + req = list_first_entry(&video->req_free, struct usb_request, + list); + list_del(&req->list); + req->length = 0; + ret = uvcg_video_ep_queue(video, req); + if (ret < 0) { + uvcg_queue_cancel(&video->queue, 0); + break; + } + count++; + } + spin_unlock_irqrestore(&video->req_lock, flags); +} + static void uvc_video_complete(struct usb_ep *ep, struct usb_request *req) { struct uvc_request *ureq = req->context; struct uvc_video *video = ureq->video; struct uvc_video_queue *queue = &video->queue; - struct uvc_device *uvc = video->uvc; + struct uvc_buffer *last_buf; unsigned long flags; + bool is_bulk = video->max_payload_size; + int ret = 0; + + spin_lock_irqsave(&video->req_lock, flags); + if (!video->is_enabled) { + /* + * When is_enabled is false, uvcg_video_disable() ensures + * that in-flight uvc_buffers are returned, so we can + * safely call free_request without worrying about + * last_buf. + */ + uvc_video_free_request(ureq, ep); + spin_unlock_irqrestore(&video->req_lock, flags); + return; + } + + last_buf = ureq->last_buf; + ureq->last_buf = NULL; + spin_unlock_irqrestore(&video->req_lock, flags); switch (req->status) { case 0: @@ -277,44 +412,85 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) uvcg_queue_cancel(queue, 0); } - if (ureq->last_buf) { - uvcg_complete_buffer(&video->queue, ureq->last_buf); - ureq->last_buf = NULL; + if (last_buf) { + spin_lock_irqsave(&queue->irqlock, flags); + uvcg_complete_buffer(queue, last_buf); + spin_unlock_irqrestore(&queue->irqlock, flags); } spin_lock_irqsave(&video->req_lock, flags); - list_add_tail(&req->list, &video->req_free); - spin_unlock_irqrestore(&video->req_lock, flags); + /* + * Video stream might have been disabled while we were + * processing the current usb_request. So make sure + * we're still streaming before queueing the usb_request + * back to req_free + */ + if (video->is_enabled) { + /* + * Here we check whether any request is available in the ready + * list. If it is, queue it to the ep and add the current + * usb_request to the req_free list - for video_pump to fill in. + * Otherwise, just use the current usb_request to queue a 0 + * length request to the ep. Since we always add to the req_free + * list if we dequeue from the ready list, there will never + * be a situation where the req_free list is completely out of + * requests and cannot recover. + */ + struct usb_request *to_queue = req; - if (uvc->state == UVC_STATE_STREAMING) - queue_work(video->async_wq, &video->pump); + to_queue->length = 0; + if (!list_empty(&video->req_ready)) { + to_queue = list_first_entry(&video->req_ready, + struct usb_request, list); + list_del(&to_queue->list); + list_add_tail(&req->list, &video->req_free); + /* + * Queue work to the wq as well since it is possible that a + * buffer may not have been completely encoded with the set of + * in-flight usb requests for whih the complete callbacks are + * firing. + * In that case, if we do not queue work to the worker thread, + * the buffer will never be marked as complete - and therefore + * not be returned to userpsace. As a result, + * dequeue -> queue -> dequeue flow of uvc buffers will not + * happen. + */ + queue_work(video->async_wq, &video->pump); + } + /* + * Queue to the endpoint. The actual queueing to ep will + * only happen on one thread - the async_wq for bulk endpoints + * and this thread for isoc endpoints. + */ + ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk); + if (ret < 0) { + /* + * Endpoint error, but the stream is still enabled. + * Put request back in req_free for it to be cleaned + * up later. + */ + list_add_tail(&to_queue->list, &video->req_free); + } + } else { + uvc_video_free_request(ureq, ep); + ret = 0; + } + spin_unlock_irqrestore(&video->req_lock, flags); + if (ret < 0) + uvcg_queue_cancel(queue, 0); } static int uvc_video_free_requests(struct uvc_video *video) { - unsigned int i; + struct uvc_request *ureq, *temp; - if (video->ureq) { - for (i = 0; i < video->uvc_num_requests; ++i) { - sg_free_table(&video->ureq[i].sgt); - - if (video->ureq[i].req) { - usb_ep_free_request(video->ep, video->ureq[i].req); - video->ureq[i].req = NULL; - } - - if (video->ureq[i].req_buffer) { - kfree(video->ureq[i].req_buffer); - video->ureq[i].req_buffer = NULL; - } - } - - kfree(video->ureq); - video->ureq = NULL; - } + list_for_each_entry_safe(ureq, temp, &video->ureqs, list) + uvc_video_free_request(ureq, video->ep); + INIT_LIST_HEAD(&video->ureqs); INIT_LIST_HEAD(&video->req_free); + INIT_LIST_HEAD(&video->req_ready); video->req_size = 0; return 0; } @@ -322,6 +498,7 @@ uvc_video_free_requests(struct uvc_video *video) static int uvc_video_alloc_requests(struct uvc_video *video) { + struct uvc_request *ureq; unsigned int req_size; unsigned int i; int ret = -ENOMEM; @@ -332,29 +509,33 @@ uvc_video_alloc_requests(struct uvc_video *video) * max_t(unsigned int, video->ep->maxburst, 1) * (video->ep->mult); - video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL); - if (video->ureq == NULL) - return -ENOMEM; - - for (i = 0; i < video->uvc_num_requests; ++i) { - video->ureq[i].req_buffer = kmalloc(req_size, GFP_KERNEL); - if (video->ureq[i].req_buffer == NULL) + for (i = 0; i < video->uvc_num_requests; i++) { + ureq = kzalloc(sizeof(struct uvc_request), GFP_KERNEL); + if (ureq == NULL) goto error; - video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL); - if (video->ureq[i].req == NULL) + INIT_LIST_HEAD(&ureq->list); + + list_add_tail(&ureq->list, &video->ureqs); + + ureq->req_buffer = kmalloc(req_size, GFP_KERNEL); + if (ureq->req_buffer == NULL) goto error; - video->ureq[i].req->buf = video->ureq[i].req_buffer; - video->ureq[i].req->length = 0; - video->ureq[i].req->complete = uvc_video_complete; - video->ureq[i].req->context = &video->ureq[i]; - video->ureq[i].video = video; - video->ureq[i].last_buf = NULL; + ureq->req = usb_ep_alloc_request(video->ep, GFP_KERNEL); + if (ureq->req == NULL) + goto error; - list_add_tail(&video->ureq[i].req->list, &video->req_free); + ureq->req->buf = ureq->req_buffer; + ureq->req->length = 0; + ureq->req->complete = uvc_video_complete; + ureq->req->context = ureq; + ureq->video = video; + ureq->last_buf = NULL; + + list_add_tail(&ureq->req->list, &video->req_free); /* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */ - sg_alloc_table(&video->ureq[i].sgt, + sg_alloc_table(&ureq->sgt, DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN, PAGE_SIZE) + 2, GFP_KERNEL); } @@ -387,16 +568,18 @@ static void uvcg_video_pump(struct work_struct *work) struct usb_request *req = NULL; struct uvc_buffer *buf; unsigned long flags; - bool buf_done; - int ret; + int ret = 0; + + while (true) { + if (!video->ep->enabled) + return; - while (video->ep->enabled) { /* - * Retrieve the first available USB request, protected by the - * request lock. + * Check is_enabled and retrieve the first available USB + * request, protected by the request lock. */ spin_lock_irqsave(&video->req_lock, flags); - if (list_empty(&video->req_free)) { + if (!video->is_enabled || list_empty(&video->req_free)) { spin_unlock_irqrestore(&video->req_lock, flags); return; } @@ -414,15 +597,6 @@ static void uvcg_video_pump(struct work_struct *work) if (buf != NULL) { video->encode(req, video, buf); - buf_done = buf->state == UVC_BUF_STATE_DONE; - } else if (!(queue->flags & UVC_QUEUE_DISCONNECTED) && !is_bulk) { - /* - * No video buffer available; the queue is still connected and - * we're transferring over ISOC. Queue a 0 length request to - * prevent missed ISOC transfers. - */ - req->length = 0; - buf_done = false; } else { /* * Either the queue has been disconnected or no video buffer @@ -433,62 +607,123 @@ static void uvcg_video_pump(struct work_struct *work) break; } - /* - * With USB3 handling more requests at a higher speed, we can't - * afford to generate an interrupt for every request. Decide to - * interrupt: - * - * - When no more requests are available in the free queue, as - * this may be our last chance to refill the endpoint's - * request queue. - * - * - When this is request is the last request for the video - * buffer, as we want to start sending the next video buffer - * ASAP in case it doesn't get started already in the next - * iteration of this loop. - * - * - Four times over the length of the requests queue (as - * indicated by video->uvc_num_requests), as a trade-off - * between latency and interrupt load. - */ - if (list_empty(&video->req_free) || buf_done || - !(video->req_int_count % - DIV_ROUND_UP(video->uvc_num_requests, 4))) { - video->req_int_count = 0; - req->no_interrupt = 0; - } else { - req->no_interrupt = 1; - } - - /* Queue the USB request */ - ret = uvcg_video_ep_queue(video, req); spin_unlock_irqrestore(&queue->irqlock, flags); + spin_lock_irqsave(&video->req_lock, flags); + /* For bulk end points we queue from the worker thread + * since we would preferably not want to wait on requests + * to be ready, in the uvcg_video_complete() handler. + * For isoc endpoints we add the request to the ready list + * and only queue it to the endpoint from the complete handler. + */ + ret = uvcg_video_usb_req_queue(video, req, is_bulk); + spin_unlock_irqrestore(&video->req_lock, flags); + if (ret < 0) { uvcg_queue_cancel(queue, 0); break; } - /* Endpoint now owns the request */ + /* The request is owned by the endpoint / ready list. */ req = NULL; - video->req_int_count++; } if (!req) return; spin_lock_irqsave(&video->req_lock, flags); - list_add_tail(&req->list, &video->req_free); + if (video->is_enabled) + list_add_tail(&req->list, &video->req_free); + else + uvc_video_free_request(req->context, video->ep); spin_unlock_irqrestore(&video->req_lock, flags); - return; } /* - * Enable or disable the video stream. + * Disable the video stream */ -int uvcg_video_enable(struct uvc_video *video, int enable) +int +uvcg_video_disable(struct uvc_video *video) +{ + unsigned long flags; + struct list_head inflight_bufs; + struct usb_request *req, *temp; + struct uvc_buffer *buf, *btemp; + struct uvc_request *ureq, *utemp; + + if (video->ep == NULL) { + uvcg_info(&video->uvc->func, + "Video disable failed, device is uninitialized.\n"); + return -ENODEV; + } + + INIT_LIST_HEAD(&inflight_bufs); + spin_lock_irqsave(&video->req_lock, flags); + video->is_enabled = false; + + /* + * Remove any in-flight buffers from the uvc_requests + * because we want to return them before cancelling the + * queue. This ensures that we aren't stuck waiting for + * all complete callbacks to come through before disabling + * vb2 queue. + */ + list_for_each_entry(ureq, &video->ureqs, list) { + if (ureq->last_buf) { + list_add_tail(&ureq->last_buf->queue, &inflight_bufs); + ureq->last_buf = NULL; + } + } + spin_unlock_irqrestore(&video->req_lock, flags); + + cancel_work_sync(&video->pump); + uvcg_queue_cancel(&video->queue, 0); + + spin_lock_irqsave(&video->req_lock, flags); + /* + * Remove all uvc_requests from ureqs with list_del_init + * This lets uvc_video_free_request correctly identify + * if the uvc_request is attached to a list or not when freeing + * memory. + */ + list_for_each_entry_safe(ureq, utemp, &video->ureqs, list) + list_del_init(&ureq->list); + + list_for_each_entry_safe(req, temp, &video->req_free, list) { + list_del(&req->list); + uvc_video_free_request(req->context, video->ep); + } + + list_for_each_entry_safe(req, temp, &video->req_ready, list) { + list_del(&req->list); + uvc_video_free_request(req->context, video->ep); + } + + INIT_LIST_HEAD(&video->ureqs); + INIT_LIST_HEAD(&video->req_free); + INIT_LIST_HEAD(&video->req_ready); + video->req_size = 0; + spin_unlock_irqrestore(&video->req_lock, flags); + + /* + * Return all the video buffers before disabling the queue. + */ + spin_lock_irqsave(&video->queue.irqlock, flags); + list_for_each_entry_safe(buf, btemp, &inflight_bufs, queue) { + list_del(&buf->queue); + uvcg_complete_buffer(&video->queue, buf); + } + spin_unlock_irqrestore(&video->queue.irqlock, flags); + + uvcg_queue_enable(&video->queue, 0); + return 0; +} + +/* + * Enable the video stream. + */ +int uvcg_video_enable(struct uvc_video *video) { - unsigned int i; int ret; if (video->ep == NULL) { @@ -497,18 +732,13 @@ int uvcg_video_enable(struct uvc_video *video, int enable) return -ENODEV; } - if (!enable) { - cancel_work_sync(&video->pump); - uvcg_queue_cancel(&video->queue, 0); - - for (i = 0; i < video->uvc_num_requests; ++i) - if (video->ureq && video->ureq[i].req) - usb_ep_dequeue(video->ep, video->ureq[i].req); - - uvc_video_free_requests(video); - uvcg_queue_enable(&video->queue, 0); - return 0; - } + /* + * Safe to access request related fields without req_lock because + * this is the only thread currently active, and no other + * request handling thread will become active until this function + * returns. + */ + video->is_enabled = true; if ((ret = uvcg_queue_enable(&video->queue, 1)) < 0) return ret; @@ -525,7 +755,7 @@ int uvcg_video_enable(struct uvc_video *video, int enable) video->req_int_count = 0; - queue_work(video->async_wq, &video->pump); + uvc_video_ep_queue_initial_requests(video); return ret; } @@ -535,7 +765,10 @@ int uvcg_video_enable(struct uvc_video *video, int enable) */ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) { + video->is_enabled = false; + INIT_LIST_HEAD(&video->ureqs); INIT_LIST_HEAD(&video->req_free); + INIT_LIST_HEAD(&video->req_ready); spin_lock_init(&video->req_lock); INIT_WORK(&video->pump, uvcg_video_pump); diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index 03adeefa343b..8ef6259741f1 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h @@ -14,7 +14,8 @@ struct uvc_video; -int uvcg_video_enable(struct uvc_video *video, int enable); +int uvcg_video_enable(struct uvc_video *video); +int uvcg_video_disable(struct uvc_video *video); int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc); diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c index c06dd1af7a0c..c395438d3978 100644 --- a/drivers/usb/gadget/legacy/webcam.c +++ b/drivers/usb/gadget/legacy/webcam.c @@ -12,6 +12,7 @@ #include #include "u_uvc.h" +#include "uvc_configfs.h" USB_GADGET_COMPOSITE_OPTIONS(); @@ -84,8 +85,6 @@ static struct usb_device_descriptor webcam_device_descriptor = { .bNumConfigurations = 0, /* dynamic */ }; -DECLARE_UVC_HEADER_DESCRIPTOR(1); - static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = { .bLength = UVC_DT_HEADER_SIZE(1), .bDescriptorType = USB_DT_CS_INTERFACE, @@ -158,72 +157,179 @@ static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = { .bmaControls[1][0] = 4, }; -static const struct uvc_format_uncompressed uvc_format_yuv = { - .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED, - .bFormatIndex = 1, - .bNumFrameDescriptors = 2, - .guidFormat = - { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}, - .bBitsPerPixel = 16, - .bDefaultFrameIndex = 1, - .bAspectRatioX = 0, - .bAspectRatioY = 0, - .bmInterlaceFlags = 0, - .bCopyProtect = 0, +static const struct uvcg_color_matching uvcg_color_matching = { + .desc = { + .bLength = UVC_DT_COLOR_MATCHING_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_COLORFORMAT, + .bColorPrimaries = 1, + .bTransferCharacteristics = 1, + .bMatrixCoefficients = 4, + }, +}; + +static struct uvcg_uncompressed uvcg_format_yuv = { + .fmt = { + .type = UVCG_UNCOMPRESSED, + /* add to .frames and fill .num_frames at runtime */ + .color_matching = (struct uvcg_color_matching *)&uvcg_color_matching, + }, + .desc = { + .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED, + .bFormatIndex = 1, + .bNumFrameDescriptors = 2, + .guidFormat = { + 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + }, + .bBitsPerPixel = 16, + .bDefaultFrameIndex = 1, + .bAspectRatioX = 0, + .bAspectRatioY = 0, + .bmInterlaceFlags = 0, + .bCopyProtect = 0, + }, +}; + +static struct uvcg_format_ptr uvcg_format_ptr_yuv = { + .fmt = &uvcg_format_yuv.fmt, }; DECLARE_UVC_FRAME_UNCOMPRESSED(1); DECLARE_UVC_FRAME_UNCOMPRESSED(3); +#define UVCG_WIDTH_360P 640 +#define UVCG_HEIGHT_360P 360 +#define UVCG_MIN_BITRATE_360P 18432000 +#define UVCG_MAX_BITRATE_360P 55296000 +#define UVCG_MAX_VIDEO_FB_SZ_360P 460800 +#define UVCG_FRM_INTERV_0_360P 666666 +#define UVCG_FRM_INTERV_1_360P 1000000 +#define UVCG_FRM_INTERV_2_360P 5000000 +#define UVCG_DEFAULT_FRM_INTERV_360P UVCG_FRM_INTERV_0_360P + static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = { .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, .bFrameIndex = 1, .bmCapabilities = 0, - .wWidth = cpu_to_le16(640), - .wHeight = cpu_to_le16(360), - .dwMinBitRate = cpu_to_le32(18432000), - .dwMaxBitRate = cpu_to_le32(55296000), - .dwMaxVideoFrameBufferSize = cpu_to_le32(460800), - .dwDefaultFrameInterval = cpu_to_le32(666666), + .wWidth = cpu_to_le16(UVCG_WIDTH_360P), + .wHeight = cpu_to_le16(UVCG_HEIGHT_360P), + .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P), + .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P), + .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P), + .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P), .bFrameIntervalType = 3, - .dwFrameInterval[0] = cpu_to_le32(666666), - .dwFrameInterval[1] = cpu_to_le32(1000000), - .dwFrameInterval[2] = cpu_to_le32(5000000), + .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P), + .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P), + .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P), }; +static u32 uvcg_frame_yuv_360p_dw_frame_interval[] = { + [0] = UVCG_FRM_INTERV_0_360P, + [1] = UVCG_FRM_INTERV_1_360P, + [2] = UVCG_FRM_INTERV_2_360P, +}; + +static const struct uvcg_frame uvcg_frame_yuv_360p = { + .fmt_type = UVCG_UNCOMPRESSED, + .frame = { + .b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3), + .b_descriptor_type = USB_DT_CS_INTERFACE, + .b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED, + .b_frame_index = 1, + .bm_capabilities = 0, + .w_width = UVCG_WIDTH_360P, + .w_height = UVCG_HEIGHT_360P, + .dw_min_bit_rate = UVCG_MIN_BITRATE_360P, + .dw_max_bit_rate = UVCG_MAX_BITRATE_360P, + .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P, + .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P, + .b_frame_interval_type = 3, + }, + .dw_frame_interval = uvcg_frame_yuv_360p_dw_frame_interval, +}; + +static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_360p = { + .frm = (struct uvcg_frame *)&uvcg_frame_yuv_360p, +}; +#define UVCG_WIDTH_720P 1280 +#define UVCG_HEIGHT_720P 720 +#define UVCG_MIN_BITRATE_720P 29491200 +#define UVCG_MAX_BITRATE_720P 29491200 +#define UVCG_MAX_VIDEO_FB_SZ_720P 1843200 +#define UVCG_FRM_INTERV_0_720P 5000000 +#define UVCG_DEFAULT_FRM_INTERV_720P UVCG_FRM_INTERV_0_720P + static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = { .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, .bFrameIndex = 2, .bmCapabilities = 0, - .wWidth = cpu_to_le16(1280), - .wHeight = cpu_to_le16(720), - .dwMinBitRate = cpu_to_le32(29491200), - .dwMaxBitRate = cpu_to_le32(29491200), - .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), - .dwDefaultFrameInterval = cpu_to_le32(5000000), + .wWidth = cpu_to_le16(UVCG_WIDTH_720P), + .wHeight = cpu_to_le16(UVCG_HEIGHT_720P), + .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P), + .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P), + .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P), + .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P), .bFrameIntervalType = 1, - .dwFrameInterval[0] = cpu_to_le32(5000000), + .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P), }; -static const struct uvc_format_mjpeg uvc_format_mjpg = { - .bLength = UVC_DT_FORMAT_MJPEG_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FORMAT_MJPEG, - .bFormatIndex = 2, - .bNumFrameDescriptors = 2, - .bmFlags = 0, - .bDefaultFrameIndex = 1, - .bAspectRatioX = 0, - .bAspectRatioY = 0, - .bmInterlaceFlags = 0, - .bCopyProtect = 0, +static u32 uvcg_frame_yuv_720p_dw_frame_interval[] = { + [0] = UVCG_FRM_INTERV_0_720P, +}; + +static const struct uvcg_frame uvcg_frame_yuv_720p = { + .fmt_type = UVCG_UNCOMPRESSED, + .frame = { + .b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1), + .b_descriptor_type = USB_DT_CS_INTERFACE, + .b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED, + .b_frame_index = 2, + .bm_capabilities = 0, + .w_width = UVCG_WIDTH_720P, + .w_height = UVCG_HEIGHT_720P, + .dw_min_bit_rate = UVCG_MIN_BITRATE_720P, + .dw_max_bit_rate = UVCG_MAX_BITRATE_720P, + .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P, + .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P, + .b_frame_interval_type = 1, + }, + .dw_frame_interval = uvcg_frame_yuv_720p_dw_frame_interval, +}; + +static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_720p = { + .frm = (struct uvcg_frame *)&uvcg_frame_yuv_720p, +}; + +static struct uvcg_mjpeg uvcg_format_mjpeg = { + .fmt = { + .type = UVCG_MJPEG, + /* add to .frames and fill .num_frames at runtime */ + .color_matching = (struct uvcg_color_matching *)&uvcg_color_matching, + }, + .desc = { + .bLength = UVC_DT_FORMAT_MJPEG_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VS_FORMAT_MJPEG, + .bFormatIndex = 2, + .bNumFrameDescriptors = 2, + .bmFlags = 0, + .bDefaultFrameIndex = 1, + .bAspectRatioX = 0, + .bAspectRatioY = 0, + .bmInterlaceFlags = 0, + .bCopyProtect = 0, + }, +}; + +static struct uvcg_format_ptr uvcg_format_ptr_mjpeg = { + .fmt = &uvcg_format_mjpeg.fmt, }; DECLARE_UVC_FRAME_MJPEG(1); @@ -235,16 +341,45 @@ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = { .bDescriptorSubType = UVC_VS_FRAME_MJPEG, .bFrameIndex = 1, .bmCapabilities = 0, - .wWidth = cpu_to_le16(640), - .wHeight = cpu_to_le16(360), - .dwMinBitRate = cpu_to_le32(18432000), - .dwMaxBitRate = cpu_to_le32(55296000), - .dwMaxVideoFrameBufferSize = cpu_to_le32(460800), - .dwDefaultFrameInterval = cpu_to_le32(666666), + .wWidth = cpu_to_le16(UVCG_WIDTH_360P), + .wHeight = cpu_to_le16(UVCG_HEIGHT_360P), + .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P), + .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P), + .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P), + .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P), .bFrameIntervalType = 3, - .dwFrameInterval[0] = cpu_to_le32(666666), - .dwFrameInterval[1] = cpu_to_le32(1000000), - .dwFrameInterval[2] = cpu_to_le32(5000000), + .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P), + .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P), + .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P), +}; + +static u32 uvcg_frame_mjpeg_360p_dw_frame_interval[] = { + [0] = UVCG_FRM_INTERV_0_360P, + [1] = UVCG_FRM_INTERV_1_360P, + [2] = UVCG_FRM_INTERV_2_360P, +}; + +static const struct uvcg_frame uvcg_frame_mjpeg_360p = { + .fmt_type = UVCG_MJPEG, + .frame = { + .b_length = UVC_DT_FRAME_MJPEG_SIZE(3), + .b_descriptor_type = USB_DT_CS_INTERFACE, + .b_descriptor_subtype = UVC_VS_FRAME_MJPEG, + .b_frame_index = 1, + .bm_capabilities = 0, + .w_width = UVCG_WIDTH_360P, + .w_height = UVCG_HEIGHT_360P, + .dw_min_bit_rate = UVCG_MIN_BITRATE_360P, + .dw_max_bit_rate = UVCG_MAX_BITRATE_360P, + .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P, + .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P, + .b_frame_interval_type = 3, + }, + .dw_frame_interval = uvcg_frame_mjpeg_360p_dw_frame_interval, +}; + +static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_360p = { + .frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_360p, }; static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { @@ -253,23 +388,44 @@ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { .bDescriptorSubType = UVC_VS_FRAME_MJPEG, .bFrameIndex = 2, .bmCapabilities = 0, - .wWidth = cpu_to_le16(1280), - .wHeight = cpu_to_le16(720), - .dwMinBitRate = cpu_to_le32(29491200), - .dwMaxBitRate = cpu_to_le32(29491200), - .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), - .dwDefaultFrameInterval = cpu_to_le32(5000000), + .wWidth = cpu_to_le16(UVCG_WIDTH_720P), + .wHeight = cpu_to_le16(UVCG_HEIGHT_720P), + .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P), + .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P), + .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P), + .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P), .bFrameIntervalType = 1, - .dwFrameInterval[0] = cpu_to_le32(5000000), + .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P), }; -static const struct uvc_color_matching_descriptor uvc_color_matching = { - .bLength = UVC_DT_COLOR_MATCHING_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_COLORFORMAT, - .bColorPrimaries = 1, - .bTransferCharacteristics = 1, - .bMatrixCoefficients = 4, +static u32 uvcg_frame_mjpeg_720p_dw_frame_interval[] = { + [0] = UVCG_FRM_INTERV_0_720P, +}; + +static const struct uvcg_frame uvcg_frame_mjpeg_720p = { + .fmt_type = UVCG_MJPEG, + .frame = { + .b_length = UVC_DT_FRAME_MJPEG_SIZE(1), + .b_descriptor_type = USB_DT_CS_INTERFACE, + .b_descriptor_subtype = UVC_VS_FRAME_MJPEG, + .b_frame_index = 2, + .bm_capabilities = 0, + .w_width = UVCG_WIDTH_720P, + .w_height = UVCG_HEIGHT_720P, + .dw_min_bit_rate = UVCG_MIN_BITRATE_720P, + .dw_max_bit_rate = UVCG_MAX_BITRATE_720P, + .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P, + .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P, + .b_frame_interval_type = 1, + }, + .dw_frame_interval = uvcg_frame_mjpeg_720p_dw_frame_interval, +}; + +static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_720p = { + .frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_720p, +}; + +static struct uvcg_streaming_header uvcg_streaming_header = { }; static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = { @@ -290,40 +446,40 @@ static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = { static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_input_header, - (const struct uvc_descriptor_header *) &uvc_format_yuv, + (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, - (const struct uvc_descriptor_header *) &uvc_format_mjpg, + (const struct uvc_descriptor_header *) &uvcg_color_matching.desc, + (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, + (const struct uvc_descriptor_header *) &uvcg_color_matching.desc, NULL, }; static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_input_header, - (const struct uvc_descriptor_header *) &uvc_format_yuv, + (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, - (const struct uvc_descriptor_header *) &uvc_format_mjpg, + (const struct uvc_descriptor_header *) &uvcg_color_matching.desc, + (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, + (const struct uvc_descriptor_header *) &uvcg_color_matching.desc, NULL, }; static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_input_header, - (const struct uvc_descriptor_header *) &uvc_format_yuv, + (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, - (const struct uvc_descriptor_header *) &uvc_format_mjpg, + (const struct uvc_descriptor_header *) &uvcg_color_matching.desc, + (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, + (const struct uvc_descriptor_header *) &uvcg_color_matching.desc, NULL, }; @@ -387,6 +543,23 @@ webcam_bind(struct usb_composite_dev *cdev) uvc_opts->hs_streaming = uvc_hs_streaming_cls; uvc_opts->ss_streaming = uvc_ss_streaming_cls; + INIT_LIST_HEAD(&uvcg_format_yuv.fmt.frames); + list_add_tail(&uvcg_frame_ptr_yuv_360p.entry, &uvcg_format_yuv.fmt.frames); + list_add_tail(&uvcg_frame_ptr_yuv_720p.entry, &uvcg_format_yuv.fmt.frames); + uvcg_format_yuv.fmt.num_frames = 2; + + INIT_LIST_HEAD(&uvcg_format_mjpeg.fmt.frames); + list_add_tail(&uvcg_frame_ptr_mjpeg_360p.entry, &uvcg_format_mjpeg.fmt.frames); + list_add_tail(&uvcg_frame_ptr_mjpeg_720p.entry, &uvcg_format_mjpeg.fmt.frames); + uvcg_format_mjpeg.fmt.num_frames = 2; + + INIT_LIST_HEAD(&uvcg_streaming_header.formats); + list_add_tail(&uvcg_format_ptr_yuv.entry, &uvcg_streaming_header.formats); + list_add_tail(&uvcg_format_ptr_mjpeg.entry, &uvcg_streaming_header.formats); + uvcg_streaming_header.num_fmt = 2; + + uvc_opts->header = &uvcg_streaming_header; + /* Allocate string descriptor numbers ... note that string contents * can be overridden by the composite_dev glue. */ diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 30ea4a9d5301..e3bf17a98b38 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1924,7 +1924,7 @@ err_unprepare_fclk: return retval; } -static int at91udc_remove(struct platform_device *pdev) +static void at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); unsigned long flags; @@ -1932,8 +1932,11 @@ static int at91udc_remove(struct platform_device *pdev) DBG("remove\n"); usb_del_gadget_udc(&udc->gadget); - if (udc->driver) - return -EBUSY; + if (udc->driver) { + dev_err(&pdev->dev, + "Driver still in use but removing anyhow\n"); + return; + } spin_lock_irqsave(&udc->lock, flags); pullup(udc, 0); @@ -1943,8 +1946,6 @@ static int at91udc_remove(struct platform_device *pdev) remove_debug_file(udc); clk_unprepare(udc->fclk); clk_unprepare(udc->iclk); - - return 0; } #ifdef CONFIG_PM @@ -2001,7 +2002,7 @@ static int at91udc_resume(struct platform_device *pdev) static struct platform_driver at91_udc_driver = { .probe = at91udc_probe, - .remove = at91udc_remove, + .remove_new = at91udc_remove, .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, .resume = at91udc_resume, diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 02b1bef5e22e..b76885d78e8a 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -94,7 +94,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf, inode_lock(file_inode(file)); list_for_each_entry_safe(req, tmp_req, queue, queue) { - len = snprintf(tmpbuf, sizeof(tmpbuf), + len = scnprintf(tmpbuf, sizeof(tmpbuf), "%8p %08x %c%c%c %5d %c%c%c\n", req->req.buf, req->req.length, req->req.no_interrupt ? 'i' : 'I', @@ -104,7 +104,6 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf, req->submitted ? 'F' : 'f', req->using_dma ? 'D' : 'd', req->last_transaction ? 'L' : 'l'); - len = min(len, sizeof(tmpbuf)); if (len > nbytes) break; diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-debug.h b/drivers/usb/gadget/udc/cdns2/cdns2-debug.h index be9ae0d28a40..f5f330004190 100644 --- a/drivers/usb/gadget/udc/cdns2/cdns2-debug.h +++ b/drivers/usb/gadget/udc/cdns2/cdns2-debug.h @@ -16,34 +16,34 @@ static inline const char *cdns2_decode_usb_irq(char *str, size_t size, { int ret; - ret = snprintf(str, size, "usbirq: 0x%02x - ", usb_irq); + ret = scnprintf(str, size, "usbirq: 0x%02x - ", usb_irq); if (usb_irq & USBIRQ_SOF) - ret += snprintf(str + ret, size - ret, "SOF "); + ret += scnprintf(str + ret, size - ret, "SOF "); if (usb_irq & USBIRQ_SUTOK) - ret += snprintf(str + ret, size - ret, "SUTOK "); + ret += scnprintf(str + ret, size - ret, "SUTOK "); if (usb_irq & USBIRQ_SUDAV) - ret += snprintf(str + ret, size - ret, "SETUP "); + ret += scnprintf(str + ret, size - ret, "SETUP "); if (usb_irq & USBIRQ_SUSPEND) - ret += snprintf(str + ret, size - ret, "Suspend "); + ret += scnprintf(str + ret, size - ret, "Suspend "); if (usb_irq & USBIRQ_URESET) - ret += snprintf(str + ret, size - ret, "Reset "); + ret += scnprintf(str + ret, size - ret, "Reset "); if (usb_irq & USBIRQ_HSPEED) - ret += snprintf(str + ret, size - ret, "HS "); + ret += scnprintf(str + ret, size - ret, "HS "); if (usb_irq & USBIRQ_LPM) - ret += snprintf(str + ret, size - ret, "LPM "); + ret += scnprintf(str + ret, size - ret, "LPM "); - ret += snprintf(str + ret, size - ret, ", EXT: 0x%02x - ", ext_irq); + ret += scnprintf(str + ret, size - ret, ", EXT: 0x%02x - ", ext_irq); if (ext_irq & EXTIRQ_WAKEUP) - ret += snprintf(str + ret, size - ret, "Wakeup "); + ret += scnprintf(str + ret, size - ret, "Wakeup "); if (ext_irq & EXTIRQ_VBUSFAULT_FALL) - ret += snprintf(str + ret, size - ret, "VBUS_FALL "); + ret += scnprintf(str + ret, size - ret, "VBUS_FALL "); if (ext_irq & EXTIRQ_VBUSFAULT_RISE) - ret += snprintf(str + ret, size - ret, "VBUS_RISE "); + ret += scnprintf(str + ret, size - ret, "VBUS_RISE "); - if (ret >= size) - pr_info("CDNS2: buffer overflowed.\n"); + if (ret == size - 1) + pr_info("CDNS2: buffer may be truncated.\n"); return str; } @@ -54,28 +54,28 @@ static inline const char *cdns2_decode_dma_irq(char *str, size_t size, { int ret; - ret = snprintf(str, size, "ISTS: %08x, %s: %08x ", - ep_ists, ep_name, ep_sts); + ret = scnprintf(str, size, "ISTS: %08x, %s: %08x ", + ep_ists, ep_name, ep_sts); if (ep_sts & DMA_EP_STS_IOC) - ret += snprintf(str + ret, size - ret, "IOC "); + ret += scnprintf(str + ret, size - ret, "IOC "); if (ep_sts & DMA_EP_STS_ISP) - ret += snprintf(str + ret, size - ret, "ISP "); + ret += scnprintf(str + ret, size - ret, "ISP "); if (ep_sts & DMA_EP_STS_DESCMIS) - ret += snprintf(str + ret, size - ret, "DESCMIS "); + ret += scnprintf(str + ret, size - ret, "DESCMIS "); if (ep_sts & DMA_EP_STS_TRBERR) - ret += snprintf(str + ret, size - ret, "TRBERR "); + ret += scnprintf(str + ret, size - ret, "TRBERR "); if (ep_sts & DMA_EP_STS_OUTSMM) - ret += snprintf(str + ret, size - ret, "OUTSMM "); + ret += scnprintf(str + ret, size - ret, "OUTSMM "); if (ep_sts & DMA_EP_STS_ISOERR) - ret += snprintf(str + ret, size - ret, "ISOERR "); + ret += scnprintf(str + ret, size - ret, "ISOERR "); if (ep_sts & DMA_EP_STS_DBUSY) - ret += snprintf(str + ret, size - ret, "DBUSY "); + ret += scnprintf(str + ret, size - ret, "DBUSY "); if (DMA_EP_STS_CCS(ep_sts)) - ret += snprintf(str + ret, size - ret, "CCS "); + ret += scnprintf(str + ret, size - ret, "CCS "); - if (ret >= size) - pr_info("CDNS2: buffer overflowed.\n"); + if (ret == size - 1) + pr_info("CDNS2: buffer may be truncated.\n"); return str; } @@ -105,43 +105,43 @@ static inline const char *cdns2_raw_ring(struct cdns2_endpoint *pep, int ret; int i; - ret = snprintf(str, size, "\n\t\tTR for %s:", pep->name); + ret = scnprintf(str, size, "\n\t\tTR for %s:", pep->name); trb = &trbs[ring->dequeue]; dma = cdns2_trb_virt_to_dma(pep, trb); - ret += snprintf(str + ret, size - ret, - "\n\t\tRing deq index: %d, trb: V=%p, P=0x%pad\n", - ring->dequeue, trb, &dma); + ret += scnprintf(str + ret, size - ret, + "\n\t\tRing deq index: %d, trb: V=%p, P=0x%pad\n", + ring->dequeue, trb, &dma); trb = &trbs[ring->enqueue]; dma = cdns2_trb_virt_to_dma(pep, trb); - ret += snprintf(str + ret, size - ret, - "\t\tRing enq index: %d, trb: V=%p, P=0x%pad\n", - ring->enqueue, trb, &dma); + ret += scnprintf(str + ret, size - ret, + "\t\tRing enq index: %d, trb: V=%p, P=0x%pad\n", + ring->enqueue, trb, &dma); - ret += snprintf(str + ret, size - ret, - "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", - ring->free_trbs, ring->ccs, ring->pcs); + ret += scnprintf(str + ret, size - ret, + "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", + ring->free_trbs, ring->ccs, ring->pcs); if (TRBS_PER_SEGMENT > 40) { - ret += snprintf(str + ret, size - ret, - "\t\tTransfer ring %d too big\n", TRBS_PER_SEGMENT); + ret += scnprintf(str + ret, size - ret, + "\t\tTransfer ring %d too big\n", TRBS_PER_SEGMENT); return str; } dma = ring->dma; for (i = 0; i < TRBS_PER_SEGMENT; ++i) { trb = &trbs[i]; - ret += snprintf(str + ret, size - ret, - "\t\t@%pad %08x %08x %08x\n", &dma, - le32_to_cpu(trb->buffer), - le32_to_cpu(trb->length), - le32_to_cpu(trb->control)); + ret += scnprintf(str + ret, size - ret, + "\t\t@%pad %08x %08x %08x\n", &dma, + le32_to_cpu(trb->buffer), + le32_to_cpu(trb->length), + le32_to_cpu(trb->control)); dma += sizeof(*trb); } - if (ret >= size) - pr_info("CDNS2: buffer overflowed.\n"); + if (ret == size - 1) + pr_info("CDNS2: buffer may be truncated.\n"); return str; } @@ -166,36 +166,36 @@ static inline const char *cdns2_decode_trb(char *str, size_t size, u32 flags, switch (type) { case TRB_LINK: - ret = snprintf(str, size, - "LINK %08x type '%s' flags %c:%c:%c%c:%c", - buffer, cdns2_trb_type_string(type), - flags & TRB_CYCLE ? 'C' : 'c', - flags & TRB_TOGGLE ? 'T' : 't', - flags & TRB_CHAIN ? 'C' : 'c', - flags & TRB_CHAIN ? 'H' : 'h', - flags & TRB_IOC ? 'I' : 'i'); + ret = scnprintf(str, size, + "LINK %08x type '%s' flags %c:%c:%c%c:%c", + buffer, cdns2_trb_type_string(type), + flags & TRB_CYCLE ? 'C' : 'c', + flags & TRB_TOGGLE ? 'T' : 't', + flags & TRB_CHAIN ? 'C' : 'c', + flags & TRB_CHAIN ? 'H' : 'h', + flags & TRB_IOC ? 'I' : 'i'); break; case TRB_NORMAL: - ret = snprintf(str, size, - "type: '%s', Buffer: %08x, length: %ld, burst len: %ld, " - "flags %c:%c:%c%c:%c", - cdns2_trb_type_string(type), - buffer, TRB_LEN(length), - TRB_FIELD_TO_BURST(length), - flags & TRB_CYCLE ? 'C' : 'c', - flags & TRB_ISP ? 'I' : 'i', - flags & TRB_CHAIN ? 'C' : 'c', - flags & TRB_CHAIN ? 'H' : 'h', - flags & TRB_IOC ? 'I' : 'i'); + ret = scnprintf(str, size, + "type: '%s', Buffer: %08x, length: %ld, burst len: %ld, " + "flags %c:%c:%c%c:%c", + cdns2_trb_type_string(type), + buffer, TRB_LEN(length), + TRB_FIELD_TO_BURST(length), + flags & TRB_CYCLE ? 'C' : 'c', + flags & TRB_ISP ? 'I' : 'i', + flags & TRB_CHAIN ? 'C' : 'c', + flags & TRB_CHAIN ? 'H' : 'h', + flags & TRB_IOC ? 'I' : 'i'); break; default: - ret = snprintf(str, size, "type '%s' -> raw %08x %08x %08x", - cdns2_trb_type_string(type), - buffer, length, flags); + ret = scnprintf(str, size, "type '%s' -> raw %08x %08x %08x", + cdns2_trb_type_string(type), + buffer, length, flags); } - if (ret >= size) - pr_info("CDNS2: buffer overflowed.\n"); + if (ret == size - 1) + pr_info("CDNS2: buffer may be truncated.\n"); return str; } diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 2693a10eb0c7..e8042c158f6d 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1360,7 +1360,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, udc->ep0_dir = USB_DIR_IN; /* Borrow the per device status_req */ req = udc->status_req; - /* Fill in the reqest structure */ + /* Fill in the request structure */ *((u16 *) req->req.buf) = cpu_to_le16(tmp); req->ep = ep; @@ -2532,15 +2532,18 @@ err_kfree: /* Driver removal function * Free resources and finish pending transactions */ -static int fsl_udc_remove(struct platform_device *pdev) +static void fsl_udc_remove(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); DECLARE_COMPLETION_ONSTACK(done); - if (!udc_controller) - return -ENODEV; + if (!udc_controller) { + dev_err(&pdev->dev, + "Driver still in use but removing anyhow\n"); + return; + } udc_controller->done = &done; usb_del_gadget_udc(&udc_controller->gadget); @@ -2568,8 +2571,6 @@ static int fsl_udc_remove(struct platform_device *pdev) */ if (pdata->exit) pdata->exit(pdev); - - return 0; } /*----------------------------------------------------------------- @@ -2667,7 +2668,7 @@ static const struct platform_device_id fsl_udc_devtype[] = { MODULE_DEVICE_TABLE(platform, fsl_udc_devtype); static struct platform_driver udc_driver = { .probe = fsl_udc_probe, - .remove = fsl_udc_remove, + .remove_new = fsl_udc_remove, .id_table = fsl_udc_devtype, /* these suspend and resume are not usb suspend and resume */ .suspend = fsl_udc_suspend, diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index c6dfa7cccc11..fb901be5dac1 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -2089,15 +2089,18 @@ static void gr_ep_remove(struct gr_udc *dev, int num, int is_in) ep->tailbuf, ep->tailbuf_paddr); } -static int gr_remove(struct platform_device *pdev) +static void gr_remove(struct platform_device *pdev) { struct gr_udc *dev = platform_get_drvdata(pdev); int i; if (dev->added) usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */ - if (dev->driver) - return -EBUSY; + if (dev->driver) { + dev_err(&pdev->dev, + "Driver still in use but removing anyhow\n"); + return; + } gr_dfs_delete(dev); dma_pool_destroy(dev->desc_pool); @@ -2110,8 +2113,6 @@ static int gr_remove(struct platform_device *pdev) gr_ep_remove(dev, i, 0); for (i = 0; i < dev->nepi; i++) gr_ep_remove(dev, i, 1); - - return 0; } static int gr_request_irq(struct gr_udc *dev, int irq) { @@ -2248,7 +2249,7 @@ static struct platform_driver gr_driver = { .of_match_table = gr_match, }, .probe = gr_probe, - .remove = gr_remove, + .remove_new = gr_remove, }; module_platform_driver(gr_driver); diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index a917cc9a32ab..d5f29f8fe481 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3174,13 +3174,16 @@ i2c_fail: return retval; } -static int lpc32xx_udc_remove(struct platform_device *pdev) +static void lpc32xx_udc_remove(struct platform_device *pdev) { struct lpc32xx_udc *udc = platform_get_drvdata(pdev); usb_del_gadget_udc(&udc->gadget); - if (udc->driver) - return -EBUSY; + if (udc->driver) { + dev_err(&pdev->dev, + "Driver still in use but removing anyhow\n"); + return; + } udc_clk_set(udc, 1); udc_disable(udc); @@ -3194,8 +3197,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev) udc->udca_v_base, udc->udca_p_base); clk_disable_unprepare(udc->usb_slv_clk); - - return 0; } #ifdef CONFIG_PM @@ -3255,7 +3256,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match); static struct platform_driver lpc32xx_udc_driver = { .probe = lpc32xx_udc_probe, - .remove = lpc32xx_udc_remove, + .remove_new = lpc32xx_udc_remove, .shutdown = lpc32xx_udc_shutdown, .suspend = lpc32xx_udc_suspend, .resume = lpc32xx_udc_resume, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index d888dcda2bc8..78308b64955d 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -1451,7 +1451,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) req = udc->status_req; - /* fill in the reqest structure */ + /* fill in the request structure */ if (empty == false) { *((u16 *) req->req.buf) = cpu_to_le16(status); req->req.length = 2; diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index df0551ecc810..1ac26cb49ecf 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -2397,12 +2397,15 @@ static void pxa25x_udc_shutdown(struct platform_device *_dev) pullup_off(); } -static int pxa25x_udc_remove(struct platform_device *pdev) +static void pxa25x_udc_remove(struct platform_device *pdev) { struct pxa25x_udc *dev = platform_get_drvdata(pdev); - if (dev->driver) - return -EBUSY; + if (dev->driver) { + dev_err(&pdev->dev, + "Driver still in use but removing anyhow\n"); + return; + } usb_del_gadget_udc(&dev->gadget); dev->pullup = 0; @@ -2414,7 +2417,6 @@ static int pxa25x_udc_remove(struct platform_device *pdev) dev->transceiver = NULL; the_controller = NULL; - return 0; } /*-------------------------------------------------------------------------*/ @@ -2472,7 +2474,7 @@ static int pxa25x_udc_resume(struct platform_device *dev) static struct platform_driver udc_driver = { .shutdown = pxa25x_udc_shutdown, .probe = pxa25x_udc_probe, - .remove = pxa25x_udc_remove, + .remove_new = pxa25x_udc_remove, .suspend = pxa25x_udc_suspend, .resume = pxa25x_udc_resume, .driver = { diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index d152d72de126..9fe4f48b1898 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1158,12 +1158,12 @@ dump_eps(struct usb_hcd *hcd) end = dp + sizeof(ubuf); *dp = '\0'; list_for_each_entry(urb, &ep->urb_list, urb_list) { - ret = snprintf(dp, end - dp, " %p(%d.%s %d/%d)", urb, - usb_pipetype(urb->pipe), - usb_urb_dir_in(urb) ? "IN" : "OUT", - urb->actual_length, - urb->transfer_buffer_length); - if (ret < 0 || ret >= end - dp) + ret = scnprintf(dp, end - dp, " %p(%d.%s %d/%d)", urb, + usb_pipetype(urb->pipe), + usb_urb_dir_in(urb) ? "IN" : "OUT", + urb->actual_length, + urb->transfer_buffer_length); + if (ret == end - dp - 1) break; /* error or buffer full */ dp += ret; } @@ -1255,9 +1255,9 @@ max3421_handle_irqs(struct usb_hcd *hcd) end = sbuf + sizeof(sbuf); *dp = '\0'; for (i = 0; i < 16; ++i) { - int ret = snprintf(dp, end - dp, " %lu", - max3421_hcd->err_stat[i]); - if (ret < 0 || ret >= end - dp) + int ret = scnprintf(dp, end - dp, " %lu", + max3421_hcd->err_stat[i]); + if (ret == end - dp - 1) break; /* error or buffer full */ dp += ret; } diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index b40d9238d447..d82935d31126 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -6,9 +6,24 @@ * * Author: Lu Baolu */ +#include +#include #include -#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include #include "xhci.h" #include "xhci-trace.h" @@ -28,7 +43,7 @@ static void dbc_ring_free(struct device *dev, struct xhci_ring *ring) if (!ring) return; - if (ring->first_seg && ring->first_seg->trbs) { + if (ring->first_seg) { dma_free_coherent(dev, TRB_SEGMENT_SIZE, ring->first_seg->trbs, ring->first_seg->dma); @@ -374,13 +389,13 @@ static void xhci_dbc_eps_init(struct xhci_dbc *dbc) static void xhci_dbc_eps_exit(struct xhci_dbc *dbc) { - memset(dbc->eps, 0, sizeof(struct dbc_ep) * ARRAY_SIZE(dbc->eps)); + memset(dbc->eps, 0, sizeof_field(struct xhci_dbc, eps)); } static int dbc_erst_alloc(struct device *dev, struct xhci_ring *evt_ring, struct xhci_erst *erst, gfp_t flags) { - erst->entries = dma_alloc_coherent(dev, sizeof(struct xhci_erst_entry), + erst->entries = dma_alloc_coherent(dev, sizeof(*erst->entries), &erst->erst_dma_addr, flags); if (!erst->entries) return -ENOMEM; @@ -394,9 +409,8 @@ static int dbc_erst_alloc(struct device *dev, struct xhci_ring *evt_ring, static void dbc_erst_free(struct device *dev, struct xhci_erst *erst) { - if (erst->entries) - dma_free_coherent(dev, sizeof(struct xhci_erst_entry), - erst->entries, erst->erst_dma_addr); + dma_free_coherent(dev, sizeof(*erst->entries), erst->entries, + erst->erst_dma_addr); erst->entries = NULL; } @@ -495,7 +509,7 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags) goto ctx_fail; /* Allocate the string table: */ - dbc->string_size = sizeof(struct dbc_str_descs); + dbc->string_size = sizeof(*dbc->string); dbc->string = dma_alloc_coherent(dev, dbc->string_size, &dbc->string_dma, flags); if (!dbc->string) @@ -543,11 +557,8 @@ static void xhci_dbc_mem_cleanup(struct xhci_dbc *dbc) xhci_dbc_eps_exit(dbc); - if (dbc->string) { - dma_free_coherent(dbc->dev, dbc->string_size, - dbc->string, dbc->string_dma); - dbc->string = NULL; - } + dma_free_coherent(dbc->dev, dbc->string_size, dbc->string, dbc->string_dma); + dbc->string = NULL; dbc_free_ctx(dbc->dev, dbc->ctx); dbc->ctx = NULL; @@ -597,7 +608,7 @@ static int xhci_do_dbc_start(struct xhci_dbc *dbc) static int xhci_do_dbc_stop(struct xhci_dbc *dbc) { if (dbc->state == DS_DISABLED) - return -1; + return -EINVAL; writel(0, &dbc->regs->control); dbc->state = DS_DISABLED; @@ -650,11 +661,11 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc) spin_lock_irqsave(&dbc->lock, flags); ret = xhci_do_dbc_stop(dbc); spin_unlock_irqrestore(&dbc->lock, flags); + if (ret) + return; - if (!ret) { - xhci_dbc_mem_cleanup(dbc); - pm_runtime_put_sync(dbc->dev); /* note, was self.controller */ - } + xhci_dbc_mem_cleanup(dbc); + pm_runtime_put_sync(dbc->dev); /* note, was self.controller */ } static void @@ -914,41 +925,29 @@ static void xhci_dbc_handle_events(struct work_struct *work) mod_delayed_work(system_wq, &dbc->event_work, 1); } +static const char * const dbc_state_strings[DS_MAX] = { + [DS_DISABLED] = "disabled", + [DS_INITIALIZED] = "initialized", + [DS_ENABLED] = "enabled", + [DS_CONNECTED] = "connected", + [DS_CONFIGURED] = "configured", + [DS_STALLED] = "stalled", +}; + static ssize_t dbc_show(struct device *dev, struct device_attribute *attr, char *buf) { - const char *p; struct xhci_dbc *dbc; struct xhci_hcd *xhci; xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; - switch (dbc->state) { - case DS_DISABLED: - p = "disabled"; - break; - case DS_INITIALIZED: - p = "initialized"; - break; - case DS_ENABLED: - p = "enabled"; - break; - case DS_CONNECTED: - p = "connected"; - break; - case DS_CONFIGURED: - p = "configured"; - break; - case DS_STALLED: - p = "stalled"; - break; - default: - p = "unknown"; - } + if (dbc->state >= ARRAY_SIZE(dbc_state_strings)) + return sysfs_emit(buf, "unknown\n"); - return sprintf(buf, "%s\n", p); + return sysfs_emit(buf, "%s\n", dbc_state_strings[dbc->state]); } static ssize_t dbc_store(struct device *dev, @@ -961,9 +960,9 @@ static ssize_t dbc_store(struct device *dev, xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; - if (!strncmp(buf, "enable", 6)) + if (sysfs_streq(buf, "enable")) xhci_dbc_start(dbc); - else if (!strncmp(buf, "disable", 7)) + else if (sysfs_streq(buf, "disable")) xhci_dbc_stop(dbc); else return -EINVAL; @@ -981,7 +980,7 @@ static ssize_t dbc_idVendor_show(struct device *dev, xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; - return sprintf(buf, "%04x\n", dbc->idVendor); + return sysfs_emit(buf, "%04x\n", dbc->idVendor); } static ssize_t dbc_idVendor_store(struct device *dev, @@ -993,9 +992,11 @@ static ssize_t dbc_idVendor_store(struct device *dev, void __iomem *ptr; u16 value; u32 dev_info; + int ret; - if (kstrtou16(buf, 0, &value)) - return -EINVAL; + ret = kstrtou16(buf, 0, &value); + if (ret) + return ret; xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; @@ -1021,7 +1022,7 @@ static ssize_t dbc_idProduct_show(struct device *dev, xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; - return sprintf(buf, "%04x\n", dbc->idProduct); + return sysfs_emit(buf, "%04x\n", dbc->idProduct); } static ssize_t dbc_idProduct_store(struct device *dev, @@ -1033,9 +1034,11 @@ static ssize_t dbc_idProduct_store(struct device *dev, void __iomem *ptr; u32 dev_info; u16 value; + int ret; - if (kstrtou16(buf, 0, &value)) - return -EINVAL; + ret = kstrtou16(buf, 0, &value); + if (ret) + return ret; xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; @@ -1060,7 +1063,7 @@ static ssize_t dbc_bcdDevice_show(struct device *dev, xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; - return sprintf(buf, "%04x\n", dbc->bcdDevice); + return sysfs_emit(buf, "%04x\n", dbc->bcdDevice); } static ssize_t dbc_bcdDevice_store(struct device *dev, @@ -1072,9 +1075,11 @@ static ssize_t dbc_bcdDevice_store(struct device *dev, void __iomem *ptr; u32 dev_info; u16 value; + int ret; - if (kstrtou16(buf, 0, &value)) - return -EINVAL; + ret = kstrtou16(buf, 0, &value); + if (ret) + return ret; xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; @@ -1100,7 +1105,7 @@ static ssize_t dbc_bInterfaceProtocol_show(struct device *dev, xhci = hcd_to_xhci(dev_get_drvdata(dev)); dbc = xhci->dbc; - return sprintf(buf, "%02x\n", dbc->bInterfaceProtocol); + return sysfs_emit(buf, "%02x\n", dbc->bInterfaceProtocol); } static ssize_t dbc_bInterfaceProtocol_store(struct device *dev, @@ -1114,9 +1119,13 @@ static ssize_t dbc_bInterfaceProtocol_store(struct device *dev, u8 value; int ret; - /* bInterfaceProtocol is 8 bit, but xhci only supports values 0 and 1 */ + /* bInterfaceProtocol is 8 bit, but... */ ret = kstrtou8(buf, 0, &value); - if (ret || value > 1) + if (ret) + return ret; + + /* ...xhci only supports values 0 and 1 */ + if (value > 1) return -EINVAL; xhci = hcd_to_xhci(dev_get_drvdata(dev)); @@ -1139,7 +1148,7 @@ static DEVICE_ATTR_RW(dbc_idProduct); static DEVICE_ATTR_RW(dbc_bcdDevice); static DEVICE_ATTR_RW(dbc_bInterfaceProtocol); -static struct attribute *dbc_dev_attributes[] = { +static struct attribute *dbc_dev_attrs[] = { &dev_attr_dbc.attr, &dev_attr_dbc_idVendor.attr, &dev_attr_dbc_idProduct.attr, @@ -1147,10 +1156,7 @@ static struct attribute *dbc_dev_attributes[] = { &dev_attr_dbc_bInterfaceProtocol.attr, NULL }; - -static const struct attribute_group dbc_dev_attrib_grp = { - .attrs = dbc_dev_attributes, -}; +ATTRIBUTE_GROUPS(dbc_dev); struct xhci_dbc * xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver) @@ -1176,7 +1182,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 = sysfs_create_group(&dev->kobj, &dbc_dev_attrib_grp); + ret = sysfs_create_groups(&dev->kobj, dbc_dev_groups); if (ret) goto err; @@ -1195,7 +1201,7 @@ void xhci_dbc_remove(struct xhci_dbc *dbc) xhci_dbc_stop(dbc); /* remove sysfs files */ - sysfs_remove_group(&dbc->dev->kobj, &dbc_dev_attrib_grp); + sysfs_remove_groups(&dbc->dev->kobj, dbc_dev_groups); kfree(dbc); } diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index 51a7ab3ba0ca..e39e3ae1677a 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -82,6 +82,7 @@ enum dbc_state { DS_CONNECTED, DS_CONFIGURED, DS_STALLED, + DS_MAX }; struct dbc_ep { diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 6d142cd61bd6..f8ba15e7c225 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci) "command-ring", xhci->debugfs_root); - xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring, + xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring, "event-ring", xhci->debugfs_root); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 62116586848b..4460fa7e9fab 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -323,6 +323,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, */ ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; } +EXPORT_SYMBOL_GPL(xhci_initialize_ring_info); /* Allocate segments and link them for a ring */ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, @@ -1739,6 +1740,8 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, } command->status = 0; + /* set default timeout to 5000 ms */ + command->timeout_ms = XHCI_CMD_DEFAULT_TIMEOUT; INIT_LIST_HEAD(&command->cmd_list); return command; } @@ -1853,6 +1856,31 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) kfree(ir); } +void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + unsigned int intr_num; + + /* interrupter 0 is primary interrupter, don't touch it */ + if (!ir || !ir->intr_num || ir->intr_num >= xhci->max_interrupters) + xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n"); + + /* fixme, should we check xhci->interrupter[intr_num] == ir */ + /* fixme locking */ + + spin_lock_irq(&xhci->lock); + + intr_num = ir->intr_num; + + xhci_remove_interrupter(xhci, ir); + xhci->interrupters[intr_num] = NULL; + + spin_unlock_irq(&xhci->lock); + + xhci_free_interrupter(xhci, ir); +} +EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter); + void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; @@ -1860,10 +1888,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) cancel_delayed_work_sync(&xhci->cmd_timer); - xhci_remove_interrupter(xhci, xhci->interrupter); - xhci_free_interrupter(xhci, xhci->interrupter); - xhci->interrupter = NULL; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring"); + for (i = 0; i < xhci->max_interrupters; i++) { + if (xhci->interrupters[i]) { + xhci_remove_interrupter(xhci, xhci->interrupters[i]); + xhci_free_interrupter(xhci, xhci->interrupters[i]); + xhci->interrupters[i] = NULL; + } + } + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters"); if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); @@ -1933,6 +1965,7 @@ no_bw: for (i = 0; i < xhci->num_port_caps; i++) kfree(xhci->port_caps[i].psi); kfree(xhci->port_caps); + kfree(xhci->interrupters); xhci->num_port_caps = 0; xhci->usb2_rhub.ports = NULL; @@ -1941,6 +1974,7 @@ no_bw: xhci->rh_bw = NULL; xhci->ext_caps = NULL; xhci->port_caps = NULL; + xhci->interrupters = NULL; xhci->page_size = 0; xhci->page_shift = 0; @@ -2246,18 +2280,20 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) } static struct xhci_interrupter * -xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags) +xhci_alloc_interrupter(struct xhci_hcd *xhci, int segs, gfp_t flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; struct xhci_interrupter *ir; - unsigned int num_segs; + unsigned int num_segs = segs; int ret; ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); if (!ir) return NULL; - num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2), + /* number of ring segments should be greater than 0 */ + if (segs <= 0) + num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2), ERST_MAX_SEGS); ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0, @@ -2292,6 +2328,13 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, return -EINVAL; } + if (xhci->interrupters[intr_num]) { + xhci_warn(xhci, "Interrupter %d\n already set up", intr_num); + return -EINVAL; + } + + xhci->interrupters[intr_num] = ir; + ir->intr_num = intr_num; ir->ir_set = &xhci->run_regs->ir_set[intr_num]; /* set ERST count with the number of entries in the segment table */ @@ -2311,10 +2354,52 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, return 0; } +struct xhci_interrupter * +xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct xhci_interrupter *ir; + unsigned int i; + int err = -ENOSPC; + + if (!xhci->interrupters || xhci->max_interrupters <= 1) + return NULL; + + ir = xhci_alloc_interrupter(xhci, num_seg, GFP_KERNEL); + if (!ir) + return NULL; + + spin_lock_irq(&xhci->lock); + + /* Find available secondary interrupter, interrupter 0 is reserved for primary */ + for (i = 1; i < xhci->max_interrupters; i++) { + if (xhci->interrupters[i] == NULL) { + err = xhci_add_interrupter(xhci, ir, i); + break; + } + } + + spin_unlock_irq(&xhci->lock); + + if (err) { + xhci_warn(xhci, "Failed to add secondary interrupter, max interrupters %d\n", + xhci->max_interrupters); + xhci_free_interrupter(xhci, ir); + return NULL; + } + + xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n", + i, xhci->max_interrupters); + + return ir; +} +EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter); + int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) { - dma_addr_t dma; + struct xhci_interrupter *ir; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + dma_addr_t dma; unsigned int val, val2; u64 val_64; u32 page_size, temp; @@ -2438,11 +2523,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) /* Allocate and set up primary interrupter 0 with an event ring. */ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating primary event ring"); - xhci->interrupter = xhci_alloc_interrupter(xhci, flags); - if (!xhci->interrupter) + xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters), + flags, dev_to_node(dev)); + + ir = xhci_alloc_interrupter(xhci, 0, flags); + if (!ir) goto fail; - if (xhci_add_interrupter(xhci, xhci->interrupter, 0)) + if (xhci_add_interrupter(xhci, ir, 0)) goto fail; xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index bbdf1b0b7be1..3252e3d2d79c 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -7,6 +7,7 @@ * Chunfeng Yun */ +#include #include #include #include @@ -73,6 +74,9 @@ #define FRMCNT_LEV1_RANG (0x12b << 8) #define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8) +#define HSCH_CFG1 0x960 +#define SCH3_RXFIFO_DEPTH_MASK GENMASK(21, 20) + #define SS_GEN2_EOF_CFG 0x990 #define SSG2EOF_OFFSET 0x3c @@ -114,6 +118,8 @@ #define SSC_IP_SLEEP_EN BIT(4) #define SSC_SPM_INT_EN BIT(1) +#define SCH_FIFO_TO_KB(x) ((x) >> 10) + enum ssusb_uwk_vers { SSUSB_UWK_V1 = 1, SSUSB_UWK_V2, @@ -165,6 +171,35 @@ static void xhci_mtk_set_frame_interval(struct xhci_hcd_mtk *mtk) writel(value, hcd->regs + SS_GEN2_EOF_CFG); } +/* + * workaround: usb3.2 gen1 isoc rx hw issue + * host send out unexpected ACK afer device fininsh a burst transfer with + * a short packet. + */ +static void xhci_mtk_rxfifo_depth_set(struct xhci_hcd_mtk *mtk) +{ + struct usb_hcd *hcd = mtk->hcd; + u32 value; + + if (!mtk->rxfifo_depth) + return; + + value = readl(hcd->regs + HSCH_CFG1); + value &= ~SCH3_RXFIFO_DEPTH_MASK; + value |= FIELD_PREP(SCH3_RXFIFO_DEPTH_MASK, + SCH_FIFO_TO_KB(mtk->rxfifo_depth) - 1); + writel(value, hcd->regs + HSCH_CFG1); +} + +static void xhci_mtk_init_quirk(struct xhci_hcd_mtk *mtk) +{ + /* workaround only for mt8195 */ + xhci_mtk_set_frame_interval(mtk); + + /* workaround for SoCs using SSUSB about before IPM v1.6.0 */ + xhci_mtk_rxfifo_depth_set(mtk); +} + static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) { struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs; @@ -448,8 +483,7 @@ static int xhci_mtk_setup(struct usb_hcd *hcd) if (ret) return ret; - /* workaround only for mt8195 */ - xhci_mtk_set_frame_interval(mtk); + xhci_mtk_init_quirk(mtk); } ret = xhci_gen_setup(hcd, xhci_mtk_quirks); @@ -527,6 +561,8 @@ static int xhci_mtk_probe(struct platform_device *pdev) of_property_read_u32(node, "mediatek,u2p-dis-msk", &mtk->u2p_dis_msk); + of_property_read_u32(node, "rx-fifo-depth", &mtk->rxfifo_depth); + ret = usb_wakeup_of_property_parse(mtk, node); if (ret) { dev_err(dev, "failed to parse uwk property\n"); diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index 39f7ae7d3087..f5e2bd66bb1b 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -171,6 +171,8 @@ struct xhci_hcd_mtk { struct regmap *uwk; u32 uwk_reg_base; u32 uwk_vers; + /* quirk */ + u32 rxfifo_depth; }; static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index d6fc08e5db8f..b534ca9752be 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -95,10 +95,9 @@ static void xhci_msix_sync_irqs(struct xhci_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)); + /* for now, the driver only supports one primary interrupter */ + synchronize_irq(pci_irq_vector(pdev, 0)); } } @@ -112,100 +111,18 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci) 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)); - } - + free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); pci_free_irq_vectors(pdev); hcd->msix_enabled = 0; } -/* - * 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; -} - +/* Try enabling MSI-X with MSI and legacy IRQ as fallback */ static int xhci_try_enable_msi(struct usb_hcd *hcd) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev; int ret; - 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. @@ -218,32 +135,53 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd) free_irq(hcd->irq, hcd); hcd->irq = 0; - ret = xhci_setup_msix(xhci); - if (ret) - /* fall back to msi*/ - ret = xhci_setup_msi(xhci); + /* + * 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->nvecs = min(num_online_cpus() + 1, + HCS_MAX_INTRS(xhci->hcs_params1)); - if (!ret) { - hcd->msi_enabled = 1; - return 0; + /* TODO: Check with MSI Soc for sysdev */ + xhci->nvecs = pci_alloc_irq_vectors(pdev, 1, xhci->nvecs, + PCI_IRQ_MSIX | PCI_IRQ_MSI); + if (xhci->nvecs < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "failed to allocate IRQ vectors"); + goto legacy_irq; } + ret = request_irq(pci_irq_vector(pdev, 0), xhci_msi_irq, 0, "xhci_hcd", + xhci_to_hcd(xhci)); + if (ret) + goto free_irq_vectors; + + hcd->msi_enabled = 1; + hcd->msix_enabled = pdev->msix_enabled; + return 0; + +free_irq_vectors: + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable %s interrupt", + pdev->msix_enabled ? "MSI-X" : "MSI"); + pci_free_irq_vectors(pdev); + +legacy_irq: 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); + /* 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); + xhci_err(xhci, "request interrupt %d failed\n", pdev->irq); return ret; } hcd->irq = pdev->irq; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 732cdeb73920..f04fde19f551 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -130,6 +130,9 @@ static const struct of_device_id usb_xhci_of_match[] = { }, { .compatible = "brcm,xhci-brcm-v2", .data = &xhci_plat_brcm, + }, { + .compatible = "brcm,bcm2711-xhci", + .data = &xhci_plat_brcm, }, { .compatible = "brcm,bcm7445-xhci", .data = &xhci_plat_brcm, @@ -433,7 +436,7 @@ void xhci_plat_remove(struct platform_device *dev) } EXPORT_SYMBOL_GPL(xhci_plat_remove); -static int __maybe_unused xhci_plat_suspend(struct device *dev) +static int xhci_plat_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -461,7 +464,7 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev) return 0; } -static int __maybe_unused xhci_plat_resume(struct device *dev) +static int xhci_plat_resume_common(struct device *dev, struct pm_message pmsg) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -483,7 +486,7 @@ static int __maybe_unused xhci_plat_resume(struct device *dev) if (ret) goto disable_clks; - ret = xhci_resume(xhci, PMSG_RESUME); + ret = xhci_resume(xhci, pmsg); if (ret) goto disable_clks; @@ -502,6 +505,16 @@ disable_clks: return ret; } +static int xhci_plat_resume(struct device *dev) +{ + return xhci_plat_resume_common(dev, PMSG_RESUME); +} + +static int xhci_plat_restore(struct device *dev) +{ + return xhci_plat_resume_common(dev, PMSG_RESTORE); +} + static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -524,7 +537,12 @@ static int __maybe_unused xhci_plat_runtime_resume(struct device *dev) } const struct dev_pm_ops xhci_plat_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume) + .suspend = pm_sleep_ptr(xhci_plat_suspend), + .resume = pm_sleep_ptr(xhci_plat_resume), + .freeze = pm_sleep_ptr(xhci_plat_suspend), + .thaw = pm_sleep_ptr(xhci_plat_resume), + .poweroff = pm_sleep_ptr(xhci_plat_suspend), + .restore = pm_sleep_ptr(xhci_plat_restore), SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, xhci_plat_runtime_resume, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f3b5e6345858..33806ae966f9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -366,9 +366,10 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci) readl(&xhci->dba->doorbell[0]); } -static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci, unsigned long delay) +static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci) { - return mod_delayed_work(system_wq, &xhci->cmd_timer, delay); + return mod_delayed_work(system_wq, &xhci->cmd_timer, + msecs_to_jiffies(xhci->current_cmd->timeout_ms)); } static struct xhci_command *xhci_next_queued_cmd(struct xhci_hcd *xhci) @@ -412,7 +413,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) && !(xhci->xhc_state & XHCI_STATE_DYING)) { xhci->current_cmd = cur_cmd; - xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); + xhci_mod_cmd_timer(xhci); xhci_ring_cmd_db(xhci); } } @@ -1787,7 +1788,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, if (!list_is_singular(&xhci->cmd_list)) { xhci->current_cmd = list_first_entry(&cmd->cmd_list, struct xhci_command, cmd_list); - xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); + xhci_mod_cmd_timer(xhci); } else if (xhci->current_cmd == cmd) { xhci->current_cmd = NULL; } @@ -3060,7 +3061,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) writel(status, &xhci->op_regs->status); /* This is the handler of the primary interrupter */ - ir = xhci->interrupter; + ir = xhci->interrupters[0]; if (!hcd->msi_enabled) { u32 irq_pending; irq_pending = readl(&ir->ir_set->irq_pending); @@ -4287,7 +4288,7 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, /* if there are no other commands queued we start the timeout timer */ if (list_empty(&xhci->cmd_list)) { xhci->current_cmd = cmd; - xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); + xhci_mod_cmd_timer(xhci); } list_add_tail(&cmd->cmd_list, &xhci->cmd_list); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 884b0898d9c9..c057c42c36f4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -480,7 +480,7 @@ static int xhci_init(struct usb_hcd *hcd) static int xhci_run_finished(struct xhci_hcd *xhci) { - struct xhci_interrupter *ir = xhci->interrupter; + struct xhci_interrupter *ir = xhci->interrupters[0]; unsigned long flags; u32 temp; @@ -532,7 +532,7 @@ int xhci_run(struct usb_hcd *hcd) u64 temp_64; int ret; struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_interrupter *ir = xhci->interrupter; + struct xhci_interrupter *ir = xhci->interrupters[0]; /* Start the xHCI host controller running only after the USB 2.0 roothub * is setup. */ @@ -596,7 +596,7 @@ void xhci_stop(struct usb_hcd *hcd) { u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_interrupter *ir = xhci->interrupter; + struct xhci_interrupter *ir = xhci->interrupters[0]; mutex_lock(&xhci->mutex); @@ -692,36 +692,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown); #ifdef CONFIG_PM static void xhci_save_registers(struct xhci_hcd *xhci) { - struct xhci_interrupter *ir = xhci->interrupter; + struct xhci_interrupter *ir; + unsigned int i; xhci->s3.command = readl(&xhci->op_regs->command); xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification); xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); xhci->s3.config_reg = readl(&xhci->op_regs->config_reg); - if (!ir) - return; + /* save both primary and all secondary interrupters */ + /* fixme, shold we lock to prevent race with remove secondary interrupter? */ + for (i = 0; i < xhci->max_interrupters; i++) { + ir = xhci->interrupters[i]; + if (!ir) + continue; - ir->s3_erst_size = readl(&ir->ir_set->erst_size); - ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); - ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); - ir->s3_irq_pending = readl(&ir->ir_set->irq_pending); - ir->s3_irq_control = readl(&ir->ir_set->irq_control); + ir->s3_erst_size = readl(&ir->ir_set->erst_size); + ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); + ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); + ir->s3_irq_pending = readl(&ir->ir_set->irq_pending); + ir->s3_irq_control = readl(&ir->ir_set->irq_control); + } } static void xhci_restore_registers(struct xhci_hcd *xhci) { - struct xhci_interrupter *ir = xhci->interrupter; + struct xhci_interrupter *ir; + unsigned int i; writel(xhci->s3.command, &xhci->op_regs->command); writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification); xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); writel(xhci->s3.config_reg, &xhci->op_regs->config_reg); - writel(ir->s3_erst_size, &ir->ir_set->erst_size); - xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base); - xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue); - writel(ir->s3_irq_pending, &ir->ir_set->irq_pending); - writel(ir->s3_irq_control, &ir->ir_set->irq_control); + + /* FIXME should we lock to protect against freeing of interrupters */ + for (i = 0; i < xhci->max_interrupters; i++) { + ir = xhci->interrupters[i]; + if (!ir) + continue; + + writel(ir->s3_erst_size, &ir->ir_set->erst_size); + xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base); + xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue); + writel(ir->s3_irq_pending, &ir->ir_set->irq_pending); + writel(ir->s3_irq_control, &ir->ir_set->irq_control); + } } static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) @@ -1084,7 +1099,7 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg) xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status); - xhci_disable_interrupter(xhci->interrupter); + xhci_disable_interrupter(xhci->interrupters[0]); xhci_dbg(xhci, "cleaning up memory\n"); xhci_mem_cleanup(xhci); @@ -1438,10 +1453,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, * descriptor. If the usb_device's max packet size changes after that point, * we need to issue an evaluate context command and wait on it. */ -static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, - unsigned int ep_index, struct urb *urb, gfp_t mem_flags) +static int xhci_check_ep0_maxpacket(struct xhci_hcd *xhci, struct xhci_virt_device *vdev) { - struct xhci_container_ctx *out_ctx; struct xhci_input_control_ctx *ctrl_ctx; struct xhci_ep_ctx *ep_ctx; struct xhci_command *command; @@ -1449,11 +1462,15 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, int hw_max_packet_size; int ret = 0; - out_ctx = xhci->devs[slot_id]->out_ctx; - ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); + ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, 0); hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); - max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc); - if (hw_max_packet_size != max_packet_size) { + max_packet_size = usb_endpoint_maxp(&vdev->udev->ep0.desc); + + if (hw_max_packet_size == max_packet_size) + return 0; + + switch (max_packet_size) { + case 8: case 16: case 32: case 64: case 9: xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, "Max Packet Size for ep 0 changed."); xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, @@ -1465,28 +1482,22 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, "Issuing evaluate context command."); - /* Set up the input context flags for the command */ - /* FIXME: This won't work if a non-default control endpoint - * changes max packet sizes. - */ - - command = xhci_alloc_command(xhci, true, mem_flags); + command = xhci_alloc_command(xhci, true, GFP_KERNEL); if (!command) return -ENOMEM; - command->in_ctx = xhci->devs[slot_id]->in_ctx; + command->in_ctx = vdev->in_ctx; ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); if (!ctrl_ctx) { xhci_warn(xhci, "%s: Could not get input context, bad type.\n", __func__); ret = -ENOMEM; - goto command_cleanup; + break; } /* Set up the modified control endpoint 0 */ - xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, - xhci->devs[slot_id]->out_ctx, ep_index); + xhci_endpoint_copy(xhci, vdev->in_ctx, vdev->out_ctx, 0); - ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index); + ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, 0); ep_ctx->ep_info &= cpu_to_le32(~EP_STATE_MASK);/* must clear */ ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK); ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); @@ -1494,17 +1505,20 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG); ctrl_ctx->drop_flags = 0; - ret = xhci_configure_endpoint(xhci, urb->dev, command, - true, false); - - /* Clean up the input context for later use by bandwidth - * functions. - */ + ret = xhci_configure_endpoint(xhci, vdev->udev, command, + true, false); + /* Clean up the input context for later use by bandwidth functions */ ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); -command_cleanup: - kfree(command->completion); - kfree(command); + break; + default: + dev_dbg(&vdev->udev->dev, "incorrect max packet size %d for ep0\n", + max_packet_size); + return -EINVAL; } + + kfree(command->completion); + kfree(command); + return ret; } @@ -1522,24 +1536,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag struct urb_priv *urb_priv; int num_tds; - if (!urb) - return -EINVAL; - ret = xhci_check_args(hcd, urb->dev, urb->ep, - true, true, __func__); - if (ret <= 0) - return ret ? ret : -EINVAL; - - slot_id = urb->dev->slot_id; ep_index = xhci_get_endpoint_index(&urb->ep->desc); - ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state; - - if (!HCD_HW_ACCESSIBLE(hcd)) - return -ESHUTDOWN; - - if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) { - xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); - return -ENODEV; - } if (usb_endpoint_xfer_isoc(&urb->ep->desc)) num_tds = urb->number_of_packets; @@ -1561,22 +1558,27 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag trace_xhci_urb_enqueue(urb); - if (usb_endpoint_xfer_control(&urb->ep->desc)) { - /* Check to see if the max packet size for the default control - * endpoint changed during FS device enumeration - */ - if (urb->dev->speed == USB_SPEED_FULL) { - ret = xhci_check_maxpacket(xhci, slot_id, - ep_index, urb, mem_flags); - if (ret < 0) { - xhci_urb_free_priv(urb_priv); - urb->hcpriv = NULL; - return ret; - } - } + spin_lock_irqsave(&xhci->lock, flags); + + ret = xhci_check_args(hcd, urb->dev, urb->ep, + true, true, __func__); + if (ret <= 0) { + ret = ret ? ret : -EINVAL; + goto free_priv; } - spin_lock_irqsave(&xhci->lock, flags); + slot_id = urb->dev->slot_id; + + if (!HCD_HW_ACCESSIBLE(hcd)) { + ret = -ESHUTDOWN; + goto free_priv; + } + + if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) { + xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); + ret = -ENODEV; + goto free_priv; + } if (xhci->xhc_state & XHCI_STATE_DYING) { xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n", @@ -1584,6 +1586,9 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ret = -ESHUTDOWN; goto free_priv; } + + ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state; + if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", *ep_state); @@ -3087,6 +3092,9 @@ done: * of an endpoint that isn't in the halted state this function will issue a * configure endpoint command with the Drop and Add bits set for the target * endpoint. Refer to the additional note in xhci spcification section 4.6.8. + * + * vdev may be lost due to xHC restore error and re-initialization during S3/S4 + * resume. A new vdev will be allocated later by xhci_discover_or_reset_device() */ static void xhci_endpoint_reset(struct usb_hcd *hcd, @@ -3104,19 +3112,37 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, int err; xhci = hcd_to_xhci(hcd); + ep_index = xhci_get_endpoint_index(&host_ep->desc); + + /* + * Usb core assumes a max packet value for ep0 on FS devices until the + * real value is read from the descriptor. Core resets Ep0 if values + * mismatch. Reconfigure the xhci ep0 endpoint context here in that case + */ + if (usb_endpoint_xfer_control(&host_ep->desc) && ep_index == 0) { + + udev = container_of(host_ep, struct usb_device, ep0); + if (udev->speed != USB_SPEED_FULL || !udev->slot_id) + return; + + vdev = xhci->devs[udev->slot_id]; + if (!vdev || vdev->udev != udev) + return; + + xhci_check_ep0_maxpacket(xhci, vdev); + + /* Nothing else should be done here for ep0 during ep reset */ + return; + } + if (!host_ep->hcpriv) return; udev = (struct usb_device *) host_ep->hcpriv; vdev = xhci->devs[udev->slot_id]; - /* - * vdev may be lost due to xHC restore error and re-initialization - * during S3/S4 resume. A new vdev will be allocated later by - * xhci_discover_or_reset_device() - */ if (!udev->slot_id || !vdev) return; - ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = &vdev->eps[ep_index]; /* Bail out if toggle is already being cleared by a endpoint reset */ @@ -4029,12 +4055,18 @@ disable_slot: return 0; } -/* - * Issue an Address Device command and optionally send a corresponding - * SetAddress request to the device. +/** + * xhci_setup_device - issues an Address Device command to assign a unique + * USB bus address. + * @hcd: USB host controller data structure. + * @udev: USB dev structure representing the connected device. + * @setup: Enum specifying setup mode: address only or with context. + * @timeout_ms: Max wait time (ms) for the command operation to complete. + * + * Return: 0 if successful; otherwise, negative error code. */ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, - enum xhci_setup_dev setup) + enum xhci_setup_dev setup, unsigned int timeout_ms) { const char *act = setup == SETUP_CONTEXT_ONLY ? "context" : "address"; unsigned long flags; @@ -4091,6 +4123,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, } command->in_ctx = virt_dev->in_ctx; + command->timeout_ms = timeout_ms; slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx); @@ -4217,14 +4250,16 @@ out: return ret; } -static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev, + unsigned int timeout_ms) { - return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS); + return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS, timeout_ms); } static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev) { - return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY); + return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY, + XHCI_CMD_DEFAULT_TIMEOUT); } /* diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3ea5c092bba7..a5c72a634e6a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -791,6 +791,8 @@ struct xhci_command { struct completion *completion; union xhci_trb *command_trb; struct list_head cmd_list; + /* xHCI command response timeout in milliseconds */ + unsigned int timeout_ms; }; /* drop context bitmasks */ @@ -1550,8 +1552,11 @@ struct xhci_td { unsigned int num_trbs; }; -/* xHCI command default timeout value */ -#define XHCI_CMD_DEFAULT_TIMEOUT (5 * HZ) +/* + * xHCI command default timeout value in milliseconds. + * USB 3.2 spec, section 9.2.6.1 + */ +#define XHCI_CMD_DEFAULT_TIMEOUT 5000 /* command descriptor */ struct xhci_cd { @@ -1760,8 +1765,8 @@ struct xhci_hcd { int page_size; /* Valid values are 12 to 20, inclusive */ int page_shift; - /* msi-x vectors */ - int msix_count; + /* MSI-X/MSI vectors */ + int nvecs; /* optional clocks */ struct clk *clk; struct clk *reg_clk; @@ -1769,7 +1774,7 @@ struct xhci_hcd { struct reset_control *reset; /* data structures */ struct xhci_device_context_array *dcbaa; - struct xhci_interrupter *interrupter; + struct xhci_interrupter **interrupters; struct xhci_ring *cmd_ring; unsigned int cmd_ring_state; #define CMD_RING_STATE_RUNNING (1 << 0) @@ -2080,6 +2085,10 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, int type, gfp_t flags); void xhci_free_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +struct xhci_interrupter * +xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg); +void xhci_remove_secondary_interrupter(struct usb_hcd + *hcd, struct xhci_interrupter *ir); /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 1e3df27bab58..6d28467ce352 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -501,7 +501,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, dev->minor, cmd, arg); retval = 0; - io_res = 0; switch (cmd) { case IOW_WRITE: if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index 2b45404e9732..0dd2b032c90b 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -5,8 +5,10 @@ * Copyright (c) 2022, Google LLC */ +#include #include #include +#include #include #include #include @@ -60,15 +62,22 @@ struct onboard_hub { bool going_away; struct list_head udev_list; struct mutex lock; + struct clk *clk; }; static int onboard_hub_power_on(struct onboard_hub *hub) { int err; + err = clk_prepare_enable(hub->clk); + if (err) { + dev_err(hub->dev, "failed to enable clock: %pe\n", ERR_PTR(err)); + return err; + } + err = regulator_bulk_enable(hub->pdata->num_supplies, hub->supplies); if (err) { - dev_err(hub->dev, "failed to enable supplies: %d\n", err); + dev_err(hub->dev, "failed to enable supplies: %pe\n", ERR_PTR(err)); return err; } @@ -88,10 +97,12 @@ static int onboard_hub_power_off(struct onboard_hub *hub) err = regulator_bulk_disable(hub->pdata->num_supplies, hub->supplies); if (err) { - dev_err(hub->dev, "failed to disable supplies: %d\n", err); + dev_err(hub->dev, "failed to disable supplies: %pe\n", ERR_PTR(err)); return err; } + clk_disable_unprepare(hub->clk); + hub->is_powered_on = false; return 0; @@ -233,9 +244,9 @@ static void onboard_hub_attach_usb_driver(struct work_struct *work) { int err; - err = driver_attach(&onboard_hub_usbdev_driver.drvwrap.driver); + err = driver_attach(&onboard_hub_usbdev_driver.driver); if (err) - pr_err("Failed to attach USB driver: %d\n", err); + pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err)); } static int onboard_hub_probe(struct platform_device *pdev) @@ -262,10 +273,14 @@ static int onboard_hub_probe(struct platform_device *pdev) err = devm_regulator_bulk_get(dev, hub->pdata->num_supplies, hub->supplies); if (err) { - dev_err(dev, "Failed to get regulator supplies: %d\n", err); + dev_err(dev, "Failed to get regulator supplies: %pe\n", ERR_PTR(err)); return err; } + hub->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(hub->clk)) + return dev_err_probe(dev, PTR_ERR(hub->clk), "failed to get clock\n"); + hub->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hub->reset_gpio)) @@ -426,6 +441,7 @@ static void onboard_hub_usbdev_disconnect(struct usb_device *udev) static const struct usb_device_id onboard_hub_id_table[] = { { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6504) }, /* CYUSB33{0,1,2}x/CYUSB230x 3.0 */ { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6506) }, /* CYUSB33{0,1,2}x/CYUSB230x 2.0 */ + { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6570) }, /* CY7C6563x 2.0 */ { USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */ { USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 */ { USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 */ diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h index 292110e64a1d..f360d5cf8d8a 100644 --- a/drivers/usb/misc/onboard_usb_hub.h +++ b/drivers/usb/misc/onboard_usb_hub.h @@ -36,6 +36,11 @@ static const struct onboard_hub_pdata cypress_hx3_data = { .num_supplies = 2, }; +static const struct onboard_hub_pdata cypress_hx2vl_data = { + .reset_us = 1, + .num_supplies = 1, +}; + static const struct onboard_hub_pdata genesys_gl850g_data = { .reset_us = 3, .num_supplies = 1, @@ -61,6 +66,7 @@ static const struct of_device_id onboard_hub_match[] = { { .compatible = "usb451,8142", .data = &ti_tusb8041_data, }, { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, }, { .compatible = "usb4b4,6506", .data = &cypress_hx3_data, }, + { .compatible = "usb4b4,6570", .data = &cypress_hx2vl_data, }, { .compatible = "usb5e3,608", .data = &genesys_gl850g_data, }, { .compatible = "usb5e3,610", .data = &genesys_gl852g_data, }, { .compatible = "usb5e3,620", .data = &genesys_gl852g_data, }, diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c index 7f371ea1248c..26e9b8749d8a 100644 --- a/drivers/usb/misc/qcom_eud.c +++ b/drivers/usb/misc/qcom_eud.c @@ -205,6 +205,9 @@ static int eud_probe(struct platform_device *pdev) return PTR_ERR(chip->mode_mgr); chip->irq = platform_get_irq(pdev, 0); + if (chip->irq < 0) + return chip->irq; + ret = devm_request_threaded_irq(&pdev->dev, chip->irq, handle_eud_irq, handle_eud_irq_thread, IRQF_ONESHOT, NULL, chip); if (ret) diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index c640f98d20c5..9a0649d23693 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -34,6 +34,8 @@ #define YUREX_BUF_SIZE 8 #define YUREX_WRITE_TIMEOUT (HZ*2) +#define MAX_S64_STRLEN 20 /* {-}922337203685477580{7,8} */ + /* table of devices that work with this driver */ static struct usb_device_id yurex_table[] = { { USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) }, @@ -401,7 +403,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, { struct usb_yurex *dev; int len = 0; - char in_buffer[20]; + char in_buffer[MAX_S64_STRLEN]; unsigned long flags; dev = file->private_data; @@ -412,14 +414,16 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, return -ENODEV; } + if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN)) { + mutex_unlock(&dev->io_mutex); + return -EIO; + } + spin_lock_irqsave(&dev->lock, flags); - len = snprintf(in_buffer, 20, "%lld\n", dev->bbu); + scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu); spin_unlock_irqrestore(&dev->lock, flags); mutex_unlock(&dev->io_mutex); - if (WARN_ON_ONCE(len >= sizeof(in_buffer))) - return -EIO; - return simple_read_from_buffer(buffer, count, ppos, in_buffer, len); } diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 9ca9305243fe..4e30de4db1c0 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1250,14 +1250,19 @@ static vm_fault_t mon_bin_vma_fault(struct vm_fault *vmf) struct mon_reader_bin *rp = vmf->vma->vm_private_data; unsigned long offset, chunk_idx; struct page *pageptr; + unsigned long flags; + spin_lock_irqsave(&rp->b_lock, flags); offset = vmf->pgoff << PAGE_SHIFT; - if (offset >= rp->b_size) + if (offset >= rp->b_size) { + spin_unlock_irqrestore(&rp->b_lock, flags); return VM_FAULT_SIGBUS; + } chunk_idx = offset / CHUNK_SIZE; pageptr = rp->b_vec[chunk_idx].pg; get_page(pageptr); vmf->page = pageptr; + spin_unlock_irqrestore(&rp->b_lock, flags); return 0; } diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index 98ab0cc473d6..3c23805ab1a4 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -35,9 +35,9 @@ static int mon_stat_open(struct inode *inode, struct file *file) mbus = inode->i_private; - sp->slen = snprintf(sp->str, STAT_BUF_SIZE, - "nreaders %d events %u text_lost %u\n", - mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost); + sp->slen = scnprintf(sp->str, STAT_BUF_SIZE, + "nreaders %d events %u text_lost %u\n", + mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost); file->private_data = sp; return 0; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 39cb14164652..2fe9b95bac1d 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -352,7 +352,7 @@ static int mon_text_open(struct inode *inode, struct file *file) rp->r.rnf_error = mon_text_error; rp->r.rnf_complete = mon_text_complete; - snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp); + scnprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp); rp->e_slab = kmem_cache_create(rp->slab_name, sizeof(struct mon_event_text), sizeof(long), 0, mon_text_ctor); @@ -700,46 +700,28 @@ static const struct file_operations mon_fops_text_u = { int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) { - enum { NAMESZ = 10 }; + enum { NAMESZ = 12 }; char name[NAMESZ]; int busnum = ubus? ubus->busnum: 0; - int rc; if (mon_dir == NULL) return 0; if (ubus != NULL) { - rc = snprintf(name, NAMESZ, "%dt", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_t; + scnprintf(name, NAMESZ, "%dt", busnum); mbus->dent_t = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t); } - rc = snprintf(name, NAMESZ, "%du", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_u; + scnprintf(name, NAMESZ, "%du", busnum); mbus->dent_u = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_u); - rc = snprintf(name, NAMESZ, "%ds", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_s; + scnprintf(name, NAMESZ, "%ds", busnum); mbus->dent_s = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat); return 1; - -err_print_s: - debugfs_remove(mbus->dent_u); - mbus->dent_u = NULL; -err_print_u: - if (ubus != NULL) { - debugfs_remove(mbus->dent_t); - mbus->dent_t = NULL; - } -err_print_t: - return 0; } void mon_text_del(struct mon_bus *mbus) diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 770081b828a4..9ab50f26db60 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -46,15 +46,21 @@ EXPORT_SYMBOL_GPL(usb_phy_generic_unregister); static int nop_set_suspend(struct usb_phy *x, int suspend) { struct usb_phy_generic *nop = dev_get_drvdata(x->dev); + int ret = 0; - if (!IS_ERR(nop->clk)) { - if (suspend) + if (suspend) { + if (!IS_ERR(nop->clk)) clk_disable_unprepare(nop->clk); - else + if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev)) + ret = regulator_disable(nop->vcc); + } else { + if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev)) + ret = regulator_enable(nop->vcc); + if (!IS_ERR(nop->clk)) clk_prepare_enable(nop->clk); } - return 0; + return ret; } static void nop_reset(struct usb_phy_generic *nop) diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index acd46b72899e..920a32cd094d 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -388,8 +388,7 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect) static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy) { - return IS_ENABLED(CONFIG_USB_OTG) && - mxs_phy->phy.last_event == USB_EVENT_ID; + return mxs_phy->phy.last_event == USB_EVENT_ID; } static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index c3ce6b1054f1..da09cff55abc 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -179,16 +179,16 @@ static ssize_t vbus_show(struct device *dev, switch (twl->linkstat) { case MUSB_VBUS_VALID: - ret = snprintf(buf, PAGE_SIZE, "vbus\n"); + ret = sysfs_emit(buf, "vbus\n"); break; case MUSB_ID_GROUND: - ret = snprintf(buf, PAGE_SIZE, "id\n"); + ret = sysfs_emit(buf, "id\n"); break; case MUSB_VBUS_OFF: - ret = snprintf(buf, PAGE_SIZE, "none\n"); + ret = sysfs_emit(buf, "none\n"); break; default: - ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n"); + ret = sysfs_emit(buf, "UNKNOWN\n"); } spin_unlock_irqrestore(&twl->lock, flags); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 3eb8dc3a1a8f..6c812d01b37d 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -113,7 +113,7 @@ static ssize_t new_id_store(struct device_driver *driver, if (retval >= 0 && usb_drv->usb_driver != NULL) retval = usb_store_new_id(&usb_drv->usb_driver->dynids, usb_drv->usb_driver->id_table, - &usb_drv->usb_driver->drvwrap.driver, + &usb_drv->usb_driver->driver, buf, count); return retval; } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 17b09f03ef84..f1e91eb7f8a4 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1521,7 +1521,7 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[] /* Now set udriver's id_table and look for matches */ udriver->id_table = id_table; - rc = driver_attach(&udriver->drvwrap.driver); + rc = driver_attach(&udriver->driver); return 0; err_deregister_drivers: diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 0774ba22fb66..177fa6cd143a 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -98,26 +98,26 @@ static ssize_t truinst_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev = interface_to_usbdev(intf); int result; if (swi_tru_install == TRU_FORCE_MS) { - result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n"); + result = sysfs_emit(buf, "Forced Mass Storage\n"); } else { swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL); if (!swocInfo) { - snprintf(buf, PAGE_SIZE, "Error\n"); + sysfs_emit(buf, "Error\n"); return -ENOMEM; } result = sierra_get_swoc_info(udev, swocInfo); if (result < 0) { dev_dbg(dev, "SWIMS: failed SWoC query\n"); kfree(swocInfo); - snprintf(buf, PAGE_SIZE, "Error\n"); + sysfs_emit(buf, "Error\n"); return -EIO; } debug_swoc(dev, swocInfo); - result = snprintf(buf, PAGE_SIZE, - "REV=%02d SKU=%04X VER=%04X\n", - swocInfo->rev, - swocInfo->LinuxSKU, - swocInfo->LinuxVer); + result = sysfs_emit(buf, + "REV=%02d SKU=%04X VER=%04X\n", + swocInfo->rev, + swocInfo->LinuxSKU, + swocInfo->LinuxVer); kfree(swocInfo); } return result; diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 696bb0b23599..9707f53cfda9 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1246,7 +1246,7 @@ static struct usb_driver uas_driver = { .suspend = uas_suspend, .resume = uas_resume, .reset_resume = uas_reset_resume, - .drvwrap.driver.shutdown = uas_shutdown, + .driver.shutdown = uas_shutdown, .id_table = uas_usb_ids, }; diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 16a670828dde..015aa9253353 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -263,11 +263,13 @@ static void typec_altmode_put_partner(struct altmode *altmode) { struct altmode *partner = altmode->partner; struct typec_altmode *adev; + struct typec_altmode *partner_adev; if (!partner) return; adev = &altmode->adev; + partner_adev = &partner->adev; if (is_typec_plug(adev->dev.parent)) { struct typec_plug *plug = to_typec_plug(adev->dev.parent); @@ -276,7 +278,7 @@ static void typec_altmode_put_partner(struct altmode *altmode) } else { partner->partner = NULL; } - put_device(&adev->dev); + put_device(&partner_adev->dev); } /** @@ -476,7 +478,7 @@ static int altmode_id_get(struct device *dev) else ids = &to_typec_port(dev)->mode_ids; - return ida_simple_get(ids, 0, 0, GFP_KERNEL); + return ida_alloc(ids, GFP_KERNEL); } static void altmode_id_remove(struct device *dev, int id) @@ -490,7 +492,7 @@ static void altmode_id_remove(struct device *dev, int id) else ids = &to_typec_port(dev)->mode_ids; - ida_simple_remove(ids, id); + ida_free(ids, id); } static void typec_altmode_release(struct device *dev) @@ -1798,7 +1800,7 @@ static void typec_release(struct device *dev) { struct typec_port *port = to_typec_port(dev); - ida_simple_remove(&typec_index_ida, port->id); + ida_free(&typec_index_ida, port->id); ida_destroy(&port->mode_ids); typec_switch_put(port->sw); typec_mux_put(port->mux); @@ -2231,7 +2233,8 @@ void typec_port_register_altmodes(struct typec_port *port, struct typec_altmode_desc desc; struct typec_altmode *alt; size_t index = 0; - u32 svid, vdo; + u16 svid; + u32 vdo; int ret; altmodes_node = device_get_named_child_node(&port->dev, "altmodes"); @@ -2239,7 +2242,7 @@ void typec_port_register_altmodes(struct typec_port *port, return; /* No altmodes specified */ fwnode_for_each_child_node(altmodes_node, child) { - ret = fwnode_property_read_u32(child, "svid", &svid); + ret = fwnode_property_read_u16(child, "svid", &svid); if (ret) { dev_err(&port->dev, "Error reading svid for altmode %s\n", fwnode_get_name(child)); @@ -2297,7 +2300,7 @@ struct typec_port *typec_register_port(struct device *parent, if (!port) return ERR_PTR(-ENOMEM); - id = ida_simple_get(&typec_index_ida, 0, 0, GFP_KERNEL); + id = ida_alloc(&typec_index_ida, GFP_KERNEL); if (id < 0) { kfree(port); return ERR_PTR(id); diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 38416fb0cc3c..d2cb5e733e57 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -56,4 +56,14 @@ config TYPEC_MUX_PTN36502 Say Y or M if your system has a NXP PTN36502 Type-C redriver chip found on some devices with a Type-C port. +config TYPEC_MUX_WCD939X_USBSS + tristate "Qualcomm WCD939x USBSS Analog Audio Switch driver" + depends on I2C + select REGMAP_I2C + help + Driver for the Qualcomm WCD939x Audio Codec USBSS domain which + provides support for muxing analog audio and sideband signals on a + common USB Type-C connector. + If compiled as a module, the module will be named wcd939x-usbss. + endmenu diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile index 9d6a5557b0bd..57dc9ac6f8dc 100644 --- a/drivers/usb/typec/mux/Makefile +++ b/drivers/usb/typec/mux/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M) += nb7vpq904m.o obj-$(CONFIG_TYPEC_MUX_PTN36502) += ptn36502.o +obj-$(CONFIG_TYPEC_MUX_WCD939X_USBSS) += wcd939x-usbss.o diff --git a/drivers/usb/typec/mux/wcd939x-usbss.c b/drivers/usb/typec/mux/wcd939x-usbss.c new file mode 100644 index 000000000000..d46c353dfaf2 --- /dev/null +++ b/drivers/usb/typec/mux/wcd939x-usbss.c @@ -0,0 +1,779 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (C) 2023 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WCD_USBSS_PMP_OUT1 0x2 + +#define WCD_USBSS_DP_DN_MISC1 0x20 + +#define WCD_USBSS_DP_DN_MISC1_DP_PCOMP_2X_DYN_BST_ON_EN BIT(3) +#define WCD_USBSS_DP_DN_MISC1_DN_PCOMP_2X_DYN_BST_ON_EN BIT(0) + +#define WCD_USBSS_MG1_EN 0x24 + +#define WCD_USBSS_MG1_EN_CT_SNS_EN BIT(1) + +#define WCD_USBSS_MG1_BIAS 0x25 + +#define WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN BIT(3) + +#define WCD_USBSS_MG1_MISC 0x27 + +#define WCD_USBSS_MG1_MISC_PCOMP_2X_DYN_BST_ON_EN BIT(5) + +#define WCD_USBSS_MG2_EN 0x28 + +#define WCD_USBSS_MG2_EN_CT_SNS_EN BIT(1) + +#define WCD_USBSS_MG2_BIAS 0x29 + +#define WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN BIT(3) + +#define WCD_USBSS_MG2_MISC 0x30 + +#define WCD_USBSS_MG2_MISC_PCOMP_2X_DYN_BST_ON_EN BIT(5) + +#define WCD_USBSS_DISP_AUXP_THRESH 0x80 + +#define WCD_USBSS_DISP_AUXP_THRESH_DISP_AUXP_OVPON_CM GENMASK(7, 5) + +#define WCD_USBSS_DISP_AUXP_CTL 0x81 + +#define WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF GENMASK(2, 0) + +#define WCD_USBSS_CPLDO_CTL2 0xa1 + +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE 0x403 + +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DEVICE_ENABLE BIT(7) +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES BIT(6) +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES BIT(5) +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES BIT(4) +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES BIT(3) +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES BIT(2) +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES BIT(1) +#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES BIT(0) + +#define WCD_USBSS_SWITCH_SELECT0 0x404 + +#define WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES BIT(7) /* 1-> MG2 */ +#define WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES BIT(6) /* 1-> MG2 */ +#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES GENMASK(5, 4) +#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES GENMASK(3, 2) +#define WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES BIT(1) /* 1-> SBU2 */ +#define WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES BIT(0) /* 1-> MG2 */ + +#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_L 0 +#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN 1 +#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN2 2 + +#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_R 0 +#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DP 1 +#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DR2 2 + +#define WCD_USBSS_SWITCH_SELECT1 0x405 + +#define WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES BIT(0) /* 1-> MG2 */ + +#define WCD_USBSS_DELAY_R_SW 0x40d +#define WCD_USBSS_DELAY_MIC_SW 0x40e +#define WCD_USBSS_DELAY_SENSE_SW 0x40f +#define WCD_USBSS_DELAY_GND_SW 0x410 +#define WCD_USBSS_DELAY_L_SW 0x411 + +#define WCD_USBSS_FUNCTION_ENABLE 0x413 + +#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT GENMASK(1, 0) + +#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_MANUAL 1 +#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_AUDIO_FSM 2 + +#define WCD_USBSS_EQUALIZER1 0x415 + +#define WCD_USBSS_EQUALIZER1_EQ_EN BIT(7) +#define WCD_USBSS_EQUALIZER1_BW_SETTINGS GENMASK(6, 3) + +#define WCD_USBSS_USB_SS_CNTL 0x419 + +#define WCD_USBSS_USB_SS_CNTL_STANDBY_STATE BIT(4) +#define WCD_USBSS_USB_SS_CNTL_RCO_EN BIT(3) +#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE GENMASK(2, 0) + +#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_AATC 2 +#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_USB 5 + +#define WCD_USBSS_AUDIO_FSM_START 0x433 + +#define WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG BIT(0) + +#define WCD_USBSS_RATIO_SPKR_REXT_L_LSB 0x461 +#define WCD_USBSS_RATIO_SPKR_REXT_L_MSB 0x462 +#define WCD_USBSS_RATIO_SPKR_REXT_R_LSB 0x463 +#define WCD_USBSS_RATIO_SPKR_REXT_R_MSB 0x464 +#define WCD_USBSS_AUD_COEF_L_K0_0 0x475 +#define WCD_USBSS_AUD_COEF_L_K0_1 0x476 +#define WCD_USBSS_AUD_COEF_L_K0_2 0x477 +#define WCD_USBSS_AUD_COEF_L_K1_0 0x478 +#define WCD_USBSS_AUD_COEF_L_K1_1 0x479 +#define WCD_USBSS_AUD_COEF_L_K2_0 0x47a +#define WCD_USBSS_AUD_COEF_L_K2_1 0x47b +#define WCD_USBSS_AUD_COEF_L_K3_0 0x47c +#define WCD_USBSS_AUD_COEF_L_K3_1 0x47d +#define WCD_USBSS_AUD_COEF_L_K4_0 0x47e +#define WCD_USBSS_AUD_COEF_L_K4_1 0x47f +#define WCD_USBSS_AUD_COEF_L_K5_0 0x480 +#define WCD_USBSS_AUD_COEF_L_K5_1 0x481 +#define WCD_USBSS_AUD_COEF_R_K0_0 0x482 +#define WCD_USBSS_AUD_COEF_R_K0_1 0x483 +#define WCD_USBSS_AUD_COEF_R_K0_2 0x484 +#define WCD_USBSS_AUD_COEF_R_K1_0 0x485 +#define WCD_USBSS_AUD_COEF_R_K1_1 0x486 +#define WCD_USBSS_AUD_COEF_R_K2_0 0x487 +#define WCD_USBSS_AUD_COEF_R_K2_1 0x488 +#define WCD_USBSS_AUD_COEF_R_K3_0 0x489 +#define WCD_USBSS_AUD_COEF_R_K3_1 0x48a +#define WCD_USBSS_AUD_COEF_R_K4_0 0x48b +#define WCD_USBSS_AUD_COEF_R_K4_1 0x48c +#define WCD_USBSS_AUD_COEF_R_K5_0 0x48d +#define WCD_USBSS_AUD_COEF_R_K5_1 0x48e +#define WCD_USBSS_GND_COEF_L_K0_0 0x48f +#define WCD_USBSS_GND_COEF_L_K0_1 0x490 +#define WCD_USBSS_GND_COEF_L_K0_2 0x491 +#define WCD_USBSS_GND_COEF_L_K1_0 0x492 +#define WCD_USBSS_GND_COEF_L_K1_1 0x493 +#define WCD_USBSS_GND_COEF_L_K2_0 0x494 +#define WCD_USBSS_GND_COEF_L_K2_1 0x495 +#define WCD_USBSS_GND_COEF_L_K3_0 0x496 +#define WCD_USBSS_GND_COEF_L_K3_1 0x497 +#define WCD_USBSS_GND_COEF_L_K4_0 0x498 +#define WCD_USBSS_GND_COEF_L_K4_1 0x499 +#define WCD_USBSS_GND_COEF_L_K5_0 0x49a +#define WCD_USBSS_GND_COEF_L_K5_1 0x49b +#define WCD_USBSS_GND_COEF_R_K0_0 0x49c +#define WCD_USBSS_GND_COEF_R_K0_1 0x49d +#define WCD_USBSS_GND_COEF_R_K0_2 0x49e +#define WCD_USBSS_GND_COEF_R_K1_0 0x49f +#define WCD_USBSS_GND_COEF_R_K1_1 0x4a0 +#define WCD_USBSS_GND_COEF_R_K2_0 0x4a1 +#define WCD_USBSS_GND_COEF_R_K2_1 0x4a2 +#define WCD_USBSS_GND_COEF_R_K3_0 0x4a3 +#define WCD_USBSS_GND_COEF_R_K3_1 0x4a4 +#define WCD_USBSS_GND_COEF_R_K4_0 0x4a5 +#define WCD_USBSS_GND_COEF_R_K4_1 0x4a6 +#define WCD_USBSS_GND_COEF_R_K5_0 0x4a7 +#define WCD_USBSS_GND_COEF_R_K5_1 0x4a8 + +#define WCD_USBSS_MAX_REGISTER 0x4c1 + +struct wcd939x_usbss { + struct i2c_client *client; + struct gpio_desc *reset_gpio; + struct regulator *vdd_supply; + + /* used to serialize concurrent change requests */ + struct mutex lock; + + struct typec_switch_dev *sw; + struct typec_mux_dev *mux; + + struct regmap *regmap; + + struct typec_mux *codec; + struct typec_switch *codec_switch; + + enum typec_orientation orientation; + unsigned long mode; + unsigned int svid; +}; + +static const struct regmap_range_cfg wcd939x_usbss_ranges[] = { + { + .range_min = 0, + .range_max = WCD_USBSS_MAX_REGISTER, + .selector_reg = 0x0, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, + }, +}; + +static const struct regmap_config wcd939x_usbss_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = WCD_USBSS_MAX_REGISTER, + .ranges = wcd939x_usbss_ranges, + .num_ranges = ARRAY_SIZE(wcd939x_usbss_ranges), +}; + +/* Linearlizer coefficients for 32ohm load */ +static const struct { + unsigned int offset; + unsigned int mask; + unsigned int value; +} wcd939x_usbss_coeff_init[] = { + { WCD_USBSS_AUD_COEF_L_K5_0, GENMASK(7, 0), 0x39 }, + { WCD_USBSS_AUD_COEF_R_K5_0, GENMASK(7, 0), 0x39 }, + { WCD_USBSS_GND_COEF_L_K2_0, GENMASK(7, 0), 0xe8 }, + { WCD_USBSS_GND_COEF_L_K4_0, GENMASK(7, 0), 0x73 }, + { WCD_USBSS_GND_COEF_R_K2_0, GENMASK(7, 0), 0xe8 }, + { WCD_USBSS_GND_COEF_R_K4_0, GENMASK(7, 0), 0x73 }, + { WCD_USBSS_RATIO_SPKR_REXT_L_LSB, GENMASK(7, 0), 0x00 }, + { WCD_USBSS_RATIO_SPKR_REXT_L_MSB, GENMASK(6, 0), 0x04 }, + { WCD_USBSS_RATIO_SPKR_REXT_R_LSB, GENMASK(7, 0), 0x00 }, + { WCD_USBSS_RATIO_SPKR_REXT_R_MSB, GENMASK(6, 0), 0x04 }, +}; + +static int wcd939x_usbss_set(struct wcd939x_usbss *usbss) +{ + bool reverse = (usbss->orientation == TYPEC_ORIENTATION_REVERSE); + bool enable_audio = false; + bool enable_usb = false; + bool enable_dp = false; + int ret; + + /* USB Mode */ + if (usbss->mode < TYPEC_STATE_MODAL || + (!usbss->svid && (usbss->mode == TYPEC_MODE_USB2 || + usbss->mode == TYPEC_MODE_USB3))) { + enable_usb = true; + } else if (usbss->svid) { + switch (usbss->mode) { + /* DP Only */ + case TYPEC_DP_STATE_C: + case TYPEC_DP_STATE_E: + enable_dp = true; + break; + + /* DP + USB */ + case TYPEC_DP_STATE_D: + case TYPEC_DP_STATE_F: + enable_usb = true; + enable_dp = true; + break; + + default: + return -EOPNOTSUPP; + } + } else if (usbss->mode == TYPEC_MODE_AUDIO) { + enable_audio = true; + } else { + return -EOPNOTSUPP; + } + + /* Disable all switches */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES); + if (ret) + return ret; + + /* Clear switches */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, + WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES); + if (ret) + return ret; + + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1, + WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES); + if (ret) + return ret; + + /* Enable OVP_MG1_BIAS PCOMP_DYN_BST_EN */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG1_BIAS, + WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN); + if (ret) + return ret; + + /* Enable OVP_MG2_BIAS PCOMP_DYN_BST_EN */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG2_BIAS, + WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN); + if (ret) + return ret; + + /* Disable Equalizer in safe mode */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_EQUALIZER1, + WCD_USBSS_EQUALIZER1_EQ_EN); + if (ret) + return ret; + + /* Start FSM with all disabled, force write */ + ret = regmap_write_bits(usbss->regmap, WCD_USBSS_AUDIO_FSM_START, + WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG, + WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG); + + /* 35us to allow the SBU switch to turn off */ + usleep_range(35, 1000); + + /* Setup Audio Accessory mux/switch */ + if (enable_audio) { + int i; + + /* + * AATC switch configuration: + * "Normal": + * - R: DNR + * - L: DNL + * - Sense: GSBU2 + * - Mic: MG1 + * - AGND: MG2 + * "Swapped": + * - R: DNR + * - L: DNL + * - Sense: GSBU1 + * - Mic: MG2 + * - AGND: MG1 + * Swapped information is given by the codec MBHC logic + */ + + /* Set AATC mode */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, + WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, + FIELD_PREP(WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, + WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_AATC)); + if (ret) + return ret; + + /* Select L for DNL_SWITCHES and R for DPR_SWITCHES */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, + WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, + FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_L) | + FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_R)); + if (ret) + return ret; + + if (reverse) + /* Select MG2 for MIC, SBU1 for Sense */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, + WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES); + else + /* Select MG1 for MIC, SBU2 for Sense */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, + WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES); + if (ret) + return ret; + + if (reverse) + /* Disable OVP_MG1_BIAS PCOMP_DYN_BST_EN */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_MG1_BIAS, + WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN); + else + /* Disable OVP_MG2_BIAS PCOMP_DYN_BST_EN */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_MG2_BIAS, + WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN); + if (ret) + return ret; + + /* Enable SENSE, MIC switches */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, + WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES); + if (ret) + return ret; + + if (reverse) + /* Select MG1 for AGND_SWITCHES */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1, + WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES); + else + /* Select MG2 for AGND_SWITCHES */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1, + WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES); + if (ret) + return ret; + + /* Enable AGND switches */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, + WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES); + if (ret) + return ret; + + /* Enable DPR, DNL switches */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES); + if (ret) + return ret; + + /* Setup FSM delays */ + ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_L_SW, 0x02); + if (ret) + return ret; + + ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_R_SW, 0x02); + if (ret) + return ret; + + ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_MIC_SW, 0x01); + if (ret) + return ret; + + /* Start FSM, force write */ + ret = regmap_write_bits(usbss->regmap, WCD_USBSS_AUDIO_FSM_START, + WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG, + WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG); + if (ret) + return ret; + + /* Default Linearlizer coefficients */ + for (i = 0; i < ARRAY_SIZE(wcd939x_usbss_coeff_init); ++i) + regmap_update_bits(usbss->regmap, + wcd939x_usbss_coeff_init[i].offset, + wcd939x_usbss_coeff_init[i].mask, + wcd939x_usbss_coeff_init[i].value); + + return 0; + } + + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, + WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, + FIELD_PREP(WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, + WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_USB)); + if (ret) + return ret; + + /* Enable USB muxes */ + if (enable_usb) { + /* Do not enable Equalizer in safe mode */ + if (usbss->mode != TYPEC_STATE_SAFE) { + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_EQUALIZER1, + WCD_USBSS_EQUALIZER1_EQ_EN); + if (ret) + return ret; + } + + /* Select DN for DNL_SWITCHES and DP for DPR_SWITCHES */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, + WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, + FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN) | + FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DP)); + if (ret) + return ret; + + /* Enable DNL_SWITCHES and DPR_SWITCHES */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES); + if (ret) + return ret; + } + + /* Enable DP AUX muxes */ + if (enable_dp) { + /* Update Leakage Canceller Coefficient for AUXP pins */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_DISP_AUXP_CTL, + WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF, + FIELD_PREP(WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF, + 5)); + if (ret) + return ret; + + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_DISP_AUXP_THRESH, + WCD_USBSS_DISP_AUXP_THRESH_DISP_AUXP_OVPON_CM); + if (ret) + return ret; + + if (reverse) + /* Select MG2 for AUXP and MG1 for AUXM */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, + WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES); + else + /* Select MG1 for AUXP and MG2 for AUXM */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, + WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES | + WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES, + WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES); + if (ret) + return ret; + + /* Enable DP_AUXP_TO_MGX and DP_AUXM_TO_MGX switches */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES | + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES); + + /* 15us to allow the SBU switch to turn on again */ + usleep_range(15, 1000); + } + + return 0; +} + +static int wcd939x_usbss_switch_set(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + struct wcd939x_usbss *usbss = typec_switch_get_drvdata(sw); + int ret = 0; + + mutex_lock(&usbss->lock); + + if (usbss->orientation != orientation) { + usbss->orientation = orientation; + + ret = wcd939x_usbss_set(usbss); + } + + mutex_unlock(&usbss->lock); + + if (ret) + return ret; + + /* Report orientation to codec after switch has been done */ + return typec_switch_set(usbss->codec_switch, orientation); +} + +static int wcd939x_usbss_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) +{ + struct wcd939x_usbss *usbss = typec_mux_get_drvdata(mux); + int ret = 0; + + mutex_lock(&usbss->lock); + + if (usbss->mode != state->mode) { + usbss->mode = state->mode; + + if (state->alt) + usbss->svid = state->alt->svid; + else + usbss->svid = 0; // No SVID + + ret = wcd939x_usbss_set(usbss); + } + + mutex_unlock(&usbss->lock); + + if (ret) + return ret; + + /* Report event to codec after switch has been done */ + return typec_mux_set(usbss->codec, state); +} + +static int wcd939x_usbss_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct typec_switch_desc sw_desc = { }; + struct typec_mux_desc mux_desc = { }; + struct wcd939x_usbss *usbss; + int ret; + + usbss = devm_kzalloc(dev, sizeof(*usbss), GFP_KERNEL); + if (!usbss) + return -ENOMEM; + + usbss->client = client; + mutex_init(&usbss->lock); + + usbss->regmap = devm_regmap_init_i2c(client, &wcd939x_usbss_regmap_config); + if (IS_ERR(usbss->regmap)) + return dev_err_probe(dev, PTR_ERR(usbss->regmap), "failed to initialize regmap\n"); + + usbss->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(usbss->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(usbss->reset_gpio), + "unable to acquire reset gpio\n"); + + usbss->vdd_supply = devm_regulator_get_optional(dev, "vdd"); + if (IS_ERR(usbss->vdd_supply)) + return PTR_ERR(usbss->vdd_supply); + + /* Get Codec's MUX & Switch devices */ + usbss->codec = fwnode_typec_mux_get(dev->fwnode); + if (IS_ERR(usbss->codec)) + return dev_err_probe(dev, PTR_ERR(usbss->codec), + "failed to acquire codec mode-switch\n"); + + usbss->codec_switch = fwnode_typec_switch_get(dev->fwnode); + if (IS_ERR(usbss->codec_switch)) { + ret = dev_err_probe(dev, PTR_ERR(usbss->codec_switch), + "failed to acquire codec orientation-switch\n"); + goto err_mux_put; + } + + usbss->mode = TYPEC_STATE_SAFE; + usbss->orientation = TYPEC_ORIENTATION_NONE; + + gpiod_set_value(usbss->reset_gpio, 1); + + ret = regulator_enable(usbss->vdd_supply); + if (ret) { + dev_err(dev, "Failed to enable vdd: %d\n", ret); + goto err_mux_switch; + } + + msleep(20); + + gpiod_set_value(usbss->reset_gpio, 0); + + msleep(20); + + /* Disable standby */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, + WCD_USBSS_USB_SS_CNTL_STANDBY_STATE); + if (ret) + goto err_regulator_disable; + + /* Set manual mode by default */ + ret = regmap_update_bits(usbss->regmap, WCD_USBSS_FUNCTION_ENABLE, + WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT, + FIELD_PREP(WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT, + WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_MANUAL)); + if (ret) + goto err_regulator_disable; + + /* Enable dynamic boosting for DP and DN */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_DP_DN_MISC1, + WCD_USBSS_DP_DN_MISC1_DP_PCOMP_2X_DYN_BST_ON_EN | + WCD_USBSS_DP_DN_MISC1_DN_PCOMP_2X_DYN_BST_ON_EN); + if (ret) + goto err_regulator_disable; + + /* Enable dynamic boosting for MG1 OVP */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG1_MISC, + WCD_USBSS_MG1_MISC_PCOMP_2X_DYN_BST_ON_EN); + if (ret) + goto err_regulator_disable; + + /* Enable dynamic boosting for MG2 OVP */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG2_MISC, + WCD_USBSS_MG2_MISC_PCOMP_2X_DYN_BST_ON_EN); + if (ret) + goto err_regulator_disable; + + /* Write 0xFF to WCD_USBSS_CPLDO_CTL2 */ + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_CPLDO_CTL2, 0xff); + if (ret) + goto err_regulator_disable; + + /* Set RCO_EN: WCD_USBSS_USB_SS_CNTL Bit<3> --> 0x0 --> 0x1 */ + ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, + WCD_USBSS_USB_SS_CNTL_RCO_EN); + if (ret) + goto err_regulator_disable; + + ret = regmap_set_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, + WCD_USBSS_USB_SS_CNTL_RCO_EN); + if (ret) + goto err_regulator_disable; + + /* Disable all switches but enable the mux */ + ret = regmap_write(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, + WCD_USBSS_SWITCH_SETTINGS_ENABLE_DEVICE_ENABLE); + if (ret) + goto err_regulator_disable; + + /* Setup in SAFE mode */ + ret = wcd939x_usbss_set(usbss); + if (ret) + goto err_regulator_disable; + + sw_desc.drvdata = usbss; + sw_desc.fwnode = dev_fwnode(dev); + sw_desc.set = wcd939x_usbss_switch_set; + + usbss->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(usbss->sw)) { + ret = dev_err_probe(dev, PTR_ERR(usbss->sw), "failed to register typec switch\n"); + goto err_regulator_disable; + } + + mux_desc.drvdata = usbss; + mux_desc.fwnode = dev_fwnode(dev); + mux_desc.set = wcd939x_usbss_mux_set; + + usbss->mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(usbss->mux)) { + ret = dev_err_probe(dev, PTR_ERR(usbss->mux), "failed to register typec mux\n"); + goto err_switch_unregister; + } + + i2c_set_clientdata(client, usbss); + + return 0; + +err_switch_unregister: + typec_switch_unregister(usbss->sw); + +err_regulator_disable: + regulator_disable(usbss->vdd_supply); + +err_mux_switch: + typec_switch_put(usbss->codec_switch); + +err_mux_put: + typec_mux_put(usbss->codec); + + return ret; +} + +static void wcd939x_usbss_remove(struct i2c_client *client) +{ + struct wcd939x_usbss *usbss = i2c_get_clientdata(client); + + typec_mux_unregister(usbss->mux); + typec_switch_unregister(usbss->sw); + + regulator_disable(usbss->vdd_supply); + + typec_switch_put(usbss->codec_switch); + typec_mux_put(usbss->codec); +} + +static const struct i2c_device_id wcd939x_usbss_table[] = { + { "wcd9390-usbss" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wcd939x_usbss_table); + +static const struct of_device_id wcd939x_usbss_of_table[] = { + { .compatible = "qcom,wcd9390-usbss" }, + { } +}; +MODULE_DEVICE_TABLE(of, wcd939x_usbss_of_table); + +static struct i2c_driver wcd939x_usbss_driver = { + .driver = { + .name = "wcd939x-usbss", + .of_match_table = wcd939x_usbss_of_table, + }, + .probe = wcd939x_usbss_probe, + .remove = wcd939x_usbss_remove, + .id_table = wcd939x_usbss_table, +}; +module_i2c_driver(wcd939x_usbss_driver); + +MODULE_DESCRIPTION("Qualcomm WCD939x USBSS driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c index 85d015cdbe1f..b9cca2be76fc 100644 --- a/drivers/usb/typec/pd.c +++ b/drivers/usb/typec/pd.c @@ -468,7 +468,7 @@ static struct device_type pd_capabilities_type = { /** * usb_power_delivery_register_capabilities - Register a set of capabilities. * @pd: The USB PD instance that the capabilities belong to. - * @desc: Description of the Capablities Message. + * @desc: Description of the Capabilities Message. * * This function registers a Capabilities Message described in @desc. The * capabilities will have their own sub-directory under @pd in sysfs. @@ -571,7 +571,7 @@ static void pd_release(struct device *dev) { struct usb_power_delivery *pd = to_usb_power_delivery(dev); - ida_simple_remove(&pd_ida, pd->id); + ida_free(&pd_ida, pd->id); kfree(pd); } @@ -616,7 +616,7 @@ usb_power_delivery_register(struct device *parent, struct usb_power_delivery_des if (!pd) return ERR_PTR(-ENOMEM); - ret = ida_simple_get(&pd_ida, 0, 0, GFP_KERNEL); + ret = ida_alloc(&pd_ida, GFP_KERNEL); if (ret < 0) { kfree(pd); return ERR_PTR(ret); diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c index 9454b12a073c..7fb966fd639b 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c @@ -92,11 +92,16 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip) return; } + /* Vconn Over Current Protection */ + ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS_MASK, TCPC_FAULT_STATUS_MASK_VCONN_OC); + if (ret < 0) + return; + alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS | TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS | /* Enable Extended alert for detecting Fast Role Swap Signal */ - TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS; + TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS | TCPC_ALERT_FAULT; ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask); if (ret < 0) { @@ -295,6 +300,19 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status) } } + if (status & TCPC_ALERT_FAULT) { + ret = max_tcpci_read8(chip, TCPC_FAULT_STATUS, ®_status); + if (ret < 0) + return ret; + + ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS, reg_status); + if (ret < 0) + return ret; + + if (reg_status & TCPC_FAULT_STATUS_VCONN_OC) + tcpm_port_error_recovery(chip->port); + } + if (status & TCPC_ALERT_EXTND) { ret = max_tcpci_read8(chip, TCPC_ALERT_EXTENDED, ®_status); if (ret < 0) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a1487bc670f1..9d410718eaf4 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -251,6 +251,7 @@ enum frs_typec_current { #define TCPM_FRS_EVENT BIT(3) #define TCPM_SOURCING_VBUS BIT(4) #define TCPM_PORT_CLEAN BIT(5) +#define TCPM_PORT_ERROR BIT(6) #define LOG_BUFFER_ENTRIES 1024 #define LOG_BUFFER_ENTRY_SIZE 128 @@ -296,6 +297,15 @@ struct pd_pps_data { bool active; }; +struct pd_data { + struct usb_power_delivery *pd; + struct usb_power_delivery_capabilities *source_cap; + struct usb_power_delivery_capabilities_desc source_desc; + struct usb_power_delivery_capabilities *sink_cap; + struct usb_power_delivery_capabilities_desc sink_desc; + unsigned int operating_snk_mw; +}; + struct tcpm_port { struct device *dev; @@ -397,12 +407,14 @@ struct tcpm_port { unsigned int rx_msgid; /* USB PD objects */ - struct usb_power_delivery *pd; + struct usb_power_delivery **pds; + struct pd_data **pd_list; struct usb_power_delivery_capabilities *port_source_caps; struct usb_power_delivery_capabilities *port_sink_caps; struct usb_power_delivery *partner_pd; struct usb_power_delivery_capabilities *partner_source_caps; struct usb_power_delivery_capabilities *partner_sink_caps; + struct usb_power_delivery *selected_pd; /* Partner capabilities/requests */ u32 sink_request; @@ -412,6 +424,7 @@ struct tcpm_port { unsigned int nr_sink_caps; /* Local capabilities */ + unsigned int pd_count; u32 src_pdo[PDO_MAX_OBJECTS]; unsigned int nr_src_pdo; u32 snk_pdo[PDO_MAX_OBJECTS]; @@ -2847,7 +2860,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); } else { - if (port->send_discover) { + if (port->send_discover && port->negotiated_rev < PD_REV30) { tcpm_queue_message(port, PD_MSG_CTRL_WAIT); break; } @@ -2863,7 +2876,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); } else { - if (port->send_discover) { + if (port->send_discover && port->negotiated_rev < PD_REV30) { tcpm_queue_message(port, PD_MSG_CTRL_WAIT); break; } @@ -2872,7 +2885,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, } break; case PD_CTRL_VCONN_SWAP: - if (port->send_discover) { + if (port->send_discover && port->negotiated_rev < PD_REV30) { tcpm_queue_message(port, PD_MSG_CTRL_WAIT); break; } @@ -4401,7 +4414,8 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_current_limit(port, tcpm_get_current_limit(port), 5000); tcpm_swap_complete(port, 0); tcpm_typec_connect(port); - mod_enable_frs_delayed_work(port, 0); + if (port->pd_capable && port->source_caps[0] & PDO_FIXED_DUAL_ROLE) + mod_enable_frs_delayed_work(port, 0); tcpm_pps_complete(port, port->pps_status); if (port->ams != NONE_AMS) @@ -5486,6 +5500,10 @@ static void tcpm_pd_event_handler(struct kthread_work *work) tcpm_set_state(port, tcpm_default_state(port), 0); } } + if (events & TCPM_PORT_ERROR) { + tcpm_log(port, "port triggering error recovery"); + tcpm_set_state(port, ERROR_RECOVERY, 0); + } spin_lock(&port->pd_event_lock); } @@ -5553,6 +5571,15 @@ bool tcpm_port_is_toggling(struct tcpm_port *port) } EXPORT_SYMBOL_GPL(tcpm_port_is_toggling); +void tcpm_port_error_recovery(struct tcpm_port *port) +{ + spin_lock(&port->pd_event_lock); + port->pd_events |= TCPM_PORT_ERROR; + spin_unlock(&port->pd_event_lock); + kthread_queue_work(port->wq, &port->event_work); +} +EXPORT_SYMBOL_GPL(tcpm_port_error_recovery); + static void tcpm_enable_frs_work(struct kthread_work *work) { struct tcpm_port *port = container_of(work, struct tcpm_port, enable_frs); @@ -6044,12 +6071,114 @@ port_unlock: return 0; } +static struct pd_data *tcpm_find_pd_data(struct tcpm_port *port, struct usb_power_delivery *pd) +{ + int i; + + for (i = 0; port->pd_list[i]; i++) { + if (port->pd_list[i]->pd == pd) + return port->pd_list[i]; + } + + return ERR_PTR(-ENODATA); +} + +static struct usb_power_delivery **tcpm_pd_get(struct typec_port *p) +{ + struct tcpm_port *port = typec_get_drvdata(p); + + return port->pds; +} + +static int tcpm_pd_set(struct typec_port *p, struct usb_power_delivery *pd) +{ + struct tcpm_port *port = typec_get_drvdata(p); + struct pd_data *data; + int i, ret = 0; + + mutex_lock(&port->lock); + + if (port->selected_pd == pd) + goto unlock; + + data = tcpm_find_pd_data(port, pd); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + goto unlock; + } + + if (data->sink_desc.pdo[0]) { + for (i = 0; i < PDO_MAX_OBJECTS && data->sink_desc.pdo[i]; i++) + port->snk_pdo[i] = data->sink_desc.pdo[i]; + port->nr_snk_pdo = i + 1; + port->operating_snk_mw = data->operating_snk_mw; + } + + if (data->source_desc.pdo[0]) { + for (i = 0; i < PDO_MAX_OBJECTS && data->source_desc.pdo[i]; i++) + port->snk_pdo[i] = data->source_desc.pdo[i]; + port->nr_src_pdo = i + 1; + } + + switch (port->state) { + case SRC_UNATTACHED: + case SRC_ATTACH_WAIT: + case SRC_TRYWAIT: + tcpm_set_cc(port, tcpm_rp_cc(port)); + break; + case SRC_SEND_CAPABILITIES: + case SRC_SEND_CAPABILITIES_TIMEOUT: + case SRC_NEGOTIATE_CAPABILITIES: + case SRC_READY: + case SRC_WAIT_NEW_CAPABILITIES: + port->caps_count = 0; + port->upcoming_state = SRC_SEND_CAPABILITIES; + ret = tcpm_ams_start(port, POWER_NEGOTIATION); + if (ret == -EAGAIN) { + port->upcoming_state = INVALID_STATE; + goto unlock; + } + break; + case SNK_NEGOTIATE_CAPABILITIES: + case SNK_NEGOTIATE_PPS_CAPABILITIES: + case SNK_READY: + case SNK_TRANSITION_SINK: + case SNK_TRANSITION_SINK_VBUS: + if (port->pps_data.active) + port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES; + else if (port->pd_capable) + port->upcoming_state = SNK_NEGOTIATE_CAPABILITIES; + else + break; + + port->update_sink_caps = true; + + ret = tcpm_ams_start(port, POWER_NEGOTIATION); + if (ret == -EAGAIN) { + port->upcoming_state = INVALID_STATE; + goto unlock; + } + break; + default: + break; + } + + port->port_source_caps = data->source_cap; + port->port_sink_caps = data->sink_cap; + port->selected_pd = pd; +unlock: + mutex_unlock(&port->lock); + return ret; +} + static const struct typec_operations tcpm_ops = { .try_role = tcpm_try_role, .dr_set = tcpm_dr_set, .pr_set = tcpm_pr_set, .vconn_set = tcpm_vconn_set, - .port_type_set = tcpm_port_type_set + .port_type_set = tcpm_port_type_set, + .pd_get = tcpm_pd_get, + .pd_set = tcpm_pd_set }; void tcpm_tcpc_reset(struct tcpm_port *port) @@ -6063,58 +6192,63 @@ EXPORT_SYMBOL_GPL(tcpm_tcpc_reset); static void tcpm_port_unregister_pd(struct tcpm_port *port) { - usb_power_delivery_unregister_capabilities(port->port_sink_caps); + int i; + port->port_sink_caps = NULL; - usb_power_delivery_unregister_capabilities(port->port_source_caps); port->port_source_caps = NULL; - usb_power_delivery_unregister(port->pd); - port->pd = NULL; + for (i = 0; i < port->pd_count; i++) { + usb_power_delivery_unregister_capabilities(port->pd_list[i]->sink_cap); + kfree(port->pd_list[i]->sink_cap); + usb_power_delivery_unregister_capabilities(port->pd_list[i]->source_cap); + kfree(port->pd_list[i]->source_cap); + devm_kfree(port->dev, port->pd_list[i]); + port->pd_list[i] = NULL; + usb_power_delivery_unregister(port->pds[i]); + port->pds[i] = NULL; + } } static int tcpm_port_register_pd(struct tcpm_port *port) { struct usb_power_delivery_desc desc = { port->typec_caps.pd_revision }; - struct usb_power_delivery_capabilities_desc caps = { }; struct usb_power_delivery_capabilities *cap; - int ret; + int ret, i; if (!port->nr_src_pdo && !port->nr_snk_pdo) return 0; - port->pd = usb_power_delivery_register(port->dev, &desc); - if (IS_ERR(port->pd)) { - ret = PTR_ERR(port->pd); - goto err_unregister; - } - - if (port->nr_src_pdo) { - memcpy_and_pad(caps.pdo, sizeof(caps.pdo), port->src_pdo, - port->nr_src_pdo * sizeof(u32), 0); - caps.role = TYPEC_SOURCE; - - cap = usb_power_delivery_register_capabilities(port->pd, &caps); - if (IS_ERR(cap)) { - ret = PTR_ERR(cap); + for (i = 0; i < port->pd_count; i++) { + port->pds[i] = usb_power_delivery_register(port->dev, &desc); + if (IS_ERR(port->pds[i])) { + ret = PTR_ERR(port->pds[i]); goto err_unregister; } + port->pd_list[i]->pd = port->pds[i]; - port->port_source_caps = cap; - } - - if (port->nr_snk_pdo) { - memcpy_and_pad(caps.pdo, sizeof(caps.pdo), port->snk_pdo, - port->nr_snk_pdo * sizeof(u32), 0); - caps.role = TYPEC_SINK; - - cap = usb_power_delivery_register_capabilities(port->pd, &caps); - if (IS_ERR(cap)) { - ret = PTR_ERR(cap); - goto err_unregister; + if (port->pd_list[i]->source_desc.pdo[0]) { + cap = usb_power_delivery_register_capabilities(port->pds[i], + &port->pd_list[i]->source_desc); + if (IS_ERR(cap)) { + ret = PTR_ERR(cap); + goto err_unregister; + } + port->pd_list[i]->source_cap = cap; } - port->port_sink_caps = cap; + if (port->pd_list[i]->sink_desc.pdo[0]) { + cap = usb_power_delivery_register_capabilities(port->pds[i], + &port->pd_list[i]->sink_desc); + if (IS_ERR(cap)) { + ret = PTR_ERR(cap); + goto err_unregister; + } + port->pd_list[i]->sink_cap = cap; + } } + port->port_source_caps = port->pd_list[0]->source_cap; + port->port_sink_caps = port->pd_list[0]->sink_cap; + port->selected_pd = port->pds[0]; return 0; err_unregister: @@ -6123,12 +6257,15 @@ err_unregister: return ret; } -static int tcpm_fw_get_caps(struct tcpm_port *port, - struct fwnode_handle *fwnode) +static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode) { + struct fwnode_handle *capabilities, *child, *caps = NULL; + unsigned int nr_src_pdo, nr_snk_pdo; const char *opmode_str; - int ret; - u32 mw, frs_current; + u32 *src_pdo, *snk_pdo; + u32 uw, frs_current; + int ret = 0, i; + int mode; if (!fwnode) return -EINVAL; @@ -6146,30 +6283,20 @@ static int tcpm_fw_get_caps(struct tcpm_port *port, if (ret < 0) return ret; + mode = 0; + + if (fwnode_property_read_bool(fwnode, "accessory-mode-audio")) + port->typec_caps.accessory[mode++] = TYPEC_ACCESSORY_AUDIO; + + if (fwnode_property_read_bool(fwnode, "accessory-mode-debug")) + port->typec_caps.accessory[mode++] = TYPEC_ACCESSORY_DEBUG; + port->port_type = port->typec_caps.type; port->pd_supported = !fwnode_property_read_bool(fwnode, "pd-disable"); - port->slow_charger_loop = fwnode_property_read_bool(fwnode, "slow-charger-loop"); - if (port->port_type == TYPEC_PORT_SNK) - goto sink; + port->self_powered = fwnode_property_read_bool(fwnode, "self-powered"); - /* Get Source PDOs for the PD port or Source Rp value for the non-PD port */ - if (port->pd_supported) { - ret = fwnode_property_count_u32(fwnode, "source-pdos"); - if (ret == 0) - return -EINVAL; - else if (ret < 0) - return ret; - - port->nr_src_pdo = min(ret, PDO_MAX_OBJECTS); - ret = fwnode_property_read_u32_array(fwnode, "source-pdos", - port->src_pdo, port->nr_src_pdo); - if (ret) - return ret; - ret = tcpm_validate_caps(port, port->src_pdo, port->nr_src_pdo); - if (ret) - return ret; - } else { + if (!port->pd_supported) { ret = fwnode_property_read_string(fwnode, "typec-power-opmode", &opmode_str); if (ret) return ret; @@ -6177,45 +6304,150 @@ static int tcpm_fw_get_caps(struct tcpm_port *port, if (ret < 0) return ret; port->src_rp = tcpm_pwr_opmode_to_rp(ret); + return 0; } - if (port->port_type == TYPEC_PORT_SRC) - return 0; - -sink: - port->self_powered = fwnode_property_read_bool(fwnode, "self-powered"); - - if (!port->pd_supported) - return 0; - - /* Get sink pdos */ - ret = fwnode_property_count_u32(fwnode, "sink-pdos"); - if (ret <= 0) - return -EINVAL; - - port->nr_snk_pdo = min(ret, PDO_MAX_OBJECTS); - ret = fwnode_property_read_u32_array(fwnode, "sink-pdos", - port->snk_pdo, port->nr_snk_pdo); - if ((ret < 0) || tcpm_validate_caps(port, port->snk_pdo, - port->nr_snk_pdo)) - return -EINVAL; - - if (fwnode_property_read_u32(fwnode, "op-sink-microwatt", &mw) < 0) - return -EINVAL; - port->operating_snk_mw = mw / 1000; + /* The following code are applicable to pd-capable ports, i.e. pd_supported is true. */ /* FRS can only be supported by DRP ports */ if (port->port_type == TYPEC_PORT_DRP) { ret = fwnode_property_read_u32(fwnode, "new-source-frs-typec-current", &frs_current); - if (ret >= 0 && frs_current <= FRS_5V_3A) + if (!ret && frs_current <= FRS_5V_3A) port->new_source_frs_current = frs_current; + + if (ret) + ret = 0; } + /* For the backward compatibility, "capabilities" node is optional. */ + capabilities = fwnode_get_named_child_node(fwnode, "capabilities"); + if (!capabilities) { + port->pd_count = 1; + } else { + fwnode_for_each_child_node(capabilities, child) + port->pd_count++; + + if (!port->pd_count) { + ret = -ENODATA; + goto put_capabilities; + } + } + + port->pds = devm_kcalloc(port->dev, port->pd_count, sizeof(struct usb_power_delivery *), + GFP_KERNEL); + if (!port->pds) { + ret = -ENOMEM; + goto put_capabilities; + } + + port->pd_list = devm_kcalloc(port->dev, port->pd_count, sizeof(struct pd_data *), + GFP_KERNEL); + if (!port->pd_list) { + ret = -ENOMEM; + goto put_capabilities; + } + + for (i = 0; i < port->pd_count; i++) { + port->pd_list[i] = devm_kzalloc(port->dev, sizeof(struct pd_data), GFP_KERNEL); + if (!port->pd_list[i]) { + ret = -ENOMEM; + goto put_capabilities; + } + + src_pdo = port->pd_list[i]->source_desc.pdo; + port->pd_list[i]->source_desc.role = TYPEC_SOURCE; + snk_pdo = port->pd_list[i]->sink_desc.pdo; + port->pd_list[i]->sink_desc.role = TYPEC_SINK; + + /* If "capabilities" is NULL, fall back to single pd cap population. */ + if (!capabilities) + caps = fwnode; + else + caps = fwnode_get_next_child_node(capabilities, caps); + + if (port->port_type != TYPEC_PORT_SNK) { + ret = fwnode_property_count_u32(caps, "source-pdos"); + if (ret == 0) { + ret = -EINVAL; + goto put_caps; + } + if (ret < 0) + goto put_caps; + + nr_src_pdo = min(ret, PDO_MAX_OBJECTS); + ret = fwnode_property_read_u32_array(caps, "source-pdos", src_pdo, + nr_src_pdo); + if (ret) + goto put_caps; + + ret = tcpm_validate_caps(port, src_pdo, nr_src_pdo); + if (ret) + goto put_caps; + + if (i == 0) { + port->nr_src_pdo = nr_src_pdo; + memcpy_and_pad(port->src_pdo, sizeof(u32) * PDO_MAX_OBJECTS, + port->pd_list[0]->source_desc.pdo, + sizeof(u32) * nr_src_pdo, + 0); + } + } + + if (port->port_type != TYPEC_PORT_SRC) { + ret = fwnode_property_count_u32(caps, "sink-pdos"); + if (ret == 0) { + ret = -EINVAL; + goto put_caps; + } + + if (ret < 0) + goto put_caps; + + nr_snk_pdo = min(ret, PDO_MAX_OBJECTS); + ret = fwnode_property_read_u32_array(caps, "sink-pdos", snk_pdo, + nr_snk_pdo); + if (ret) + goto put_caps; + + ret = tcpm_validate_caps(port, snk_pdo, nr_snk_pdo); + if (ret) + goto put_caps; + + if (fwnode_property_read_u32(caps, "op-sink-microwatt", &uw) < 0) { + ret = -EINVAL; + goto put_caps; + } + + port->pd_list[i]->operating_snk_mw = uw / 1000; + + if (i == 0) { + port->nr_snk_pdo = nr_snk_pdo; + memcpy_and_pad(port->snk_pdo, sizeof(u32) * PDO_MAX_OBJECTS, + port->pd_list[0]->sink_desc.pdo, + sizeof(u32) * nr_snk_pdo, + 0); + port->operating_snk_mw = port->pd_list[0]->operating_snk_mw; + } + } + } + +put_caps: + if (caps != fwnode) + fwnode_handle_put(caps); +put_capabilities: + fwnode_handle_put(capabilities); + return ret; +} + +static int tcpm_fw_get_snk_vdos(struct tcpm_port *port, struct fwnode_handle *fwnode) +{ + int ret; + /* sink-vdos is optional */ ret = fwnode_property_count_u32(fwnode, "sink-vdos"); if (ret < 0) - ret = 0; + return 0; port->nr_snk_vdo = min(ret, VDO_MAX_OBJECTS); if (port->nr_snk_vdo) { @@ -6581,12 +6813,14 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpm_debugfs_init(port); err = tcpm_fw_get_caps(port, tcpc->fwnode); + if (err < 0) + goto out_destroy_wq; + err = tcpm_fw_get_snk_vdos(port, tcpc->fwnode); if (err < 0) goto out_destroy_wq; port->try_role = port->typec_caps.prefer_role; - port->typec_caps.fwnode = tcpc->fwnode; port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */ port->typec_caps.pd_revision = 0x0300; /* USB-PD spec release 3.0 */ port->typec_caps.svdm_version = SVDM_VER_2_0; @@ -6595,7 +6829,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->typec_caps.orientation_aware = 1; port->partner_desc.identity = &port->partner_ident; - port->port_type = port->typec_caps.type; port->role_sw = usb_role_switch_get(port->dev); if (!port->role_sw) @@ -6614,7 +6847,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) if (err) goto out_role_sw_put; - port->typec_caps.pd = port->pd; + port->typec_caps.pd = port->pds[0]; port->typec_port = typec_register_port(port->dev, &port->typec_caps); if (IS_ERR(port->typec_port)) { diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 196535ad996d..0717cfcd9f8c 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,9 @@ #define TPS_PBMC_RC 0 /* Return code */ #define TPS_PBMC_DPCS 2 /* device patch complete status */ +/* reset de-assertion to ready for operation */ +#define TPS_SETUP_MS 1000 + enum { TPS_PORTINFO_SINK, TPS_PORTINFO_SINK_ACCESSORY, @@ -111,6 +115,8 @@ struct tipd_data { void (*trace_power_status)(u16 status); void (*trace_status)(u32 status); int (*apply_patch)(struct tps6598x *tps); + int (*init)(struct tps6598x *tps); + int (*reset)(struct tps6598x *tps); }; struct tps6598x { @@ -119,6 +125,7 @@ struct tps6598x { struct mutex lock; /* device lock */ u8 i2c_protocol:1; + struct gpio_desc *reset; struct typec_port *port; struct typec_partner *partner; struct usb_pd_identity partner_identity; @@ -323,7 +330,7 @@ static void tps6598x_disconnect(struct tps6598x *tps, u32 status) } static int tps6598x_exec_cmd_tmo(struct tps6598x *tps, const char *cmd, - size_t in_len, u8 *in_data, + size_t in_len, const u8 *in_data, size_t out_len, u8 *out_data, u32 cmd_timeout_ms, u32 res_delay_ms) { @@ -389,7 +396,7 @@ static int tps6598x_exec_cmd_tmo(struct tps6598x *tps, const char *cmd, } static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, - size_t in_len, u8 *in_data, + size_t in_len, const u8 *in_data, size_t out_len, u8 *out_data) { return tps6598x_exec_cmd_tmo(tps, cmd, in_len, in_data, @@ -866,6 +873,30 @@ tps6598x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) return 0; } +static int tps_request_firmware(struct tps6598x *tps, const struct firmware **fw) +{ + const char *firmware_name; + int ret; + + ret = device_property_read_string(tps->dev, "firmware-name", + &firmware_name); + if (ret) + return ret; + + ret = request_firmware(fw, firmware_name, tps->dev); + if (ret) { + dev_err(tps->dev, "failed to retrieve \"%s\"\n", firmware_name); + return ret; + } + + if ((*fw)->size == 0) { + release_firmware(*fw); + ret = -EINVAL; + } + + return ret; +} + static int tps25750_write_firmware(struct tps6598x *tps, u8 bpms_addr, const u8 *data, size_t len) @@ -954,16 +985,9 @@ static int tps25750_start_patch_burst_mode(struct tps6598x *tps) if (ret) return ret; - ret = request_firmware(&fw, firmware_name, tps->dev); - if (ret) { - dev_err(tps->dev, "failed to retrieve \"%s\"\n", firmware_name); + ret = tps_request_firmware(tps, &fw); + if (ret) return ret; - } - - if (fw->size == 0) { - ret = -EINVAL; - goto release_fw; - } ret = of_property_match_string(np, "reg-names", "patch-address"); if (ret < 0) { @@ -1101,6 +1125,76 @@ wait_for_app: return 0; }; +static int tps6598x_apply_patch(struct tps6598x *tps) +{ + u8 in = TPS_PTCS_CONTENT_DEV | TPS_PTCS_CONTENT_APP; + u8 out[TPS_MAX_LEN] = {0}; + size_t in_len = sizeof(in); + size_t copied_bytes = 0; + size_t bytes_left; + const struct firmware *fw; + const char *firmware_name; + int ret; + + ret = device_property_read_string(tps->dev, "firmware-name", + &firmware_name); + if (ret) + return ret; + + ret = tps_request_firmware(tps, &fw); + if (ret) + return ret; + + ret = tps6598x_exec_cmd(tps, "PTCs", in_len, &in, + TPS_PTCS_OUT_BYTES, out); + if (ret || out[TPS_PTCS_STATUS] == TPS_PTCS_STATUS_FAIL) { + if (!ret) + ret = -EBUSY; + dev_err(tps->dev, "Update start failed (%d)\n", ret); + goto release_fw; + } + + bytes_left = fw->size; + while (bytes_left) { + if (bytes_left < TPS_MAX_LEN) + in_len = bytes_left; + else + in_len = TPS_MAX_LEN; + ret = tps6598x_exec_cmd(tps, "PTCd", in_len, + fw->data + copied_bytes, + TPS_PTCD_OUT_BYTES, out); + if (ret || out[TPS_PTCD_TRANSFER_STATUS] || + out[TPS_PTCD_LOADING_STATE] == TPS_PTCD_LOAD_ERR) { + if (!ret) + ret = -EBUSY; + dev_err(tps->dev, "Patch download failed (%d)\n", ret); + goto release_fw; + } + copied_bytes += in_len; + bytes_left -= in_len; + } + + ret = tps6598x_exec_cmd(tps, "PTCc", 0, NULL, TPS_PTCC_OUT_BYTES, out); + if (ret || out[TPS_PTCC_DEV] || out[TPS_PTCC_APP]) { + if (!ret) + ret = -EBUSY; + dev_err(tps->dev, "Update completion failed (%d)\n", ret); + goto release_fw; + } + msleep(TPS_SETUP_MS); + dev_info(tps->dev, "Firmware update succeeded\n"); + +release_fw: + release_firmware(fw); + + return ret; +}; + +static int cd321x_init(struct tps6598x *tps) +{ + return 0; +} + static int tps25750_init(struct tps6598x *tps) { int ret; @@ -1119,6 +1213,26 @@ static int tps25750_init(struct tps6598x *tps) return 0; } +static int tps6598x_init(struct tps6598x *tps) +{ + return tps->data->apply_patch(tps); +} + +static int cd321x_reset(struct tps6598x *tps) +{ + return 0; +} + +static int tps25750_reset(struct tps6598x *tps) +{ + return tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0); +} + +static int tps6598x_reset(struct tps6598x *tps) +{ + return 0; +} + static int tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) { @@ -1182,7 +1296,6 @@ static int tps6598x_probe(struct i2c_client *client) u32 vid; int ret; u64 mask1; - bool is_tps25750; tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) @@ -1191,12 +1304,18 @@ static int tps6598x_probe(struct i2c_client *client) mutex_init(&tps->lock); tps->dev = &client->dev; + tps->reset = devm_gpiod_get_optional(tps->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(tps->reset)) + return dev_err_probe(tps->dev, PTR_ERR(tps->reset), + "failed to get reset GPIO\n"); + if (tps->reset) + msleep(TPS_SETUP_MS); + tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config); if (IS_ERR(tps->regmap)) return PTR_ERR(tps->regmap); - is_tps25750 = device_is_compatible(tps->dev, "ti,tps25750"); - if (!is_tps25750) { + if (!device_is_compatible(tps->dev, "ti,tps25750")) { ret = tps6598x_read32(tps, TPS_REG_VID, &vid); if (ret < 0 || !vid) return -ENODEV; @@ -1239,8 +1358,8 @@ static int tps6598x_probe(struct i2c_client *client) if (ret < 0) return ret; - if (is_tps25750 && ret == TPS_MODE_PTCH) { - ret = tps25750_init(tps); + if (ret == TPS_MODE_PTCH) { + ret = tps->data->init(tps); if (ret) return ret; } @@ -1328,8 +1447,8 @@ err_clear_mask: tps6598x_write64(tps, TPS_REG_INT_MASK1, 0); err_reset_controller: /* Reset PD controller to remove any applied patch */ - if (is_tps25750) - tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0); + tps->data->reset(tps); + return ret; } @@ -1346,8 +1465,10 @@ static void tps6598x_remove(struct i2c_client *client) usb_role_switch_put(tps->role_sw); /* Reset PD controller to remove any applied patch */ - if (device_is_compatible(tps->dev, "ti,tps25750")) - tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0); + tps->data->reset(tps); + + if (tps->reset) + gpiod_set_value_cansleep(tps->reset, 1); } static int __maybe_unused tps6598x_suspend(struct device *dev) @@ -1358,6 +1479,8 @@ static int __maybe_unused tps6598x_suspend(struct device *dev) if (tps->wakeup) { disable_irq(client->irq); enable_irq_wake(client->irq); + } else if (tps->reset) { + gpiod_set_value_cansleep(tps->reset, 1); } if (!client->irq) @@ -1376,8 +1499,8 @@ static int __maybe_unused tps6598x_resume(struct device *dev) if (ret < 0) return ret; - if (device_is_compatible(tps->dev, "ti,tps25750") && ret == TPS_MODE_PTCH) { - ret = tps25750_init(tps); + if (ret == TPS_MODE_PTCH) { + ret = tps->data->init(tps); if (ret) return ret; } @@ -1385,6 +1508,9 @@ static int __maybe_unused tps6598x_resume(struct device *dev) if (tps->wakeup) { disable_irq_wake(client->irq); enable_irq(client->irq); + } else if (tps->reset) { + gpiod_set_value_cansleep(tps->reset, 0); + msleep(TPS_SETUP_MS); } if (!client->irq) @@ -1403,6 +1529,8 @@ static const struct tipd_data cd321x_data = { .register_port = tps6598x_register_port, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, + .init = cd321x_init, + .reset = cd321x_reset, }; static const struct tipd_data tps6598x_data = { @@ -1410,6 +1538,9 @@ static const struct tipd_data tps6598x_data = { .register_port = tps6598x_register_port, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, + .apply_patch = tps6598x_apply_patch, + .init = tps6598x_init, + .reset = tps6598x_reset, }; static const struct tipd_data tps25750_data = { @@ -1418,6 +1549,8 @@ static const struct tipd_data tps25750_data = { .trace_power_status = trace_tps25750_power_status, .trace_status = trace_tps25750_status, .apply_patch = tps25750_apply_patch, + .init = tps25750_init, + .reset = tps25750_reset, }; static const struct of_device_id tps6598x_of_match[] = { diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h index 01609bf509e4..89b24519463a 100644 --- a/drivers/usb/typec/tipd/tps6598x.h +++ b/drivers/usb/typec/tipd/tps6598x.h @@ -235,4 +235,22 @@ /* SLEEP CONF REG */ #define TPS_SLEEP_CONF_SLEEP_MODE_ALLOWED BIT(0) +/* Start Patch Download Sequence */ +#define TPS_PTCS_CONTENT_APP BIT(0) +#define TPS_PTCS_CONTENT_DEV BIT(1) +#define TPS_PTCS_OUT_BYTES 4 +#define TPS_PTCS_STATUS 1 + +#define TPS_PTCS_STATUS_FAIL 0x80 +/* Patch Download */ +#define TPS_PTCD_OUT_BYTES 10 +#define TPS_PTCD_TRANSFER_STATUS 1 +#define TPS_PTCD_LOADING_STATE 2 + +#define TPS_PTCD_LOAD_ERR 0x09 +/* Patch Download Complete */ +#define TPS_PTCC_OUT_BYTES 4 +#define TPS_PTCC_DEV 2 +#define TPS_PTCC_APP 3 + #endif /* __TPS6598X_H__ */ diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 0a6624d37929..79110a69d697 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -377,14 +377,14 @@ static int __init usbip_host_init(void) goto err_usb_register; } - ret = driver_create_file(&stub_driver.drvwrap.driver, + ret = driver_create_file(&stub_driver.driver, &driver_attr_match_busid); if (ret) { pr_err("driver_create_file failed\n"); goto err_create_file; } - ret = driver_create_file(&stub_driver.drvwrap.driver, + ret = driver_create_file(&stub_driver.driver, &driver_attr_rebind); if (ret) { pr_err("driver_create_file failed\n"); @@ -402,10 +402,10 @@ err_usb_register: static void __exit usbip_host_exit(void) { - driver_remove_file(&stub_driver.drvwrap.driver, + driver_remove_file(&stub_driver.driver, &driver_attr_match_busid); - driver_remove_file(&stub_driver.drvwrap.driver, + driver_remove_file(&stub_driver.driver, &driver_attr_rebind); /* diff --git a/drivers/usb/usbip/vudc.h b/drivers/usb/usbip/vudc.h index 1bd4bc005829..faf61c9c6a98 100644 --- a/drivers/usb/usbip/vudc.h +++ b/drivers/usb/usbip/vudc.h @@ -173,6 +173,6 @@ struct vudc_device *alloc_vudc_device(int devid); void put_vudc_device(struct vudc_device *udc_dev); int vudc_probe(struct platform_device *pdev); -int vudc_remove(struct platform_device *pdev); +void vudc_remove(struct platform_device *pdev); #endif /* __USBIP_VUDC_H */ diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c index 44b04c54c086..f11535020e35 100644 --- a/drivers/usb/usbip/vudc_dev.c +++ b/drivers/usb/usbip/vudc_dev.c @@ -628,12 +628,11 @@ out: return ret; } -int vudc_remove(struct platform_device *pdev) +void vudc_remove(struct platform_device *pdev) { struct vudc *udc = platform_get_drvdata(pdev); usb_del_gadget_udc(&udc->gadget); cleanup_vudc_hw(udc); kfree(udc); - return 0; } diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c index 993e721cb840..8bee553e4894 100644 --- a/drivers/usb/usbip/vudc_main.c +++ b/drivers/usb/usbip/vudc_main.c @@ -19,7 +19,7 @@ MODULE_PARM_DESC(num, "number of emulated controllers"); static struct platform_driver vudc_driver = { .probe = vudc_probe, - .remove = vudc_remove, + .remove_new = vudc_remove, .driver = { .name = GADGET_NAME, .dev_groups = vudc_groups, diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index a1307b58cc2c..9120de05ead0 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h @@ -10,6 +10,11 @@ #ifndef ASM_ARM_HARDWARE_SERIAL_AMBA_H #define ASM_ARM_HARDWARE_SERIAL_AMBA_H +#ifndef __ASSEMBLY__ +#include +#include +#endif + #include /* ------------------------------------------------------------------------------- @@ -70,141 +75,145 @@ #define ZX_UART011_ICR 0x4c #define ZX_UART011_DMACR 0x50 -#define UART011_DR_OE (1 << 11) -#define UART011_DR_BE (1 << 10) -#define UART011_DR_PE (1 << 9) -#define UART011_DR_FE (1 << 8) +#define UART011_DR_OE BIT(11) +#define UART011_DR_BE BIT(10) +#define UART011_DR_PE BIT(9) +#define UART011_DR_FE BIT(8) -#define UART01x_RSR_OE 0x08 -#define UART01x_RSR_BE 0x04 -#define UART01x_RSR_PE 0x02 -#define UART01x_RSR_FE 0x01 +#define UART01x_RSR_OE BIT(3) +#define UART01x_RSR_BE BIT(2) +#define UART01x_RSR_PE BIT(1) +#define UART01x_RSR_FE BIT(0) -#define UART011_FR_RI 0x100 -#define UART011_FR_TXFE 0x080 -#define UART011_FR_RXFF 0x040 -#define UART01x_FR_TXFF 0x020 -#define UART01x_FR_RXFE 0x010 -#define UART01x_FR_BUSY 0x008 -#define UART01x_FR_DCD 0x004 -#define UART01x_FR_DSR 0x002 -#define UART01x_FR_CTS 0x001 +#define UART011_FR_RI BIT(8) +#define UART011_FR_TXFE BIT(7) +#define UART011_FR_RXFF BIT(6) +#define UART01x_FR_TXFF (1 << 5) /* used in ASM */ +#define UART01x_FR_RXFE BIT(4) +#define UART01x_FR_BUSY (1 << 3) /* used in ASM */ +#define UART01x_FR_DCD BIT(2) +#define UART01x_FR_DSR BIT(1) +#define UART01x_FR_CTS BIT(0) #define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) /* * Some bits of Flag Register on ZTE device have different position from * standard ones. */ -#define ZX_UART01x_FR_BUSY 0x100 -#define ZX_UART01x_FR_DSR 0x008 -#define ZX_UART01x_FR_CTS 0x002 -#define ZX_UART011_FR_RI 0x001 +#define ZX_UART01x_FR_BUSY BIT(8) +#define ZX_UART01x_FR_DSR BIT(3) +#define ZX_UART01x_FR_CTS BIT(1) +#define ZX_UART011_FR_RI BIT(0) -#define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ -#define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */ -#define UART011_CR_OUT2 0x2000 /* OUT2 */ -#define UART011_CR_OUT1 0x1000 /* OUT1 */ -#define UART011_CR_RTS 0x0800 /* RTS */ -#define UART011_CR_DTR 0x0400 /* DTR */ -#define UART011_CR_RXE 0x0200 /* receive enable */ -#define UART011_CR_TXE 0x0100 /* transmit enable */ -#define UART011_CR_LBE 0x0080 /* loopback enable */ -#define UART010_CR_RTIE 0x0040 -#define UART010_CR_TIE 0x0020 -#define UART010_CR_RIE 0x0010 -#define UART010_CR_MSIE 0x0008 -#define ST_UART011_CR_OVSFACT 0x0008 /* Oversampling factor */ -#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */ -#define UART01x_CR_SIREN 0x0002 /* SIR enable */ -#define UART01x_CR_UARTEN 0x0001 /* UART enable */ - -#define UART011_LCRH_SPS 0x80 +#define UART011_CR_CTSEN BIT(15) /* CTS hardware flow control */ +#define UART011_CR_RTSEN BIT(14) /* RTS hardware flow control */ +#define UART011_CR_OUT2 BIT(13) /* OUT2 */ +#define UART011_CR_OUT1 BIT(12) /* OUT1 */ +#define UART011_CR_RTS BIT(11) /* RTS */ +#define UART011_CR_DTR BIT(10) /* DTR */ +#define UART011_CR_RXE BIT(9) /* receive enable */ +#define UART011_CR_TXE BIT(8) /* transmit enable */ +#define UART011_CR_LBE BIT(7) /* loopback enable */ +#define UART010_CR_RTIE BIT(6) +#define UART010_CR_TIE BIT(5) +#define UART010_CR_RIE BIT(4) +#define UART010_CR_MSIE BIT(3) +#define ST_UART011_CR_OVSFACT BIT(3) /* Oversampling factor */ +#define UART01x_CR_IIRLP BIT(2) /* SIR low power mode */ +#define UART01x_CR_SIREN BIT(1) /* SIR enable */ +#define UART01x_CR_UARTEN BIT(0) /* UART enable */ + +#define UART011_LCRH_SPS BIT(7) #define UART01x_LCRH_WLEN_8 0x60 #define UART01x_LCRH_WLEN_7 0x40 #define UART01x_LCRH_WLEN_6 0x20 #define UART01x_LCRH_WLEN_5 0x00 -#define UART01x_LCRH_FEN 0x10 -#define UART01x_LCRH_STP2 0x08 -#define UART01x_LCRH_EPS 0x04 -#define UART01x_LCRH_PEN 0x02 -#define UART01x_LCRH_BRK 0x01 +#define UART01x_LCRH_FEN BIT(4) +#define UART01x_LCRH_STP2 BIT(3) +#define UART01x_LCRH_EPS BIT(2) +#define UART01x_LCRH_PEN BIT(1) +#define UART01x_LCRH_BRK BIT(0) -#define ST_UART011_DMAWM_RX_1 (0 << 3) -#define ST_UART011_DMAWM_RX_2 (1 << 3) -#define ST_UART011_DMAWM_RX_4 (2 << 3) -#define ST_UART011_DMAWM_RX_8 (3 << 3) -#define ST_UART011_DMAWM_RX_16 (4 << 3) -#define ST_UART011_DMAWM_RX_32 (5 << 3) -#define ST_UART011_DMAWM_RX_48 (6 << 3) -#define ST_UART011_DMAWM_TX_1 0 -#define ST_UART011_DMAWM_TX_2 1 -#define ST_UART011_DMAWM_TX_4 2 -#define ST_UART011_DMAWM_TX_8 3 -#define ST_UART011_DMAWM_TX_16 4 -#define ST_UART011_DMAWM_TX_32 5 -#define ST_UART011_DMAWM_TX_48 6 +#define ST_UART011_DMAWM_RX GENMASK(5, 3) +#define ST_UART011_DMAWM_RX_1 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 0) +#define ST_UART011_DMAWM_RX_2 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 1) +#define ST_UART011_DMAWM_RX_4 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 2) +#define ST_UART011_DMAWM_RX_8 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 3) +#define ST_UART011_DMAWM_RX_16 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 4) +#define ST_UART011_DMAWM_RX_32 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 5) +#define ST_UART011_DMAWM_RX_48 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 6) +#define ST_UART011_DMAWM_TX GENMASK(2, 0) +#define ST_UART011_DMAWM_TX_1 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 0) +#define ST_UART011_DMAWM_TX_2 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 1) +#define ST_UART011_DMAWM_TX_4 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 2) +#define ST_UART011_DMAWM_TX_8 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 3) +#define ST_UART011_DMAWM_TX_16 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 4) +#define ST_UART011_DMAWM_TX_32 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 5) +#define ST_UART011_DMAWM_TX_48 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 6) -#define UART010_IIR_RTIS 0x08 -#define UART010_IIR_TIS 0x04 -#define UART010_IIR_RIS 0x02 -#define UART010_IIR_MIS 0x01 +#define UART010_IIR_RTIS BIT(3) +#define UART010_IIR_TIS BIT(2) +#define UART010_IIR_RIS BIT(1) +#define UART010_IIR_MIS BIT(0) -#define UART011_IFLS_RX1_8 (0 << 3) -#define UART011_IFLS_RX2_8 (1 << 3) -#define UART011_IFLS_RX4_8 (2 << 3) -#define UART011_IFLS_RX6_8 (3 << 3) -#define UART011_IFLS_RX7_8 (4 << 3) -#define UART011_IFLS_TX1_8 (0 << 0) -#define UART011_IFLS_TX2_8 (1 << 0) -#define UART011_IFLS_TX4_8 (2 << 0) -#define UART011_IFLS_TX6_8 (3 << 0) -#define UART011_IFLS_TX7_8 (4 << 0) +#define UART011_IFLS_RXIFLSEL GENMASK(5, 3) +#define UART011_IFLS_RX1_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 0) +#define UART011_IFLS_RX2_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 1) +#define UART011_IFLS_RX4_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 2) +#define UART011_IFLS_RX6_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 3) +#define UART011_IFLS_RX7_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 4) +#define UART011_IFLS_TXIFLSEL GENMASK(2, 0) +#define UART011_IFLS_TX1_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 0) +#define UART011_IFLS_TX2_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 1) +#define UART011_IFLS_TX4_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 2) +#define UART011_IFLS_TX6_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 3) +#define UART011_IFLS_TX7_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 4) /* special values for ST vendor with deeper fifo */ -#define UART011_IFLS_RX_HALF (5 << 3) -#define UART011_IFLS_TX_HALF (5 << 0) +#define UART011_IFLS_RX_HALF FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 5) +#define UART011_IFLS_TX_HALF FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 5) -#define UART011_OEIM (1 << 10) /* overrun error interrupt mask */ -#define UART011_BEIM (1 << 9) /* break error interrupt mask */ -#define UART011_PEIM (1 << 8) /* parity error interrupt mask */ -#define UART011_FEIM (1 << 7) /* framing error interrupt mask */ -#define UART011_RTIM (1 << 6) /* receive timeout interrupt mask */ -#define UART011_TXIM (1 << 5) /* transmit interrupt mask */ -#define UART011_RXIM (1 << 4) /* receive interrupt mask */ -#define UART011_DSRMIM (1 << 3) /* DSR interrupt mask */ -#define UART011_DCDMIM (1 << 2) /* DCD interrupt mask */ -#define UART011_CTSMIM (1 << 1) /* CTS interrupt mask */ -#define UART011_RIMIM (1 << 0) /* RI interrupt mask */ +#define UART011_OEIM BIT(10) /* overrun error interrupt mask */ +#define UART011_BEIM BIT(9) /* break error interrupt mask */ +#define UART011_PEIM BIT(8) /* parity error interrupt mask */ +#define UART011_FEIM BIT(7) /* framing error interrupt mask */ +#define UART011_RTIM BIT(6) /* receive timeout interrupt mask */ +#define UART011_TXIM BIT(5) /* transmit interrupt mask */ +#define UART011_RXIM BIT(4) /* receive interrupt mask */ +#define UART011_DSRMIM BIT(3) /* DSR interrupt mask */ +#define UART011_DCDMIM BIT(2) /* DCD interrupt mask */ +#define UART011_CTSMIM BIT(1) /* CTS interrupt mask */ +#define UART011_RIMIM BIT(0) /* RI interrupt mask */ -#define UART011_OEIS (1 << 10) /* overrun error interrupt status */ -#define UART011_BEIS (1 << 9) /* break error interrupt status */ -#define UART011_PEIS (1 << 8) /* parity error interrupt status */ -#define UART011_FEIS (1 << 7) /* framing error interrupt status */ -#define UART011_RTIS (1 << 6) /* receive timeout interrupt status */ -#define UART011_TXIS (1 << 5) /* transmit interrupt status */ -#define UART011_RXIS (1 << 4) /* receive interrupt status */ -#define UART011_DSRMIS (1 << 3) /* DSR interrupt status */ -#define UART011_DCDMIS (1 << 2) /* DCD interrupt status */ -#define UART011_CTSMIS (1 << 1) /* CTS interrupt status */ -#define UART011_RIMIS (1 << 0) /* RI interrupt status */ +#define UART011_OEIS BIT(10) /* overrun error interrupt status */ +#define UART011_BEIS BIT(9) /* break error interrupt status */ +#define UART011_PEIS BIT(8) /* parity error interrupt status */ +#define UART011_FEIS BIT(7) /* framing error interrupt status */ +#define UART011_RTIS BIT(6) /* receive timeout interrupt status */ +#define UART011_TXIS BIT(5) /* transmit interrupt status */ +#define UART011_RXIS BIT(4) /* receive interrupt status */ +#define UART011_DSRMIS BIT(3) /* DSR interrupt status */ +#define UART011_DCDMIS BIT(2) /* DCD interrupt status */ +#define UART011_CTSMIS BIT(1) /* CTS interrupt status */ +#define UART011_RIMIS BIT(0) /* RI interrupt status */ -#define UART011_OEIC (1 << 10) /* overrun error interrupt clear */ -#define UART011_BEIC (1 << 9) /* break error interrupt clear */ -#define UART011_PEIC (1 << 8) /* parity error interrupt clear */ -#define UART011_FEIC (1 << 7) /* framing error interrupt clear */ -#define UART011_RTIC (1 << 6) /* receive timeout interrupt clear */ -#define UART011_TXIC (1 << 5) /* transmit interrupt clear */ -#define UART011_RXIC (1 << 4) /* receive interrupt clear */ -#define UART011_DSRMIC (1 << 3) /* DSR interrupt clear */ -#define UART011_DCDMIC (1 << 2) /* DCD interrupt clear */ -#define UART011_CTSMIC (1 << 1) /* CTS interrupt clear */ -#define UART011_RIMIC (1 << 0) /* RI interrupt clear */ +#define UART011_OEIC BIT(10) /* overrun error interrupt clear */ +#define UART011_BEIC BIT(9) /* break error interrupt clear */ +#define UART011_PEIC BIT(8) /* parity error interrupt clear */ +#define UART011_FEIC BIT(7) /* framing error interrupt clear */ +#define UART011_RTIC BIT(6) /* receive timeout interrupt clear */ +#define UART011_TXIC BIT(5) /* transmit interrupt clear */ +#define UART011_RXIC BIT(4) /* receive interrupt clear */ +#define UART011_DSRMIC BIT(3) /* DSR interrupt clear */ +#define UART011_DCDMIC BIT(2) /* DCD interrupt clear */ +#define UART011_CTSMIC BIT(1) /* CTS interrupt clear */ +#define UART011_RIMIC BIT(0) /* RI interrupt clear */ -#define UART011_DMAONERR (1 << 2) /* disable dma on error */ -#define UART011_TXDMAE (1 << 1) /* enable transmit dma */ -#define UART011_RXDMAE (1 << 0) /* enable receive dma */ +#define UART011_DMAONERR BIT(2) /* disable dma on error */ +#define UART011_TXDMAE BIT(1) /* enable transmit dma */ +#define UART011_RXDMAE BIT(0) /* enable receive dma */ -#define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE) -#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS) +#define UART01x_RSR_ANY (UART01x_RSR_OE | UART01x_RSR_BE | UART01x_RSR_PE | UART01x_RSR_FE) +#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD | UART01x_FR_DSR | UART01x_FR_CTS) #ifndef __ASSEMBLY__ struct amba_device; /* in uncompress this is included but amba/bus.h is not */ @@ -220,8 +229,8 @@ struct amba_pl011_data { bool dma_rx_poll_enable; unsigned int dma_rx_poll_rate; unsigned int dma_rx_poll_timeout; - void (*init) (void); - void (*exit) (void); + void (*init)(void); + void (*exit)(void); }; #endif diff --git a/include/linux/serdev.h b/include/linux/serdev.h index f5f97fa25e8a..3fab88ba265e 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -27,7 +27,7 @@ struct serdev_device; * not sleep. */ struct serdev_device_ops { - int (*receive_buf)(struct serdev_device *, const unsigned char *, size_t); + ssize_t (*receive_buf)(struct serdev_device *, const u8 *, size_t); void (*write_wakeup)(struct serdev_device *); }; @@ -82,7 +82,7 @@ enum serdev_parity { * serdev controller structures */ struct serdev_controller_ops { - int (*write_buf)(struct serdev_controller *, const unsigned char *, size_t); + ssize_t (*write_buf)(struct serdev_controller *, const u8 *, size_t); void (*write_flush)(struct serdev_controller *); int (*write_room)(struct serdev_controller *); int (*open)(struct serdev_controller *); @@ -99,12 +99,14 @@ struct serdev_controller_ops { /** * struct serdev_controller - interface to the serdev controller * @dev: Driver model representation of the device. + * @host: Serial port hardware controller device * @nr: number identifier for this controller/bus. * @serdev: Pointer to slave device for this controller. * @ops: Controller operations. */ struct serdev_controller { struct device dev; + struct device *host; unsigned int nr; struct serdev_device *serdev; const struct serdev_controller_ops *ops; @@ -167,7 +169,9 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *); int serdev_device_add(struct serdev_device *); void serdev_device_remove(struct serdev_device *); -struct serdev_controller *serdev_controller_alloc(struct device *, size_t); +struct serdev_controller *serdev_controller_alloc(struct device *host, + struct device *parent, + size_t size); int serdev_controller_add(struct serdev_controller *); void serdev_controller_remove(struct serdev_controller *); @@ -181,9 +185,9 @@ static inline void serdev_controller_write_wakeup(struct serdev_controller *ctrl serdev->ops->write_wakeup(serdev); } -static inline int serdev_controller_receive_buf(struct serdev_controller *ctrl, - const unsigned char *data, - size_t count) +static inline ssize_t serdev_controller_receive_buf(struct serdev_controller *ctrl, + const u8 *data, + size_t count) { struct serdev_device *serdev = ctrl->serdev; @@ -200,13 +204,13 @@ void serdev_device_close(struct serdev_device *); int devm_serdev_device_open(struct device *, struct serdev_device *); unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int); void serdev_device_set_flow_control(struct serdev_device *, bool); -int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t); +int serdev_device_write_buf(struct serdev_device *, const u8 *, size_t); void serdev_device_wait_until_sent(struct serdev_device *, long); int serdev_device_get_tiocm(struct serdev_device *); int serdev_device_set_tiocm(struct serdev_device *, int, int); int serdev_device_break_ctl(struct serdev_device *serdev, int break_state); void serdev_device_write_wakeup(struct serdev_device *); -int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, long); +ssize_t serdev_device_write(struct serdev_device *, const u8 *, size_t, long); void serdev_device_write_flush(struct serdev_device *); int serdev_device_write_room(struct serdev_device *); @@ -244,7 +248,7 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev } static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {} static inline int serdev_device_write_buf(struct serdev_device *serdev, - const unsigned char *buf, + const u8 *buf, size_t count) { return -ENODEV; @@ -262,8 +266,9 @@ static inline int serdev_device_break_ctl(struct serdev_device *serdev, int brea { return -EOPNOTSUPP; } -static inline int serdev_device_write(struct serdev_device *sdev, const unsigned char *buf, - size_t count, unsigned long timeout) +static inline ssize_t serdev_device_write(struct serdev_device *sdev, + const u8 *buf, size_t count, + unsigned long timeout) { return -ENODEV; } @@ -311,11 +316,13 @@ struct tty_driver; #ifdef CONFIG_SERIAL_DEV_CTRL_TTYPORT struct device *serdev_tty_port_register(struct tty_port *port, + struct device *host, struct device *parent, struct tty_driver *drv, int idx); int serdev_tty_port_unregister(struct tty_port *port); #else static inline struct device *serdev_tty_port_register(struct tty_port *port, + struct device *host, struct device *parent, struct tty_driver *drv, int idx) { diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 89f7b6c63598..536b2581d3e2 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -852,9 +852,9 @@ static inline unsigned long uart_fifo_timeout(struct uart_port *port) } /* Base timer interval for polling */ -static inline int uart_poll_timeout(struct uart_port *port) +static inline unsigned long uart_poll_timeout(struct uart_port *port) { - int timeout = uart_fifo_timeout(port); + unsigned long timeout = uart_fifo_timeout(port); return timeout > 6 ? (timeout / 2 - 2) : 1; } diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index 6151c210d987..2c835e5c41f6 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -86,7 +86,7 @@ struct tb { unsigned long privdata[]; }; -extern struct bus_type tb_bus_type; +extern const struct bus_type tb_bus_type; extern struct device_type tb_service_type; extern struct device_type tb_xdomain_type; diff --git a/include/linux/tty.h b/include/linux/tty.h index d219a11e3fe0..8c76fd97d4ad 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -242,7 +242,7 @@ struct tty_struct { void *driver_data; spinlock_t files_lock; int write_cnt; - unsigned char *write_buf; + u8 *write_buf; struct list_head tty_files; @@ -393,8 +393,10 @@ extern const struct class tty_class; * tty_kref_get - get a tty reference * @tty: tty device * - * Returns: a new reference to a tty object. The caller must hold sufficient - * locks/counts to ensure that their existing reference cannot go away + * Returns: a new reference to a tty object + * + * Locking: The caller must hold sufficient locks/counts to ensure that their + * existing reference cannot go away. */ static inline struct tty_struct *tty_kref_get(struct tty_struct *tty) { @@ -408,8 +410,8 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout); void stop_tty(struct tty_struct *tty); void start_tty(struct tty_struct *tty); void tty_write_message(struct tty_struct *tty, char *msg); -int tty_send_xchar(struct tty_struct *tty, char ch); -int tty_put_char(struct tty_struct *tty, unsigned char c); +int tty_send_xchar(struct tty_struct *tty, u8 ch); +int tty_put_char(struct tty_struct *tty, u8 c); unsigned int tty_chars_in_buffer(struct tty_struct *tty); unsigned int tty_write_room(struct tty_struct *tty); void tty_driver_flush_buffer(struct tty_struct *tty); @@ -437,12 +439,11 @@ void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, * tty_get_baud_rate - get tty bit rates * @tty: tty to query * - * Returns: the baud rate as an integer for this terminal. The termios lock - * must be held by the caller and the terminal bit flags may be updated. + * Returns: the baud rate as an integer for this terminal * - * Locking: none + * Locking: The termios lock must be held by the caller. */ -static inline speed_t tty_get_baud_rate(struct tty_struct *tty) +static inline speed_t tty_get_baud_rate(const struct tty_struct *tty) { return tty_termios_baud_rate(&tty->termios); } diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 18beff0cec1a..7372124fbf90 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -72,8 +72,7 @@ struct serial_struct; * is closed for the last time freeing up the resources. This is * actually the second part of shutdown for routines that might sleep. * - * @write: ``ssize_t ()(struct tty_struct *tty, const unsigned char *buf, - * size_t count)`` + * @write: ``ssize_t ()(struct tty_struct *tty, const u8 *buf, size_t count)`` * * This routine is called by the kernel to write a series (@count) of * characters (@buf) to the @tty device. The characters may come from @@ -85,7 +84,7 @@ struct serial_struct; * * Optional: Required for writable devices. May not sleep. * - * @put_char: ``int ()(struct tty_struct *tty, unsigned char ch)`` + * @put_char: ``int ()(struct tty_struct *tty, u8 ch)`` * * This routine is called by the kernel to write a single character @ch to * the @tty device. If the kernel uses this routine, it must call the @@ -243,7 +242,7 @@ struct serial_struct; * Optional: If not provided, the device is assumed to have no FIFO. * Usually correct to invoke via tty_wait_until_sent(). May sleep. * - * @send_xchar: ``void ()(struct tty_struct *tty, char ch)`` + * @send_xchar: ``void ()(struct tty_struct *tty, u8 ch)`` * * This routine is used to send a high-priority XON/XOFF character (@ch) * to the @tty device. @@ -375,7 +374,7 @@ struct tty_operations { void (*flush_buffer)(struct tty_struct *tty); void (*set_ldisc)(struct tty_struct *tty); void (*wait_until_sent)(struct tty_struct *tty, int timeout); - void (*send_xchar)(struct tty_struct *tty, char ch); + void (*send_xchar)(struct tty_struct *tty, u8 ch); int (*tiocmget)(struct tty_struct *tty); int (*tiocmset)(struct tty_struct *tty, unsigned int set, unsigned int clear); diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 6b367eb17979..1b861f2100b6 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -114,8 +114,8 @@ struct tty_port { unsigned char console:1; struct mutex mutex; struct mutex buf_mutex; - unsigned char *xmit_buf; - DECLARE_KFIFO_PTR(xmit_fifo, unsigned char); + u8 *xmit_buf; + DECLARE_KFIFO_PTR(xmit_fifo, u8); unsigned int close_delay; unsigned int closing_wait; int drain_delay; @@ -149,10 +149,10 @@ struct device *tty_port_register_device_attr(struct tty_port *port, const struct attribute_group **attr_grp); struct device *tty_port_register_device_serdev(struct tty_port *port, struct tty_driver *driver, unsigned index, - struct device *device); + struct device *host, struct device *parent); struct device *tty_port_register_device_attr_serdev(struct tty_port *port, struct tty_driver *driver, unsigned index, - struct device *device, void *drvdata, + struct device *host, struct device *parent, void *drvdata, const struct attribute_group **attr_grp); void tty_port_unregister_device(struct tty_port *port, struct tty_driver *driver, unsigned index); diff --git a/include/linux/usb.h b/include/linux/usb.h index 8c61643acd49..9e52179872a5 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -632,7 +632,6 @@ struct usb3_lpm_parameters { * @reset_resume: needs reset instead of resume * @port_is_suspended: the upstream port is suspended (L2 or U3) * @slot_id: Slot ID assigned by xHCI - * @removable: Device can be physically removed from this port * @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout. * @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout. * @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout. @@ -1144,16 +1143,6 @@ extern ssize_t usb_store_new_id(struct usb_dynids *dynids, extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf); -/** - * struct usbdrv_wrap - wrapper for driver-model structure - * @driver: The driver-model core driver structure. - * @for_devices: Non-zero for device drivers, 0 for interface drivers. - */ -struct usbdrv_wrap { - struct device_driver driver; - int for_devices; -}; - /** * struct usb_driver - identifies USB interface driver to usbcore * @name: The driver name should be unique among USB drivers, @@ -1194,7 +1183,7 @@ struct usbdrv_wrap { * is bound to the driver. * @dynids: used internally to hold the list of dynamically added device * ids for this driver. - * @drvwrap: Driver-model core structure wrapper. + * @driver: The driver-model core driver structure. * @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be * added to this driver by preventing the sysfs file from being created. * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend @@ -1242,13 +1231,13 @@ struct usb_driver { const struct attribute_group **dev_groups; struct usb_dynids dynids; - struct usbdrv_wrap drvwrap; + struct device_driver driver; unsigned int no_dynamic_id:1; unsigned int supports_autosuspend:1; unsigned int disable_hub_initiated_lpm:1; unsigned int soft_unbind:1; }; -#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver) +#define to_usb_driver(d) container_of(d, struct usb_driver, driver) /** * struct usb_device_driver - identifies USB device driver to usbcore @@ -1264,9 +1253,12 @@ struct usb_driver { * module is being unloaded. * @suspend: Called when the device is going to be suspended by the system. * @resume: Called when the device is being resumed by the system. + * @choose_configuration: If non-NULL, called instead of the default + * usb_choose_configuration(). If this returns an error then we'll go + * on to call the normal usb_choose_configuration(). * @dev_groups: Attributes attached to the device that will be created once it * is bound to the driver. - * @drvwrap: Driver-model core structure wrapper. + * @driver: The driver-model core driver structure. * @id_table: used with @match() to select better matching driver at * probe() time. * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend @@ -1275,7 +1267,7 @@ struct usb_driver { * resume and suspend functions will be called in addition to the driver's * own, so this part of the setup does not need to be replicated. * - * USB drivers must provide all the fields listed above except drvwrap, + * USB drivers must provide all the fields listed above except driver, * match, and id_table. */ struct usb_device_driver { @@ -1287,14 +1279,17 @@ struct usb_device_driver { int (*suspend) (struct usb_device *udev, pm_message_t message); int (*resume) (struct usb_device *udev, pm_message_t message); + + int (*choose_configuration) (struct usb_device *udev); + const struct attribute_group **dev_groups; - struct usbdrv_wrap drvwrap; + struct device_driver driver; const struct usb_device_id *id_table; unsigned int supports_autosuspend:1; unsigned int generic_subclass:1; }; #define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \ - drvwrap.driver) + driver) /** * struct usb_class_driver - identifies a USB driver that wants to use the USB major number diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 6532beb587b1..a771ccc038ac 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -236,6 +236,7 @@ struct usb_ep { unsigned max_streams:16; unsigned mult:2; unsigned maxburst:5; + unsigned fifo_mode:1; u8 address; const struct usb_endpoint_descriptor *desc; const struct usb_ss_ep_comp_descriptor *comp_desc; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 00724b4f6e12..cd77fc6095a1 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -372,8 +372,9 @@ struct hc_driver { * or bandwidth constraints. */ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); - /* Returns the hardware-chosen device address */ - int (*address_device)(struct usb_hcd *, struct usb_device *udev); + /* Set the hardware-chosen device address */ + int (*address_device)(struct usb_hcd *, struct usb_device *udev, + unsigned int timeout_ms); /* prepares the hardware to send commands to the device */ int (*enable_device)(struct usb_hcd *, struct usb_device *udev); /* Notifies the HCD after a hub descriptor is fetched. diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index eeb7c2157c72..59409c1fc3de 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -72,4 +72,7 @@ /* device has endpoints that should be ignored */ #define USB_QUIRK_ENDPOINT_IGNORE BIT(15) +/* short SET_ADDRESS request timeout */ +#define USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT BIT(16) + #endif /* __LINUX_USB_QUIRKS_H */ diff --git a/include/linux/usb/tcpci.h b/include/linux/usb/tcpci.h index 83376473ac76..467e8045e9f8 100644 --- a/include/linux/usb/tcpci.h +++ b/include/linux/usb/tcpci.h @@ -36,7 +36,9 @@ #define TCPC_ALERT_MASK 0x12 #define TCPC_POWER_STATUS_MASK 0x14 -#define TCPC_FAULT_STATUS_MASK 0x15 + +#define TCPC_FAULT_STATUS_MASK 0x15 +#define TCPC_FAULT_STATUS_MASK_VCONN_OC BIT(1) #define TCPC_EXTENDED_STATUS_MASK 0x16 #define TCPC_EXTENDED_STATUS_MASK_VSAFE0V BIT(0) @@ -104,6 +106,7 @@ #define TCPC_FAULT_STATUS 0x1f #define TCPC_FAULT_STATUS_ALL_REG_RST_TO_DEFAULT BIT(7) +#define TCPC_FAULT_STATUS_VCONN_OC BIT(1) #define TCPC_ALERT_EXTENDED 0x21 diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index ab7ca872950b..65fac5e1f317 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -173,5 +173,6 @@ void tcpm_pd_hard_reset(struct tcpm_port *port); void tcpm_tcpc_reset(struct tcpm_port *port); void tcpm_port_clean(struct tcpm_port *port); bool tcpm_port_is_toggling(struct tcpm_port *port); +void tcpm_port_error_recovery(struct tcpm_port *port); #endif /* __LINUX_USB_TCPM_H */ diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h deleted file mode 100644 index d2e2785af602..000000000000 --- a/include/linux/virtio_console.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so - * anyone can use the definitions to implement compatible drivers/servers: - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Copyright (C) Red Hat, Inc., 2009, 2010, 2011 - * Copyright (C) Amit Shah , 2009, 2010, 2011 - */ -#ifndef _LINUX_VIRTIO_CONSOLE_H -#define _LINUX_VIRTIO_CONSOLE_H - -#include - -int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)); -#endif /* _LINUX_VIRTIO_CONSOLE_H */ diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index 53bc1af67a41..9086367db043 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -11,6 +11,7 @@ #ifndef _UAPI_LINUX_SERIAL_H #define _UAPI_LINUX_SERIAL_H +#include #include #include @@ -137,17 +138,19 @@ struct serial_icounter_struct { * * %SER_RS485_ADDRB - Enable RS485 addressing mode. * * %SER_RS485_ADDR_RECV - Receive address filter (enables @addr_recv). Requires %SER_RS485_ADDRB. * * %SER_RS485_ADDR_DEST - Destination address (enables @addr_dest). Requires %SER_RS485_ADDRB. + * * %SER_RS485_MODE_RS422 - Enable RS422. Requires %SER_RS485_ENABLED. */ struct serial_rs485 { __u32 flags; -#define SER_RS485_ENABLED (1 << 0) -#define SER_RS485_RTS_ON_SEND (1 << 1) -#define SER_RS485_RTS_AFTER_SEND (1 << 2) -#define SER_RS485_RX_DURING_TX (1 << 4) -#define SER_RS485_TERMINATE_BUS (1 << 5) -#define SER_RS485_ADDRB (1 << 6) -#define SER_RS485_ADDR_RECV (1 << 7) -#define SER_RS485_ADDR_DEST (1 << 8) +#define SER_RS485_ENABLED _BITUL(0) +#define SER_RS485_RTS_ON_SEND _BITUL(1) +#define SER_RS485_RTS_AFTER_SEND _BITUL(2) +#define SER_RS485_RX_DURING_TX _BITUL(3) +#define SER_RS485_TERMINATE_BUS _BITUL(4) +#define SER_RS485_ADDRB _BITUL(5) +#define SER_RS485_ADDR_RECV _BITUL(6) +#define SER_RS485_ADDR_DEST _BITUL(7) +#define SER_RS485_MODE_RS422 _BITUL(8) __u32 delay_rts_before_send; __u32 delay_rts_after_send; diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h index d77ee6b65328..078098e73fd3 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h @@ -73,8 +73,10 @@ struct usb_os_desc_header { struct usb_ext_compat_desc { __u8 bFirstInterfaceNumber; __u8 Reserved1; - __u8 CompatibleID[8]; - __u8 SubCompatibleID[8]; + __struct_group(/* no tag */, IDs, /* no attrs */, + __u8 CompatibleID[8]; + __u8 SubCompatibleID[8]; + ); __u8 Reserved2[6]; }; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 94ec913dfb76..69c75c041fe1 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1041,7 +1041,7 @@ static void rfcomm_tty_flush_buffer(struct tty_struct *tty) tty_wakeup(tty); } -static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch) +static void rfcomm_tty_send_xchar(struct tty_struct *tty, u8 ch) { BT_DBG("tty %p ch %c", tty, ch); } diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c index c8db6c75d133..d6e5aafd697c 100644 --- a/sound/drivers/serial-generic.c +++ b/sound/drivers/serial-generic.c @@ -100,8 +100,8 @@ static void snd_serial_generic_write_wakeup(struct serdev_device *serdev) snd_serial_generic_tx_wakeup(drvdata); } -static int snd_serial_generic_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t count) +static ssize_t snd_serial_generic_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) { int ret; struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);