diff options
151 files changed, 3506 insertions, 1053 deletions
diff --git a/Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml b/Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml index 1d1fee1a16c1..8bd1abfc44d9 100644 --- a/Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml +++ b/Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml @@ -57,6 +57,15 @@ patternProperties: enum: - mscc,ocelot-miim + "^ethernet-switch@[0-9a-f]+$": + type: object + $ref: /schemas/net/mscc,vsc7514-switch.yaml + unevaluatedProperties: false + properties: + compatible: + enum: + - mscc,vsc7512-switch + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/net/amlogic,gxl-mdio-mux.yaml b/Documentation/devicetree/bindings/net/amlogic,gxl-mdio-mux.yaml new file mode 100644 index 000000000000..27ae004dbea0 --- /dev/null +++ b/Documentation/devicetree/bindings/net/amlogic,gxl-mdio-mux.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/amlogic,gxl-mdio-mux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic GXL MDIO bus multiplexer + +maintainers: + - Jerome Brunet <[email protected]> + +description: + This is a special case of a MDIO bus multiplexer. It allows to choose between + the internal mdio bus leading to the embedded 10/100 PHY or the external + MDIO bus on the Amlogic GXL SoC family. + +allOf: + - $ref: mdio-mux.yaml# + +properties: + compatible: + const: amlogic,gxl-mdio-mux + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: ref + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + eth_phy_mux: mdio@558 { + compatible = "amlogic,gxl-mdio-mux"; + reg = <0x558 0xc>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&refclk>; + clock-names = "ref"; + mdio-parent-bus = <&mdio0>; + + external_mdio: mdio@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + internal_mdio: mdio@1 { + reg = <0x1>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml b/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml index 5ffe831e59e4..8ee2c7d7ff42 100644 --- a/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml +++ b/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml @@ -18,13 +18,52 @@ description: | packets using CPU. Additionally, PTP is supported as well as FDMA for faster packet extraction/injection. -$ref: ethernet-switch.yaml# +allOf: + - if: + properties: + compatible: + const: mscc,vsc7514-switch + then: + $ref: ethernet-switch.yaml# + required: + - interrupts + - interrupt-names + properties: + reg: + minItems: 21 + reg-names: + minItems: 21 + ethernet-ports: + patternProperties: + "^port@[0-9a-f]+$": + $ref: ethernet-switch-port.yaml# + unevaluatedProperties: false + + - if: + properties: + compatible: + const: mscc,vsc7512-switch + then: + $ref: /schemas/net/dsa/dsa.yaml# + properties: + reg: + maxItems: 20 + reg-names: + maxItems: 20 + ethernet-ports: + patternProperties: + "^port@[0-9a-f]+$": + $ref: /schemas/net/dsa/dsa-port.yaml# + unevaluatedProperties: false properties: compatible: - const: mscc,vsc7514-switch + enum: + - mscc,vsc7512-switch + - mscc,vsc7514-switch reg: + minItems: 20 items: - description: system target - description: rewriter target @@ -49,6 +88,7 @@ properties: - description: fdma target reg-names: + minItems: 20 items: - const: sys - const: rew @@ -86,35 +126,16 @@ properties: - const: xtr - const: fdma - ethernet-ports: - type: object - - properties: - '#address-cells': - const: 1 - '#size-cells': - const: 0 - - additionalProperties: false - - patternProperties: - "^port@[0-9a-f]+$": - - $ref: ethernet-switch-port.yaml# - - unevaluatedProperties: false - required: - compatible - reg - reg-names - - interrupts - - interrupt-names - ethernet-ports -additionalProperties: false +unevaluatedProperties: false examples: + # VSC7514 (Switchdev) - | switch@1010000 { compatible = "mscc,vsc7514-switch"; @@ -162,5 +183,51 @@ examples: }; }; }; + # VSC7512 (DSA) + - | + ethernet-switch@1{ + compatible = "mscc,vsc7512-switch"; + reg = <0x71010000 0x10000>, + <0x71030000 0x10000>, + <0x71080000 0x100>, + <0x710e0000 0x10000>, + <0x711e0000 0x100>, + <0x711f0000 0x100>, + <0x71200000 0x100>, + <0x71210000 0x100>, + <0x71220000 0x100>, + <0x71230000 0x100>, + <0x71240000 0x100>, + <0x71250000 0x100>, + <0x71260000 0x100>, + <0x71270000 0x100>, + <0x71280000 0x100>, + <0x71800000 0x80000>, + <0x71880000 0x10000>, + <0x71040000 0x10000>, + <0x71050000 0x10000>, + <0x71060000 0x10000>; + reg-names = "sys", "rew", "qs", "ptp", "port0", "port1", + "port2", "port3", "port4", "port5", "port6", + "port7", "port8", "port9", "port10", "qsys", + "ana", "s0", "s1", "s2"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ethernet = <&mac_sw>; + phy-handle = <&phy0>; + phy-mode = "internal"; + }; + port@1 { + reg = <1>; + phy-handle = <&phy1>; + phy-mode = "internal"; + }; + }; + }; ... diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index e23e3c94a932..bbcfa2472b04 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -218,9 +218,7 @@ properties: to a single enum. "directional" has the messages sent to the kernel and from the kernel enumerated separately. - "notify-split" has the notifications and request-response types in - different enums. - enum: [ unified, directional, notify-split ] + enum: [ unified ] name-prefix: description: | Prefix for the C enum name of the command. The name is formed by concatenating diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index 88db2431ef26..5642925c4ceb 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -241,9 +241,7 @@ properties: to a single enum. "directional" has the messages sent to the kernel and from the kernel enumerated separately. - "notify-split" has the notifications and request-response types in - different enums. - enum: [ unified, directional, notify-split ] + enum: [ unified, directional ] # Trim name-prefix: description: | Prefix for the C enum name of the command. The name is formed by concatenating @@ -307,6 +305,13 @@ properties: type: array items: type: string + # Start genetlink-legacy + value: + description: | + ID of this message if value for request and response differ, + i.e. requests and responses have different message enums. + $ref: '#/$defs/uint' + # End genetlink-legacy reply: *subop-attr-list pre: description: Hook for a function to run before the main callback (pre_doit or start). diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index b5e712bbe7e7..62a922755ce2 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -188,9 +188,7 @@ properties: to a single enum. "directional" has the messages sent to the kernel and from the kernel enumerated separately. - "notify-split" has the notifications and request-response types in - different enums. - enum: [ unified, directional, notify-split ] + enum: [ unified ] name-prefix: description: | Prefix for the C enum name of the command. The name is formed by concatenating diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml new file mode 100644 index 000000000000..82f4e6f8ddd3 --- /dev/null +++ b/Documentation/netlink/specs/ethtool.yaml @@ -0,0 +1,392 @@ +name: ethtool + +protocol: genetlink-legacy + +doc: Partial family for Ethtool Netlink. + +attribute-sets: + - + name: header + attributes: + - + name: dev-index + type: u32 + value: 1 + - + name: dev-name + type: string + - + name: flags + type: u32 + + - + name: bitset-bit + attributes: + - + name: index + type: u32 + value: 1 + - + name: name + type: string + - + name: value + type: flag + - + name: bitset-bits + attributes: + - + name: bit + type: nest + nested-attributes: bitset-bit + value: 1 + - + name: bitset + attributes: + - + name: nomask + type: flag + value: 1 + - + name: size + type: u32 + - + name: bits + type: nest + nested-attributes: bitset-bits + + - + name: string + attributes: + - + name: index + type: u32 + value: 1 + - + name: value + type: string + - + name: strings + attributes: + - + name: string + type: nest + value: 1 + multi-attr: true + nested-attributes: string + - + name: stringset + attributes: + - + name: id + type: u32 + value: 1 + - + name: count + type: u32 + - + name: strings + type: nest + multi-attr: true + nested-attributes: strings + - + name: stringsets + attributes: + - + name: stringset + type: nest + multi-attr: true + value: 1 + nested-attributes: stringset + - + name: strset + attributes: + - + name: header + value: 1 + type: nest + nested-attributes: header + - + name: stringsets + type: nest + nested-attributes: stringsets + - + name: counts-only + type: flag + + - + name: privflags + attributes: + - + name: header + value: 1 + type: nest + nested-attributes: header + - + name: flags + type: nest + nested-attributes: bitset + + - + name: rings + attributes: + - + name: header + value: 1 + type: nest + nested-attributes: header + - + name: rx-max + type: u32 + - + name: rx-mini-max + type: u32 + - + name: rx-jumbo-max + type: u32 + - + name: tx-max + type: u32 + - + name: rx + type: u32 + - + name: rx-mini + type: u32 + - + name: rx-jumbo + type: u32 + - + name: tx + type: u32 + - + name: rx-buf-len + type: u32 + - + name: tcp-data-split + type: u8 + - + name: cqe-size + type: u32 + - + name: tx-push + type: u8 + + - + name: mm-stat + attributes: + - + name: pad + value: 1 + type: pad + - + name: reassembly-errors + type: u64 + - + name: smd-errors + type: u64 + - + name: reassembly-ok + type: u64 + - + name: rx-frag-count + type: u64 + - + name: tx-frag-count + type: u64 + - + name: hold-count + type: u64 + - + name: mm + attributes: + - + name: header + value: 1 + type: nest + nested-attributes: header + - + name: pmac-enabled + type: u8 + - + name: tx-enabled + type: u8 + - + name: tx-active + type: u8 + - + name: tx-min-frag-size + type: u32 + - + name: tx-min-frag-size + type: u32 + - + name: verify-enabled + type: u8 + - + name: verify-status + type: u8 + - + name: verify-time + type: u32 + - + name: max-verify-time + type: u32 + - + name: stats + type: nest + nested-attributes: mm-stat + +operations: + enum-model: directional + list: + - + name: strset-get + doc: Get string set from the kernel. + + attribute-set: strset + + do: &strset-get-op + request: + value: 1 + attributes: + - header + - stringsets + - counts-only + reply: + value: 1 + attributes: + - header + - stringsets + dump: *strset-get-op + + # TODO: fill in the requests in between + + - + name: privflags-get + doc: Get device private flags. + + attribute-set: privflags + + do: &privflag-get-op + request: + value: 13 + attributes: + - header + reply: + value: 14 + attributes: + - header + - flags + dump: *privflag-get-op + - + name: privflags-set + doc: Set device private flags. + + attribute-set: privflags + + do: + request: + attributes: + - header + - flags + - + name: privflags-ntf + doc: Notification for change in device private flags. + notify: privflags-get + + - + name: rings-get + doc: Get ring params. + + attribute-set: rings + + do: &ring-get-op + request: + attributes: + - header + reply: + attributes: + - header + - rx-max + - rx-mini-max + - rx-jumbo-max + - tx-max + - rx + - rx-mini + - rx-jumbo + - tx + - rx-buf-len + - tcp-data-split + - cqe-size + - tx-push + dump: *ring-get-op + - + name: rings-set + doc: Set ring params. + + attribute-set: rings + + do: + request: + attributes: + - header + - rx + - rx-mini + - rx-jumbo + - tx + - rx-buf-len + - tcp-data-split + - cqe-size + - tx-push + - + name: rings-ntf + doc: Notification for change in ring params. + notify: rings-get + + # TODO: fill in the requests in between + + - + name: mm-get + doc: Get MAC Merge configuration and state + + attribute-set: mm + + do: &mm-get-op + request: + value: 42 + attributes: + - header + reply: + value: 42 + attributes: + - header + - pmac-enabled + - tx-enabled + - tx-active + - tx-min-frag-size + - rx-min-frag-size + - verify-enabled + - verify-time + - max-verify-time + - stats + dump: *mm-get-op + - + name: mm-set + doc: Set MAC Merge configuration + + attribute-set: mm + + do: + request: + attributes: + - header + - verify-enabled + - verify-time + - tx-enabled + - pmac-enabled + - tx-min-frag-size + - + name: mm-ntf + doc: Notification for change in MAC Merge configuration. + notify: mm-get diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst index 60b217b436be..247c6c4127e9 100644 --- a/Documentation/networking/af_xdp.rst +++ b/Documentation/networking/af_xdp.rst @@ -419,7 +419,7 @@ XDP_UMEM_REG setsockopt ----------------------- This setsockopt registers a UMEM to a socket. This is the area that -contain all the buffers that packet can recide in. The call takes a +contain all the buffers that packet can reside in. The call takes a pointer to the beginning of this area and the size of it. Moreover, it also has parameter called chunk_size that is the size that the UMEM is divided into. It can only be 2K or 4K at the moment. If you have an @@ -592,7 +592,7 @@ A: When a netdev of a physical NIC is initialized, Linux usually A number of other ways are possible all up to the capabilities of the NIC you have. -Q: Can I use the XSKMAP to implement a switch betwen different umems +Q: Can I use the XSKMAP to implement a switch between different umems in copy mode? A: The short answer is no, that is not supported at the moment. The diff --git a/Documentation/networking/arcnet-hardware.rst b/Documentation/networking/arcnet-hardware.rst index ac249ac8fcf2..982215723582 100644 --- a/Documentation/networking/arcnet-hardware.rst +++ b/Documentation/networking/arcnet-hardware.rst @@ -1902,7 +1902,7 @@ of 32 possible I/O Base addresses using the following tables:: 6 | 10 The I/O address is sum of all switches set to "1". Remember that -the I/O address space bellow 0x200 is RESERVED for mainboard, so +the I/O address space below 0x200 is RESERVED for mainboard, so switch 1 should be ALWAYS SET TO OFF. diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst index 90121deef217..d7e1ada905b2 100644 --- a/Documentation/networking/can.rst +++ b/Documentation/networking/can.rst @@ -931,7 +931,7 @@ ival1: ival2: Throttle the received message rate down to the value of ival2. This is useful to reduce messages for the application when the signal inside the - CAN frame is stateless as state changes within the ival2 periode may get + CAN frame is stateless as state changes within the ival2 period may get lost. Broadcast Manager Multiplex Message Receive Filter diff --git a/Documentation/networking/can_ucan_protocol.rst b/Documentation/networking/can_ucan_protocol.rst index 638ac1ee7914..935d872ae87c 100644 --- a/Documentation/networking/can_ucan_protocol.rst +++ b/Documentation/networking/can_ucan_protocol.rst @@ -50,7 +50,7 @@ Setup Packet ``wIndex`` USB Interface Index (0 for device commands) ``wLength`` * Host to Device - Number of bytes to transmit * Device to Host - Maximum Number of bytes to - receive. If the device send less. Commom ZLP + receive. If the device send less. Common ZLP semantics are used. ================= ===================================================== diff --git a/Documentation/networking/cdc_mbim.rst b/Documentation/networking/cdc_mbim.rst index 0048409c06b4..37f968acc473 100644 --- a/Documentation/networking/cdc_mbim.rst +++ b/Documentation/networking/cdc_mbim.rst @@ -93,7 +93,7 @@ MBIM function can be looked up using sysfs. For example:: USB configuration descriptors ----------------------------- The wMaxControlMessage field of the CDC MBIM functional descriptor -limits the maximum control message size. The managament application is +limits the maximum control message size. The management application is responsible for negotiating a control message size complying with the requirements in section 9.3.1 of [1], taking this descriptor field into consideration. diff --git a/Documentation/networking/device_drivers/atm/iphase.rst b/Documentation/networking/device_drivers/atm/iphase.rst index 92d9b757d75a..388c7101e2cb 100644 --- a/Documentation/networking/device_drivers/atm/iphase.rst +++ b/Documentation/networking/device_drivers/atm/iphase.rst @@ -4,7 +4,7 @@ ATM (i)Chip IA Linux Driver Source ================================== - READ ME FISRT + READ ME FIRST -------------------------------------------------------------------------------- diff --git a/Documentation/networking/device_drivers/can/ctu/ctucanfd-driver.rst b/Documentation/networking/device_drivers/can/ctu/ctucanfd-driver.rst index 40c92ea272af..1a4fc6607582 100644 --- a/Documentation/networking/device_drivers/can/ctu/ctucanfd-driver.rst +++ b/Documentation/networking/device_drivers/can/ctu/ctucanfd-driver.rst @@ -577,7 +577,7 @@ CTU CAN FD IP Core and Driver Development Acknowledgment * Linux driver development * continuous integration platform architect and GHDL updates - * theses `Open-source and Open-hardware CAN FD Protocol Support <https://dspace.cvut.cz/bitstream/handle/10467/80366/F3-DP-2019-Jerabek-Martin-Jerabek-thesis-2019-canfd.pdf>`_ + * thesis `Open-source and Open-hardware CAN FD Protocol Support <https://dspace.cvut.cz/bitstream/handle/10467/80366/F3-DP-2019-Jerabek-Martin-Jerabek-thesis-2019-canfd.pdf>`_ * Jiri Novak <[email protected]> @@ -603,7 +603,7 @@ CTU CAN FD IP Core and Driver Development Acknowledgment * Jan Charvat * implemented CTU CAN FD functional model for QEMU which has been integrated into QEMU mainline (`docs/system/devices/can.rst <https://www.qemu.org/docs/master/system/devices/can.html>`_) - * Bachelor theses Model of CAN FD Communication Controller for QEMU Emulator + * Bachelor thesis Model of CAN FD Communication Controller for QEMU Emulator Notes ----- diff --git a/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg b/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg index b371650788f4..381323423b4c 100644 --- a/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg +++ b/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg @@ -129,10 +129,10 @@ </g> </g> <text transform="matrix(.264583 0 0 .264583 91.8919 139.964)" x="26.959213" y="9.11724" fill="#2aa1ff" filter="url(#filter1204-6-2-9-1-3-1)" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle" style="line-height:1.1" xml:space="preserve"><tspan x="26.959213" y="9.11724" text-align="center">Set</tspan><tspan x="26.959213" y="22.31724" text-align="center">abort</tspan></text> - <text transform="translate(49.0277 104.823)" x="57.620724" y="16.855087" filter="url(#filter1204)" font-size="3.175px" text-align="center" text-anchor="middle" style="line-height:1.1" xml:space="preserve"><tspan x="57.620724" y="16.855087" text-align="center">Transmission</tspan><tspan x="57.620724" y="20.347588" text-align="center">unsuccesfull</tspan></text> + <text transform="translate(49.0277 104.823)" x="57.620724" y="16.855087" filter="url(#filter1204)" font-size="3.175px" text-align="center" text-anchor="middle" style="line-height:1.1" xml:space="preserve"><tspan x="57.620724" y="16.855087" text-align="center">Transmission</tspan><tspan x="57.620724" y="20.347588" text-align="center">unsuccessful</tspan></text> <g font-size="12px" stroke-width="3.77953" text-anchor="middle"> <text transform="matrix(.264583 0 0 .264583 68.5988 118.913)" x="38.824219" y="9.1171875" filter="url(#filter1204)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Transmission</tspan><tspan x="38.824219" y="22.317188" text-align="center">starts</tspan></text> - <text transform="matrix(.264583 0 0 .264583 106.802 130.509)" x="38.824219" y="9.1171875" filter="url(#filter1204)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Transmission</tspan><tspan x="38.824219" y="22.317188" text-align="center">succesfull</tspan></text> + <text transform="matrix(.264583 0 0 .264583 106.802 130.509)" x="38.824219" y="9.1171875" filter="url(#filter1204)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Transmission</tspan><tspan x="38.824219" y="22.317188" text-align="center">successful</tspan></text> <text transform="matrix(.264583 0 0 .264583 107.77 145.476)" x="38.824219" y="9.1171875" filter="url(#filter1204)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Transmission</tspan><tspan x="38.824219" y="22.317188" text-align="center">sborted</tspan></text> </g> <g stroke-width="3.77953" text-anchor="middle"> diff --git a/Documentation/networking/device_drivers/ethernet/3com/vortex.rst b/Documentation/networking/device_drivers/ethernet/3com/vortex.rst index e89e4192af88..a060f84c4f96 100644 --- a/Documentation/networking/device_drivers/ethernet/3com/vortex.rst +++ b/Documentation/networking/device_drivers/ethernet/3com/vortex.rst @@ -254,7 +254,7 @@ Media selection A number of the older NICs such as the 3c590 and 3c900 series have 10base2 and AUI interfaces. -Prior to January, 2001 this driver would autoeselect the 10base2 or AUI +Prior to January, 2001 this driver would autoselect the 10base2 or AUI port if it didn't detect activity on the 10baseT port. It would then get stuck on the 10base2 port and a driver reload was necessary to switch back to 10baseT. This behaviour could not be prevented with a diff --git a/Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst b/Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst index 595ddef1c8b3..099280a261be 100644 --- a/Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst +++ b/Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst @@ -270,7 +270,7 @@ RX flow rules (ntuple filters) ethtool -K ethX ntuple <on|off> - When disabling ntuple filters, all the user programed filters are + When disabling ntuple filters, all the user programmed filters are flushed from the driver cache and hardware. All needed filters must be re-added when ntuple is re-enabled. @@ -418,7 +418,7 @@ Default value: 0xFFFF 0 Disable interrupt throttling. 1 Enable interrupt throttling and use specified tx and rx rates. 0xFFFF Auto throttling mode. Driver will choose the best RX and TX - interrupt throtting settings based on link speed. + interrupt throttling settings based on link speed. ====== ============================================================== aq_itr_tx - TX interrupt throttle rate @@ -456,7 +456,7 @@ AQ_CFG_RX_PAGEORDER Default value: 0 -RX page order override. Thats a power of 2 number of RX pages allocated for +RX page order override. That's a power of 2 number of RX pages allocated for each descriptor. Received descriptor size is still limited by AQ_CFG_RX_FRAME_MAX. diff --git a/Documentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst b/Documentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst index 1d2f55feca24..e2a36d0d88ef 100644 --- a/Documentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst +++ b/Documentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst @@ -11,7 +11,7 @@ Overview -------- The DPAA2 MAC / PHY support consists of a set of APIs that help DPAA2 network -drivers (dpaa2-eth, dpaa2-ethsw) interract with the PHY library. +drivers (dpaa2-eth, dpaa2-ethsw) interact with the PHY library. DPAA2 Software Architecture --------------------------- diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst index dd5cd69467be..5ba9015336e2 100644 --- a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst +++ b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst @@ -127,7 +127,7 @@ Type1: Type2: - RVU PF0 ie admin function creates these VFs and maps them to loopback block's channels. - A set of two VFs (VF0 & VF1, VF2 & VF3 .. so on) works as a pair ie pkts sent out of - VF0 will be received by VF1 and viceversa. + VF0 will be received by VF1 and vice versa. - These VFs can be used by applications or virtual machines to communicate between them without sending traffic outside. There is no switch present in HW, hence the support for loopback VFs. diff --git a/Documentation/networking/device_drivers/ethernet/pensando/ionic.rst b/Documentation/networking/device_drivers/ethernet/pensando/ionic.rst index 0eabbc347d6c..6ec7d686efab 100644 --- a/Documentation/networking/device_drivers/ethernet/pensando/ionic.rst +++ b/Documentation/networking/device_drivers/ethernet/pensando/ionic.rst @@ -83,7 +83,7 @@ Configuring the Driver MTU --- -Jumbo frame support is available with a maximim size of 9194 bytes. +Jumbo frame support is available with a maximum size of 9194 bytes. Interrupt coalescing -------------------- diff --git a/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst b/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst index f24adfab6a1b..25fd9aa284e2 100644 --- a/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst +++ b/Documentation/networking/device_drivers/ethernet/ti/am65_nuss_cpsw_switchdev.rst @@ -124,7 +124,7 @@ Multicast flooding ================== CPU port mcast_flooding is always on -Turning flooding on/off on swithch ports: +Turning flooding on/off on switch ports: bridge link set dev sw0p1 mcast_flood on/off Access and Trunk port diff --git a/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst b/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst index 1241ecac73bd..464dce938ed1 100644 --- a/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst +++ b/Documentation/networking/device_drivers/ethernet/ti/cpsw_switchdev.rst @@ -174,7 +174,7 @@ Multicast flooding ================== CPU port mcast_flooding is always on -Turning flooding on/off on swithch ports: +Turning flooding on/off on switch ports: bridge link set dev sw0p1 mcast_flood on/off Access and Trunk port diff --git a/Documentation/networking/device_drivers/wwan/iosm.rst b/Documentation/networking/device_drivers/wwan/iosm.rst index aceb0223eb46..6f9e955af984 100644 --- a/Documentation/networking/device_drivers/wwan/iosm.rst +++ b/Documentation/networking/device_drivers/wwan/iosm.rst @@ -69,7 +69,7 @@ wwan0-X network device The IOSM driver exposes IP link interface "wwan0-X" of type "wwan" for IP traffic. Iproute network utility is used for creating "wwan0-X" network interface and for associating it with MBIM IP session. The Driver supports -upto 8 IP sessions for simultaneous IP communication. +up to 8 IP sessions for simultaneous IP communication. The userspace management application is responsible for creating new IP link prior to establishing MBIM IP session where the SessionId is greater than 0. diff --git a/Documentation/networking/devlink/ice.rst b/Documentation/networking/devlink/ice.rst index 625efb3777d5..10f282c2117c 100644 --- a/Documentation/networking/devlink/ice.rst +++ b/Documentation/networking/devlink/ice.rst @@ -285,7 +285,7 @@ features are enabled after the hierarchy is exported, but before any changes are made. This feature is also dependent on switchdev being enabled in the system. -It's required bacause devlink-rate requires devlink-port objects to be +It's required because devlink-rate requires devlink-port objects to be present, and those objects are only created in switchdev mode. If the driver is set to the switchdev mode, it will export internal @@ -320,7 +320,7 @@ nodes and nodes with children also can't be deleted. * - ``tx_weight`` - allows for usage of Weighted Fair Queuing arbitration scheme among siblings. This arbitration scheme can be used simultaneously with - the strict priority. Range 1-200. Only relative values mater for + the strict priority. Range 1-200. Only relative values matter for arbitration. ``tx_priority`` and ``tx_weight`` can be used simultaneously. In that case diff --git a/Documentation/networking/devlink/netdevsim.rst b/Documentation/networking/devlink/netdevsim.rst index ec5e6d79b2e2..88482725422c 100644 --- a/Documentation/networking/devlink/netdevsim.rst +++ b/Documentation/networking/devlink/netdevsim.rst @@ -95,5 +95,5 @@ Driver-specific Traps * - ``fid_miss`` - ``exception`` - When a packet enters the device it is classified to a filtering - indentifier (FID) based on the ingress port and VLAN. This trap is used + identifier (FID) based on the ingress port and VLAN. This trap is used to trap packets for which a FID could not be found diff --git a/Documentation/networking/devlink/prestera.rst b/Documentation/networking/devlink/prestera.rst index 49409d1d3081..96b1124e614b 100644 --- a/Documentation/networking/devlink/prestera.rst +++ b/Documentation/networking/devlink/prestera.rst @@ -138,4 +138,4 @@ Driver-specific Traps - Drops packets with zero (0) IPV4 source address. * - ``met_red`` - ``drop`` - - Drops non-conforming packets (dropped by Ingress policer, metering drop), e.g. packet rate exceeded configured bandwith. + - Drops non-conforming packets (dropped by Ingress policer, metering drop), e.g. packet rate exceeded configured bandwidth. diff --git a/Documentation/networking/dsa/configuration.rst b/Documentation/networking/dsa/configuration.rst index 827701f8cbfe..d2934c40f0f1 100644 --- a/Documentation/networking/dsa/configuration.rst +++ b/Documentation/networking/dsa/configuration.rst @@ -5,7 +5,7 @@ DSA switch configuration from userspace ======================================= The DSA switch configuration is not integrated into the main userspace -network configuration suites by now and has to be performed manualy. +network configuration suites by now and has to be performed manually. .. _dsa-config-showcases: diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index 1626e863eec9..d144e890961d 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -106,7 +106,7 @@ modifying a bitmap, the former changes the bit set in mask to values set in value and preserves the rest; the latter sets the bits set in the bitmap and clears the rest. -Compact form: nested (bitset) atrribute contents: +Compact form: nested (bitset) attribute contents: ============================ ====== ============================ ``ETHTOOL_A_BITSET_NOMASK`` flag no mask, only a list @@ -783,7 +783,7 @@ Kernel response contents: ``ETHTOOL_A_FEATURES_ACTIVE`` bitset diff old vs. new active ==================================== ====== ========================== -Request constains only one bitset which can be either value/mask pair (request +Request contains only one bitset which can be either value/mask pair (request to change specific feature bits and leave the rest) or only a value (request to set all features to specified set). @@ -1823,7 +1823,7 @@ aPLCATransmitOpportunityTimer. The valid range for this attribute is When set, the optional ``ETHTOOL_A_PLCA_BURST_CNT`` attribute indicates the configured number of extra packets that the node is allowed to send during a single transmit opportunity. By default, this attribute is 0, meaning that -the node can only send a sigle frame per TO. When greater than 0, the PLCA RS +the node can only send a single frame per TO. When greater than 0, the PLCA RS keeps the TO after any transmission, waiting for the MAC to send a new frame for up to aPLCABurstTimer BTs. This can only happen a number of times per PLCA cycle up to the value of this parameter. After that, the burst is over and the diff --git a/Documentation/networking/gtp.rst b/Documentation/networking/gtp.rst index 1563fb94b289..9a7835cc1437 100644 --- a/Documentation/networking/gtp.rst +++ b/Documentation/networking/gtp.rst @@ -162,7 +162,7 @@ Local GTP-U entity and tunnel identification GTP-U uses UDP for transporting PDU's. The receiving UDP port is 2152 for GTPv1-U and 3386 for GTPv0-U. -There is only one GTP-U entity (and therefor SGSN/GGSN/S-GW/PDN-GW +There is only one GTP-U entity (and therefore SGSN/GGSN/S-GW/PDN-GW instance) per IP address. Tunnel Endpoint Identifier (TEID) are unique per GTP-U entity. diff --git a/Documentation/networking/ieee802154.rst b/Documentation/networking/ieee802154.rst index f27856d77c8b..c652d383fe10 100644 --- a/Documentation/networking/ieee802154.rst +++ b/Documentation/networking/ieee802154.rst @@ -70,7 +70,7 @@ Like with WiFi, there are several types of devices implementing IEEE 802.15.4. exports a management (e.g. MLME) and data API. 2) 'SoftMAC' or just radio. These types of devices are just radio transceivers possibly with some kinds of acceleration like automatic CRC computation and -comparation, automagic ACK handling, address matching, etc. +comparison, automagic ACK handling, address matching, etc. Those types of devices require different approach to be hooked into Linux kernel. diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 4cc2fab58dea..87dd1c5283e6 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -50,7 +50,7 @@ ip_no_pmtu_disc - INTEGER Default: FALSE min_pmtu - INTEGER - default 552 - minimum Path MTU. Unless this is changed mannually, + default 552 - minimum Path MTU. Unless this is changed manually, each cached pmtu will never be lower than this setting. ip_forward_use_pmtu - BOOLEAN @@ -1592,6 +1592,14 @@ proxy_arp_pvlan - BOOLEAN Hewlett-Packard call it Source-Port filtering or port-isolation. Ericsson call it MAC-Forced Forwarding (RFC Draft). +proxy_delay - INTEGER + Delay proxy response. + + Delay response to a neighbor solicitation when proxy_arp + or proxy_ndp is enabled. A random value between [0, proxy_delay) + will be chosen, setting to zero means reply with no delay. + Value in jiffies. Defaults to 80. + shared_media - BOOLEAN Send(router) or accept(host) RFC1620 shared media redirects. Overrides secure_redirects. @@ -2078,7 +2086,7 @@ skip_notify_on_dev_down - BOOLEAN nexthop_compat_mode - BOOLEAN New nexthop API provides a means for managing nexthops independent of - prefixes. Backwards compatibilty with old route format is enabled by + prefixes. Backwards compatibility with old route format is enabled by default which means route dumps and notifications contain the new nexthop attribute but also the full, expanded nexthop definition. Further, updates or deletes of a nexthop configuration generate route @@ -2811,7 +2819,7 @@ pf_expose - INTEGER can be got via SCTP_GET_PEER_ADDR_INFO sockopt; When it's enabled, a SCTP_PEER_ADDR_CHANGE event will be sent for a transport becoming SCTP_PF state and a SCTP_PF-state transport info can be got via - SCTP_GET_PEER_ADDR_INFO sockopt; When it's diabled, no + SCTP_GET_PEER_ADDR_INFO sockopt; When it's disabled, no SCTP_PEER_ADDR_CHANGE event will be sent and it returns -EACCES when trying to get a SCTP_PF-state transport info via SCTP_GET_PEER_ADDR_INFO sockopt. diff --git a/Documentation/networking/ipvlan.rst b/Documentation/networking/ipvlan.rst index 0000c1d383bc..895d0ccfd596 100644 --- a/Documentation/networking/ipvlan.rst +++ b/Documentation/networking/ipvlan.rst @@ -61,7 +61,7 @@ e.g. IPvlan has two modes of operation - L2 and L3. For a given master device, you can select one of these two modes and all slaves on that master will operate in the same (selected) mode. The RX mode is almost identical except -that in L3 mode the slaves wont receive any multicast / broadcast traffic. +that in L3 mode the slaves won't receive any multicast / broadcast traffic. L3 mode is more restrictive since routing is controlled from the other (mostly) default namespace. diff --git a/Documentation/networking/j1939.rst b/Documentation/networking/j1939.rst index b705d2801e9c..e4bd7aa1f5aa 100644 --- a/Documentation/networking/j1939.rst +++ b/Documentation/networking/j1939.rst @@ -116,7 +116,7 @@ format, the Group Extension is set in the PS-field. ---------------------------------------- 23 ... 16 15 ... 8 ============== ======================== - F0h ... FFh GE (Group Extenstion) + F0h ... FFh GE (Group Extension) ============== ======================== On the other hand, when using PDU1 format, the PS-field contains a so-called diff --git a/Documentation/networking/net_failover.rst b/Documentation/networking/net_failover.rst index 3a662f2b4d6e..f4e1b4e07adc 100644 --- a/Documentation/networking/net_failover.rst +++ b/Documentation/networking/net_failover.rst @@ -90,7 +90,7 @@ virtio-net interface, and ens11 is the slave 'primary' VF passthrough interface. One point to note here is that some user space network configuration daemons like systemd-networkd, ifupdown, etc, do not understand the 'net_failover' device; and on the first boot, the VM might end up with both 'failover' device -and VF accquiring IP addresses (either same or different) from the DHCP server. +and VF acquiring IP addresses (either same or different) from the DHCP server. This will result in lack of connectivity to the VM. So some tweaks might be needed to these network configuration daemons to make sure that an IP is received only on the 'failover' device. diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst index 1f5c4a04027c..dd0518e002f6 100644 --- a/Documentation/networking/netconsole.rst +++ b/Documentation/networking/netconsole.rst @@ -167,7 +167,7 @@ following format which is the same as /dev/kmsg:: Non printable characters in <message text> are escaped using "\xff" notation. If the message contains optional dictionary, verbatim -newline is used as the delimeter. +newline is used as the delimiter. If a message doesn't fit in certain number of bytes (currently 1000), the message is split into multiple fragments by netconsole. These diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 5db8c263b0c6..30f1344e7cca 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -11,7 +11,7 @@ Basic use involves replacing alloc_pages() calls with the page_pool_alloc_pages() call. Drivers should use page_pool_dev_alloc_pages() replacing dev_alloc_pages(). -API keeps track of inflight pages, in order to let API user know +API keeps track of in-flight pages, in order to let API user know when it is safe to free a page_pool object. Thus, API users must run page_pool_release_page() when a page is leaving the page_pool or call page_pool_put_page() where appropriate in order to maintain correct @@ -19,7 +19,7 @@ accounting. API user must call page_pool_put_page() once on a page, as it will either recycle the page, or in case of refcnt > 1, it will -release the DMA mapping and inflight state accounting. +release the DMA mapping and in-flight state accounting. Architecture overview ===================== @@ -88,7 +88,7 @@ a page will cause no race conditions is enough. directly into the pool fast cache. * page_pool_release_page(): Unmap the page (if mapped) and account for it on - inflight counters. + in-flight counters. * page_pool_dev_alloc_pages(): Get a page from the page allocator or page_pool caches. diff --git a/Documentation/networking/phonet.rst b/Documentation/networking/phonet.rst index 8668dcbc5e6a..d705cc5b09fc 100644 --- a/Documentation/networking/phonet.rst +++ b/Documentation/networking/phonet.rst @@ -131,7 +131,7 @@ Phonet resources, as follow:: Subscription is similarly cancelled using the SIOCPNDELRESOURCE I/O control request, or when the socket is closed. -Note that no more than one socket can be subcribed to any given +Note that no more than one socket can be subscribed to any given resource at a time. If not, ioctl() will return EBUSY. diff --git a/Documentation/networking/phy.rst b/Documentation/networking/phy.rst index d11329a08984..b7ac4c64cf67 100644 --- a/Documentation/networking/phy.rst +++ b/Documentation/networking/phy.rst @@ -315,7 +315,7 @@ Some of the interface modes are described below: only the port id, but also so-called "extensions". The only documented extension so-far in the specification is the inclusion of timestamps, for PTP-enabled PHYs. This mode isn't compatible with QSGMII, but offers the - same capabilities in terms of link speed and negociation. + same capabilities in terms of link speed and negotiation. ``PHY_INTERFACE_MODE_1000BASEKX`` This is 1000BASE-X as defined by IEEE 802.3 Clause 36 with Clause 73 diff --git a/Documentation/networking/regulatory.rst b/Documentation/networking/regulatory.rst index 16782a95b74a..5e42c8a175c3 100644 --- a/Documentation/networking/regulatory.rst +++ b/Documentation/networking/regulatory.rst @@ -66,7 +66,7 @@ An example:: iw reg set CR This will request the kernel to set the regulatory domain to -the specificied alpha2. The kernel in turn will then ask userspace +the specified alpha2. The kernel in turn will then ask userspace to provide a regulatory domain for the alpha2 specified by the user by sending a uevent. @@ -158,7 +158,7 @@ kmalloc() a structure big enough to hold your regulatory domain structure and you should then fill it with your data. Finally you simply call regulatory_hint() with the regulatory domain structure in it. -Bellow is a simple example, with a regulatory domain cached using the stack. +Below is a simple example, with a regulatory domain cached using the stack. Your implementation may vary (read EEPROM cache instead, for example). Example cache of some regulatory domain:: diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst index e1af54424192..ec1323d92c96 100644 --- a/Documentation/networking/rxrpc.rst +++ b/Documentation/networking/rxrpc.rst @@ -1069,7 +1069,7 @@ The kernel interface functions are as follows: This value can be used to determine if the remote client has been restarted as it shouldn't change otherwise. - (#) Set the maxmimum lifespan on a call:: + (#) Set the maximum lifespan on a call:: void rxrpc_kernel_set_max_life(struct socket *sock, struct rxrpc_call *call, diff --git a/Documentation/networking/snmp_counter.rst b/Documentation/networking/snmp_counter.rst index 423d138b5ff3..213637474478 100644 --- a/Documentation/networking/snmp_counter.rst +++ b/Documentation/networking/snmp_counter.rst @@ -980,7 +980,7 @@ How many reply packets of the SYN cookies the TCP stack receives. The MSS decoded from the SYN cookie is invalid. When this counter is updated, the received packet won't be treated as a SYN cookie and the -TcpExtSyncookiesRecv counter wont be updated. +TcpExtSyncookiesRecv counter won't be updated. Challenge ACK ============= @@ -1681,7 +1681,7 @@ RST to nstat-b:: nstatuser@nstat-a:~$ sudo iptables -A INPUT -p tcp --sport 9000 -j DROP -Send 3 SYN repeatly to nstat-b:: +Send 3 SYN repeatedly to nstat-b:: nstatuser@nstat-a:~$ for i in {1..3}; do sudo tcpreplay -i ens3 /tmp/syn_fixcsum.pcap; done diff --git a/Documentation/networking/sysfs-tagging.rst b/Documentation/networking/sysfs-tagging.rst index 83647e10c207..65307130ab63 100644 --- a/Documentation/networking/sysfs-tagging.rst +++ b/Documentation/networking/sysfs-tagging.rst @@ -43,6 +43,6 @@ Users of this interface: - current_ns() which returns current's namespace - netlink_ns() which returns a socket's namespace - - initial_ns() which returns the initial namesapce + - initial_ns() which returns the initial namespace - call kobj_ns_exit() when an individual tag is no longer valid diff --git a/Documentation/userspace-api/netlink/genetlink-legacy.rst b/Documentation/userspace-api/netlink/genetlink-legacy.rst index 65cbbffee0bf..3bf0bcdf21d8 100644 --- a/Documentation/userspace-api/netlink/genetlink-legacy.rst +++ b/Documentation/userspace-api/netlink/genetlink-legacy.rst @@ -74,6 +74,88 @@ type. Inside the attr-index nest are the policy attributes. Modern Netlink families should have instead defined this as a flat structure, the nesting serves no good purpose here. +Operations +========== + +Enum (message ID) model +----------------------- + +unified +~~~~~~~ + +Modern families use the ``unified`` message ID model, which uses +a single enumeration for all messages within family. Requests and +responses share the same message ID. Notifications have separate +IDs from the same space. For example given the following list +of operations: + +.. code-block:: yaml + + - + name: a + value: 1 + do: ... + - + name: b + do: ... + - + name: c + value: 4 + notify: a + - + name: d + do: ... + +Requests and responses for operation ``a`` will have the ID of 1, +the requests and responses of ``b`` - 2 (since there is no explicit +``value`` it's previous operation ``+ 1``). Notification ``c`` will +use the ID of 4, operation ``d`` 5 etc. + +directional +~~~~~~~~~~~ + +The ``directional`` model splits the ID assignment by the direction of +the message. Messages from and to the kernel can't be confused with +each other so this conserves the ID space (at the cost of making +the programming more cumbersome). + +In this case ``value`` attribute should be specified in the ``request`` +``reply`` sections of the operations (if an operation has both ``do`` +and ``dump`` the IDs are shared, ``value`` should be set in ``do``). +For notifications the ``value`` is provided at the op level but it +only allocates a ``reply`` (i.e. a "from-kernel" ID). Let's look +at an example: + +.. code-block:: yaml + + - + name: a + do: + request: + value: 2 + attributes: ... + reply: + value: 1 + attributes: ... + - + name: b + notify: a + - + name: c + notify: a + value: 7 + - + name: d + do: ... + +In this case ``a`` will use 2 when sending the message to the kernel +and expects message with ID 1 in response. Notification ``b`` allocates +a "from-kernel" ID which is 2. ``c`` allocates "from-kernel" ID of 7. +If operation ``d`` does not set ``values`` explicitly in the spec +it will be allocated 3 for the request (``a`` is the previous operation +with a request section and the value of 2) and 8 for response (``c`` is +the previous operation in the "from-kernel" direction). + Other quirks (todo) =================== diff --git a/Documentation/userspace-api/netlink/index.rst b/Documentation/userspace-api/netlink/index.rst index be250110c8f6..26f3720cb3be 100644 --- a/Documentation/userspace-api/netlink/index.rst +++ b/Documentation/userspace-api/netlink/index.rst @@ -10,6 +10,7 @@ Netlink documentation for users. :maxdepth: 2 intro + intro-specs specs c-code-gen genetlink-legacy diff --git a/Documentation/userspace-api/netlink/intro-specs.rst b/Documentation/userspace-api/netlink/intro-specs.rst new file mode 100644 index 000000000000..a3b847eafff7 --- /dev/null +++ b/Documentation/userspace-api/netlink/intro-specs.rst @@ -0,0 +1,80 @@ +.. SPDX-License-Identifier: BSD-3-Clause + +===================================== +Using Netlink protocol specifications +===================================== + +This document is a quick starting guide for using Netlink protocol +specifications. For more detailed description of the specs see :doc:`specs`. + +Simple CLI +========== + +Kernel comes with a simple CLI tool which should be useful when +developing Netlink related code. The tool is implemented in Python +and can use a YAML specification to issue Netlink requests +to the kernel. Only Generic Netlink is supported. + +The tool is located at ``tools/net/ynl/cli.py``. It accepts +a handul of arguments, the most important ones are: + + - ``--spec`` - point to the spec file + - ``--do $name`` / ``--dump $name`` - issue request ``$name`` + - ``--json $attrs`` - provide attributes for the request + - ``--subscribe $group`` - receive notifications from ``$group`` + +YAML specs can be found under ``Documentation/netlink/specs/``. + +Example use:: + + $ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/ethtool.yaml \ + --do rings-get \ + --json '{"header":{"dev-index": 18}}' + {'header': {'dev-index': 18, 'dev-name': 'eni1np1'}, + 'rx': 0, + 'rx-jumbo': 0, + 'rx-jumbo-max': 4096, + 'rx-max': 4096, + 'rx-mini': 0, + 'rx-mini-max': 4096, + 'tx': 0, + 'tx-max': 4096, + 'tx-push': 0} + +The input arguments are parsed as JSON, while the output is only +Python-pretty-printed. This is because some Netlink types can't +be expressed as JSON directly. If such attributes are needed in +the input some hacking of the script will be necessary. + +The spec and Netlink internals are factored out as a standalone +library - it should be easy to write Python tools / tests reusing +code from ``cli.py``. + +Generating kernel code +====================== + +``tools/net/ynl/ynl-regen.sh`` scans the kernel tree in search of +auto-generated files which need to be updated. Using this tool is the easiest +way to generate / update auto-generated code. + +By default code is re-generated only if spec is newer than the source, +to force regeneration use ``-f``. + +``ynl-regen.sh`` searches for ``YNL-GEN`` in the contents of files +(note that it only scans files in the git index, that is only files +tracked by git!) For instance the ``fou_nl.c`` kernel source contains:: + + /* Documentation/netlink/specs/fou.yaml */ + /* YNL-GEN kernel source */ + +``ynl-regen.sh`` will find this marker and replace the file with +kernel source based on fou.yaml. + +The simplest way to generate a new file based on a spec is to add +the two marker lines like above to a file, add that file to git, +and run the regeneration tool. Grep the tree for ``YNL-GEN`` +to see other examples. + +The code generation itself is performed by ``tools/net/ynl/ynl-gen-c.py`` +but it takes a few arguments so calling it directly for each file +quickly becomes tedious. diff --git a/Documentation/userspace-api/netlink/specs.rst b/Documentation/userspace-api/netlink/specs.rst index 8394d74fc63a..6ffe8137cd90 100644 --- a/Documentation/userspace-api/netlink/specs.rst +++ b/Documentation/userspace-api/netlink/specs.rst @@ -21,6 +21,9 @@ Internally kernel uses the YAML specs to generate: YAML specifications can be found under ``Documentation/netlink/specs/`` +This document describes details of the schema. +See :doc:`intro-specs` for a practical starting guide. + Compatibility levels ==================== diff --git a/MAINTAINERS b/MAINTAINERS index cb30e6b85b57..8cdba0580cb8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15155,6 +15155,7 @@ M: Colin Foster <[email protected]> S: Supported F: Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml F: drivers/mfd/ocelot* +F: drivers/net/dsa/ocelot/ocelot_ext.c F: include/linux/mfd/ocelot.h OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER diff --git a/arch/sh/include/asm/checksum_32.h b/arch/sh/include/asm/checksum_32.h index a6501b856f3e..2b5fa75b4651 100644 --- a/arch/sh/include/asm/checksum_32.h +++ b/arch/sh/include/asm/checksum_32.h @@ -7,6 +7,7 @@ */ #include <linux/in6.h> +#include <linux/uaccess.h> /* * computes the checksum of a memory block at buff, length len, diff --git a/drivers/mfd/ocelot-core.c b/drivers/mfd/ocelot-core.c index 1816d52c65c5..b0ff05c1759f 100644 --- a/drivers/mfd/ocelot-core.c +++ b/drivers/mfd/ocelot-core.c @@ -34,16 +34,49 @@ #define VSC7512_MIIM0_RES_START 0x7107009c #define VSC7512_MIIM1_RES_START 0x710700c0 -#define VSC7512_MIIM_RES_SIZE 0x024 +#define VSC7512_MIIM_RES_SIZE 0x00000024 #define VSC7512_PHY_RES_START 0x710700f0 -#define VSC7512_PHY_RES_SIZE 0x004 +#define VSC7512_PHY_RES_SIZE 0x00000004 #define VSC7512_GPIO_RES_START 0x71070034 -#define VSC7512_GPIO_RES_SIZE 0x06c +#define VSC7512_GPIO_RES_SIZE 0x0000006c #define VSC7512_SIO_CTRL_RES_START 0x710700f8 -#define VSC7512_SIO_CTRL_RES_SIZE 0x100 +#define VSC7512_SIO_CTRL_RES_SIZE 0x00000100 + +#define VSC7512_ANA_RES_START 0x71880000 +#define VSC7512_ANA_RES_SIZE 0x00010000 + +#define VSC7512_QS_RES_START 0x71080000 +#define VSC7512_QS_RES_SIZE 0x00000100 + +#define VSC7512_QSYS_RES_START 0x71800000 +#define VSC7512_QSYS_RES_SIZE 0x00200000 + +#define VSC7512_REW_RES_START 0x71030000 +#define VSC7512_REW_RES_SIZE 0x00010000 + +#define VSC7512_SYS_RES_START 0x71010000 +#define VSC7512_SYS_RES_SIZE 0x00010000 + +#define VSC7512_S0_RES_START 0x71040000 +#define VSC7512_S1_RES_START 0x71050000 +#define VSC7512_S2_RES_START 0x71060000 +#define VCAP_RES_SIZE 0x00000400 + +#define VSC7512_PORT_0_RES_START 0x711e0000 +#define VSC7512_PORT_1_RES_START 0x711f0000 +#define VSC7512_PORT_2_RES_START 0x71200000 +#define VSC7512_PORT_3_RES_START 0x71210000 +#define VSC7512_PORT_4_RES_START 0x71220000 +#define VSC7512_PORT_5_RES_START 0x71230000 +#define VSC7512_PORT_6_RES_START 0x71240000 +#define VSC7512_PORT_7_RES_START 0x71250000 +#define VSC7512_PORT_8_RES_START 0x71260000 +#define VSC7512_PORT_9_RES_START 0x71270000 +#define VSC7512_PORT_10_RES_START 0x71280000 +#define VSC7512_PORT_RES_SIZE 0x00010000 #define VSC7512_GCB_RST_SLEEP_US 100 #define VSC7512_GCB_RST_TIMEOUT_US 100000 @@ -96,6 +129,28 @@ static const struct resource vsc7512_sgpio_resources[] = { DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"), }; +static const struct resource vsc7512_switch_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_ANA_RES_START, VSC7512_ANA_RES_SIZE, "ana"), + DEFINE_RES_REG_NAMED(VSC7512_QS_RES_START, VSC7512_QS_RES_SIZE, "qs"), + DEFINE_RES_REG_NAMED(VSC7512_QSYS_RES_START, VSC7512_QSYS_RES_SIZE, "qsys"), + DEFINE_RES_REG_NAMED(VSC7512_REW_RES_START, VSC7512_REW_RES_SIZE, "rew"), + DEFINE_RES_REG_NAMED(VSC7512_SYS_RES_START, VSC7512_SYS_RES_SIZE, "sys"), + DEFINE_RES_REG_NAMED(VSC7512_S0_RES_START, VCAP_RES_SIZE, "s0"), + DEFINE_RES_REG_NAMED(VSC7512_S1_RES_START, VCAP_RES_SIZE, "s1"), + DEFINE_RES_REG_NAMED(VSC7512_S2_RES_START, VCAP_RES_SIZE, "s2"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_0_RES_START, VSC7512_PORT_RES_SIZE, "port0"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_1_RES_START, VSC7512_PORT_RES_SIZE, "port1"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_2_RES_START, VSC7512_PORT_RES_SIZE, "port2"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_3_RES_START, VSC7512_PORT_RES_SIZE, "port3"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_4_RES_START, VSC7512_PORT_RES_SIZE, "port4"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_5_RES_START, VSC7512_PORT_RES_SIZE, "port5"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_6_RES_START, VSC7512_PORT_RES_SIZE, "port6"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_7_RES_START, VSC7512_PORT_RES_SIZE, "port7"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_8_RES_START, VSC7512_PORT_RES_SIZE, "port8"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_9_RES_START, VSC7512_PORT_RES_SIZE, "port9"), + DEFINE_RES_REG_NAMED(VSC7512_PORT_10_RES_START, VSC7512_PORT_RES_SIZE, "port10") +}; + static const struct mfd_cell vsc7512_devs[] = { { .name = "ocelot-pinctrl", @@ -121,6 +176,11 @@ static const struct mfd_cell vsc7512_devs[] = { .use_of_reg = true, .num_resources = ARRAY_SIZE(vsc7512_miim1_resources), .resources = vsc7512_miim1_resources, + }, { + .name = "ocelot-switch", + .of_compatible = "mscc,vsc7512-switch", + .num_resources = ARRAY_SIZE(vsc7512_switch_resources), + .resources = vsc7512_switch_resources, }, }; diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 0546c573668a..394ca8678d2b 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -11,7 +11,6 @@ menuconfig NET_DSA_MICROCHIP_KSZ_COMMON config NET_DSA_MICROCHIP_KSZ9477_I2C tristate "KSZ series I2C connected switch driver" depends on NET_DSA_MICROCHIP_KSZ_COMMON && I2C - depends on PTP_1588_CLOCK_OPTIONAL select REGMAP_I2C help Select to enable support for registering switches configured through I2C. @@ -19,7 +18,6 @@ config NET_DSA_MICROCHIP_KSZ9477_I2C config NET_DSA_MICROCHIP_KSZ_SPI tristate "KSZ series SPI connected switch driver" depends on NET_DSA_MICROCHIP_KSZ_COMMON && SPI - depends on PTP_1588_CLOCK_OPTIONAL select REGMAP_SPI help Select to enable support for registering switches configured through SPI. @@ -27,6 +25,7 @@ config NET_DSA_MICROCHIP_KSZ_SPI config NET_DSA_MICROCHIP_KSZ_PTP bool "Support for the PTP clock on the KSZ9563/LAN937x Ethernet Switch" depends on NET_DSA_MICROCHIP_KSZ_COMMON && PTP_1588_CLOCK + depends on NET_DSA_MICROCHIP_KSZ_COMMON=m || PTP_1588_CLOCK=y help Select to enable support for timestamping & PTP clock manipulation in KSZ8563/KSZ9563/LAN937x series of switches. KSZ9563/KSZ8563 supports diff --git a/drivers/net/dsa/ocelot/Kconfig b/drivers/net/dsa/ocelot/Kconfig index 60f1f7ada465..640725524d0c 100644 --- a/drivers/net/dsa/ocelot/Kconfig +++ b/drivers/net/dsa/ocelot/Kconfig @@ -8,6 +8,26 @@ config NET_DSA_MSCC_FELIX_DSA_LIB Its name comes from the first hardware chip to make use of it (VSC9959), code named Felix. +config NET_DSA_MSCC_OCELOT_EXT + tristate "Ocelot External Ethernet switch support" + depends on NET_DSA && SPI + depends on NET_VENDOR_MICROSEMI + select MDIO_MSCC_MIIM + select MFD_OCELOT_CORE + select MSCC_OCELOT_SWITCH_LIB + select NET_DSA_MSCC_FELIX_DSA_LIB + select NET_DSA_TAG_OCELOT_8021Q + select NET_DSA_TAG_OCELOT + help + This driver supports the VSC7511, VSC7512, VSC7513 and VSC7514 chips + when controlled through SPI. + + The Ocelot switch family is a set of multi-port networking chips. All + of these chips have the ability to be controlled externally through + SPI or PCIe interfaces. + + Say "Y" here to enable external control to these chips. + config NET_DSA_MSCC_FELIX tristate "Ocelot / Felix Ethernet switch support" depends on NET_DSA && PCI diff --git a/drivers/net/dsa/ocelot/Makefile b/drivers/net/dsa/ocelot/Makefile index fd7dde570d4e..ead868a293e3 100644 --- a/drivers/net/dsa/ocelot/Makefile +++ b/drivers/net/dsa/ocelot/Makefile @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_NET_DSA_MSCC_FELIX_DSA_LIB) += mscc_felix_dsa_lib.o obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o +obj-$(CONFIG_NET_DSA_MSCC_OCELOT_EXT) += mscc_ocelot_ext.o obj-$(CONFIG_NET_DSA_MSCC_SEVILLE) += mscc_seville.o mscc_felix_dsa_lib-objs := felix.o mscc_felix-objs := felix_vsc9959.o +mscc_ocelot_ext-objs := ocelot_ext.o mscc_seville-objs := seville_vsc9953.o diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index f57b4095b793..d4cc9e60f369 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1075,9 +1075,12 @@ static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, phy_interface_t interface) { struct ocelot *ocelot = ds->priv; + struct felix *felix; + + felix = ocelot_to_felix(ocelot); ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface, - FELIX_MAC_QUIRKS); + felix->info->quirks); } static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, @@ -1092,7 +1095,7 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, ocelot_phylink_mac_link_up(ocelot, port, phydev, link_an_mode, interface, speed, duplex, tx_pause, rx_pause, - FELIX_MAC_QUIRKS); + felix->info->quirks); if (felix->info->port_sched_speed_set) felix->info->port_sched_speed_set(ocelot, port, speed); @@ -1270,10 +1273,15 @@ static int felix_parse_ports_node(struct felix *felix, err = felix_validate_phy_mode(felix, port, phy_mode); if (err < 0) { - dev_err(dev, "Unsupported PHY mode %s on port %d\n", - phy_modes(phy_mode), port); + dev_info(dev, "Unsupported PHY mode %s on port %d\n", + phy_modes(phy_mode), port); of_node_put(child); - return err; + + /* Leave port_phy_modes[port] = 0, which is also + * PHY_INTERFACE_MODE_NA. This will perform a + * best-effort to bring up as many ports as possible. + */ + continue; } port_phy_modes[port] = phy_mode; @@ -1312,6 +1320,13 @@ static struct regmap *felix_request_regmap_by_name(struct felix *felix, struct resource res; int i; + /* In an MFD configuration, regmaps are registered directly to the + * parent device before the child devices are probed, so there is no + * need to initialize a new one. + */ + if (!felix->info->resources) + return dev_get_regmap(ocelot->dev->parent, resource_name); + for (i = 0; i < felix->info->num_resources; i++) { if (strcmp(resource_name, felix->info->resources[i].name)) continue; diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index be22d6ccd7c8..d5d0b30c0b75 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -7,6 +7,7 @@ #define ocelot_to_felix(o) container_of((o), struct felix, ocelot) #define FELIX_MAC_QUIRKS OCELOT_QUIRK_PCS_PERFORMS_RATE_ADAPTATION +#define OCELOT_PORT_MODE_NONE 0 #define OCELOT_PORT_MODE_INTERNAL BIT(0) #define OCELOT_PORT_MODE_SGMII BIT(1) #define OCELOT_PORT_MODE_QSGMII BIT(2) @@ -36,6 +37,7 @@ struct felix_info { u16 vcap_pol_base2; u16 vcap_pol_max2; const struct ptp_clock_info *ptp_caps; + unsigned long quirks; /* Some Ocelot switches are integrated into the SoC without the * extraction IRQ line connected to the ARM GIC. By enabling this diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 43dc8ed4854d..354aa3dbfde7 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -2593,6 +2593,7 @@ static const struct felix_info felix_info_vsc9959 = { .num_mact_rows = 2048, .num_ports = VSC9959_NUM_PORTS, .num_tx_queues = OCELOT_NUM_TC, + .quirks = FELIX_MAC_QUIRKS, .quirk_no_xtr_irq = true, .ptp_caps = &vsc9959_ptp_caps, .mdio_bus_alloc = vsc9959_mdio_bus_alloc, diff --git a/drivers/net/dsa/ocelot/ocelot_ext.c b/drivers/net/dsa/ocelot/ocelot_ext.c new file mode 100644 index 000000000000..14efa6387bd7 --- /dev/null +++ b/drivers/net/dsa/ocelot/ocelot_ext.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021-2022 Innovative Advantage Inc. + */ + +#include <linux/mfd/ocelot.h> +#include <linux/phylink.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <soc/mscc/ocelot.h> +#include <soc/mscc/vsc7514_regs.h> +#include "felix.h" + +#define VSC7514_NUM_PORTS 11 + +#define OCELOT_PORT_MODE_SERDES (OCELOT_PORT_MODE_SGMII | \ + OCELOT_PORT_MODE_QSGMII) + +static const u32 vsc7512_port_modes[VSC7514_NUM_PORTS] = { + OCELOT_PORT_MODE_INTERNAL, + OCELOT_PORT_MODE_INTERNAL, + OCELOT_PORT_MODE_INTERNAL, + OCELOT_PORT_MODE_INTERNAL, + OCELOT_PORT_MODE_NONE, + OCELOT_PORT_MODE_NONE, + OCELOT_PORT_MODE_NONE, + OCELOT_PORT_MODE_NONE, + OCELOT_PORT_MODE_NONE, + OCELOT_PORT_MODE_NONE, + OCELOT_PORT_MODE_NONE, +}; + +static const struct ocelot_ops ocelot_ext_ops = { + .reset = ocelot_reset, + .wm_enc = ocelot_wm_enc, + .wm_dec = ocelot_wm_dec, + .wm_stat = ocelot_wm_stat, + .port_to_netdev = felix_port_to_netdev, + .netdev_to_port = felix_netdev_to_port, +}; + +static const char * const vsc7512_resource_names[TARGET_MAX] = { + [SYS] = "sys", + [REW] = "rew", + [S0] = "s0", + [S1] = "s1", + [S2] = "s2", + [QS] = "qs", + [QSYS] = "qsys", + [ANA] = "ana", +}; + +static const struct felix_info vsc7512_info = { + .resource_names = vsc7512_resource_names, + .regfields = vsc7514_regfields, + .map = vsc7514_regmap, + .ops = &ocelot_ext_ops, + .vcap = vsc7514_vcap_props, + .num_mact_rows = 1024, + .num_ports = VSC7514_NUM_PORTS, + .num_tx_queues = OCELOT_NUM_TC, + .port_modes = vsc7512_port_modes, +}; + +static int ocelot_ext_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dsa_switch *ds; + struct ocelot *ocelot; + struct felix *felix; + int err; + + felix = kzalloc(sizeof(*felix), GFP_KERNEL); + if (!felix) + return -ENOMEM; + + dev_set_drvdata(dev, felix); + + ocelot = &felix->ocelot; + ocelot->dev = dev; + + ocelot->num_flooding_pgids = 1; + + felix->info = &vsc7512_info; + + ds = kzalloc(sizeof(*ds), GFP_KERNEL); + if (!ds) { + err = -ENOMEM; + dev_err_probe(dev, err, "Failed to allocate DSA switch\n"); + goto err_free_felix; + } + + ds->dev = dev; + ds->num_ports = felix->info->num_ports; + ds->num_tx_queues = felix->info->num_tx_queues; + + ds->ops = &felix_switch_ops; + ds->priv = ocelot; + felix->ds = ds; + felix->tag_proto = DSA_TAG_PROTO_OCELOT; + + err = dsa_register_switch(ds); + if (err) { + dev_err_probe(dev, err, "Failed to register DSA switch\n"); + goto err_free_ds; + } + + return 0; + +err_free_ds: + kfree(ds); +err_free_felix: + kfree(felix); + return err; +} + +static int ocelot_ext_remove(struct platform_device *pdev) +{ + struct felix *felix = dev_get_drvdata(&pdev->dev); + + if (!felix) + return 0; + + dsa_unregister_switch(felix->ds); + + kfree(felix->ds); + kfree(felix); + + return 0; +} + +static void ocelot_ext_shutdown(struct platform_device *pdev) +{ + struct felix *felix = dev_get_drvdata(&pdev->dev); + + if (!felix) + return; + + dsa_switch_shutdown(felix->ds); + + dev_set_drvdata(&pdev->dev, NULL); +} + +static const struct of_device_id ocelot_ext_switch_of_match[] = { + { .compatible = "mscc,vsc7512-switch" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ocelot_ext_switch_of_match); + +static struct platform_driver ocelot_ext_switch_driver = { + .driver = { + .name = "ocelot-switch", + .of_match_table = of_match_ptr(ocelot_ext_switch_of_match), + }, + .probe = ocelot_ext_probe, + .remove = ocelot_ext_remove, + .shutdown = ocelot_ext_shutdown, +}; +module_platform_driver(ocelot_ext_switch_driver); + +MODULE_DESCRIPTION("External Ocelot Switch driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(MFD_OCELOT); diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 88ed3a2e487a..287b64b788db 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -971,6 +971,7 @@ static const struct felix_info seville_info_vsc9953 = { .vcap_pol_max = VSC9953_VCAP_POLICER_MAX, .vcap_pol_base2 = VSC9953_VCAP_POLICER_BASE2, .vcap_pol_max2 = VSC9953_VCAP_POLICER_MAX2, + .quirks = FELIX_MAC_QUIRKS, .num_mact_rows = 2048, .num_ports = VSC9953_NUM_PORTS, .num_tx_queues = OCELOT_NUM_TC, diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index b751dc8486dc..392ec09a1d8a 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -196,28 +196,6 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg, return 0; } -static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index) -{ - u32 val; - - bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ | - (index << CAM_CTRL_INDEX_SHIFT))); - - b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); - - val = br32(bp, B44_CAM_DATA_LO); - - data[2] = (val >> 24) & 0xFF; - data[3] = (val >> 16) & 0xFF; - data[4] = (val >> 8) & 0xFF; - data[5] = (val >> 0) & 0xFF; - - val = br32(bp, B44_CAM_DATA_HI); - - data[0] = (val >> 8) & 0xFF; - data[1] = (val >> 0) & 0xFF; -} - static inline void __b44_cam_write(struct b44 *bp, const unsigned char *data, int index) { diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index e19a6bb3f444..146ca1d8031b 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -250,10 +250,11 @@ static void ibmvnic_set_affinity(struct ibmvnic_adapter *adapter) struct ibmvnic_sub_crq_queue **rxqs = adapter->rx_scrq; struct ibmvnic_sub_crq_queue **txqs = adapter->tx_scrq; struct ibmvnic_sub_crq_queue *queue; - int num_rxqs = adapter->num_active_rx_scrqs; - int num_txqs = adapter->num_active_tx_scrqs; + int num_rxqs = adapter->num_active_rx_scrqs, i_rxqs = 0; + int num_txqs = adapter->num_active_tx_scrqs, i_txqs = 0; int total_queues, stride, stragglers, i; unsigned int num_cpu, cpu; + bool is_rx_queue; int rc = 0; netdev_dbg(adapter->netdev, "%s: Setting irq affinity hints", __func__); @@ -273,14 +274,24 @@ static void ibmvnic_set_affinity(struct ibmvnic_adapter *adapter) /* next available cpu to assign irq to */ cpu = cpumask_next(-1, cpu_online_mask); - for (i = 0; i < num_txqs; i++) { - queue = txqs[i]; + for (i = 0; i < total_queues; i++) { + is_rx_queue = false; + /* balance core load by alternating rx and tx assignments + * ex: TX0 -> RX0 -> TX1 -> RX1 etc. + */ + if ((i % 2 == 1 && i_rxqs < num_rxqs) || i_txqs == num_txqs) { + queue = rxqs[i_rxqs++]; + is_rx_queue = true; + } else { + queue = txqs[i_txqs++]; + } + rc = ibmvnic_set_queue_affinity(queue, &cpu, &stragglers, stride); if (rc) goto out; - if (!queue) + if (!queue || is_rx_queue) continue; rc = __netif_set_xps_queue(adapter->netdev, @@ -291,14 +302,6 @@ static void ibmvnic_set_affinity(struct ibmvnic_adapter *adapter) __func__, i, rc); } - for (i = 0; i < num_rxqs; i++) { - queue = rxqs[i]; - rc = ibmvnic_set_queue_affinity(queue, &cpu, &stragglers, - stride); - if (rc) - goto out; - } - out: if (rc) { netdev_warn(adapter->netdev, diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 04acd1a992fa..e1eb1de88bf9 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7418,9 +7418,6 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_pci_reg; - /* AER (Advanced Error Reporting) hooks */ - pci_enable_pcie_error_reporting(pdev); - pci_set_master(pdev); /* PCI config space info */ err = pci_save_state(pdev); @@ -7708,7 +7705,6 @@ err_flashmap: err_ioremap: free_netdev(netdev); err_alloc_etherdev: - pci_disable_pcie_error_reporting(pdev); pci_release_mem_regions(pdev); err_pci_reg: err_dma: @@ -7775,9 +7771,6 @@ static void e1000_remove(struct pci_dev *pdev) free_netdev(netdev); - /* AER disable */ - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index b473cb7d7c57..027d721feb18 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -2127,8 +2127,6 @@ static int fm10k_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pci_reg; } - pci_enable_pcie_error_reporting(pdev); - pci_set_master(pdev); pci_save_state(pdev); @@ -2227,7 +2225,6 @@ err_sw_init: err_ioremap: free_netdev(netdev); err_alloc_netdev: - pci_disable_pcie_error_reporting(pdev); pci_release_mem_regions(pdev); err_pci_reg: err_dma: @@ -2281,8 +2278,6 @@ static void fm10k_remove(struct pci_dev *pdev) pci_release_mem_regions(pdev); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 53d0083e35da..43693f902c27 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -15589,7 +15589,6 @@ err_switch_setup: timer_shutdown_sync(&pf->service_timer); i40e_shutdown_adminq(hw); iounmap(hw->hw_addr); - pci_disable_pcie_error_reporting(pf->pdev); pci_release_mem_regions(pf->pdev); pci_disable_device(pf->pdev); kfree(pf); @@ -15660,7 +15659,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pci_reg; } - pci_enable_pcie_error_reporting(pdev); pci_set_master(pdev); /* Now that we have a PCI connection, we need to do the @@ -16218,7 +16216,6 @@ err_pf_reset: err_ioremap: kfree(pf); err_pf_alloc: - pci_disable_pcie_error_reporting(pdev); pci_release_mem_regions(pdev); err_pci_reg: err_dma: @@ -16366,7 +16363,6 @@ unmap: kfree(pf); pci_release_mem_regions(pdev); - pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 2c4480b20db3..3273aeb8fa67 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -4868,8 +4868,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pci_reg; } - pci_enable_pcie_error_reporting(pdev); - pci_set_master(pdev); netdev = alloc_etherdev_mq(sizeof(struct iavf_adapter), @@ -4957,7 +4955,6 @@ err_ioremap: err_alloc_wq: free_netdev(netdev); err_alloc_etherdev: - pci_disable_pcie_error_reporting(pdev); pci_release_regions(pdev); err_pci_reg: err_dma: @@ -5175,8 +5172,6 @@ static void iavf_remove(struct pci_dev *pdev) free_netdev(netdev); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index fce86e8ff834..4aa19562fe93 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4664,7 +4664,6 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) return err; } - pci_enable_pcie_error_reporting(pdev); pci_set_master(pdev); pf->pdev = pdev; @@ -4981,7 +4980,6 @@ err_init_pf_unroll: ice_devlink_destroy_regions(pf); ice_deinit_hw(hw); err_exit_unroll: - pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); return err; } @@ -5113,7 +5111,6 @@ static void ice_remove(struct pci_dev *pdev) ice_reset(hw, ICE_RESET_PFR); pci_wait_for_pending_transaction(pdev); ice_clear_interrupt_scheme(pf); - pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 3c0c35ecea10..c56b991fa610 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3194,8 +3194,6 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_pci_reg; - pci_enable_pcie_error_reporting(pdev); - pci_set_master(pdev); pci_save_state(pdev); @@ -3626,7 +3624,6 @@ err_sw_init: err_ioremap: free_netdev(netdev); err_alloc_etherdev: - pci_disable_pcie_error_reporting(pdev); pci_release_mem_regions(pdev); err_pci_reg: err_dma: @@ -3837,8 +3834,6 @@ static void igb_remove(struct pci_dev *pdev) kfree(adapter->shadow_vfta); free_netdev(netdev); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index e86b15efaeb8..6ddcbc8b7b6a 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -6434,8 +6434,6 @@ static int igc_probe(struct pci_dev *pdev, if (err) goto err_pci_reg; - pci_enable_pcie_error_reporting(pdev); - err = pci_enable_ptm(pdev, NULL); if (err < 0) dev_info(&pdev->dev, "PCIe PTM not supported by PCIe bus/controller\n"); @@ -6640,7 +6638,6 @@ err_sw_init: err_ioremap: free_netdev(netdev); err_alloc_etherdev: - pci_disable_pcie_error_reporting(pdev); pci_release_mem_regions(pdev); err_pci_reg: err_dma: @@ -6688,8 +6685,6 @@ static void igc_remove(struct pci_dev *pdev) free_netdev(netdev); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 43a44c1e1576..992b7ae75233 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -10809,8 +10809,6 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pci_reg; } - pci_enable_pcie_error_reporting(pdev); - pci_set_master(pdev); pci_save_state(pdev); @@ -11238,7 +11236,6 @@ err_ioremap: disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); free_netdev(netdev); err_alloc_etherdev: - pci_disable_pcie_error_reporting(pdev); pci_release_mem_regions(pdev); err_pci_reg: err_dma: @@ -11327,8 +11324,6 @@ static void ixgbe_remove(struct pci_dev *pdev) disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); free_netdev(netdev); - pci_disable_pcie_error_reporting(pdev); - if (disable_dev) pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c index f69102d20c90..20ebb9c95c73 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c @@ -200,10 +200,8 @@ void npc_config_secret_key(struct rvu *rvu, int blkaddr) struct rvu_hwinfo *hw = rvu->hw; u8 intf; - if (!hwcap->npc_hash_extract) { - dev_info(rvu->dev, "HW does not support secret key configuration\n"); + if (!hwcap->npc_hash_extract) return; - } for (intf = 0; intf < hw->npc_intfs; intf++) { rvu_write64(rvu, blkaddr, NPC_AF_INTFX_SECRET_KEY0(intf), @@ -221,10 +219,8 @@ void npc_program_mkex_hash(struct rvu *rvu, int blkaddr) struct rvu_hwinfo *hw = rvu->hw; u8 intf; - if (!hwcap->npc_hash_extract) { - dev_dbg(rvu->dev, "Field hash extract feature is not supported\n"); + if (!hwcap->npc_hash_extract) return; - } for (intf = 0; intf < hw->npc_intfs; intf++) { npc_program_mkex_hash_rx(rvu, blkaddr, intf); @@ -1853,19 +1849,13 @@ int rvu_npc_exact_init(struct rvu *rvu) /* Check exact match feature is supported */ npc_const3 = rvu_read64(rvu, blkaddr, NPC_AF_CONST3); - if (!(npc_const3 & BIT_ULL(62))) { - dev_info(rvu->dev, "%s: No support for exact match support\n", - __func__); + if (!(npc_const3 & BIT_ULL(62))) return 0; - } /* Check if kex profile has enabled EXACT match nibble */ cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX)); - if (!(cfg & NPC_EXACT_NIBBLE_HIT)) { - dev_info(rvu->dev, "%s: NPC exact match nibble not enabled in KEX profile\n", - __func__); + if (!(cfg & NPC_EXACT_NIBBLE_HIT)) return 0; - } /* Set capability to true */ rvu->hw->cap.npc_exact_match_enabled = true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 382d02f6619c..b00e33ed05e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -104,6 +104,7 @@ static bool mlx5_cmd_is_throttle_opcode(u16 op) case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT: case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT: case MLX5_CMD_OP_QUERY_GENERAL_OBJECT: + case MLX5_CMD_OP_SYNC_CRYPTO: return true; } return false; @@ -523,6 +524,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_QUERY_VHCA_MIGRATION_STATE: case MLX5_CMD_OP_SAVE_VHCA_STATE: case MLX5_CMD_OP_LOAD_VHCA_STATE: + case MLX5_CMD_OP_SYNC_CRYPTO: *status = MLX5_DRIVER_STATUS_ABORTED; *synd = MLX5_DRIVER_SYND; return -ENOLINK; @@ -725,6 +727,7 @@ const char *mlx5_command_str(int command) MLX5_COMMAND_STR_CASE(QUERY_VHCA_MIGRATION_STATE); MLX5_COMMAND_STR_CASE(SAVE_VHCA_STATE); MLX5_COMMAND_STR_CASE(LOAD_VHCA_STATE); + MLX5_COMMAND_STR_CASE(SYNC_CRYPTO); default: return "unknown command opcode"; } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c index 7758a425bfa8..8218c892b161 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c @@ -204,13 +204,15 @@ mlx5e_flow_meter_create_aso_obj(struct mlx5e_flow_meters *flow_meters, int *obj_ u32 in[MLX5_ST_SZ_DW(create_flow_meter_aso_obj_in)] = {}; u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; struct mlx5_core_dev *mdev = flow_meters->mdev; - void *obj; + void *obj, *param; int err; MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO); - MLX5_SET(general_obj_in_cmd_hdr, in, log_obj_range, flow_meters->log_granularity); + param = MLX5_ADDR_OF(general_obj_in_cmd_hdr, in, op_param); + MLX5_SET(general_obj_create_param, param, log_obj_range, + flow_meters->log_granularity); obj = MLX5_ADDR_OF(create_flow_meter_aso_obj_in, in, flow_meter_aso_obj); MLX5_SET(flow_meter_aso_obj, obj, meter_aso_access_pd, flow_meters->pdn); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c index 2461462b7b99..57ac0f663fcd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c @@ -4,7 +4,7 @@ #include "mlx5_core.h" #include "en.h" #include "ipsec.h" -#include "lib/mlx5.h" +#include "lib/crypto.h" enum { MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c index eb5b09f81dec..cf704f106b7c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c @@ -4,16 +4,16 @@ #include <linux/debugfs.h> #include "en.h" #include "lib/mlx5.h" +#include "lib/crypto.h" #include "en_accel/ktls.h" #include "en_accel/ktls_utils.h" #include "en_accel/fs_tcp.h" -int mlx5_ktls_create_key(struct mlx5_core_dev *mdev, - struct tls_crypto_info *crypto_info, - u32 *p_key_id) +struct mlx5_crypto_dek *mlx5_ktls_create_key(struct mlx5_crypto_dek_pool *dek_pool, + struct tls_crypto_info *crypto_info) { + const void *key; u32 sz_bytes; - void *key; switch (crypto_info->cipher_type) { case TLS_CIPHER_AES_GCM_128: { @@ -33,17 +33,16 @@ int mlx5_ktls_create_key(struct mlx5_core_dev *mdev, break; } default: - return -EINVAL; + return ERR_PTR(-EINVAL); } - return mlx5_create_encryption_key(mdev, key, sz_bytes, - MLX5_ACCEL_OBJ_TLS_KEY, - p_key_id); + return mlx5_crypto_dek_create(dek_pool, key, sz_bytes); } -void mlx5_ktls_destroy_key(struct mlx5_core_dev *mdev, u32 key_id) +void mlx5_ktls_destroy_key(struct mlx5_crypto_dek_pool *dek_pool, + struct mlx5_crypto_dek *dek) { - mlx5_destroy_encryption_key(mdev, key_id); + mlx5_crypto_dek_destroy(dek_pool, dek); } static int mlx5e_ktls_add(struct net_device *netdev, struct sock *sk, @@ -189,6 +188,7 @@ static void mlx5e_tls_debugfs_init(struct mlx5e_tls *tls, int mlx5e_ktls_init(struct mlx5e_priv *priv) { + struct mlx5_crypto_dek_pool *dek_pool; struct mlx5e_tls *tls; if (!mlx5e_is_ktls_device(priv->mdev)) @@ -197,9 +197,15 @@ int mlx5e_ktls_init(struct mlx5e_priv *priv) tls = kzalloc(sizeof(*tls), GFP_KERNEL); if (!tls) return -ENOMEM; + tls->mdev = priv->mdev; + dek_pool = mlx5_crypto_dek_pool_create(priv->mdev, MLX5_ACCEL_OBJ_TLS_KEY); + if (IS_ERR(dek_pool)) { + kfree(tls); + return PTR_ERR(dek_pool); + } + tls->dek_pool = dek_pool; priv->tls = tls; - priv->tls->mdev = priv->mdev; mlx5e_tls_debugfs_init(tls, priv->dfs_root); @@ -216,6 +222,7 @@ void mlx5e_ktls_cleanup(struct mlx5e_priv *priv) debugfs_remove_recursive(tls->debugfs.dfs); tls->debugfs.dfs = NULL; + mlx5_crypto_dek_pool_destroy(tls->dek_pool); kfree(priv->tls); priv->tls = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h index fccf995ee16d..f11075e67658 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h @@ -10,10 +10,12 @@ #include "en.h" #ifdef CONFIG_MLX5_EN_TLS -int mlx5_ktls_create_key(struct mlx5_core_dev *mdev, - struct tls_crypto_info *crypto_info, - u32 *p_key_id); -void mlx5_ktls_destroy_key(struct mlx5_core_dev *mdev, u32 key_id); +#include "lib/crypto.h" + +struct mlx5_crypto_dek *mlx5_ktls_create_key(struct mlx5_crypto_dek_pool *dek_pool, + struct tls_crypto_info *crypto_info); +void mlx5_ktls_destroy_key(struct mlx5_crypto_dek_pool *dek_pool, + struct mlx5_crypto_dek *dek); static inline bool mlx5e_is_ktls_device(struct mlx5_core_dev *mdev) { @@ -83,6 +85,7 @@ struct mlx5e_tls { struct mlx5e_tls_sw_stats sw_stats; struct workqueue_struct *rx_wq; struct mlx5e_tls_tx_pool *tx_pool; + struct mlx5_crypto_dek_pool *dek_pool; struct mlx5e_tls_debugfs debugfs; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c index 3e54834747ce..4be770443b0c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c @@ -50,7 +50,7 @@ struct mlx5e_ktls_offload_context_rx { struct mlx5e_tls_sw_stats *sw_stats; struct completion add_ctx; struct mlx5e_tir tir; - u32 key_id; + struct mlx5_crypto_dek *dek; u32 rxq; DECLARE_BITMAP(flags, MLX5E_NUM_PRIV_RX_FLAGS); @@ -148,7 +148,8 @@ post_static_params(struct mlx5e_icosq *sq, wqe = MLX5E_TLS_FETCH_SET_STATIC_PARAMS_WQE(sq, pi); mlx5e_ktls_build_static_params(wqe, sq->pc, sq->sqn, &priv_rx->crypto_info, mlx5e_tir_get_tirn(&priv_rx->tir), - priv_rx->key_id, priv_rx->resync.seq, false, + mlx5_crypto_dek_get_id(priv_rx->dek), + priv_rx->resync.seq, false, TLS_OFFLOAD_CTX_DIR_RX); wi = (struct mlx5e_icosq_wqe_info) { .wqe_type = MLX5E_ICOSQ_WQE_UMR_TLS, @@ -610,20 +611,22 @@ int mlx5e_ktls_add_rx(struct net_device *netdev, struct sock *sk, struct mlx5e_ktls_offload_context_rx *priv_rx; struct mlx5e_ktls_rx_resync_ctx *resync; struct tls_context *tls_ctx; - struct mlx5_core_dev *mdev; + struct mlx5_crypto_dek *dek; struct mlx5e_priv *priv; int rxq, err; tls_ctx = tls_get_ctx(sk); priv = netdev_priv(netdev); - mdev = priv->mdev; priv_rx = kzalloc(sizeof(*priv_rx), GFP_KERNEL); if (unlikely(!priv_rx)) return -ENOMEM; - err = mlx5_ktls_create_key(mdev, crypto_info, &priv_rx->key_id); - if (err) + dek = mlx5_ktls_create_key(priv->tls->dek_pool, crypto_info); + if (IS_ERR(dek)) { + err = PTR_ERR(dek); goto err_create_key; + } + priv_rx->dek = dek; INIT_LIST_HEAD(&priv_rx->list); spin_lock_init(&priv_rx->lock); @@ -673,7 +676,7 @@ int mlx5e_ktls_add_rx(struct net_device *netdev, struct sock *sk, err_post_wqes: mlx5e_tir_destroy(&priv_rx->tir); err_create_tir: - mlx5_ktls_destroy_key(mdev, priv_rx->key_id); + mlx5_ktls_destroy_key(priv->tls->dek_pool, priv_rx->dek); err_create_key: kfree(priv_rx); return err; @@ -683,11 +686,9 @@ void mlx5e_ktls_del_rx(struct net_device *netdev, struct tls_context *tls_ctx) { struct mlx5e_ktls_offload_context_rx *priv_rx; struct mlx5e_ktls_rx_resync_ctx *resync; - struct mlx5_core_dev *mdev; struct mlx5e_priv *priv; priv = netdev_priv(netdev); - mdev = priv->mdev; priv_rx = mlx5e_get_ktls_rx_priv_ctx(tls_ctx); set_bit(MLX5E_PRIV_RX_FLAG_DELETING, priv_rx->flags); @@ -707,7 +708,7 @@ void mlx5e_ktls_del_rx(struct net_device *netdev, struct tls_context *tls_ctx) mlx5e_accel_fs_del_sk(priv_rx->rule.rule); mlx5e_tir_destroy(&priv_rx->tir); - mlx5_ktls_destroy_key(mdev, priv_rx->key_id); + mlx5_ktls_destroy_key(priv->tls->dek_pool, priv_rx->dek); /* priv_rx should normally be freed here, but if there is an outstanding * GET_PSV, deallocation will be delayed until the CQE for GET_PSV is * processed. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c index 6db27062b765..e80b43b7aac9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c @@ -98,7 +98,7 @@ struct mlx5e_ktls_offload_context_tx { struct tls_offload_context_tx *tx_ctx; struct mlx5_core_dev *mdev; struct mlx5e_tls_sw_stats *sw_stats; - u32 key_id; + struct mlx5_crypto_dek *dek; u8 create_err : 1; }; @@ -457,6 +457,7 @@ int mlx5e_ktls_add_tx(struct net_device *netdev, struct sock *sk, struct mlx5e_ktls_offload_context_tx *priv_tx; struct mlx5e_tls_tx_pool *pool; struct tls_context *tls_ctx; + struct mlx5_crypto_dek *dek; struct mlx5e_priv *priv; int err; @@ -468,9 +469,12 @@ int mlx5e_ktls_add_tx(struct net_device *netdev, struct sock *sk, if (IS_ERR(priv_tx)) return PTR_ERR(priv_tx); - err = mlx5_ktls_create_key(pool->mdev, crypto_info, &priv_tx->key_id); - if (err) + dek = mlx5_ktls_create_key(priv->tls->dek_pool, crypto_info); + if (IS_ERR(dek)) { + err = PTR_ERR(dek); goto err_create_key; + } + priv_tx->dek = dek; priv_tx->expected_seq = start_offload_tcp_sn; switch (crypto_info->cipher_type) { @@ -512,7 +516,7 @@ void mlx5e_ktls_del_tx(struct net_device *netdev, struct tls_context *tls_ctx) pool = priv->tls->tx_pool; atomic64_inc(&priv_tx->sw_stats->tx_tls_del); - mlx5_ktls_destroy_key(priv_tx->mdev, priv_tx->key_id); + mlx5_ktls_destroy_key(priv->tls->dek_pool, priv_tx->dek); pool_push(pool, priv_tx); } @@ -551,8 +555,9 @@ post_static_params(struct mlx5e_txqsq *sq, pi = mlx5e_txqsq_get_next_pi(sq, num_wqebbs); wqe = MLX5E_TLS_FETCH_SET_STATIC_PARAMS_WQE(sq, pi); mlx5e_ktls_build_static_params(wqe, sq->pc, sq->sqn, &priv_tx->crypto_info, - priv_tx->tisn, priv_tx->key_id, 0, fence, - TLS_OFFLOAD_CTX_DIR_TX); + priv_tx->tisn, + mlx5_crypto_dek_get_id(priv_tx->dek), + 0, fence, TLS_OFFLOAD_CTX_DIR_TX); tx_fill_wi(sq, pi, num_wqebbs, 0, NULL); sq->pc += num_wqebbs; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 7f6b940830b3..08d0929e8260 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -7,7 +7,7 @@ #include "en.h" #include "lib/aso.h" -#include "lib/mlx5.h" +#include "lib/crypto.h" #include "en_accel/macsec.h" #include "en_accel/macsec_fs.h" diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c index 68f19324db93..4c9a3210600c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -31,6 +31,7 @@ */ #include "en.h" +#include "lib/crypto.h" /* mlx5e global resources should be placed in this file. * Global resources are common to all the netdevices created on the same nic. @@ -104,6 +105,13 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev) INIT_LIST_HEAD(&res->td.tirs_list); mutex_init(&res->td.list_lock); + mdev->mlx5e_res.dek_priv = mlx5_crypto_dek_init(mdev); + if (IS_ERR(mdev->mlx5e_res.dek_priv)) { + mlx5_core_err(mdev, "crypto dek init failed, %ld\n", + PTR_ERR(mdev->mlx5e_res.dek_priv)); + mdev->mlx5e_res.dek_priv = NULL; + } + return 0; err_destroy_mkey: @@ -119,6 +127,8 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev) { struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs; + mlx5_crypto_dek_cleanup(mdev->mlx5e_res.dek_priv); + mdev->mlx5e_res.dek_priv = NULL; mlx5_free_bfreg(mdev, &res->bfreg); mlx5_core_destroy_mkey(mdev, res->mkey); mlx5_core_dealloc_transport_domain(mdev, res->td.tdn); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index f34e758a2f1f..7bb7be01225a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -267,6 +267,12 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev) return err; } + if (MLX5_CAP_GEN(dev, crypto)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_CRYPTO); + if (err) + return err; + } + if (MLX5_CAP_GEN(dev, shampo)) { err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_SHAMPO); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c index e995f8378df7..3a94b8f8031e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c @@ -2,53 +2,253 @@ // Copyright (c) 2019 Mellanox Technologies. #include "mlx5_core.h" -#include "lib/mlx5.h" +#include "lib/crypto.h" -int mlx5_create_encryption_key(struct mlx5_core_dev *mdev, - void *key, u32 sz_bytes, - u32 key_type, u32 *p_key_id) -{ - u32 in[MLX5_ST_SZ_DW(create_encryption_key_in)] = {}; - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; - u32 sz_bits = sz_bytes * BITS_PER_BYTE; - u8 general_obj_key_size; - u64 general_obj_types; - void *obj, *key_p; - int err; +#define MLX5_CRYPTO_DEK_POOLS_NUM (MLX5_ACCEL_OBJ_TYPE_KEY_NUM - 1) +#define type2idx(type) ((type) - 1) - obj = MLX5_ADDR_OF(create_encryption_key_in, in, encryption_key_object); - key_p = MLX5_ADDR_OF(encryption_key_obj, obj, key); +#define MLX5_CRYPTO_DEK_POOL_SYNC_THRESH 128 - general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types); - if (!(general_obj_types & - MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY)) - return -EINVAL; +/* calculate the num of DEKs, which are freed by any user + * (for example, TLS) after last revalidation in a pool or a bulk. + */ +#define MLX5_CRYPTO_DEK_CALC_FREED(a) \ + ({ typeof(a) _a = (a); \ + _a->num_deks - _a->avail_deks - _a->in_use_deks; }) + +#define MLX5_CRYPTO_DEK_POOL_CALC_FREED(pool) MLX5_CRYPTO_DEK_CALC_FREED(pool) +#define MLX5_CRYPTO_DEK_BULK_CALC_FREED(bulk) MLX5_CRYPTO_DEK_CALC_FREED(bulk) + +#define MLX5_CRYPTO_DEK_BULK_IDLE(bulk) \ + ({ typeof(bulk) _bulk = (bulk); \ + _bulk->avail_deks == _bulk->num_deks; }) + +enum { + MLX5_CRYPTO_DEK_ALL_TYPE = BIT(0), +}; + +struct mlx5_crypto_dek_pool { + struct mlx5_core_dev *mdev; + u32 key_purpose; + int num_deks; /* the total number of keys in this pool */ + int avail_deks; /* the number of available keys in this pool */ + int in_use_deks; /* the number of being used keys in this pool */ + struct mutex lock; /* protect the following lists, and the bulks */ + struct list_head partial_list; /* some of keys are available */ + struct list_head full_list; /* no available keys */ + struct list_head avail_list; /* all keys are available to use */ + + /* No in-used keys, and all need to be synced. + * These bulks will be put to avail list after sync. + */ + struct list_head sync_list; + + bool syncing; + struct list_head wait_for_free; + struct work_struct sync_work; + + spinlock_t destroy_lock; /* protect destroy_list */ + struct list_head destroy_list; + struct work_struct destroy_work; +}; + +struct mlx5_crypto_dek_bulk { + struct mlx5_core_dev *mdev; + int base_obj_id; + int avail_start; /* the bit to start search */ + int num_deks; /* the total number of keys in a bulk */ + int avail_deks; /* the number of keys available, with need_sync bit 0 */ + int in_use_deks; /* the number of keys being used, with in_use bit 1 */ + struct list_head entry; + + /* 0: not being used by any user, 1: otherwise */ + unsigned long *in_use; + + /* The bits are set when they are used, and reset after crypto_sync + * is executed. So, the value 0 means the key is newly created, or not + * used after sync, and 1 means it is in use, or freed but not synced + */ + unsigned long *need_sync; +}; + +struct mlx5_crypto_dek_priv { + struct mlx5_core_dev *mdev; + int log_dek_obj_range; +}; + +struct mlx5_crypto_dek { + struct mlx5_crypto_dek_bulk *bulk; + struct list_head entry; + u32 obj_id; +}; + +u32 mlx5_crypto_dek_get_id(struct mlx5_crypto_dek *dek) +{ + return dek->obj_id; +} + +static int mlx5_crypto_dek_get_key_sz(struct mlx5_core_dev *mdev, + u32 sz_bytes, u8 *key_sz_p) +{ + u32 sz_bits = sz_bytes * BITS_PER_BYTE; switch (sz_bits) { case 128: - general_obj_key_size = - MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128; - key_p += sz_bytes; + *key_sz_p = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128; break; case 256: - general_obj_key_size = - MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_256; + *key_sz_p = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_256; break; default: + mlx5_core_err(mdev, "Crypto offload error, invalid key size (%u bits)\n", + sz_bits); return -EINVAL; } - memcpy(key_p, key, sz_bytes); + return 0; +} + +static int mlx5_crypto_dek_fill_key(struct mlx5_core_dev *mdev, u8 *key_obj, + const void *key, u32 sz_bytes) +{ + void *dst; + u8 key_sz; + int err; + + err = mlx5_crypto_dek_get_key_sz(mdev, sz_bytes, &key_sz); + if (err) + return err; + + MLX5_SET(encryption_key_obj, key_obj, key_size, key_sz); + + if (sz_bytes == 16) + /* For key size of 128b the MSBs are reserved. */ + dst = MLX5_ADDR_OF(encryption_key_obj, key_obj, key[1]); + else + dst = MLX5_ADDR_OF(encryption_key_obj, key_obj, key); + + memcpy(dst, key, sz_bytes); + + return 0; +} + +static int mlx5_crypto_cmd_sync_crypto(struct mlx5_core_dev *mdev, + int crypto_type) +{ + u32 in[MLX5_ST_SZ_DW(sync_crypto_in)] = {}; + int err; + + mlx5_core_dbg(mdev, + "Execute SYNC_CRYPTO command with crypto_type(0x%x)\n", + crypto_type); + + MLX5_SET(sync_crypto_in, in, opcode, MLX5_CMD_OP_SYNC_CRYPTO); + MLX5_SET(sync_crypto_in, in, crypto_type, crypto_type); + + err = mlx5_cmd_exec_in(mdev, sync_crypto, in); + if (err) + mlx5_core_err(mdev, + "Failed to exec sync crypto, type=%d, err=%d\n", + crypto_type, err); + + return err; +} + +static int mlx5_crypto_create_dek_bulk(struct mlx5_core_dev *mdev, + u32 key_purpose, int log_obj_range, + u32 *obj_id) +{ + u32 in[MLX5_ST_SZ_DW(create_encryption_key_in)] = {}; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; + void *obj, *param; + int err; - MLX5_SET(encryption_key_obj, obj, key_size, general_obj_key_size); - MLX5_SET(encryption_key_obj, obj, key_type, key_type); MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY); + param = MLX5_ADDR_OF(general_obj_in_cmd_hdr, in, op_param); + MLX5_SET(general_obj_create_param, param, log_obj_range, log_obj_range); + + obj = MLX5_ADDR_OF(create_encryption_key_in, in, encryption_key_object); + MLX5_SET(encryption_key_obj, obj, key_purpose, key_purpose); MLX5_SET(encryption_key_obj, obj, pd, mdev->mlx5e_res.hw_objs.pdn); err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (err) + return err; + + *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); + mlx5_core_dbg(mdev, "DEK objects created, bulk=%d, obj_id=%d\n", + 1 << log_obj_range, *obj_id); + + return 0; +} + +static int mlx5_crypto_modify_dek_key(struct mlx5_core_dev *mdev, + const void *key, u32 sz_bytes, u32 key_purpose, + u32 obj_id, u32 obj_offset) +{ + u32 in[MLX5_ST_SZ_DW(modify_encryption_key_in)] = {}; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; + void *obj, *param; + int err; + + MLX5_SET(general_obj_in_cmd_hdr, in, opcode, + MLX5_CMD_OP_MODIFY_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, + MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id); + + param = MLX5_ADDR_OF(general_obj_in_cmd_hdr, in, op_param); + MLX5_SET(general_obj_query_param, param, obj_offset, obj_offset); + + obj = MLX5_ADDR_OF(modify_encryption_key_in, in, encryption_key_object); + MLX5_SET64(encryption_key_obj, obj, modify_field_select, 1); + MLX5_SET(encryption_key_obj, obj, key_purpose, key_purpose); + MLX5_SET(encryption_key_obj, obj, pd, mdev->mlx5e_res.hw_objs.pdn); + + err = mlx5_crypto_dek_fill_key(mdev, obj, key, sz_bytes); + if (err) + return err; + + err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + + /* avoid leaking key on the stack */ + memzero_explicit(in, sizeof(in)); + + return err; +} + +static int mlx5_crypto_create_dek_key(struct mlx5_core_dev *mdev, + const void *key, u32 sz_bytes, + u32 key_purpose, u32 *p_key_id) +{ + u32 in[MLX5_ST_SZ_DW(create_encryption_key_in)] = {}; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; + u64 general_obj_types; + void *obj; + int err; + + general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types); + if (!(general_obj_types & + MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY)) + return -EINVAL; + + MLX5_SET(general_obj_in_cmd_hdr, in, opcode, + MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, + MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY); + + obj = MLX5_ADDR_OF(create_encryption_key_in, in, encryption_key_object); + MLX5_SET(encryption_key_obj, obj, key_purpose, key_purpose); + MLX5_SET(encryption_key_obj, obj, pd, mdev->mlx5e_res.hw_objs.pdn); + + err = mlx5_crypto_dek_fill_key(mdev, obj, key, sz_bytes); + if (err) + return err; + + err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); if (!err) *p_key_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); @@ -58,7 +258,7 @@ int mlx5_create_encryption_key(struct mlx5_core_dev *mdev, return err; } -void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id) +static void mlx5_crypto_destroy_dek_key(struct mlx5_core_dev *mdev, u32 key_id) { u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; @@ -71,3 +271,504 @@ void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id) mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); } + +int mlx5_create_encryption_key(struct mlx5_core_dev *mdev, + const void *key, u32 sz_bytes, + u32 key_type, u32 *p_key_id) +{ + return mlx5_crypto_create_dek_key(mdev, key, sz_bytes, key_type, p_key_id); +} + +void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id) +{ + mlx5_crypto_destroy_dek_key(mdev, key_id); +} + +static struct mlx5_crypto_dek_bulk * +mlx5_crypto_dek_bulk_create(struct mlx5_crypto_dek_pool *pool) +{ + struct mlx5_crypto_dek_priv *dek_priv = pool->mdev->mlx5e_res.dek_priv; + struct mlx5_core_dev *mdev = pool->mdev; + struct mlx5_crypto_dek_bulk *bulk; + int num_deks, base_obj_id; + int err; + + bulk = kzalloc(sizeof(*bulk), GFP_KERNEL); + if (!bulk) + return ERR_PTR(-ENOMEM); + + num_deks = 1 << dek_priv->log_dek_obj_range; + bulk->need_sync = bitmap_zalloc(num_deks, GFP_KERNEL); + if (!bulk->need_sync) { + err = -ENOMEM; + goto err_out; + } + + bulk->in_use = bitmap_zalloc(num_deks, GFP_KERNEL); + if (!bulk->in_use) { + err = -ENOMEM; + goto err_out; + } + + err = mlx5_crypto_create_dek_bulk(mdev, pool->key_purpose, + dek_priv->log_dek_obj_range, + &base_obj_id); + if (err) + goto err_out; + + bulk->base_obj_id = base_obj_id; + bulk->num_deks = num_deks; + bulk->avail_deks = num_deks; + bulk->mdev = mdev; + + return bulk; + +err_out: + bitmap_free(bulk->in_use); + bitmap_free(bulk->need_sync); + kfree(bulk); + return ERR_PTR(err); +} + +static struct mlx5_crypto_dek_bulk * +mlx5_crypto_dek_pool_add_bulk(struct mlx5_crypto_dek_pool *pool) +{ + struct mlx5_crypto_dek_bulk *bulk; + + bulk = mlx5_crypto_dek_bulk_create(pool); + if (IS_ERR(bulk)) + return bulk; + + pool->avail_deks += bulk->num_deks; + pool->num_deks += bulk->num_deks; + list_add(&bulk->entry, &pool->partial_list); + + return bulk; +} + +static void mlx5_crypto_dek_bulk_free(struct mlx5_crypto_dek_bulk *bulk) +{ + mlx5_crypto_destroy_dek_key(bulk->mdev, bulk->base_obj_id); + bitmap_free(bulk->need_sync); + bitmap_free(bulk->in_use); + kfree(bulk); +} + +static void mlx5_crypto_dek_pool_remove_bulk(struct mlx5_crypto_dek_pool *pool, + struct mlx5_crypto_dek_bulk *bulk, + bool delay) +{ + pool->num_deks -= bulk->num_deks; + pool->avail_deks -= bulk->avail_deks; + pool->in_use_deks -= bulk->in_use_deks; + list_del(&bulk->entry); + if (!delay) + mlx5_crypto_dek_bulk_free(bulk); +} + +static struct mlx5_crypto_dek_bulk * +mlx5_crypto_dek_pool_pop(struct mlx5_crypto_dek_pool *pool, u32 *obj_offset) +{ + struct mlx5_crypto_dek_bulk *bulk; + int pos; + + mutex_lock(&pool->lock); + bulk = list_first_entry_or_null(&pool->partial_list, + struct mlx5_crypto_dek_bulk, entry); + + if (bulk) { + pos = find_next_zero_bit(bulk->need_sync, bulk->num_deks, + bulk->avail_start); + if (pos == bulk->num_deks) { + mlx5_core_err(pool->mdev, "Wrong DEK bulk avail_start.\n"); + pos = find_first_zero_bit(bulk->need_sync, bulk->num_deks); + } + WARN_ON(pos == bulk->num_deks); + } else { + bulk = list_first_entry_or_null(&pool->avail_list, + struct mlx5_crypto_dek_bulk, + entry); + if (bulk) { + list_move(&bulk->entry, &pool->partial_list); + } else { + bulk = mlx5_crypto_dek_pool_add_bulk(pool); + if (IS_ERR(bulk)) + goto out; + } + pos = 0; + } + + *obj_offset = pos; + bitmap_set(bulk->need_sync, pos, 1); + bitmap_set(bulk->in_use, pos, 1); + bulk->in_use_deks++; + bulk->avail_deks--; + if (!bulk->avail_deks) { + list_move(&bulk->entry, &pool->full_list); + bulk->avail_start = bulk->num_deks; + } else { + bulk->avail_start = pos + 1; + } + pool->avail_deks--; + pool->in_use_deks++; + +out: + mutex_unlock(&pool->lock); + return bulk; +} + +static bool mlx5_crypto_dek_need_sync(struct mlx5_crypto_dek_pool *pool) +{ + return !pool->syncing && + MLX5_CRYPTO_DEK_POOL_CALC_FREED(pool) > MLX5_CRYPTO_DEK_POOL_SYNC_THRESH; +} + +static int mlx5_crypto_dek_free_locked(struct mlx5_crypto_dek_pool *pool, + struct mlx5_crypto_dek *dek) +{ + struct mlx5_crypto_dek_bulk *bulk = dek->bulk; + int obj_offset; + bool old_val; + int err = 0; + + obj_offset = dek->obj_id - bulk->base_obj_id; + old_val = test_and_clear_bit(obj_offset, bulk->in_use); + WARN_ON_ONCE(!old_val); + if (!old_val) { + err = -ENOENT; + goto out_free; + } + pool->in_use_deks--; + bulk->in_use_deks--; + if (!bulk->avail_deks && !bulk->in_use_deks) + list_move(&bulk->entry, &pool->sync_list); + + if (mlx5_crypto_dek_need_sync(pool) && schedule_work(&pool->sync_work)) + pool->syncing = true; + +out_free: + kfree(dek); + return err; +} + +static int mlx5_crypto_dek_pool_push(struct mlx5_crypto_dek_pool *pool, + struct mlx5_crypto_dek *dek) +{ + int err = 0; + + mutex_lock(&pool->lock); + if (pool->syncing) + list_add(&dek->entry, &pool->wait_for_free); + else + err = mlx5_crypto_dek_free_locked(pool, dek); + mutex_unlock(&pool->lock); + + return err; +} + +/* Update the bits for a bulk while sync, and avail_next for search. + * As the combinations of (need_sync, in_use) of one DEK are + * - (0,0) means the key is ready for use, + * - (1,1) means the key is currently being used by a user, + * - (1,0) means the key is freed, and waiting for being synced, + * - (0,1) is invalid state. + * the number of revalidated DEKs can be calculated by + * hweight_long(need_sync XOR in_use), and the need_sync bits can be reset + * by simply copying from in_use bits. + */ +static void mlx5_crypto_dek_bulk_reset_synced(struct mlx5_crypto_dek_pool *pool, + struct mlx5_crypto_dek_bulk *bulk) +{ + unsigned long *need_sync = bulk->need_sync; + unsigned long *in_use = bulk->in_use; + int i, freed, reused, avail_next; + bool first = true; + + freed = MLX5_CRYPTO_DEK_BULK_CALC_FREED(bulk); + + for (i = 0; freed && i < BITS_TO_LONGS(bulk->num_deks); + i++, need_sync++, in_use++) { + reused = hweight_long((*need_sync) ^ (*in_use)); + if (!reused) + continue; + + bulk->avail_deks += reused; + pool->avail_deks += reused; + *need_sync = *in_use; + if (first) { + avail_next = i * BITS_PER_TYPE(long); + if (bulk->avail_start > avail_next) + bulk->avail_start = avail_next; + first = false; + } + + freed -= reused; + } +} + +/* Return true if the bulk is reused, false if destroyed with delay */ +static bool mlx5_crypto_dek_bulk_handle_avail(struct mlx5_crypto_dek_pool *pool, + struct mlx5_crypto_dek_bulk *bulk, + struct list_head *destroy_list) +{ + if (list_empty(&pool->avail_list)) { + list_move(&bulk->entry, &pool->avail_list); + return true; + } + + mlx5_crypto_dek_pool_remove_bulk(pool, bulk, true); + list_add(&bulk->entry, destroy_list); + return false; +} + +static void mlx5_crypto_dek_pool_splice_destroy_list(struct mlx5_crypto_dek_pool *pool, + struct list_head *list, + struct list_head *head) +{ + spin_lock(&pool->destroy_lock); + list_splice_init(list, head); + spin_unlock(&pool->destroy_lock); +} + +static void mlx5_crypto_dek_pool_free_wait_keys(struct mlx5_crypto_dek_pool *pool) +{ + struct mlx5_crypto_dek *dek, *next; + + list_for_each_entry_safe(dek, next, &pool->wait_for_free, entry) { + list_del(&dek->entry); + mlx5_crypto_dek_free_locked(pool, dek); + } +} + +/* For all the bulks in each list, reset the bits while sync. + * Move them to different lists according to the number of available DEKs. + * Destrory all the idle bulks, except one for quick service. + * And free DEKs in the waiting list at the end of this func. + */ +static void mlx5_crypto_dek_pool_reset_synced(struct mlx5_crypto_dek_pool *pool) +{ + struct mlx5_crypto_dek_bulk *bulk, *tmp; + LIST_HEAD(destroy_list); + + list_for_each_entry_safe(bulk, tmp, &pool->partial_list, entry) { + mlx5_crypto_dek_bulk_reset_synced(pool, bulk); + if (MLX5_CRYPTO_DEK_BULK_IDLE(bulk)) + mlx5_crypto_dek_bulk_handle_avail(pool, bulk, &destroy_list); + } + + list_for_each_entry_safe(bulk, tmp, &pool->full_list, entry) { + mlx5_crypto_dek_bulk_reset_synced(pool, bulk); + + if (!bulk->avail_deks) + continue; + + if (MLX5_CRYPTO_DEK_BULK_IDLE(bulk)) + mlx5_crypto_dek_bulk_handle_avail(pool, bulk, &destroy_list); + else + list_move(&bulk->entry, &pool->partial_list); + } + + list_for_each_entry_safe(bulk, tmp, &pool->sync_list, entry) { + bulk->avail_deks = bulk->num_deks; + pool->avail_deks += bulk->num_deks; + if (mlx5_crypto_dek_bulk_handle_avail(pool, bulk, &destroy_list)) { + memset(bulk->need_sync, 0, BITS_TO_BYTES(bulk->num_deks)); + bulk->avail_start = 0; + } + } + + mlx5_crypto_dek_pool_free_wait_keys(pool); + + if (!list_empty(&destroy_list)) { + mlx5_crypto_dek_pool_splice_destroy_list(pool, &destroy_list, + &pool->destroy_list); + schedule_work(&pool->destroy_work); + } +} + +static void mlx5_crypto_dek_sync_work_fn(struct work_struct *work) +{ + struct mlx5_crypto_dek_pool *pool = + container_of(work, struct mlx5_crypto_dek_pool, sync_work); + int err; + + err = mlx5_crypto_cmd_sync_crypto(pool->mdev, BIT(pool->key_purpose)); + mutex_lock(&pool->lock); + if (!err) + mlx5_crypto_dek_pool_reset_synced(pool); + pool->syncing = false; + mutex_unlock(&pool->lock); +} + +struct mlx5_crypto_dek *mlx5_crypto_dek_create(struct mlx5_crypto_dek_pool *dek_pool, + const void *key, u32 sz_bytes) +{ + struct mlx5_crypto_dek_priv *dek_priv = dek_pool->mdev->mlx5e_res.dek_priv; + struct mlx5_core_dev *mdev = dek_pool->mdev; + u32 key_purpose = dek_pool->key_purpose; + struct mlx5_crypto_dek_bulk *bulk; + struct mlx5_crypto_dek *dek; + int obj_offset; + int err; + + dek = kzalloc(sizeof(*dek), GFP_KERNEL); + if (!dek) + return ERR_PTR(-ENOMEM); + + if (!dek_priv) { + err = mlx5_crypto_create_dek_key(mdev, key, sz_bytes, + key_purpose, &dek->obj_id); + goto out; + } + + bulk = mlx5_crypto_dek_pool_pop(dek_pool, &obj_offset); + if (IS_ERR(bulk)) { + err = PTR_ERR(bulk); + goto out; + } + + dek->bulk = bulk; + dek->obj_id = bulk->base_obj_id + obj_offset; + err = mlx5_crypto_modify_dek_key(mdev, key, sz_bytes, key_purpose, + bulk->base_obj_id, obj_offset); + if (err) { + mlx5_crypto_dek_pool_push(dek_pool, dek); + return ERR_PTR(err); + } + +out: + if (err) { + kfree(dek); + return ERR_PTR(err); + } + + return dek; +} + +void mlx5_crypto_dek_destroy(struct mlx5_crypto_dek_pool *dek_pool, + struct mlx5_crypto_dek *dek) +{ + struct mlx5_crypto_dek_priv *dek_priv = dek_pool->mdev->mlx5e_res.dek_priv; + struct mlx5_core_dev *mdev = dek_pool->mdev; + + if (!dek_priv) { + mlx5_crypto_destroy_dek_key(mdev, dek->obj_id); + kfree(dek); + } else { + mlx5_crypto_dek_pool_push(dek_pool, dek); + } +} + +static void mlx5_crypto_dek_free_destroy_list(struct list_head *destroy_list) +{ + struct mlx5_crypto_dek_bulk *bulk, *tmp; + + list_for_each_entry_safe(bulk, tmp, destroy_list, entry) + mlx5_crypto_dek_bulk_free(bulk); +} + +static void mlx5_crypto_dek_destroy_work_fn(struct work_struct *work) +{ + struct mlx5_crypto_dek_pool *pool = + container_of(work, struct mlx5_crypto_dek_pool, destroy_work); + LIST_HEAD(destroy_list); + + mlx5_crypto_dek_pool_splice_destroy_list(pool, &pool->destroy_list, + &destroy_list); + mlx5_crypto_dek_free_destroy_list(&destroy_list); +} + +struct mlx5_crypto_dek_pool * +mlx5_crypto_dek_pool_create(struct mlx5_core_dev *mdev, int key_purpose) +{ + struct mlx5_crypto_dek_pool *pool; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return ERR_PTR(-ENOMEM); + + pool->mdev = mdev; + pool->key_purpose = key_purpose; + + mutex_init(&pool->lock); + INIT_LIST_HEAD(&pool->avail_list); + INIT_LIST_HEAD(&pool->partial_list); + INIT_LIST_HEAD(&pool->full_list); + INIT_LIST_HEAD(&pool->sync_list); + INIT_LIST_HEAD(&pool->wait_for_free); + INIT_WORK(&pool->sync_work, mlx5_crypto_dek_sync_work_fn); + spin_lock_init(&pool->destroy_lock); + INIT_LIST_HEAD(&pool->destroy_list); + INIT_WORK(&pool->destroy_work, mlx5_crypto_dek_destroy_work_fn); + + return pool; +} + +void mlx5_crypto_dek_pool_destroy(struct mlx5_crypto_dek_pool *pool) +{ + struct mlx5_crypto_dek_bulk *bulk, *tmp; + + cancel_work_sync(&pool->sync_work); + cancel_work_sync(&pool->destroy_work); + + mlx5_crypto_dek_pool_free_wait_keys(pool); + + list_for_each_entry_safe(bulk, tmp, &pool->avail_list, entry) + mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false); + + list_for_each_entry_safe(bulk, tmp, &pool->full_list, entry) + mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false); + + list_for_each_entry_safe(bulk, tmp, &pool->sync_list, entry) + mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false); + + list_for_each_entry_safe(bulk, tmp, &pool->partial_list, entry) + mlx5_crypto_dek_pool_remove_bulk(pool, bulk, false); + + mlx5_crypto_dek_free_destroy_list(&pool->destroy_list); + + mutex_destroy(&pool->lock); + + kfree(pool); +} + +void mlx5_crypto_dek_cleanup(struct mlx5_crypto_dek_priv *dek_priv) +{ + if (!dek_priv) + return; + + kfree(dek_priv); +} + +struct mlx5_crypto_dek_priv *mlx5_crypto_dek_init(struct mlx5_core_dev *mdev) +{ + struct mlx5_crypto_dek_priv *dek_priv; + int err; + + if (!MLX5_CAP_CRYPTO(mdev, log_dek_max_alloc)) + return NULL; + + dek_priv = kzalloc(sizeof(*dek_priv), GFP_KERNEL); + if (!dek_priv) + return ERR_PTR(-ENOMEM); + + dek_priv->mdev = mdev; + dek_priv->log_dek_obj_range = min_t(int, 12, + MLX5_CAP_CRYPTO(mdev, log_dek_max_alloc)); + + /* sync all types of objects */ + err = mlx5_crypto_cmd_sync_crypto(mdev, MLX5_CRYPTO_DEK_ALL_TYPE); + if (err) + goto err_sync_crypto; + + mlx5_core_dbg(mdev, "Crypto DEK enabled, %d deks per alloc (max %d), total %d\n", + 1 << dek_priv->log_dek_obj_range, + 1 << MLX5_CAP_CRYPTO(mdev, log_dek_max_alloc), + 1 << MLX5_CAP_CRYPTO(mdev, log_max_num_deks)); + + return dek_priv; + +err_sync_crypto: + kfree(dek_priv); + return ERR_PTR(err); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.h new file mode 100644 index 000000000000..c819c047bb9c --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#ifndef __MLX5_LIB_CRYPTO_H__ +#define __MLX5_LIB_CRYPTO_H__ + +enum { + MLX5_ACCEL_OBJ_TLS_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_TLS, + MLX5_ACCEL_OBJ_IPSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_IPSEC, + MLX5_ACCEL_OBJ_MACSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_MACSEC, + MLX5_ACCEL_OBJ_TYPE_KEY_NUM, +}; + +int mlx5_create_encryption_key(struct mlx5_core_dev *mdev, + const void *key, u32 sz_bytes, + u32 key_type, u32 *p_key_id); + +void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id); + +struct mlx5_crypto_dek_pool; +struct mlx5_crypto_dek; + +struct mlx5_crypto_dek_pool *mlx5_crypto_dek_pool_create(struct mlx5_core_dev *mdev, + int key_purpose); +void mlx5_crypto_dek_pool_destroy(struct mlx5_crypto_dek_pool *pool); +struct mlx5_crypto_dek *mlx5_crypto_dek_create(struct mlx5_crypto_dek_pool *dek_pool, + const void *key, u32 sz_bytes); +void mlx5_crypto_dek_destroy(struct mlx5_crypto_dek_pool *dek_pool, + struct mlx5_crypto_dek *dek); +u32 mlx5_crypto_dek_get_id(struct mlx5_crypto_dek *dek); + +struct mlx5_crypto_dek_priv *mlx5_crypto_dek_init(struct mlx5_core_dev *mdev); +void mlx5_crypto_dek_cleanup(struct mlx5_crypto_dek_priv *dek_priv); +#endif /* __MLX5_LIB_CRYPTO_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h index 032adb21ad4b..55bd7c4c021e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h @@ -79,18 +79,6 @@ struct mlx5_pme_stats { void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats); int mlx5_notifier_call_chain(struct mlx5_events *events, unsigned int event, void *data); -/* Crypto */ -enum { - MLX5_ACCEL_OBJ_TLS_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_TLS, - MLX5_ACCEL_OBJ_IPSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_IPSEC, - MLX5_ACCEL_OBJ_MACSEC_KEY = MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_MACSEC, -}; - -int mlx5_create_encryption_key(struct mlx5_core_dev *mdev, - void *key, u32 sz_bytes, - u32 key_type, u32 *p_key_id); -void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id); - static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev) { return devlink_net(priv_to_devlink(dev)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 8823f20d2122..9441588ac524 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1555,6 +1555,7 @@ static const int types[] = { MLX5_CAP_DEV_SHAMPO, MLX5_CAP_MACSEC, MLX5_CAP_ADV_VIRTUALIZATION, + MLX5_CAP_CRYPTO, }; static void mlx5_hca_caps_free(struct mlx5_core_dev *dev) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index c060b03f7e27..08acb7b89086 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -6,12 +6,16 @@ */ #include <linux/dsa/ocelot.h> #include <linux/if_bridge.h> +#include <linux/iopoll.h> #include <soc/mscc/ocelot_vcap.h> #include "ocelot.h" #include "ocelot_vcap.h" -#define TABLE_UPDATE_SLEEP_US 10 -#define TABLE_UPDATE_TIMEOUT_US 100000 +#define TABLE_UPDATE_SLEEP_US 10 +#define TABLE_UPDATE_TIMEOUT_US 100000 +#define MEM_INIT_SLEEP_US 1000 +#define MEM_INIT_TIMEOUT_US 100000 + #define OCELOT_RSV_VLAN_RANGE_START 4000 struct ocelot_mact_entry { @@ -2713,6 +2717,46 @@ static void ocelot_detect_features(struct ocelot *ocelot) ocelot->num_frame_refs = QSYS_MMGT_EQ_CTRL_FP_FREE_CNT(eq_ctrl); } +static int ocelot_mem_init_status(struct ocelot *ocelot) +{ + unsigned int val; + int err; + + err = regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], + &val); + + return err ?: val; +} + +int ocelot_reset(struct ocelot *ocelot) +{ + int err; + u32 val; + + err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1); + if (err) + return err; + + err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); + if (err) + return err; + + /* MEM_INIT is a self-clearing bit. Wait for it to be cleared (should be + * 100us) before enabling the switch core. + */ + err = readx_poll_timeout(ocelot_mem_init_status, ocelot, val, !val, + MEM_INIT_SLEEP_US, MEM_INIT_TIMEOUT_US); + if (err) + return err; + + err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); + if (err) + return err; + + return regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); +} +EXPORT_SYMBOL(ocelot_reset); + int ocelot_init(struct ocelot *ocelot) { int i, ret; diff --git a/drivers/net/ethernet/mscc/ocelot_devlink.c b/drivers/net/ethernet/mscc/ocelot_devlink.c index b8737efd2a85..d9ea75a14f2f 100644 --- a/drivers/net/ethernet/mscc/ocelot_devlink.c +++ b/drivers/net/ethernet/mscc/ocelot_devlink.c @@ -487,6 +487,37 @@ static void ocelot_watermark_init(struct ocelot *ocelot) ocelot_setup_sharing_watermarks(ocelot); } +/* Watermark encode + * Bit 8: Unit; 0:1, 1:16 + * Bit 7-0: Value to be multiplied with unit + */ +u16 ocelot_wm_enc(u16 value) +{ + WARN_ON(value >= 16 * BIT(8)); + + if (value >= BIT(8)) + return BIT(8) | (value / 16); + + return value; +} +EXPORT_SYMBOL(ocelot_wm_enc); + +u16 ocelot_wm_dec(u16 wm) +{ + if (wm & BIT(8)) + return (wm & GENMASK(7, 0)) * 16; + + return wm; +} +EXPORT_SYMBOL(ocelot_wm_dec); + +void ocelot_wm_stat(u32 val, u32 *inuse, u32 *maxuse) +{ + *inuse = (val & GENMASK(23, 12)) >> 12; + *maxuse = val & GENMASK(11, 0); +} +EXPORT_SYMBOL(ocelot_wm_stat); + /* Pool size and type are fixed up at runtime. Keeping this structure to * look up the cell size multipliers. */ diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c index b097fd4a4061..7388c3b0535c 100644 --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c @@ -6,7 +6,6 @@ */ #include <linux/dsa/ocelot.h> #include <linux/interrupt.h> -#include <linux/iopoll.h> #include <linux/module.h> #include <linux/of_net.h> #include <linux/netdevice.h> @@ -17,6 +16,7 @@ #include <linux/skbuff.h> #include <net/switchdev.h> +#include <soc/mscc/ocelot.h> #include <soc/mscc/ocelot_vcap.h> #include <soc/mscc/ocelot_hsio.h> #include <soc/mscc/vsc7514_regs.h> @@ -26,80 +26,6 @@ #define VSC7514_VCAP_POLICER_BASE 128 #define VSC7514_VCAP_POLICER_MAX 191 -#define MEM_INIT_SLEEP_US 1000 -#define MEM_INIT_TIMEOUT_US 100000 - -static const u32 *ocelot_regmap[TARGET_MAX] = { - [ANA] = vsc7514_ana_regmap, - [QS] = vsc7514_qs_regmap, - [QSYS] = vsc7514_qsys_regmap, - [REW] = vsc7514_rew_regmap, - [SYS] = vsc7514_sys_regmap, - [S0] = vsc7514_vcap_regmap, - [S1] = vsc7514_vcap_regmap, - [S2] = vsc7514_vcap_regmap, - [PTP] = vsc7514_ptp_regmap, - [DEV_GMII] = vsc7514_dev_gmii_regmap, -}; - -static const struct reg_field ocelot_regfields[REGFIELD_MAX] = { - [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 11, 11), - [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 10), - [ANA_ANEVENTS_MSTI_DROP] = REG_FIELD(ANA_ANEVENTS, 27, 27), - [ANA_ANEVENTS_ACLKILL] = REG_FIELD(ANA_ANEVENTS, 26, 26), - [ANA_ANEVENTS_ACLUSED] = REG_FIELD(ANA_ANEVENTS, 25, 25), - [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 24, 24), - [ANA_ANEVENTS_VS2TTL1] = REG_FIELD(ANA_ANEVENTS, 23, 23), - [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 22, 22), - [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 21, 21), - [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 20, 20), - [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 19, 19), - [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 18, 18), - [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 17, 17), - [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 16, 16), - [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 15, 15), - [ANA_ANEVENTS_DROPPED] = REG_FIELD(ANA_ANEVENTS, 14, 14), - [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 13, 13), - [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 12, 12), - [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 11, 11), - [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 10, 10), - [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 9, 9), - [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 8, 8), - [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 7, 7), - [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), - [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), - [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 4, 4), - [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 3, 3), - [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 2, 2), - [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 1, 1), - [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 0, 0), - [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 18, 18), - [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 10, 11), - [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 9), - [QSYS_TIMED_FRAME_ENTRY_TFRM_VLD] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 20, 20), - [QSYS_TIMED_FRAME_ENTRY_TFRM_FP] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 8, 19), - [QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 4, 7), - [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 1, 3), - [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 0, 0), - [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 2, 2), - [SYS_RESET_CFG_MEM_ENA] = REG_FIELD(SYS_RESET_CFG, 1, 1), - [SYS_RESET_CFG_MEM_INIT] = REG_FIELD(SYS_RESET_CFG, 0, 0), - /* Replicated per number of ports (12), register size 4 per port */ - [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 12, 4), - [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 12, 4), - [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 12, 4), - [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 12, 4), - [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 12, 4), - [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 12, 4), - [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 12, 4), - [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 12, 4), - [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 12, 4), - [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 12, 4), - [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 12, 4), - [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 12, 4), - [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 12, 4), -}; - static void ocelot_pll5_init(struct ocelot *ocelot) { /* Configure PLL5. This will need a proper CCF driver @@ -133,11 +59,11 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops) { int ret; - ocelot->map = ocelot_regmap; + ocelot->map = vsc7514_regmap; ocelot->num_mact_rows = 1024; ocelot->ops = ops; - ret = ocelot_regfields_init(ocelot, ocelot_regfields); + ret = ocelot_regfields_init(ocelot, vsc7514_regfields); if (ret) return ret; @@ -190,73 +116,6 @@ static const struct of_device_id mscc_ocelot_match[] = { }; MODULE_DEVICE_TABLE(of, mscc_ocelot_match); -static int ocelot_mem_init_status(struct ocelot *ocelot) -{ - unsigned int val; - int err; - - err = regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], - &val); - - return err ?: val; -} - -static int ocelot_reset(struct ocelot *ocelot) -{ - int err; - u32 val; - - err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1); - if (err) - return err; - - err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); - if (err) - return err; - - /* MEM_INIT is a self-clearing bit. Wait for it to be cleared (should be - * 100us) before enabling the switch core. - */ - err = readx_poll_timeout(ocelot_mem_init_status, ocelot, val, !val, - MEM_INIT_SLEEP_US, MEM_INIT_TIMEOUT_US); - if (err) - return err; - - err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); - if (err) - return err; - - return regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); -} - -/* Watermark encode - * Bit 8: Unit; 0:1, 1:16 - * Bit 7-0: Value to be multiplied with unit - */ -static u16 ocelot_wm_enc(u16 value) -{ - WARN_ON(value >= 16 * BIT(8)); - - if (value >= BIT(8)) - return BIT(8) | (value / 16); - - return value; -} - -static u16 ocelot_wm_dec(u16 wm) -{ - if (wm & BIT(8)) - return (wm & GENMASK(7, 0)) * 16; - - return wm; -} - -static void ocelot_wm_stat(u32 val, u32 *inuse, u32 *maxuse) -{ - *inuse = (val & GENMASK(23, 12)) >> 12; - *maxuse = val & GENMASK(11, 0); -} - static const struct ocelot_ops ocelot_ops = { .reset = ocelot_reset, .wm_enc = ocelot_wm_enc, @@ -266,49 +125,6 @@ static const struct ocelot_ops ocelot_ops = { .netdev_to_port = ocelot_netdev_to_port, }; -static struct vcap_props vsc7514_vcap_props[] = { - [VCAP_ES0] = { - .action_type_width = 0, - .action_table = { - [ES0_ACTION_TYPE_NORMAL] = { - .width = 73, /* HIT_STICKY not included */ - .count = 1, - }, - }, - .target = S0, - .keys = vsc7514_vcap_es0_keys, - .actions = vsc7514_vcap_es0_actions, - }, - [VCAP_IS1] = { - .action_type_width = 0, - .action_table = { - [IS1_ACTION_TYPE_NORMAL] = { - .width = 78, /* HIT_STICKY not included */ - .count = 4, - }, - }, - .target = S1, - .keys = vsc7514_vcap_is1_keys, - .actions = vsc7514_vcap_is1_actions, - }, - [VCAP_IS2] = { - .action_type_width = 1, - .action_table = { - [IS2_ACTION_TYPE_NORMAL] = { - .width = 49, - .count = 2 - }, - [IS2_ACTION_TYPE_SMAC_SIP] = { - .width = 6, - .count = 4 - }, - }, - .target = S2, - .keys = vsc7514_vcap_is2_keys, - .actions = vsc7514_vcap_is2_actions, - }, -}; - static struct ptp_clock_info ocelot_ptp_clock_info = { .owner = THIS_MODULE, .name = "ocelot ptp", diff --git a/drivers/net/ethernet/mscc/vsc7514_regs.c b/drivers/net/ethernet/mscc/vsc7514_regs.c index 9d2d3e13cacf..da0c0dcc8f81 100644 --- a/drivers/net/ethernet/mscc/vsc7514_regs.c +++ b/drivers/net/ethernet/mscc/vsc7514_regs.c @@ -9,6 +9,65 @@ #include <soc/mscc/vsc7514_regs.h> #include "ocelot.h" +const struct reg_field vsc7514_regfields[REGFIELD_MAX] = { + [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 11, 11), + [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 10), + [ANA_ANEVENTS_MSTI_DROP] = REG_FIELD(ANA_ANEVENTS, 27, 27), + [ANA_ANEVENTS_ACLKILL] = REG_FIELD(ANA_ANEVENTS, 26, 26), + [ANA_ANEVENTS_ACLUSED] = REG_FIELD(ANA_ANEVENTS, 25, 25), + [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 24, 24), + [ANA_ANEVENTS_VS2TTL1] = REG_FIELD(ANA_ANEVENTS, 23, 23), + [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 22, 22), + [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 21, 21), + [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 20, 20), + [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 19, 19), + [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 18, 18), + [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 17, 17), + [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 16, 16), + [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 15, 15), + [ANA_ANEVENTS_DROPPED] = REG_FIELD(ANA_ANEVENTS, 14, 14), + [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 13, 13), + [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 12, 12), + [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 11, 11), + [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 10, 10), + [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 9, 9), + [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 8, 8), + [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 7, 7), + [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), + [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), + [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 4, 4), + [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 3, 3), + [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 2, 2), + [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 1, 1), + [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 0, 0), + [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 18, 18), + [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 10, 11), + [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 9), + [QSYS_TIMED_FRAME_ENTRY_TFRM_VLD] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 20, 20), + [QSYS_TIMED_FRAME_ENTRY_TFRM_FP] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 8, 19), + [QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 4, 7), + [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 1, 3), + [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 0, 0), + [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 2, 2), + [SYS_RESET_CFG_MEM_ENA] = REG_FIELD(SYS_RESET_CFG, 1, 1), + [SYS_RESET_CFG_MEM_INIT] = REG_FIELD(SYS_RESET_CFG, 0, 0), + /* Replicated per number of ports (12), register size 4 per port */ + [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 12, 4), + [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 12, 4), + [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 12, 4), + [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 12, 4), + [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 12, 4), + [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 12, 4), + [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 12, 4), + [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 12, 4), + [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 12, 4), + [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 12, 4), + [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 12, 4), + [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 12, 4), + [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 12, 4), +}; +EXPORT_SYMBOL(vsc7514_regfields); + const u32 vsc7514_ana_regmap[] = { REG(ANA_ADVLEARN, 0x009000), REG(ANA_VLANMASK, 0x009004), @@ -370,6 +429,20 @@ const u32 vsc7514_dev_gmii_regmap[] = { }; EXPORT_SYMBOL(vsc7514_dev_gmii_regmap); +const u32 *vsc7514_regmap[TARGET_MAX] = { + [ANA] = vsc7514_ana_regmap, + [QS] = vsc7514_qs_regmap, + [QSYS] = vsc7514_qsys_regmap, + [REW] = vsc7514_rew_regmap, + [SYS] = vsc7514_sys_regmap, + [S0] = vsc7514_vcap_regmap, + [S1] = vsc7514_vcap_regmap, + [S2] = vsc7514_vcap_regmap, + [PTP] = vsc7514_ptp_regmap, + [DEV_GMII] = vsc7514_dev_gmii_regmap, +}; +EXPORT_SYMBOL(vsc7514_regmap); + const struct vcap_field vsc7514_vcap_es0_keys[] = { [VCAP_ES0_EGR_PORT] = { 0, 4 }, [VCAP_ES0_IGR_PORT] = { 4, 4 }, @@ -580,3 +653,47 @@ const struct vcap_field vsc7514_vcap_is2_actions[] = { [VCAP_IS2_ACT_HIT_CNT] = { 49, 32 }, }; EXPORT_SYMBOL(vsc7514_vcap_is2_actions); + +struct vcap_props vsc7514_vcap_props[] = { + [VCAP_ES0] = { + .action_type_width = 0, + .action_table = { + [ES0_ACTION_TYPE_NORMAL] = { + .width = 73, /* HIT_STICKY not included */ + .count = 1, + }, + }, + .target = S0, + .keys = vsc7514_vcap_es0_keys, + .actions = vsc7514_vcap_es0_actions, + }, + [VCAP_IS1] = { + .action_type_width = 0, + .action_table = { + [IS1_ACTION_TYPE_NORMAL] = { + .width = 78, /* HIT_STICKY not included */ + .count = 4, + }, + }, + .target = S1, + .keys = vsc7514_vcap_is1_keys, + .actions = vsc7514_vcap_is1_actions, + }, + [VCAP_IS2] = { + .action_type_width = 1, + .action_table = { + [IS2_ACTION_TYPE_NORMAL] = { + .width = 49, + .count = 2 + }, + [IS2_ACTION_TYPE_SMAC_SIP] = { + .width = 6, + .count = 4 + }, + }, + .target = S2, + .keys = vsc7514_vcap_is2_keys, + .actions = vsc7514_vcap_is2_actions, + }, +}; +EXPORT_SYMBOL(vsc7514_vcap_props); diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.c b/drivers/net/ethernet/netronome/nfp/nic/main.c index f78c2447d45b..9dd5afe37f6e 100644 --- a/drivers/net/ethernet/netronome/nfp/nic/main.c +++ b/drivers/net/ethernet/netronome/nfp/nic/main.c @@ -32,9 +32,12 @@ static void nfp_nic_sriov_disable(struct nfp_app *app) static int nfp_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn) { - nfp_nic_dcb_init(nn); + return nfp_nic_dcb_init(nn); +} - return 0; +static void nfp_nic_vnic_clean(struct nfp_app *app, struct nfp_net *nn) +{ + nfp_nic_dcb_clean(nn); } static int nfp_nic_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, @@ -72,4 +75,5 @@ const struct nfp_app_type app_nic = { .sriov_disable = nfp_nic_sriov_disable, .vnic_init = nfp_nic_vnic_init, + .vnic_clean = nfp_nic_vnic_clean, }; diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.h b/drivers/net/ethernet/netronome/nfp/nic/main.h index 7ba04451b8ba..094374df42b8 100644 --- a/drivers/net/ethernet/netronome/nfp/nic/main.h +++ b/drivers/net/ethernet/netronome/nfp/nic/main.h @@ -33,7 +33,7 @@ struct nfp_dcb { int nfp_nic_dcb_init(struct nfp_net *nn); void nfp_nic_dcb_clean(struct nfp_net *nn); #else -static inline int nfp_nic_dcb_init(struct nfp_net *nn) {return 0; } +static inline int nfp_nic_dcb_init(struct nfp_net *nn) { return 0; } static inline void nfp_nic_dcb_clean(struct nfp_net *nn) {} #endif diff --git a/drivers/net/ipa/ipa_cmd.c b/drivers/net/ipa/ipa_cmd.c index bb3dfa9a2bc8..16169641ddeb 100644 --- a/drivers/net/ipa/ipa_cmd.c +++ b/drivers/net/ipa/ipa_cmd.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2022 Linaro Ltd. + * Copyright (C) 2019-2023 Linaro Ltd. */ #include <linux/types.h> @@ -94,11 +94,11 @@ struct ipa_cmd_register_write { /* IPA_CMD_IP_PACKET_INIT */ struct ipa_cmd_ip_packet_init { - u8 dest_endpoint; + u8 dest_endpoint; /* Full 8 bits used for IPA v5.0+ */ u8 reserved[7]; }; -/* Field masks for ipa_cmd_ip_packet_init dest_endpoint field */ +/* Field mask for ipa_cmd_ip_packet_init dest_endpoint field (unused v5.0+) */ #define IPA_PACKET_INIT_DEST_ENDPOINT_FMASK GENMASK(4, 0) /* IPA_CMD_DMA_SHARED_MEM */ @@ -157,9 +157,14 @@ static void ipa_cmd_validate_build(void) BUILD_BUG_ON(field_max(IP_FLTRT_FLAGS_HASH_ADDR_FMASK) != field_max(IP_FLTRT_FLAGS_NHASH_ADDR_FMASK)); - /* Valid endpoint numbers must fit in the IP packet init command */ - BUILD_BUG_ON(field_max(IPA_PACKET_INIT_DEST_ENDPOINT_FMASK) < - IPA_ENDPOINT_MAX - 1); + /* Prior to IPA v5.0, we supported no more than 32 endpoints, + * and this was reflected in some 5-bit fields that held + * endpoint numbers. Starting with IPA v5.0, the widths of + * these fields were extended to 8 bits, meaning up to 256 + * endpoints. If the driver claims to support more than + * that it's an error. + */ + BUILD_BUG_ON(IPA_ENDPOINT_MAX - 1 > U8_MAX); } /* Validate a memory region holding a table */ @@ -290,7 +295,11 @@ static bool ipa_cmd_register_write_valid(struct ipa *ipa) * offset will fit in a register write IPA immediate command. */ if (ipa_table_hash_support(ipa)) { - reg = ipa_reg(ipa, FILT_ROUT_HASH_FLUSH); + if (ipa->version < IPA_VERSION_5_0) + reg = ipa_reg(ipa, FILT_ROUT_HASH_FLUSH); + else + reg = ipa_reg(ipa, FILT_ROUT_CACHE_FLUSH); + offset = ipa_reg_offset(reg); name = "filter/route hash flush"; if (!ipa_cmd_register_write_offset_valid(ipa, name, offset)) @@ -486,8 +495,13 @@ static void ipa_cmd_ip_packet_init_add(struct gsi_trans *trans, u8 endpoint_id) cmd_payload = ipa_cmd_payload_alloc(ipa, &payload_addr); payload = &cmd_payload->ip_packet_init; - payload->dest_endpoint = u8_encode_bits(endpoint_id, - IPA_PACKET_INIT_DEST_ENDPOINT_FMASK); + if (ipa->version < IPA_VERSION_5_0) { + payload->dest_endpoint = + u8_encode_bits(endpoint_id, + IPA_PACKET_INIT_DEST_ENDPOINT_FMASK); + } else { + payload->dest_endpoint = endpoint_id; + } gsi_trans_cmd_add(trans, payload, sizeof(*payload), payload_addr, opcode); diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index ce7f2d6e447e..798dfa4484d5 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2022 Linaro Ltd. + * Copyright (C) 2019-2023 Linaro Ltd. */ #include <linux/types.h> @@ -922,64 +922,72 @@ static void ipa_endpoint_init_mode(struct ipa_endpoint *endpoint) iowrite32(val, ipa->reg_virt + offset); } -/* For IPA v4.5+, times are expressed using Qtime. The AP uses one of two - * pulse generators (0 and 1) to measure elapsed time. In ipa_qtime_config() - * they're configured to have granularity 100 usec and 1 msec, respectively. - * - * The return value is the positive or negative Qtime value to use to - * express the (microsecond) time provided. A positive return value - * means pulse generator 0 can be used; otherwise use pulse generator 1. +/* For IPA v4.5+, times are expressed using Qtime. A time is represented + * at one of several available granularities, which are configured in + * ipa_qtime_config(). Three (or, starting with IPA v5.0, four) pulse + * generators are set up with different "tick" periods. A Qtime value + * encodes a tick count along with an indication of a pulse generator + * (which has a fixed tick period). Two pulse generators are always + * available to the AP; a third is available starting with IPA v5.0. + * This function determines which pulse generator most accurately + * represents the time period provided, and returns the tick count to + * use to represent that time. */ -static int ipa_qtime_val(u32 microseconds, u32 max) -{ - u32 val; - - /* Use 100 microsecond granularity if possible */ - val = DIV_ROUND_CLOSEST(microseconds, 100); - if (val <= max) - return (int)val; - - /* Have to use pulse generator 1 (millisecond granularity) */ - val = DIV_ROUND_CLOSEST(microseconds, 1000); - WARN_ON(val > max); +static u32 +ipa_qtime_val(struct ipa *ipa, u32 microseconds, u32 max, u32 *select) +{ + u32 which = 0; + u32 ticks; + + /* Pulse generator 0 has 100 microsecond granularity */ + ticks = DIV_ROUND_CLOSEST(microseconds, 100); + if (ticks <= max) + goto out; + + /* Pulse generator 1 has millisecond granularity */ + which = 1; + ticks = DIV_ROUND_CLOSEST(microseconds, 1000); + if (ticks <= max) + goto out; + + if (ipa->version >= IPA_VERSION_5_0) { + /* Pulse generator 2 has 10 millisecond granularity */ + which = 2; + ticks = DIV_ROUND_CLOSEST(microseconds, 100); + } + WARN_ON(ticks > max); +out: + *select = which; - return (int)-val; + return ticks; } /* Encode the aggregation timer limit (microseconds) based on IPA version */ static u32 aggr_time_limit_encode(struct ipa *ipa, const struct ipa_reg *reg, u32 microseconds) { + u32 ticks; u32 max; - u32 val; if (!microseconds) return 0; /* Nothing to compute if time limit is 0 */ max = ipa_reg_field_max(reg, TIME_LIMIT); if (ipa->version >= IPA_VERSION_4_5) { - u32 gran_sel; - int ret; - - /* Compute the Qtime limit value to use */ - ret = ipa_qtime_val(microseconds, max); - if (ret < 0) { - val = -ret; - gran_sel = ipa_reg_bit(reg, AGGR_GRAN_SEL); - } else { - val = ret; - gran_sel = 0; - } + u32 select; + + ticks = ipa_qtime_val(ipa, microseconds, max, &select); - return gran_sel | ipa_reg_encode(reg, TIME_LIMIT, val); + return ipa_reg_encode(reg, AGGR_GRAN_SEL, select) | + ipa_reg_encode(reg, TIME_LIMIT, ticks); } /* We program aggregation granularity in ipa_hardware_config() */ - val = DIV_ROUND_CLOSEST(microseconds, IPA_AGGR_GRANULARITY); - WARN(val > max, "aggr_time_limit too large (%u > %u usec)\n", + ticks = DIV_ROUND_CLOSEST(microseconds, IPA_AGGR_GRANULARITY); + WARN(ticks > max, "aggr_time_limit too large (%u > %u usec)\n", microseconds, max * IPA_AGGR_GRANULARITY); - return ipa_reg_encode(reg, TIME_LIMIT, val); + return ipa_reg_encode(reg, TIME_LIMIT, ticks); } static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint) @@ -1050,20 +1058,13 @@ static u32 hol_block_timer_encode(struct ipa *ipa, const struct ipa_reg *reg, if (ipa->version >= IPA_VERSION_4_5) { u32 max = ipa_reg_field_max(reg, TIMER_LIMIT); - u32 gran_sel; - int ret; - - /* Compute the Qtime limit value to use */ - ret = ipa_qtime_val(microseconds, max); - if (ret < 0) { - val = -ret; - gran_sel = ipa_reg_bit(reg, TIMER_GRAN_SEL); - } else { - val = ret; - gran_sel = 0; - } + u32 select; + u32 ticks; - return gran_sel | ipa_reg_encode(reg, TIMER_LIMIT, val); + ticks = ipa_qtime_val(ipa, microseconds, max, &select); + + return ipa_reg_encode(reg, TIMER_GRAN_SEL, 1) | + ipa_reg_encode(reg, TIMER_LIMIT, ticks); } /* Use 64 bit arithmetic to avoid overflow */ @@ -1986,6 +1987,7 @@ int ipa_endpoint_config(struct ipa *ipa) struct device *dev = &ipa->pdev->dev; const struct ipa_reg *reg; u32 endpoint_id; + u32 hw_limit; u32 tx_count; u32 rx_count; u32 rx_base; @@ -2031,6 +2033,14 @@ int ipa_endpoint_config(struct ipa *ipa) return -EINVAL; } + /* Until IPA v5.0, the max endpoint ID was 32 */ + hw_limit = ipa->version < IPA_VERSION_5_0 ? 32 : U8_MAX + 1; + if (limit > hw_limit) { + dev_err(dev, "unexpected endpoint count, %u > %u\n", + limit, hw_limit); + return -EINVAL; + } + /* Allocate and initialize the available endpoint bitmap */ ipa->available = bitmap_zalloc(limit, GFP_KERNEL); if (!ipa->available) diff --git a/drivers/net/ipa/ipa_endpoint.h b/drivers/net/ipa/ipa_endpoint.h index 4a5c3bc549df..3ad2e802040a 100644 --- a/drivers/net/ipa/ipa_endpoint.h +++ b/drivers/net/ipa/ipa_endpoint.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2022 Linaro Ltd. + * Copyright (C) 2019-2023 Linaro Ltd. */ #ifndef _IPA_ENDPOINT_H_ #define _IPA_ENDPOINT_H_ @@ -38,7 +38,7 @@ enum ipa_endpoint_name { IPA_ENDPOINT_COUNT, /* Number of names (not an index) */ }; -#define IPA_ENDPOINT_MAX 32 /* Max supported by driver */ +#define IPA_ENDPOINT_MAX 36 /* Max supported by driver */ /** * struct ipa_endpoint_tx - Endpoint configuration for TX endpoints diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index c19cd27ac852..9a1153e80a3a 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -22,6 +22,7 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/pm_runtime.h> +#include <linux/pm_wakeirq.h> #include "ipa.h" #include "ipa_reg.h" @@ -269,9 +270,9 @@ struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa) goto err_kfree; } - ret = enable_irq_wake(irq); + ret = dev_pm_set_wake_irq(dev, irq); if (ret) { - dev_err(dev, "error %d enabling wakeup for \"ipa\" IRQ\n", ret); + dev_err(dev, "error %d registering \"ipa\" IRQ as wakeirq\n", ret); goto err_free_irq; } @@ -289,11 +290,8 @@ err_kfree: void ipa_interrupt_deconfig(struct ipa_interrupt *interrupt) { struct device *dev = &interrupt->ipa->pdev->dev; - int ret; - ret = disable_irq_wake(interrupt->irq); - if (ret) - dev_err(dev, "error %d disabling \"ipa\" IRQ wakeup\n", ret); + dev_pm_clear_wake_irq(dev); free_irq(interrupt->irq, interrupt); kfree(interrupt); } diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 4fb92f771974..60d7c558163f 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2018-2022 Linaro Ltd. + * Copyright (C) 2018-2023 Linaro Ltd. */ #include <linux/types.h> @@ -390,7 +390,12 @@ static void ipa_qtime_config(struct ipa *ipa) reg = ipa_reg(ipa, TIMERS_PULSE_GRAN_CFG); val = ipa_reg_encode(reg, PULSE_GRAN_0, IPA_GRAN_100_US); val |= ipa_reg_encode(reg, PULSE_GRAN_1, IPA_GRAN_1_MS); - val |= ipa_reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_1_MS); + if (ipa->version >= IPA_VERSION_5_0) { + val |= ipa_reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_10_MS); + val |= ipa_reg_encode(reg, PULSE_GRAN_3, IPA_GRAN_10_MS); + } else { + val |= ipa_reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_1_MS); + } iowrite32(val, ipa->reg_virt + ipa_reg_offset(reg)); @@ -432,6 +437,11 @@ static void ipa_hardware_config_hashing(struct ipa *ipa) { const struct ipa_reg *reg; + /* Other than IPA v4.2, all versions enable "hashing". Starting + * with IPA v5.0, the filter and router tables are implemented + * differently, but the default configuration enables this feature + * (now referred to as "cacheing"), so there's nothing to do here. + */ if (ipa->version != IPA_VERSION_4_2) return; diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c index 9ec5af323f73..a07776e20cb0 100644 --- a/drivers/net/ipa/ipa_mem.c +++ b/drivers/net/ipa/ipa_mem.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2022 Linaro Ltd. + * Copyright (C) 2019-2023 Linaro Ltd. */ #include <linux/types.h> @@ -163,6 +163,12 @@ static bool ipa_mem_id_valid(struct ipa *ipa, enum ipa_mem_id mem_id) return false; break; + case IPA_MEM_AP_V4_FILTER: + case IPA_MEM_AP_V6_FILTER: + if (version != IPA_VERSION_5_0) + return false; + break; + case IPA_MEM_NAT_TABLE: case IPA_MEM_STATS_FILTER_ROUTE: if (version < IPA_VERSION_4_5) diff --git a/drivers/net/ipa/ipa_mem.h b/drivers/net/ipa/ipa_mem.h index 570bfdd99bff..868e9c20e8c4 100644 --- a/drivers/net/ipa/ipa_mem.h +++ b/drivers/net/ipa/ipa_mem.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2021 Linaro Ltd. + * Copyright (C) 2019-2023 Linaro Ltd. */ #ifndef _IPA_MEM_H_ #define _IPA_MEM_H_ @@ -62,13 +62,15 @@ enum ipa_mem_id { IPA_MEM_PDN_CONFIG, /* 0/2 canaries (IPA v4.0+) */ IPA_MEM_STATS_QUOTA_MODEM, /* 2/4 canaries (IPA v4.0+) */ IPA_MEM_STATS_QUOTA_AP, /* 0 canaries, optional (IPA v4.0+) */ - IPA_MEM_STATS_TETHERING, /* 0 canaries (IPA v4.0+) */ + IPA_MEM_STATS_TETHERING, /* 0 canaries, optional (IPA v4.0+) */ IPA_MEM_STATS_DROP, /* 0 canaries, optional (IPA v4.0+) */ - /* The next 5 filter and route statistics regions are optional */ + /* The next 7 filter and route statistics regions are optional */ IPA_MEM_STATS_V4_FILTER, /* 0 canaries (IPA v4.0-v4.2) */ IPA_MEM_STATS_V6_FILTER, /* 0 canaries (IPA v4.0-v4.2) */ IPA_MEM_STATS_V4_ROUTE, /* 0 canaries (IPA v4.0-v4.2) */ IPA_MEM_STATS_V6_ROUTE, /* 0 canaries (IPA v4.0-v4.2) */ + IPA_MEM_AP_V4_FILTER, /* 2 canaries (IPA v5.0) */ + IPA_MEM_AP_V6_FILTER, /* 0 canaries (IPA v5.0) */ IPA_MEM_STATS_FILTER_ROUTE, /* 0 canaries (IPA v4.5+) */ IPA_MEM_NAT_TABLE, /* 4 canaries, optional (IPA v4.5+) */ IPA_MEM_END_MARKER, /* 1 canary (not a real region) */ diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index b1a3c2c7e167..82d43eca170e 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2018-2022 Linaro Ltd. + * Copyright (C) 2018-2023 Linaro Ltd. */ #ifndef _IPA_REG_H_ #define _IPA_REG_H_ @@ -59,8 +59,10 @@ enum ipa_reg_id { SHARED_MEM_SIZE, QSB_MAX_WRITES, QSB_MAX_READS, - FILT_ROUT_HASH_EN, - FILT_ROUT_HASH_FLUSH, + FILT_ROUT_HASH_EN, /* Not IPA v5.0+ */ + FILT_ROUT_CACHE_CFG, /* IPA v5.0+ */ + FILT_ROUT_HASH_FLUSH, /* Not IPA v5.0+ */ + FILT_ROUT_CACHE_FLUSH, /* IPA v5.0+ */ STATE_AGGR_ACTIVE, IPA_BCR, /* Not IPA v4.5+ */ LOCAL_PKT_PROC_CNTXT, @@ -95,7 +97,9 @@ enum ipa_reg_id { ENDP_INIT_SEQ, /* TX only */ ENDP_STATUS, ENDP_FILTER_ROUTER_HSH_CFG, /* Not IPA v4.2 */ - /* The IRQ registers are only used for GSI_EE_AP */ + ENDP_FILTER_CACHE_CFG, /* IPA v5.0+ */ + ENDP_ROUTER_CACHE_CFG, /* IPA v5.0+ */ + /* The IRQ registers that follow are only used for GSI_EE_AP */ IPA_IRQ_STTS, IPA_IRQ_EN, IPA_IRQ_CLR, @@ -251,14 +255,28 @@ enum ipa_reg_qsb_max_reads_field_id { GEN_QMB_1_MAX_READS_BEATS, /* IPA v4.0+ */ }; +/* FILT_ROUT_CACHE_CFG register */ +enum ipa_reg_filt_rout_cache_cfg_field_id { + ROUTER_CACHE_EN, + FILTER_CACHE_EN, + LOW_PRI_HASH_HIT_DISABLE, + LRU_EVICTION_THRESHOLD, +}; + /* FILT_ROUT_HASH_EN and FILT_ROUT_HASH_FLUSH registers */ -enum ipa_reg_rout_hash_field_id { +enum ipa_reg_filt_rout_hash_field_id { IPV6_ROUTER_HASH, IPV6_FILTER_HASH, IPV4_ROUTER_HASH, IPV4_FILTER_HASH, }; +/* FILT_ROUT_CACHE_FLUSH register */ +enum ipa_reg_filt_rout_cache_field_id { + ROUTER_CACHE, + FILTER_CACHE, +}; + /* BCR register */ enum ipa_bcr_compat { BCR_CMDQ_L_LACK_ONE_ENTRY = 0x0, /* Not IPA v4.2+ */ @@ -298,6 +316,7 @@ enum ipa_reg_ipa_tx_cfg_field_id { DUAL_TX_ENABLE, /* v4.5+ */ SSPND_PA_NO_START_STATE, /* v4,2+, not v4.5 */ SSPND_PA_NO_BQ_STATE, /* v4.2 only */ + HOLB_STICKY_DROP_EN, /* v5.0+ */ }; /* FLAVOR_0 register */ @@ -333,6 +352,7 @@ enum ipa_reg_timers_pulse_gran_cfg_field_id { PULSE_GRAN_0, PULSE_GRAN_1, PULSE_GRAN_2, + PULSE_GRAN_3, }; /* Values for IPA_GRAN_x fields of TIMERS_PULSE_GRAN_CFG */ @@ -415,6 +435,8 @@ enum ipa_reg_endp_init_hdr_ext_field_id { HDR_TOTAL_LEN_OR_PAD_OFFSET_MSB, /* v4.5+ */ HDR_OFST_PKT_SIZE_MSB, /* v4.5+ */ HDR_ADDITIONAL_CONST_LEN_MSB, /* v4.5+ */ + HDR_BYTES_TO_REMOVE_VALID, /* v5.0+ */ + HDR_BYTES_TO_REMOVE, /* v5.0+ */ }; /* ENDP_INIT_MODE register */ @@ -573,6 +595,17 @@ enum ipa_reg_endp_filter_router_hsh_cfg_field_id { ROUTER_HASH_MSK_ALL, /* Bitwise OR of the above 6 fields */ }; +/* ENDP_FILTER_CACHE_CFG and ENDP_ROUTER_CACHE_CFG registers */ +enum ipa_reg_endp_cache_cfg_field_id { + CACHE_MSK_SRC_ID, + CACHE_MSK_SRC_IP, + CACHE_MSK_DST_IP, + CACHE_MSK_SRC_PORT, + CACHE_MSK_DST_PORT, + CACHE_MSK_PROTOCOL, + CACHE_MSK_METADATA, +}; + /* IPA_IRQ_STTS, IPA_IRQ_EN, and IPA_IRQ_CLR registers */ /** * enum ipa_irq_id - Bit positions representing type of IPA IRQ diff --git a/drivers/net/ipa/ipa_table.c b/drivers/net/ipa/ipa_table.c index b81e27b61354..b9d505191f88 100644 --- a/drivers/net/ipa/ipa_table.c +++ b/drivers/net/ipa/ipa_table.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2018-2022 Linaro Ltd. + * Copyright (C) 2018-2023 Linaro Ltd. */ #include <linux/types.h> @@ -359,13 +359,22 @@ int ipa_table_hash_flush(struct ipa *ipa) return -EBUSY; } - reg = ipa_reg(ipa, FILT_ROUT_HASH_FLUSH); - offset = ipa_reg_offset(reg); + if (ipa->version < IPA_VERSION_5_0) { + reg = ipa_reg(ipa, FILT_ROUT_HASH_FLUSH); + offset = ipa_reg_offset(reg); - val = ipa_reg_bit(reg, IPV6_ROUTER_HASH); - val |= ipa_reg_bit(reg, IPV6_FILTER_HASH); - val |= ipa_reg_bit(reg, IPV4_ROUTER_HASH); - val |= ipa_reg_bit(reg, IPV4_FILTER_HASH); + val = ipa_reg_bit(reg, IPV6_ROUTER_HASH); + val |= ipa_reg_bit(reg, IPV6_FILTER_HASH); + val |= ipa_reg_bit(reg, IPV4_ROUTER_HASH); + val |= ipa_reg_bit(reg, IPV4_FILTER_HASH); + } else { + reg = ipa_reg(ipa, FILT_ROUT_CACHE_FLUSH); + offset = ipa_reg_offset(reg); + + /* IPA v5.0+ uses a unified cache (both IPv4 and IPv6) */ + val = ipa_reg_bit(reg, ROUTER_CACHE); + val |= ipa_reg_bit(reg, FILTER_CACHE); + } ipa_cmd_register_write_add(trans, offset, val, val, false); @@ -490,13 +499,22 @@ static void ipa_filter_tuple_zero(struct ipa_endpoint *endpoint) u32 offset; u32 val; - reg = ipa_reg(ipa, ENDP_FILTER_ROUTER_HSH_CFG); + if (ipa->version < IPA_VERSION_5_0) { + reg = ipa_reg(ipa, ENDP_FILTER_ROUTER_HSH_CFG); - offset = ipa_reg_n_offset(reg, endpoint_id); - val = ioread32(endpoint->ipa->reg_virt + offset); + offset = ipa_reg_n_offset(reg, endpoint_id); + val = ioread32(endpoint->ipa->reg_virt + offset); - /* Zero all filter-related fields, preserving the rest */ - val &= ~ipa_reg_fmask(reg, FILTER_HASH_MSK_ALL); + /* Zero all filter-related fields, preserving the rest */ + val &= ~ipa_reg_fmask(reg, FILTER_HASH_MSK_ALL); + } else { + /* IPA v5.0 separates filter and router cache configuration */ + reg = ipa_reg(ipa, ENDP_FILTER_CACHE_CFG); + offset = ipa_reg_n_offset(reg, endpoint_id); + + /* Zero all filter-related fields */ + val = 0; + } iowrite32(val, endpoint->ipa->reg_virt + offset); } @@ -540,13 +558,22 @@ static void ipa_route_tuple_zero(struct ipa *ipa, u32 route_id) u32 offset; u32 val; - reg = ipa_reg(ipa, ENDP_FILTER_ROUTER_HSH_CFG); - offset = ipa_reg_n_offset(reg, route_id); + if (ipa->version < IPA_VERSION_5_0) { + reg = ipa_reg(ipa, ENDP_FILTER_ROUTER_HSH_CFG); + offset = ipa_reg_n_offset(reg, route_id); + + val = ioread32(ipa->reg_virt + offset); - val = ioread32(ipa->reg_virt + offset); + /* Zero all route-related fields, preserving the rest */ + val &= ~ipa_reg_fmask(reg, ROUTER_HASH_MSK_ALL); + } else { + /* IPA v5.0 separates filter and router cache configuration */ + reg = ipa_reg(ipa, ENDP_ROUTER_CACHE_CFG); + offset = ipa_reg_n_offset(reg, route_id); - /* Zero all route-related fields, preserving the rest */ - val &= ~ipa_reg_fmask(reg, ROUTER_HASH_MSK_ALL); + /* Zero all route-related fields */ + val = 0; + } iowrite32(val, ipa->reg_virt + offset); } diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index bb1c298c1e78..460b3d4f2245 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -157,7 +157,7 @@ void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type) return NULL; ip4h = ip_hdr(skb); - pktlen = ntohs(ip4h->tot_len); + pktlen = skb_ip_totlen(skb); if (ip4h->ihl < 5 || ip4h->version != 4) return NULL; if (skb->len < pktlen || pktlen < (ip4h->ihl * 4)) diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig index bfa16826a6e1..90309980686e 100644 --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -215,6 +215,17 @@ config MDIO_BUS_MUX_MESON_G12A the amlogic g12a SoC. The multiplexers connects either the external or the internal MDIO bus to the parent bus. +config MDIO_BUS_MUX_MESON_GXL + tristate "Amlogic GXL based MDIO bus multiplexer" + depends on ARCH_MESON || COMPILE_TEST + depends on OF_MDIO && HAS_IOMEM && COMMON_CLK + select MDIO_BUS_MUX + default m if ARCH_MESON + help + This module provides a driver for the MDIO multiplexer/glue of + the amlogic GXL SoC. The multiplexer connects either the external + or the internal MDIO bus to the parent bus. + config MDIO_BUS_MUX_BCM6368 tristate "Broadcom BCM6368 MDIO bus multiplexers" depends on OF && OF_MDIO && (BMIPS_GENERIC || COMPILE_TEST) diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile index 15f8dc4042ce..7d4cb4c11e4e 100644 --- a/drivers/net/mdio/Makefile +++ b/drivers/net/mdio/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_MDIO_BUS_MUX_BCM6368) += mdio-mux-bcm6368.o obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC) += mdio-mux-bcm-iproc.o obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o obj-$(CONFIG_MDIO_BUS_MUX_MESON_G12A) += mdio-mux-meson-g12a.o +obj-$(CONFIG_MDIO_BUS_MUX_MESON_GXL) += mdio-mux-meson-gxl.o obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o obj-$(CONFIG_MDIO_BUS_MUX_MULTIPLEXER) += mdio-mux-multiplexer.o diff --git a/drivers/net/mdio/mdio-mux-meson-gxl.c b/drivers/net/mdio/mdio-mux-meson-gxl.c new file mode 100644 index 000000000000..76188575ca1f --- /dev/null +++ b/drivers/net/mdio/mdio-mux-meson-gxl.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 Baylibre, SAS. + * Author: Jerome Brunet <[email protected]> + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/mdio-mux.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define ETH_REG2 0x0 +#define REG2_PHYID GENMASK(21, 0) +#define EPHY_GXL_ID 0x110181 +#define REG2_LEDACT GENMASK(23, 22) +#define REG2_LEDLINK GENMASK(25, 24) +#define REG2_DIV4SEL BIT(27) +#define REG2_ADCBYPASS BIT(30) +#define REG2_CLKINSEL BIT(31) +#define ETH_REG3 0x4 +#define REG3_ENH BIT(3) +#define REG3_CFGMODE GENMASK(6, 4) +#define REG3_AUTOMDIX BIT(7) +#define REG3_PHYADDR GENMASK(12, 8) +#define REG3_PWRUPRST BIT(21) +#define REG3_PWRDOWN BIT(22) +#define REG3_LEDPOL BIT(23) +#define REG3_PHYMDI BIT(26) +#define REG3_CLKINEN BIT(29) +#define REG3_PHYIP BIT(30) +#define REG3_PHYEN BIT(31) +#define ETH_REG4 0x8 +#define REG4_PWRUPRSTSIG BIT(0) + +#define MESON_GXL_MDIO_EXTERNAL_ID 0 +#define MESON_GXL_MDIO_INTERNAL_ID 1 + +struct gxl_mdio_mux { + void __iomem *regs; + void *mux_handle; +}; + +static void gxl_enable_internal_mdio(struct gxl_mdio_mux *priv) +{ + u32 val; + + /* Setup the internal phy */ + val = (REG3_ENH | + FIELD_PREP(REG3_CFGMODE, 0x7) | + REG3_AUTOMDIX | + FIELD_PREP(REG3_PHYADDR, 8) | + REG3_LEDPOL | + REG3_PHYMDI | + REG3_CLKINEN | + REG3_PHYIP); + + writel(REG4_PWRUPRSTSIG, priv->regs + ETH_REG4); + writel(val, priv->regs + ETH_REG3); + mdelay(10); + + /* NOTE: The HW kept the phy id configurable at runtime. + * The id below is arbitrary. It is the one used in the vendor code. + * The only constraint is that it must match the one in + * drivers/net/phy/meson-gxl.c to properly match the PHY. + */ + writel(FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), + priv->regs + ETH_REG2); + + /* Enable the internal phy */ + val |= REG3_PHYEN; + writel(val, priv->regs + ETH_REG3); + writel(0, priv->regs + ETH_REG4); + + /* The phy needs a bit of time to power up */ + mdelay(10); +} + +static void gxl_enable_external_mdio(struct gxl_mdio_mux *priv) +{ + /* Reset the mdio bus mux to the external phy */ + writel(0, priv->regs + ETH_REG3); +} + +static int gxl_mdio_switch_fn(int current_child, int desired_child, + void *data) +{ + struct gxl_mdio_mux *priv = dev_get_drvdata(data); + + if (current_child == desired_child) + return 0; + + switch (desired_child) { + case MESON_GXL_MDIO_EXTERNAL_ID: + gxl_enable_external_mdio(priv); + break; + case MESON_GXL_MDIO_INTERNAL_ID: + gxl_enable_internal_mdio(priv); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct of_device_id gxl_mdio_mux_match[] = { + { .compatible = "amlogic,gxl-mdio-mux", }, + {}, +}; +MODULE_DEVICE_TABLE(of, gxl_mdio_mux_match); + +static int gxl_mdio_mux_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gxl_mdio_mux *priv; + struct clk *rclk; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + priv->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + rclk = devm_clk_get_enabled(dev, "ref"); + if (IS_ERR(rclk)) + return dev_err_probe(dev, PTR_ERR(rclk), + "failed to get reference clock\n"); + + ret = mdio_mux_init(dev, dev->of_node, gxl_mdio_switch_fn, + &priv->mux_handle, dev, NULL); + if (ret) + dev_err_probe(dev, ret, "mdio multiplexer init failed\n"); + + return ret; +} + +static int gxl_mdio_mux_remove(struct platform_device *pdev) +{ + struct gxl_mdio_mux *priv = platform_get_drvdata(pdev); + + mdio_mux_uninit(priv->mux_handle); + + return 0; +} + +static struct platform_driver gxl_mdio_mux_driver = { + .probe = gxl_mdio_mux_probe, + .remove = gxl_mdio_mux_remove, + .driver = { + .name = "gxl-mdio-mux", + .of_match_table = gxl_mdio_mux_match, + }, +}; +module_platform_driver(gxl_mdio_mux_driver); + +MODULE_DESCRIPTION("Amlogic GXL MDIO multiplexer driver"); +MODULE_AUTHOR("Jerome Brunet <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 685190db72de..aa02e722c51d 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -12,8 +12,8 @@ #include <linux/phy.h> #define PHY_ID_YT8511 0x0000010a -#define PHY_ID_YT8521 0x0000011A -#define PHY_ID_YT8531S 0x4F51E91A +#define PHY_ID_YT8521 0x0000011a +#define PHY_ID_YT8531S 0x4f51e91a /* YT8521/YT8531S Register Overview * UTP Register space | FIBER Register space @@ -1804,7 +1804,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, - { /* sentinal */ } + { /* sentinel */ } }; MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7e1a98430190..0f0036b1514d 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -723,7 +723,7 @@ static unsigned int virtnet_get_headroom(struct virtnet_info *vi) * have enough headroom. */ static struct page *xdp_linearize_page(struct receive_queue *rq, - u16 *num_buf, + int *num_buf, struct page *p, int offset, int page_off, @@ -823,7 +823,7 @@ static struct sk_buff *receive_small(struct net_device *dev, if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) { int offset = buf - page_address(page) + header_offset; unsigned int tlen = len + vi->hdr_len; - u16 num_buf = 1; + int num_buf = 1; xdp_headroom = virtnet_get_headroom(vi); header_offset = VIRTNET_RX_PAD + xdp_headroom; @@ -996,7 +996,7 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, void *buf, unsigned int len, unsigned int frame_sz, - u16 *num_buf, + int *num_buf, unsigned int *xdp_frags_truesize, struct virtnet_rq_stats *stats) { @@ -1014,6 +1014,9 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, xdp_prepare_buff(xdp, buf - VIRTIO_XDP_HEADROOM, VIRTIO_XDP_HEADROOM + vi->hdr_len, len - vi->hdr_len, true); + if (!*num_buf) + return 0; + if (*num_buf > 1) { /* If we want to build multi-buffer xdp, we need * to specify that the flags of xdp_buff have the @@ -1027,10 +1030,10 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, shinfo->xdp_frags_size = 0; } - if ((*num_buf - 1) > MAX_SKB_FRAGS) + if (*num_buf > MAX_SKB_FRAGS + 1) return -EINVAL; - while ((--*num_buf) >= 1) { + while (--*num_buf > 0) { buf = virtqueue_get_buf_ctx(rq->vq, &len, &ctx); if (unlikely(!buf)) { pr_debug("%s: rx error: %d buffers out of %d missing\n", @@ -1083,7 +1086,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, struct virtnet_rq_stats *stats) { struct virtio_net_hdr_mrg_rxbuf *hdr = buf; - u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers); + int num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers); struct page *page = virt_to_head_page(buf); int offset = buf - page_address(page); struct sk_buff *head_skb, *curr_skb; @@ -3813,6 +3816,12 @@ static int virtnet_validate(struct virtio_device *vdev) __virtio_clear_bit(vdev, VIRTIO_NET_F_MTU); } + if (virtio_has_feature(vdev, VIRTIO_NET_F_STANDBY) && + !virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) { + dev_warn(&vdev->dev, "device advertises feature VIRTIO_NET_F_STANDBY but not VIRTIO_NET_F_MAC, disabling standby"); + __virtio_clear_bit(vdev, VIRTIO_NET_F_STANDBY); + } + return 0; } @@ -3925,6 +3934,8 @@ static int virtnet_probe(struct virtio_device *vdev) eth_hw_addr_set(dev, addr); } else { eth_hw_addr_random(dev); + dev_info(&vdev->dev, "Assigned random MAC address %pM\n", + dev->dev_addr); } /* Set up our device-specific information */ @@ -4052,6 +4063,24 @@ static int virtnet_probe(struct virtio_device *vdev) virtio_device_ready(vdev); + /* a random MAC address has been assigned, notify the device. + * We don't fail probe if VIRTIO_NET_F_CTRL_MAC_ADDR is not there + * because many devices work fine without getting MAC explicitly + */ + if (!virtio_has_feature(vdev, VIRTIO_NET_F_MAC) && + virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) { + struct scatterlist sg; + + sg_init_one(&sg, dev->dev_addr, dev->addr_len); + if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, + VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) { + pr_debug("virtio_net: setting MAC address failed\n"); + rtnl_unlock(); + err = -EINVAL; + goto free_unregister_netdev; + } + } + rtnl_unlock(); err = virtnet_cpu_notif_add(vi); diff --git a/include/linux/ip.h b/include/linux/ip.h index 3d9c6750af62..d11c25f5030a 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -35,4 +35,25 @@ static inline unsigned int ip_transport_len(const struct sk_buff *skb) { return ntohs(ip_hdr(skb)->tot_len) - skb_network_header_len(skb); } + +static inline unsigned int iph_totlen(const struct sk_buff *skb, const struct iphdr *iph) +{ + u32 len = ntohs(iph->tot_len); + + return (len || !skb_is_gso(skb) || !skb_is_gso_tcp(skb)) ? + len : skb->len - skb_network_offset(skb); +} + +static inline unsigned int skb_ip_totlen(const struct sk_buff *skb) +{ + return iph_totlen(skb, ip_hdr(skb)); +} + +/* IPv4 datagram length is stored into 16bit field (tot_len) */ +#define IP_MAX_MTU 0xFFFFU + +static inline void iph_set_totlen(struct iphdr *iph, unsigned int len) +{ + iph->tot_len = len <= IP_MAX_MTU ? htons(len) : 0; +} #endif /* _LINUX_IP_H */ diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 29d4b201c7b2..bc531bd9804f 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -1204,6 +1204,7 @@ enum mlx5_cap_type { MLX5_CAP_VDPA_EMULATION = 0x13, MLX5_CAP_DEV_EVENT = 0x14, MLX5_CAP_IPSEC, + MLX5_CAP_CRYPTO = 0x1a, MLX5_CAP_DEV_SHAMPO = 0x1d, MLX5_CAP_MACSEC = 0x1f, MLX5_CAP_GENERAL_2 = 0x20, @@ -1460,6 +1461,9 @@ enum mlx5_qcam_feature_groups { #define MLX5_CAP_IPSEC(mdev, cap)\ MLX5_GET(ipsec_cap, (mdev)->caps.hca[MLX5_CAP_IPSEC]->cur, cap) +#define MLX5_CAP_CRYPTO(mdev, cap)\ + MLX5_GET(crypto_cap, (mdev)->caps.hca[MLX5_CAP_CRYPTO]->cur, cap) + #define MLX5_CAP_DEV_SHAMPO(mdev, cap)\ MLX5_GET(shampo_cap, mdev->caps.hca_cur[MLX5_CAP_DEV_SHAMPO], cap) diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 44167760ff29..cd529e051b4d 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -516,6 +516,7 @@ struct mlx5_vhca_state_notifier; struct mlx5_sf_dev_table; struct mlx5_sf_hw_table; struct mlx5_sf_table; +struct mlx5_crypto_dek_priv; struct mlx5_rate_limit { u32 rate; @@ -673,6 +674,7 @@ struct mlx5e_resources { } hw_objs; struct devlink_port dl_port; struct net_device *uplink_netdev; + struct mlx5_crypto_dek_priv *dek_priv; }; enum mlx5_sw_icm_type { diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 0b102c651fe2..1b6201bb04c1 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -306,6 +306,7 @@ enum { MLX5_CMD_OP_SYNC_STEERING = 0xb00, MLX5_CMD_OP_QUERY_VHCA_STATE = 0xb0d, MLX5_CMD_OP_MODIFY_VHCA_STATE = 0xb0e, + MLX5_CMD_OP_SYNC_CRYPTO = 0xb12, MLX5_CMD_OP_MAX }; @@ -1112,6 +1113,30 @@ struct mlx5_ifc_sync_steering_out_bits { u8 reserved_at_40[0x40]; }; +struct mlx5_ifc_sync_crypto_in_bits { + u8 opcode[0x10]; + u8 uid[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x20]; + + u8 reserved_at_60[0x10]; + u8 crypto_type[0x10]; + + u8 reserved_at_80[0x80]; +}; + +struct mlx5_ifc_sync_crypto_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x40]; +}; + struct mlx5_ifc_device_mem_cap_bits { u8 memic[0x1]; u8 reserved_at_1[0x1f]; @@ -1768,7 +1793,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 ats[0x1]; u8 reserved_at_462[0x1]; u8 log_max_uctx[0x5]; - u8 reserved_at_468[0x2]; + u8 reserved_at_468[0x1]; + u8 crypto[0x1]; u8 ipsec_offload[0x1]; u8 log_max_umem[0x5]; u8 max_num_eqs[0x10]; @@ -3351,6 +3377,30 @@ struct mlx5_ifc_shampo_cap_bits { u8 reserved_at_40[0x7c0]; }; +struct mlx5_ifc_crypto_cap_bits { + u8 reserved_at_0[0x3]; + u8 synchronize_dek[0x1]; + u8 int_kek_manual[0x1]; + u8 int_kek_auto[0x1]; + u8 reserved_at_6[0x1a]; + + u8 reserved_at_20[0x3]; + u8 log_dek_max_alloc[0x5]; + u8 reserved_at_28[0x3]; + u8 log_max_num_deks[0x5]; + u8 reserved_at_30[0x10]; + + u8 reserved_at_40[0x20]; + + u8 reserved_at_60[0x3]; + u8 log_dek_granularity[0x5]; + u8 reserved_at_68[0x3]; + u8 log_max_num_int_kek[0x5]; + u8 sw_wrapped_dek[0x10]; + + u8 reserved_at_80[0x780]; +}; + union mlx5_ifc_hca_cap_union_bits { struct mlx5_ifc_cmd_hca_cap_bits cmd_hca_cap; struct mlx5_ifc_cmd_hca_cap_2_bits cmd_hca_cap_2; @@ -3371,6 +3421,7 @@ union mlx5_ifc_hca_cap_union_bits { struct mlx5_ifc_virtio_emulation_cap_bits virtio_emulation_cap; struct mlx5_ifc_shampo_cap_bits shampo_cap; struct mlx5_ifc_macsec_cap_bits macsec_cap; + struct mlx5_ifc_crypto_cap_bits crypto_cap; u8 reserved_at_0[0x8000]; }; @@ -6196,6 +6247,18 @@ struct mlx5_ifc_match_definer_bits { }; }; +struct mlx5_ifc_general_obj_create_param_bits { + u8 alias_object[0x1]; + u8 reserved_at_1[0x2]; + u8 log_obj_range[0x5]; + u8 reserved_at_8[0x18]; +}; + +struct mlx5_ifc_general_obj_query_param_bits { + u8 alias_object[0x1]; + u8 obj_offset[0x1f]; +}; + struct mlx5_ifc_general_obj_in_cmd_hdr_bits { u8 opcode[0x10]; u8 uid[0x10]; @@ -6205,9 +6268,10 @@ struct mlx5_ifc_general_obj_in_cmd_hdr_bits { u8 obj_id[0x20]; - u8 reserved_at_60[0x3]; - u8 log_obj_range[0x5]; - u8 reserved_at_68[0x18]; + union { + struct mlx5_ifc_general_obj_create_param_bits create; + struct mlx5_ifc_general_obj_query_param_bits query; + } op_param; }; struct mlx5_ifc_general_obj_out_cmd_hdr_bits { @@ -11702,6 +11766,7 @@ enum { MLX5_GENERAL_OBJECT_TYPES_SAMPLER = 0x20, MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO = 0x24, MLX5_GENERAL_OBJECT_TYPES_MACSEC = 0x27, + MLX5_GENERAL_OBJECT_TYPES_INT_KEK = 0x47, }; enum { @@ -11881,21 +11946,62 @@ struct mlx5_ifc_query_macsec_obj_out_bits { struct mlx5_ifc_macsec_offload_obj_bits macsec_object; }; +struct mlx5_ifc_wrapped_dek_bits { + u8 gcm_iv[0x60]; + + u8 reserved_at_60[0x20]; + + u8 const0[0x1]; + u8 key_size[0x1]; + u8 reserved_at_82[0x2]; + u8 key2_invalid[0x1]; + u8 reserved_at_85[0x3]; + u8 pd[0x18]; + + u8 key_purpose[0x5]; + u8 reserved_at_a5[0x13]; + u8 kek_id[0x8]; + + u8 reserved_at_c0[0x40]; + + u8 key1[0x8][0x20]; + + u8 key2[0x8][0x20]; + + u8 reserved_at_300[0x40]; + + u8 const1[0x1]; + u8 reserved_at_341[0x1f]; + + u8 reserved_at_360[0x20]; + + u8 auth_tag[0x80]; +}; + struct mlx5_ifc_encryption_key_obj_bits { u8 modify_field_select[0x40]; - u8 reserved_at_40[0x14]; + u8 state[0x8]; + u8 sw_wrapped[0x1]; + u8 reserved_at_49[0xb]; u8 key_size[0x4]; u8 reserved_at_58[0x4]; - u8 key_type[0x4]; + u8 key_purpose[0x4]; u8 reserved_at_60[0x8]; u8 pd[0x18]; - u8 reserved_at_80[0x180]; - u8 key[8][0x20]; + u8 reserved_at_80[0x100]; + + u8 opaque[0x40]; + + u8 reserved_at_1c0[0x40]; + + u8 key[8][0x80]; + + u8 sw_wrapped_dek[8][0x80]; - u8 reserved_at_300[0x500]; + u8 reserved_at_a00[0x600]; }; struct mlx5_ifc_create_encryption_key_in_bits { @@ -11903,6 +12009,11 @@ struct mlx5_ifc_create_encryption_key_in_bits { struct mlx5_ifc_encryption_key_obj_bits encryption_key_object; }; +struct mlx5_ifc_modify_encryption_key_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits general_obj_in_cmd_hdr; + struct mlx5_ifc_encryption_key_obj_bits encryption_key_object; +}; + enum { MLX5_FLOW_METER_MODE_BYTES_IP_LENGTH = 0x0, MLX5_FLOW_METER_MODE_BYTES_CALC_WITH_L2 = 0x1, @@ -11958,6 +12069,34 @@ struct mlx5_ifc_create_flow_meter_aso_obj_in_bits { struct mlx5_ifc_flow_meter_aso_obj_bits flow_meter_aso_obj; }; +struct mlx5_ifc_int_kek_obj_bits { + u8 modify_field_select[0x40]; + + u8 state[0x8]; + u8 auto_gen[0x1]; + u8 reserved_at_49[0xb]; + u8 key_size[0x4]; + u8 reserved_at_58[0x8]; + + u8 reserved_at_60[0x8]; + u8 pd[0x18]; + + u8 reserved_at_80[0x180]; + u8 key[8][0x80]; + + u8 reserved_at_600[0x200]; +}; + +struct mlx5_ifc_create_int_kek_obj_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits general_obj_in_cmd_hdr; + struct mlx5_ifc_int_kek_obj_bits int_kek_object; +}; + +struct mlx5_ifc_create_int_kek_obj_out_bits { + struct mlx5_ifc_general_obj_out_cmd_hdr_bits general_obj_out_cmd_hdr; + struct mlx5_ifc_int_kek_obj_bits int_kek_object; +}; + struct mlx5_ifc_sampler_obj_bits { u8 modify_field_select[0x40]; @@ -11996,9 +12135,9 @@ enum { }; enum { - MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_TLS = 0x1, - MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_IPSEC = 0x2, - MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_MACSEC = 0x4, + MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_TLS = 0x1, + MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_IPSEC = 0x2, + MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_PURPOSE_MACSEC = 0x4, }; struct mlx5_ifc_tls_static_params_bits { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2466afa25078..d5ef4c1fedd2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1964,6 +1964,8 @@ enum netdev_ml_priv_type { * @gso_max_segs: Maximum number of segments that can be passed to the * NIC for GSO * @tso_max_segs: Device (as in HW) limit on the max TSO segment count + * @gso_ipv4_max_size: Maximum size of generic segmentation offload, + * for IPv4. * * @dcbnl_ops: Data Center Bridging netlink ops * @num_tc: Number of traffic classes in the net device @@ -2004,6 +2006,8 @@ enum netdev_ml_priv_type { * keep a list of interfaces to be deleted. * @gro_max_size: Maximum size of aggregated packet in generic * receive offload (GRO) + * @gro_ipv4_max_size: Maximum size of aggregated packet in generic + * receive offload (GRO), for IPv4. * * @dev_addr_shadow: Copy of @dev_addr to catch direct writes. * @linkwatch_dev_tracker: refcount tracker used by linkwatch. @@ -2207,6 +2211,7 @@ struct net_device { */ #define GRO_MAX_SIZE (8 * 65535u) unsigned int gro_max_size; + unsigned int gro_ipv4_max_size; rx_handler_func_t __rcu *rx_handler; void __rcu *rx_handler_data; @@ -2330,6 +2335,7 @@ struct net_device { u16 gso_max_segs; #define TSO_MAX_SEGS U16_MAX u16 tso_max_segs; + unsigned int gso_ipv4_max_size; #ifdef CONFIG_DCB const struct dcbnl_rtnl_ops *dcbnl_ops; diff --git a/include/linux/netlink.h b/include/linux/netlink.h index fa4d86da0ec7..c43ac7690eca 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -130,6 +130,16 @@ struct netlink_ext_ack { #define NL_SET_ERR_MSG_FMT_MOD(extack, fmt, args...) \ NL_SET_ERR_MSG_FMT((extack), KBUILD_MODNAME ": " fmt, ##args) +#define NL_SET_ERR_MSG_WEAK(extack, msg) do { \ + if ((extack) && !(extack)->_msg) \ + NL_SET_ERR_MSG((extack), msg); \ +} while (0) + +#define NL_SET_ERR_MSG_WEAK_MOD(extack, msg) do { \ + if ((extack) && !(extack)->_msg) \ + NL_SET_ERR_MSG_MOD((extack), msg); \ +} while (0) + #define NL_SET_BAD_ATTR_POLICY(extack, attr, pol) do { \ if ((extack)) { \ (extack)->bad_attr = (attr); \ diff --git a/include/net/netfilter/nf_tables_ipv4.h b/include/net/netfilter/nf_tables_ipv4.h index 112708f7a6b4..947973623dc7 100644 --- a/include/net/netfilter/nf_tables_ipv4.h +++ b/include/net/netfilter/nf_tables_ipv4.h @@ -29,7 +29,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt) if (iph->ihl < 5 || iph->version != 4) return -1; - len = ntohs(iph->tot_len); + len = iph_totlen(pkt->skb, iph); thoff = iph->ihl * 4; if (pkt->skb->len < len) return -1; @@ -64,7 +64,7 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt) if (iph->ihl < 5 || iph->version != 4) goto inhdr_error; - len = ntohs(iph->tot_len); + len = iph_totlen(pkt->skb, iph); thoff = iph->ihl * 4; if (pkt->skb->len < len) { __IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INTRUNCATEDPKTS); diff --git a/include/net/route.h b/include/net/route.h index 6e92dd5bcd61..fe00b0a2e475 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -35,9 +35,6 @@ #include <linux/cache.h> #include <linux/security.h> -/* IPv4 datagram length is stored into 16bit field (tot_len) */ -#define IP_MAX_MTU 0xFFFFU - #define RTO_ONLINK 0x01 #define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE)) diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index afb11680a793..2080879e4134 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -967,6 +967,7 @@ void ocelot_ptp_rx_timestamp(struct ocelot *ocelot, struct sk_buff *skb, int ocelot_regfields_init(struct ocelot *ocelot, const struct reg_field *const regfields); struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res); +int ocelot_reset(struct ocelot *ocelot); int ocelot_init(struct ocelot *ocelot); void ocelot_deinit(struct ocelot *ocelot); void ocelot_init_port(struct ocelot *ocelot, int port); @@ -978,6 +979,11 @@ void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port, int cpu); void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port); u32 ocelot_port_assigned_dsa_8021q_cpu_mask(struct ocelot *ocelot, int port); +/* Watermark interface */ +u16 ocelot_wm_enc(u16 value); +u16 ocelot_wm_dec(u16 wm); +void ocelot_wm_stat(u32 val, u32 *inuse, u32 *maxuse); + /* DSA callbacks */ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data); void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data); diff --git a/include/soc/mscc/vsc7514_regs.h b/include/soc/mscc/vsc7514_regs.h index ceee26c96959..dfb91629c8bd 100644 --- a/include/soc/mscc/vsc7514_regs.h +++ b/include/soc/mscc/vsc7514_regs.h @@ -10,6 +10,10 @@ #include <soc/mscc/ocelot_vcap.h> +extern struct vcap_props vsc7514_vcap_props[]; + +extern const struct reg_field vsc7514_regfields[REGFIELD_MAX]; + extern const u32 vsc7514_ana_regmap[]; extern const u32 vsc7514_qs_regmap[]; extern const u32 vsc7514_qsys_regmap[]; @@ -19,6 +23,8 @@ extern const u32 vsc7514_vcap_regmap[]; extern const u32 vsc7514_ptp_regmap[]; extern const u32 vsc7514_dev_gmii_regmap[]; +extern const u32 *vsc7514_regmap[TARGET_MAX]; + extern const struct vcap_field vsc7514_vcap_es0_keys[]; extern const struct vcap_field vsc7514_vcap_es0_actions[]; extern const struct vcap_field vsc7514_vcap_is1_keys[]; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 1021a7e47a86..02b87e4c65be 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -374,6 +374,9 @@ enum { IFLA_DEVLINK_PORT, + IFLA_GSO_IPV4_MAX_SIZE, + IFLA_GRO_IPV4_MAX_SIZE, + __IFLA_MAX }; diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index a8516b3594a4..78c981d6a9d4 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -115,6 +115,7 @@ struct tpacket_auxdata { #define TP_STATUS_BLK_TMO (1 << 5) #define TP_STATUS_VLAN_TPID_VALID (1 << 6) /* auxdata has valid tp_vlan_tpid */ #define TP_STATUS_CSUM_VALID (1 << 7) +#define TP_STATUS_GSO_TCP (1 << 8) /* Tx ring - header status */ #define TP_STATUS_AVAILABLE 0 diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index f20f4373ff40..b67c9c98effa 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -214,7 +214,7 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb) if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) goto csum_error; - len = ntohs(iph->tot_len); + len = skb_ip_totlen(skb); if (skb->len < len) { __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS); goto drop; diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 7eb6fd5bb917..de18e9c1d7a7 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -104,9 +104,8 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, return 0; if (err) { - if (extack && !extack->_msg) - NL_SET_ERR_MSG_MOD(extack, - "bridge flag offload is not supported"); + NL_SET_ERR_MSG_WEAK_MOD(extack, + "bridge flag offload is not supported"); return -EOPNOTSUPP; } @@ -115,9 +114,8 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, err = switchdev_port_attr_set(p->dev, &attr, extack); if (err) { - if (extack && !extack->_msg) - NL_SET_ERR_MSG_MOD(extack, - "error setting offload flag on port"); + NL_SET_ERR_MSG_WEAK_MOD(extack, + "error setting offload flag on port"); return err; } diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c index 5c5dd437f1c2..71056ee84773 100644 --- a/net/bridge/netfilter/nf_conntrack_bridge.c +++ b/net/bridge/netfilter/nf_conntrack_bridge.c @@ -212,7 +212,7 @@ static int nf_ct_br_ip_check(const struct sk_buff *skb) iph->version != 4) return -1; - len = ntohs(iph->tot_len); + len = skb_ip_totlen(skb); if (skb->len < nhoff + len || len < (iph->ihl * 4)) return -1; @@ -256,7 +256,7 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb, if (!pskb_may_pull(skb, sizeof(struct iphdr))) return NF_ACCEPT; - len = ntohs(ip_hdr(skb)->tot_len); + len = skb_ip_totlen(skb); if (pskb_trim_rcsum(skb, len)) return NF_ACCEPT; diff --git a/net/core/dev.c b/net/core/dev.c index f72f5c4ee7e2..bb42150a38ec 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3001,6 +3001,8 @@ void netif_set_tso_max_size(struct net_device *dev, unsigned int size) dev->tso_max_size = min(GSO_MAX_SIZE, size); if (size < READ_ONCE(dev->gso_max_size)) netif_set_gso_max_size(dev, size); + if (size < READ_ONCE(dev->gso_ipv4_max_size)) + netif_set_gso_ipv4_max_size(dev, size); } EXPORT_SYMBOL(netif_set_tso_max_size); @@ -10614,6 +10616,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev->gso_max_size = GSO_LEGACY_MAX_SIZE; dev->gso_max_segs = GSO_MAX_SEGS; dev->gro_max_size = GRO_LEGACY_MAX_SIZE; + dev->gso_ipv4_max_size = GSO_LEGACY_MAX_SIZE; + dev->gro_ipv4_max_size = GRO_LEGACY_MAX_SIZE; dev->tso_max_size = TSO_LEGACY_MAX_SIZE; dev->tso_max_segs = TSO_MAX_SEGS; dev->upper_level = 1; diff --git a/net/core/dev.h b/net/core/dev.h index 814ed5b7b960..a065b7571441 100644 --- a/net/core/dev.h +++ b/net/core/dev.h @@ -100,6 +100,8 @@ static inline void netif_set_gso_max_size(struct net_device *dev, { /* dev->gso_max_size is read locklessly from sk_setup_caps() */ WRITE_ONCE(dev->gso_max_size, size); + if (size <= GSO_LEGACY_MAX_SIZE) + WRITE_ONCE(dev->gso_ipv4_max_size, size); } static inline void netif_set_gso_max_segs(struct net_device *dev, @@ -114,6 +116,22 @@ static inline void netif_set_gro_max_size(struct net_device *dev, { /* This pairs with the READ_ONCE() in skb_gro_receive() */ WRITE_ONCE(dev->gro_max_size, size); + if (size <= GRO_LEGACY_MAX_SIZE) + WRITE_ONCE(dev->gro_ipv4_max_size, size); +} + +static inline void netif_set_gso_ipv4_max_size(struct net_device *dev, + unsigned int size) +{ + /* dev->gso_ipv4_max_size is read locklessly from sk_setup_caps() */ + WRITE_ONCE(dev->gso_ipv4_max_size, size); +} + +static inline void netif_set_gro_ipv4_max_size(struct net_device *dev, + unsigned int size) +{ + /* This pairs with the READ_ONCE() in skb_gro_receive() */ + WRITE_ONCE(dev->gro_ipv4_max_size, size); } #endif diff --git a/net/core/gro.c b/net/core/gro.c index 506f83d715f8..b15f85546bdd 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -162,16 +162,18 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) struct sk_buff *lp; int segs; - /* pairs with WRITE_ONCE() in netif_set_gro_max_size() */ - gro_max_size = READ_ONCE(p->dev->gro_max_size); + /* pairs with WRITE_ONCE() in netif_set_gro(_ipv4)_max_size() */ + gro_max_size = p->protocol == htons(ETH_P_IPV6) ? + READ_ONCE(p->dev->gro_max_size) : + READ_ONCE(p->dev->gro_ipv4_max_size); if (unlikely(p->len + len >= gro_max_size || NAPI_GRO_CB(skb)->flush)) return -E2BIG; if (unlikely(p->len + len >= GRO_LEGACY_MAX_SIZE)) { - if (p->protocol != htons(ETH_P_IPV6) || - skb_headroom(p) < sizeof(struct hop_jumbo_hdr) || - ipv6_hdr(p)->nexthdr != IPPROTO_TCP || + if (NAPI_GRO_CB(skb)->proto != IPPROTO_TCP || + (p->protocol == htons(ETH_P_IPV6) && + skb_headroom(p) < sizeof(struct hop_jumbo_hdr)) || p->encapsulation) return -E2BIG; } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index f00a79fc301b..57258110bccd 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1662,11 +1662,21 @@ static void neigh_proxy_process(struct timer_list *t) spin_unlock(&tbl->proxy_queue.lock); } +static unsigned long neigh_proxy_delay(struct neigh_parms *p) +{ + /* If proxy_delay is zero, do not call get_random_u32_below() + * as it is undefined behavior. + */ + unsigned long proxy_delay = NEIGH_VAR(p, PROXY_DELAY); + + return proxy_delay ? + jiffies + get_random_u32_below(proxy_delay) : jiffies; +} + void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, struct sk_buff *skb) { - unsigned long sched_next = jiffies + - get_random_u32_below(NEIGH_VAR(p, PROXY_DELAY)); + unsigned long sched_next = neigh_proxy_delay(p); if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) { kfree_skb(skb); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 64289bc98887..b9f584955b77 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1074,6 +1074,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + nla_total_size(4) /* IFLA_GSO_MAX_SEGS */ + nla_total_size(4) /* IFLA_GSO_MAX_SIZE */ + nla_total_size(4) /* IFLA_GRO_MAX_SIZE */ + + nla_total_size(4) /* IFLA_GSO_IPV4_MAX_SIZE */ + + nla_total_size(4) /* IFLA_GRO_IPV4_MAX_SIZE */ + nla_total_size(4) /* IFLA_TSO_MAX_SIZE */ + nla_total_size(4) /* IFLA_TSO_MAX_SEGS */ + nla_total_size(1) /* IFLA_OPERSTATE */ @@ -1807,6 +1809,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, nla_put_u32(skb, IFLA_GSO_MAX_SEGS, dev->gso_max_segs) || nla_put_u32(skb, IFLA_GSO_MAX_SIZE, dev->gso_max_size) || nla_put_u32(skb, IFLA_GRO_MAX_SIZE, dev->gro_max_size) || + nla_put_u32(skb, IFLA_GSO_IPV4_MAX_SIZE, dev->gso_ipv4_max_size) || + nla_put_u32(skb, IFLA_GRO_IPV4_MAX_SIZE, dev->gro_ipv4_max_size) || nla_put_u32(skb, IFLA_TSO_MAX_SIZE, dev->tso_max_size) || nla_put_u32(skb, IFLA_TSO_MAX_SEGS, dev->tso_max_segs) || #ifdef CONFIG_RPS @@ -1968,6 +1972,8 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_TSO_MAX_SIZE] = { .type = NLA_REJECT }, [IFLA_TSO_MAX_SEGS] = { .type = NLA_REJECT }, [IFLA_ALLMULTI] = { .type = NLA_REJECT }, + [IFLA_GSO_IPV4_MAX_SIZE] = { .type = NLA_U32 }, + [IFLA_GRO_IPV4_MAX_SIZE] = { .type = NLA_U32 }, }; static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { @@ -2883,6 +2889,29 @@ static int do_setlink(const struct sk_buff *skb, } } + if (tb[IFLA_GSO_IPV4_MAX_SIZE]) { + u32 max_size = nla_get_u32(tb[IFLA_GSO_IPV4_MAX_SIZE]); + + if (max_size > dev->tso_max_size) { + err = -EINVAL; + goto errout; + } + + if (dev->gso_ipv4_max_size ^ max_size) { + netif_set_gso_ipv4_max_size(dev, max_size); + status |= DO_SETLINK_MODIFIED; + } + } + + if (tb[IFLA_GRO_IPV4_MAX_SIZE]) { + u32 gro_max_size = nla_get_u32(tb[IFLA_GRO_IPV4_MAX_SIZE]); + + if (dev->gro_ipv4_max_size ^ gro_max_size) { + netif_set_gro_ipv4_max_size(dev, gro_max_size); + status |= DO_SETLINK_MODIFIED; + } + } + if (tb[IFLA_OPERSTATE]) set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); @@ -3325,6 +3354,10 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname, netif_set_gso_max_segs(dev, nla_get_u32(tb[IFLA_GSO_MAX_SEGS])); if (tb[IFLA_GRO_MAX_SIZE]) netif_set_gro_max_size(dev, nla_get_u32(tb[IFLA_GRO_MAX_SIZE])); + if (tb[IFLA_GSO_IPV4_MAX_SIZE]) + netif_set_gso_ipv4_max_size(dev, nla_get_u32(tb[IFLA_GSO_IPV4_MAX_SIZE])); + if (tb[IFLA_GRO_IPV4_MAX_SIZE]) + netif_set_gro_ipv4_max_size(dev, nla_get_u32(tb[IFLA_GRO_IPV4_MAX_SIZE])); return dev; } diff --git a/net/core/sock.c b/net/core/sock.c index 7ba4891460ad..f08b76acde9b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2373,17 +2373,22 @@ void sk_free_unlock_clone(struct sock *sk) } EXPORT_SYMBOL_GPL(sk_free_unlock_clone); -static void sk_trim_gso_size(struct sock *sk) +static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst) { - if (sk->sk_gso_max_size <= GSO_LEGACY_MAX_SIZE) - return; + bool is_ipv6 = false; + u32 max_size; + #if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == AF_INET6 && - sk_is_tcp(sk) && - !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)) - return; + is_ipv6 = (sk->sk_family == AF_INET6 && + !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)); #endif - sk->sk_gso_max_size = GSO_LEGACY_MAX_SIZE; + /* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */ + max_size = is_ipv6 ? READ_ONCE(dst->dev->gso_max_size) : + READ_ONCE(dst->dev->gso_ipv4_max_size); + if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk)) + max_size = GSO_LEGACY_MAX_SIZE; + + return max_size - (MAX_TCP_HEADER + 1); } void sk_setup_caps(struct sock *sk, struct dst_entry *dst) @@ -2403,10 +2408,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } else { sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; - /* pairs with the WRITE_ONCE() in netif_set_gso_max_size() */ - sk->sk_gso_max_size = READ_ONCE(dst->dev->gso_max_size); - sk_trim_gso_size(sk); - sk->sk_gso_max_size -= (MAX_TCP_HEADER + 1); + sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dst); /* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */ max_segs = max_t(u32, READ_ONCE(dst->dev->gso_max_segs), 1); } diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index ba161de4120e..bdd7ad25c7e8 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -115,7 +115,7 @@ struct devlink_nl_dump_state { }; }; -struct devlink_gen_cmd { +struct devlink_cmd { int (*dump_one)(struct sk_buff *msg, struct devlink *devlink, struct netlink_callback *cb); }; @@ -128,8 +128,8 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs); void devlink_notify_unregister(struct devlink *devlink); void devlink_notify_register(struct devlink *devlink); -int devlink_nl_instance_iter_dump(struct sk_buff *msg, - struct netlink_callback *cb); +int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, + struct netlink_callback *cb); static inline struct devlink_nl_dump_state * devlink_dump_state(struct netlink_callback *cb) @@ -139,22 +139,23 @@ devlink_dump_state(struct netlink_callback *cb) return (struct devlink_nl_dump_state *)cb->ctx; } -/* gen cmds */ -extern const struct devlink_gen_cmd devl_gen_inst; -extern const struct devlink_gen_cmd devl_gen_port; -extern const struct devlink_gen_cmd devl_gen_sb; -extern const struct devlink_gen_cmd devl_gen_sb_pool; -extern const struct devlink_gen_cmd devl_gen_sb_port_pool; -extern const struct devlink_gen_cmd devl_gen_sb_tc_pool_bind; -extern const struct devlink_gen_cmd devl_gen_selftests; -extern const struct devlink_gen_cmd devl_gen_param; -extern const struct devlink_gen_cmd devl_gen_region; -extern const struct devlink_gen_cmd devl_gen_info; -extern const struct devlink_gen_cmd devl_gen_health_reporter; -extern const struct devlink_gen_cmd devl_gen_trap; -extern const struct devlink_gen_cmd devl_gen_trap_group; -extern const struct devlink_gen_cmd devl_gen_trap_policer; -extern const struct devlink_gen_cmd devl_gen_linecard; +/* Commands */ +extern const struct devlink_cmd devl_cmd_get; +extern const struct devlink_cmd devl_cmd_port_get; +extern const struct devlink_cmd devl_cmd_sb_get; +extern const struct devlink_cmd devl_cmd_sb_pool_get; +extern const struct devlink_cmd devl_cmd_sb_port_pool_get; +extern const struct devlink_cmd devl_cmd_sb_tc_pool_bind_get; +extern const struct devlink_cmd devl_cmd_param_get; +extern const struct devlink_cmd devl_cmd_region_get; +extern const struct devlink_cmd devl_cmd_info_get; +extern const struct devlink_cmd devl_cmd_health_reporter_get; +extern const struct devlink_cmd devl_cmd_trap_get; +extern const struct devlink_cmd devl_cmd_trap_group_get; +extern const struct devlink_cmd devl_cmd_trap_policer_get; +extern const struct devlink_cmd devl_cmd_rate_get; +extern const struct devlink_cmd devl_cmd_linecard_get; +extern const struct devlink_cmd devl_cmd_selftests_get; /* Ports */ int devlink_port_netdevice_event(struct notifier_block *nb, @@ -182,8 +183,6 @@ struct devlink_linecard * devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info); /* Rates */ -extern const struct devlink_gen_cmd devl_gen_rate_get; - struct devlink_rate * devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info); struct devlink_rate * diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 92210587d349..056d9ca14a3d 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1236,7 +1236,7 @@ devlink_nl_cmd_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink, return err; } -const struct devlink_gen_cmd devl_gen_rate_get = { +const struct devlink_cmd devl_cmd_rate_get = { .dump_one = devlink_nl_cmd_rate_get_dump_one, }; @@ -1303,7 +1303,7 @@ devlink_nl_cmd_get_dump_one(struct sk_buff *msg, struct devlink *devlink, cb->nlh->nlmsg_seq, NLM_F_MULTI); } -const struct devlink_gen_cmd devl_gen_inst = { +const struct devlink_cmd devl_cmd_get = { .dump_one = devlink_nl_cmd_get_dump_one, }; @@ -1359,7 +1359,7 @@ devlink_nl_cmd_port_get_dump_one(struct sk_buff *msg, struct devlink *devlink, return err; } -const struct devlink_gen_cmd devl_gen_port = { +const struct devlink_cmd devl_cmd_port_get = { .dump_one = devlink_nl_cmd_port_get_dump_one, }; @@ -2137,7 +2137,7 @@ static int devlink_nl_cmd_linecard_get_dump_one(struct sk_buff *msg, return err; } -const struct devlink_gen_cmd devl_gen_linecard = { +const struct devlink_cmd devl_cmd_linecard_get = { .dump_one = devlink_nl_cmd_linecard_get_dump_one, }; @@ -2392,7 +2392,7 @@ devlink_nl_cmd_sb_get_dump_one(struct sk_buff *msg, struct devlink *devlink, return err; } -const struct devlink_gen_cmd devl_gen_sb = { +const struct devlink_cmd devl_cmd_sb_get = { .dump_one = devlink_nl_cmd_sb_get_dump_one, }; @@ -2530,7 +2530,7 @@ devlink_nl_cmd_sb_pool_get_dump_one(struct sk_buff *msg, return err; } -const struct devlink_gen_cmd devl_gen_sb_pool = { +const struct devlink_cmd devl_cmd_sb_pool_get = { .dump_one = devlink_nl_cmd_sb_pool_get_dump_one, }; @@ -2738,7 +2738,7 @@ devlink_nl_cmd_sb_port_pool_get_dump_one(struct sk_buff *msg, return err; } -const struct devlink_gen_cmd devl_gen_sb_port_pool = { +const struct devlink_cmd devl_cmd_sb_port_pool_get = { .dump_one = devlink_nl_cmd_sb_port_pool_get_dump_one, }; @@ -2973,7 +2973,7 @@ devlink_nl_cmd_sb_tc_pool_bind_get_dump_one(struct sk_buff *msg, return err; } -const struct devlink_gen_cmd devl_gen_sb_tc_pool_bind = { +const struct devlink_cmd devl_cmd_sb_tc_pool_bind_get = { .dump_one = devlink_nl_cmd_sb_tc_pool_bind_get_dump_one, }; @@ -4785,7 +4785,7 @@ devlink_nl_cmd_selftests_get_dump_one(struct sk_buff *msg, cb->extack); } -const struct devlink_gen_cmd devl_gen_selftests = { +const struct devlink_cmd devl_cmd_selftests_get = { .dump_one = devlink_nl_cmd_selftests_get_dump_one, }; @@ -5271,7 +5271,7 @@ devlink_nl_cmd_param_get_dump_one(struct sk_buff *msg, struct devlink *devlink, return err; } -const struct devlink_gen_cmd devl_gen_param = { +const struct devlink_cmd devl_cmd_param_get = { .dump_one = devlink_nl_cmd_param_get_dump_one, }; @@ -5978,7 +5978,7 @@ devlink_nl_cmd_region_get_dump_one(struct sk_buff *msg, struct devlink *devlink, return 0; } -const struct devlink_gen_cmd devl_gen_region = { +const struct devlink_cmd devl_cmd_region_get = { .dump_one = devlink_nl_cmd_region_get_dump_one, }; @@ -6625,7 +6625,7 @@ devlink_nl_cmd_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink, return err; } -const struct devlink_gen_cmd devl_gen_info = { +const struct devlink_cmd devl_cmd_info_get = { .dump_one = devlink_nl_cmd_info_get_dump_one, }; @@ -7793,7 +7793,7 @@ devlink_nl_cmd_health_reporter_get_dump_one(struct sk_buff *msg, return 0; } -const struct devlink_gen_cmd devl_gen_health_reporter = { +const struct devlink_cmd devl_cmd_health_reporter_get = { .dump_one = devlink_nl_cmd_health_reporter_get_dump_one, }; @@ -8311,7 +8311,7 @@ devlink_nl_cmd_trap_get_dump_one(struct sk_buff *msg, struct devlink *devlink, return err; } -const struct devlink_gen_cmd devl_gen_trap = { +const struct devlink_cmd devl_cmd_trap_get = { .dump_one = devlink_nl_cmd_trap_get_dump_one, }; @@ -8524,7 +8524,7 @@ devlink_nl_cmd_trap_group_get_dump_one(struct sk_buff *msg, return err; } -const struct devlink_gen_cmd devl_gen_trap_group = { +const struct devlink_cmd devl_cmd_trap_group_get = { .dump_one = devlink_nl_cmd_trap_group_get_dump_one, }; @@ -8817,7 +8817,7 @@ devlink_nl_cmd_trap_policer_get_dump_one(struct sk_buff *msg, return err; } -const struct devlink_gen_cmd devl_gen_trap_policer = { +const struct devlink_cmd devl_cmd_trap_policer_get = { .dump_one = devlink_nl_cmd_trap_policer_get_dump_one, }; @@ -8898,14 +8898,14 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { .cmd = DEVLINK_CMD_PORT_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_port_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, /* can be retrieved by unprivileged users */ }, @@ -8919,7 +8919,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { { .cmd = DEVLINK_CMD_RATE_GET, .doit = devlink_nl_cmd_rate_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, .internal_flags = DEVLINK_NL_FLAG_NEED_RATE, /* can be retrieved by unprivileged users */ }, @@ -8967,7 +8967,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { { .cmd = DEVLINK_CMD_LINECARD_GET, .doit = devlink_nl_cmd_linecard_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD, /* can be retrieved by unprivileged users */ }, @@ -8981,14 +8981,14 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_SB_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_sb_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { .cmd = DEVLINK_CMD_SB_POOL_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_sb_pool_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { @@ -9001,7 +9001,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_SB_PORT_POOL_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_sb_port_pool_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, /* can be retrieved by unprivileged users */ }, @@ -9016,7 +9016,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, /* can be retrieved by unprivileged users */ }, @@ -9097,7 +9097,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_PARAM_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_param_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { @@ -9125,7 +9125,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_REGION_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_region_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, .flags = GENL_ADMIN_PERM, }, { @@ -9151,14 +9151,14 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_INFO_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_info_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = devlink_nl_cmd_health_reporter_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT, /* can be retrieved by unprivileged users */ }, @@ -9213,7 +9213,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { { .cmd = DEVLINK_CMD_TRAP_GET, .doit = devlink_nl_cmd_trap_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { @@ -9224,7 +9224,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { { .cmd = DEVLINK_CMD_TRAP_GROUP_GET, .doit = devlink_nl_cmd_trap_group_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { @@ -9235,7 +9235,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { { .cmd = DEVLINK_CMD_TRAP_POLICER_GET, .doit = devlink_nl_cmd_trap_policer_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { @@ -9246,7 +9246,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { { .cmd = DEVLINK_CMD_SELFTESTS_GET, .doit = devlink_nl_cmd_selftests_get_doit, - .dumpit = devlink_nl_instance_iter_dump, + .dumpit = devlink_nl_instance_iter_dumpit, /* can be retrieved by unprivileged users */ }, { diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c index 3f44633af01c..7a332eb70f70 100644 --- a/net/devlink/netlink.c +++ b/net/devlink/netlink.c @@ -177,35 +177,35 @@ static void devlink_nl_post_doit(const struct genl_split_ops *ops, devlink_put(devlink); } -static const struct devlink_gen_cmd *devl_gen_cmds[] = { - [DEVLINK_CMD_GET] = &devl_gen_inst, - [DEVLINK_CMD_PORT_GET] = &devl_gen_port, - [DEVLINK_CMD_SB_GET] = &devl_gen_sb, - [DEVLINK_CMD_SB_POOL_GET] = &devl_gen_sb_pool, - [DEVLINK_CMD_SB_PORT_POOL_GET] = &devl_gen_sb_port_pool, - [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = &devl_gen_sb_tc_pool_bind, - [DEVLINK_CMD_PARAM_GET] = &devl_gen_param, - [DEVLINK_CMD_REGION_GET] = &devl_gen_region, - [DEVLINK_CMD_INFO_GET] = &devl_gen_info, - [DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_gen_health_reporter, - [DEVLINK_CMD_RATE_GET] = &devl_gen_rate_get, - [DEVLINK_CMD_TRAP_GET] = &devl_gen_trap, - [DEVLINK_CMD_TRAP_GROUP_GET] = &devl_gen_trap_group, - [DEVLINK_CMD_TRAP_POLICER_GET] = &devl_gen_trap_policer, - [DEVLINK_CMD_LINECARD_GET] = &devl_gen_linecard, - [DEVLINK_CMD_SELFTESTS_GET] = &devl_gen_selftests, +static const struct devlink_cmd *devl_cmds[] = { + [DEVLINK_CMD_GET] = &devl_cmd_get, + [DEVLINK_CMD_PORT_GET] = &devl_cmd_port_get, + [DEVLINK_CMD_SB_GET] = &devl_cmd_sb_get, + [DEVLINK_CMD_SB_POOL_GET] = &devl_cmd_sb_pool_get, + [DEVLINK_CMD_SB_PORT_POOL_GET] = &devl_cmd_sb_port_pool_get, + [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = &devl_cmd_sb_tc_pool_bind_get, + [DEVLINK_CMD_PARAM_GET] = &devl_cmd_param_get, + [DEVLINK_CMD_REGION_GET] = &devl_cmd_region_get, + [DEVLINK_CMD_INFO_GET] = &devl_cmd_info_get, + [DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_cmd_health_reporter_get, + [DEVLINK_CMD_TRAP_GET] = &devl_cmd_trap_get, + [DEVLINK_CMD_TRAP_GROUP_GET] = &devl_cmd_trap_group_get, + [DEVLINK_CMD_TRAP_POLICER_GET] = &devl_cmd_trap_policer_get, + [DEVLINK_CMD_RATE_GET] = &devl_cmd_rate_get, + [DEVLINK_CMD_LINECARD_GET] = &devl_cmd_linecard_get, + [DEVLINK_CMD_SELFTESTS_GET] = &devl_cmd_selftests_get, }; -int devlink_nl_instance_iter_dump(struct sk_buff *msg, - struct netlink_callback *cb) +int devlink_nl_instance_iter_dumpit(struct sk_buff *msg, + struct netlink_callback *cb) { const struct genl_dumpit_info *info = genl_dumpit_info(cb); struct devlink_nl_dump_state *state = devlink_dump_state(cb); - const struct devlink_gen_cmd *cmd; + const struct devlink_cmd *cmd; struct devlink *devlink; int err = 0; - cmd = devl_gen_cmds[info->op.cmd]; + cmd = devl_cmds[info->op.cmd]; while ((devlink = devlinks_xa_find_get(sock_net(msg->sk), &state->instance))) { diff --git a/net/dsa/master.c b/net/dsa/master.c index 26d90140d271..1507b8cdb360 100644 --- a/net/dsa/master.c +++ b/net/dsa/master.c @@ -464,9 +464,7 @@ int dsa_master_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp, err = dsa_port_lag_join(cpu_dp, lag_dev, uinfo, extack); if (err) { - if (extack && !extack->_msg) - NL_SET_ERR_MSG_MOD(extack, - "CPU port failed to join LAG"); + NL_SET_ERR_MSG_WEAK_MOD(extack, "CPU port failed to join LAG"); goto out_master_teardown; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 6014ac3aad34..26c458f50ac6 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2692,9 +2692,7 @@ static int dsa_slave_changeupper(struct net_device *dev, if (!err) dsa_bridge_mtu_normalization(dp); if (err == -EOPNOTSUPP) { - if (extack && !extack->_msg) - NL_SET_ERR_MSG_MOD(extack, - "Offloading not supported"); + NL_SET_ERR_MSG_WEAK_MOD(extack, "Offloading not supported"); err = 0; } err = notifier_from_errno(err); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 6c0ec2789943..2f992a323b95 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1485,6 +1485,7 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb) if (unlikely(ip_fast_csum((u8 *)iph, 5))) goto out; + NAPI_GRO_CB(skb)->proto = proto; id = ntohl(*(__be32 *)&iph->id); flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF)); id >>= 16; @@ -1618,9 +1619,9 @@ int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) int inet_gro_complete(struct sk_buff *skb, int nhoff) { - __be16 newlen = htons(skb->len - nhoff); struct iphdr *iph = (struct iphdr *)(skb->data + nhoff); const struct net_offload *ops; + __be16 totlen = iph->tot_len; int proto = iph->protocol; int err = -ENOSYS; @@ -1629,8 +1630,8 @@ int inet_gro_complete(struct sk_buff *skb, int nhoff) skb_set_inner_network_header(skb, nhoff); } - csum_replace2(&iph->check, iph->tot_len, newlen); - iph->tot_len = newlen; + iph_set_totlen(iph, skb->len - nhoff); + csum_replace2(&iph->check, totlen, iph->tot_len); ops = rcu_dereference(inet_offloads[proto]); if (WARN_ON(!ops || !ops->callbacks.gro_complete)) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 6cd3b6c559f0..79ae7204e8ed 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -2222,7 +2222,7 @@ int cipso_v4_skbuff_setattr(struct sk_buff *skb, memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len); if (len_delta != 0) { iph->ihl = 5 + (opt_len >> 2); - iph->tot_len = htons(skb->len); + iph_set_totlen(iph, skb->len); } ip_send_check(iph); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index e880ce77322a..fe9ead9ee863 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -511,7 +511,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) goto csum_error; - len = ntohs(iph->tot_len); + len = iph_totlen(skb, iph); if (skb->len < len) { drop_reason = SKB_DROP_REASON_PKT_TOO_SMALL; __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 922c87ef1ab5..4e4e308c3230 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -100,7 +100,7 @@ int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) { struct iphdr *iph = ip_hdr(skb); - iph->tot_len = htons(skb->len); + iph_set_totlen(iph, skb->len); ip_send_check(iph); /* if egress device is enslaved to an L3 master device pass the diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 79c769c0d113..c9346515e24d 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -332,7 +332,6 @@ static void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt { struct ipv6hdr *iph = ipv6_hdr(skb); struct ipv6_destopt_hao *hao; - struct in6_addr tmp; int off; if (opt->dsthao) { @@ -340,9 +339,7 @@ static void mip6_addr_swap(struct sk_buff *skb, const struct inet6_skb_parm *opt if (likely(off >= 0)) { hao = (struct ipv6_destopt_hao *) (skb_network_header(skb) + off); - tmp = iph->saddr; - iph->saddr = hao->addr; - hao->addr = tmp; + swap(iph->saddr, hao->addr); } } } diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 029171379884..80448885c3d7 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -994,7 +994,7 @@ ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af, old_dsfield = ipv4_get_dsfield(old_iph); *ttl = old_iph->ttl; if (payload_len) - *payload_len = ntohs(old_iph->tot_len); + *payload_len = skb_ip_totlen(skb); } /* Implement full-functionality option for ECN encapsulation */ diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c index cb894f0d63e9..c66689ad2b49 100644 --- a/net/netfilter/nf_log_syslog.c +++ b/net/netfilter/nf_log_syslog.c @@ -322,7 +322,7 @@ dump_ipv4_packet(struct net *net, struct nf_log_buf *m, /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", - ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, + iph_totlen(skb, ih), ih->tos & IPTOS_TOS_MASK, ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); /* Max length: 6 "CE DF MF " */ diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c index 1873da3a945a..b3d623a52885 100644 --- a/net/netfilter/xt_length.c +++ b/net/netfilter/xt_length.c @@ -21,7 +21,7 @@ static bool length_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_length_info *info = par->matchinfo; - u_int16_t pktlen = ntohs(ip_hdr(skb)->tot_len); + u32 pktlen = skb_ip_totlen(skb); return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; } diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index c8b137649ca4..2172930b1f17 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -1103,7 +1103,7 @@ static int ovs_skb_network_trim(struct sk_buff *skb) switch (skb->protocol) { case htons(ETH_P_IP): - len = ntohs(ip_hdr(skb)->tot_len); + len = skb_ip_totlen(skb); break; case htons(ETH_P_IPV6): len = sizeof(struct ipv6hdr) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index b5ab98ca2511..8ffb19c643ab 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2296,6 +2296,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, else if (skb->pkt_type != PACKET_OUTGOING && skb_csum_unnecessary(skb)) status |= TP_STATUS_CSUM_VALID; + if (skb_is_gso(skb) && skb_is_gso_tcp(skb)) + status |= TP_STATUS_GSO_TCP; if (snaplen > res) snaplen = res; @@ -3522,6 +3524,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, else if (skb->pkt_type != PACKET_OUTGOING && skb_csum_unnecessary(skb)) aux.tp_status |= TP_STATUS_CSUM_VALID; + if (skb_is_gso(skb) && skb_is_gso_tcp(skb)) + aux.tp_status |= TP_STATUS_GSO_TCP; aux.tp_len = origlen; aux.tp_snaplen = skb->len; diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index 0ca2bb8ed026..d68bb5dbf0dc 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -707,7 +707,7 @@ static int tcf_ct_skb_network_trim(struct sk_buff *skb, int family) switch (family) { case NFPROTO_IPV4: - len = ntohs(ip_hdr(skb)->tot_len); + len = skb_ip_totlen(skb); break; case NFPROTO_IPV6: len = sizeof(struct ipv6hdr) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 3ed0c3342189..7970217b565a 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1209,7 +1209,7 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q, iph_check->daddr != iph->daddr) continue; - seglen = ntohs(iph_check->tot_len) - + seglen = iph_totlen(skb, iph_check) - (4 * iph_check->ihl); } else if (iph_check->version == 6) { ipv6h = (struct ipv6hdr *)iph; diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 562b9d951598..95f1436bf6a2 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -325,8 +325,10 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, * authors to do not return -EOPNOTSUPP in packet offload mode. */ WARN_ON(err == -EOPNOTSUPP && is_packet_offload); - if (err != -EOPNOTSUPP || is_packet_offload) + if (err != -EOPNOTSUPP || is_packet_offload) { + NL_SET_ERR_MSG_WEAK(extack, "Device failed to offload this state"); return err; + } } return 0; @@ -388,6 +390,7 @@ int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp, xdo->type = XFRM_DEV_OFFLOAD_UNSPECIFIED; xdo->dir = 0; netdev_put(dev, &xdo->dev_tracker); + NL_SET_ERR_MSG_WEAK(extack, "Device failed to offload this policy"); return err; } diff --git a/tools/net/ynl/samples/cli.py b/tools/net/ynl/cli.py index b27159c70710..db410b74d539 100755 --- a/tools/net/ynl/samples/cli.py +++ b/tools/net/ynl/cli.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # SPDX-License-Identifier: BSD-3-Clause import argparse @@ -6,13 +6,14 @@ import json import pprint import time -from ynl import YnlFamily +from lib import YnlFamily def main(): parser = argparse.ArgumentParser(description='YNL CLI sample') parser.add_argument('--spec', dest='spec', type=str, required=True) parser.add_argument('--schema', dest='schema', type=str) + parser.add_argument('--no-schema', action='store_true') parser.add_argument('--json', dest='json_text', type=str) parser.add_argument('--do', dest='do', type=str) parser.add_argument('--dump', dest='dump', type=str) @@ -20,6 +21,9 @@ def main(): parser.add_argument('--subscribe', dest='ntf', type=str) args = parser.parse_args() + if args.no_schema: + args.schema = '' + attrs = {} if args.json_text: attrs = json.loads(args.json_text) @@ -32,10 +36,11 @@ def main(): if args.sleep: time.sleep(args.sleep) - if args.do or args.dump: - method = getattr(ynl, args.do if args.do else args.dump) - - reply = method(attrs, dump=bool(args.dump)) + if args.do: + reply = ynl.do(args.do, attrs) + pprint.PrettyPrinter().pprint(reply) + if args.dump: + reply = ynl.dump(args.dump, attrs) pprint.PrettyPrinter().pprint(reply) if args.ntf: diff --git a/tools/net/ynl/lib/__init__.py b/tools/net/ynl/lib/__init__.py new file mode 100644 index 000000000000..3c73f59eabab --- /dev/null +++ b/tools/net/ynl/lib/__init__.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause + +from .nlspec import SpecAttr, SpecAttrSet, SpecFamily, SpecOperation +from .ynl import YnlFamily + +__all__ = ["SpecAttr", "SpecAttrSet", "SpecFamily", "SpecOperation", + "YnlFamily"] diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py new file mode 100644 index 000000000000..e204679ad8b7 --- /dev/null +++ b/tools/net/ynl/lib/nlspec.py @@ -0,0 +1,310 @@ +# SPDX-License-Identifier: BSD-3-Clause + +import collections +import importlib +import os +import traceback +import yaml + + +# To be loaded dynamically as needed +jsonschema = None + + +class SpecElement: + """Netlink spec element. + + Abstract element of the Netlink spec. Implements the dictionary interface + for access to the raw spec. Supports iterative resolution of dependencies + across elements and class inheritance levels. The elements of the spec + may refer to each other, and although loops should be very rare, having + to maintain correct ordering of instantiation is painful, so the resolve() + method should be used to perform parts of init which require access to + other parts of the spec. + + Attributes: + yaml raw spec as loaded from the spec file + family back reference to the full family + + name name of the entity as listed in the spec (optional) + ident_name name which can be safely used as identifier in code (optional) + """ + def __init__(self, family, yaml): + self.yaml = yaml + self.family = family + + if 'name' in self.yaml: + self.name = self.yaml['name'] + self.ident_name = self.name.replace('-', '_') + + self._super_resolved = False + family.add_unresolved(self) + + def __getitem__(self, key): + return self.yaml[key] + + def __contains__(self, key): + return key in self.yaml + + def get(self, key, default=None): + return self.yaml.get(key, default) + + def resolve_up(self, up): + if not self._super_resolved: + up.resolve() + self._super_resolved = True + + def resolve(self): + pass + + +class SpecAttr(SpecElement): + """ Single Netlink atttribute type + + Represents a single attribute type within an attr space. + + Attributes: + value numerical ID when serialized + attr_set Attribute Set containing this attr + """ + def __init__(self, family, attr_set, yaml, value): + super().__init__(family, yaml) + + self.value = value + self.attr_set = attr_set + self.is_multi = yaml.get('multi-attr', False) + + +class SpecAttrSet(SpecElement): + """ Netlink Attribute Set class. + + Represents a ID space of attributes within Netlink. + + Note that unlike other elements, which expose contents of the raw spec + via the dictionary interface Attribute Set exposes attributes by name. + + Attributes: + attrs ordered dict of all attributes (indexed by name) + attrs_by_val ordered dict of all attributes (indexed by value) + subset_of parent set if this is a subset, otherwise None + """ + def __init__(self, family, yaml): + super().__init__(family, yaml) + + self.subset_of = self.yaml.get('subset-of', None) + + self.attrs = collections.OrderedDict() + self.attrs_by_val = collections.OrderedDict() + + val = 0 + for elem in self.yaml['attributes']: + if 'value' in elem: + val = elem['value'] + + attr = self.new_attr(elem, val) + self.attrs[attr.name] = attr + self.attrs_by_val[attr.value] = attr + val += 1 + + def new_attr(self, elem, value): + return SpecAttr(self.family, self, elem, value) + + def __getitem__(self, key): + return self.attrs[key] + + def __contains__(self, key): + return key in self.attrs + + def __iter__(self): + yield from self.attrs + + def items(self): + return self.attrs.items() + + +class SpecOperation(SpecElement): + """Netlink Operation + + Information about a single Netlink operation. + + Attributes: + value numerical ID when serialized, None if req/rsp values differ + + req_value numerical ID when serialized, user -> kernel + rsp_value numerical ID when serialized, user <- kernel + is_call bool, whether the operation is a call + is_async bool, whether the operation is a notification + is_resv bool, whether the operation does not exist (it's just a reserved ID) + attr_set attribute set name + + yaml raw spec as loaded from the spec file + """ + def __init__(self, family, yaml, req_value, rsp_value): + super().__init__(family, yaml) + + self.value = req_value if req_value == rsp_value else None + self.req_value = req_value + self.rsp_value = rsp_value + + self.is_call = 'do' in yaml or 'dump' in yaml + self.is_async = 'notify' in yaml or 'event' in yaml + self.is_resv = not self.is_async and not self.is_call + + # Added by resolve: + self.attr_set = None + delattr(self, "attr_set") + + def resolve(self): + self.resolve_up(super()) + + if 'attribute-set' in self.yaml: + attr_set_name = self.yaml['attribute-set'] + elif 'notify' in self.yaml: + msg = self.family.msgs[self.yaml['notify']] + attr_set_name = msg['attribute-set'] + elif self.is_resv: + attr_set_name = '' + else: + raise Exception(f"Can't resolve attribute set for op '{self.name}'") + if attr_set_name: + self.attr_set = self.family.attr_sets[attr_set_name] + + +class SpecFamily(SpecElement): + """ Netlink Family Spec class. + + Netlink family information loaded from a spec (e.g. in YAML). + Takes care of unfolding implicit information which can be skipped + in the spec itself for brevity. + + The class can be used like a dictionary to access the raw spec + elements but that's usually a bad idea. + + Attributes: + proto protocol type (e.g. genetlink) + + attr_sets dict of attribute sets + msgs dict of all messages (index by name) + msgs_by_value dict of all messages (indexed by name) + ops dict of all valid requests / responses + """ + def __init__(self, spec_path, schema_path=None): + with open(spec_path, "r") as stream: + spec = yaml.safe_load(stream) + + self._resolution_list = [] + + super().__init__(self, spec) + + self.proto = self.yaml.get('protocol', 'genetlink') + + if schema_path is None: + schema_path = os.path.dirname(os.path.dirname(spec_path)) + f'/{self.proto}.yaml' + if schema_path: + global jsonschema + + with open(schema_path, "r") as stream: + schema = yaml.safe_load(stream) + + if jsonschema is None: + jsonschema = importlib.import_module("jsonschema") + + jsonschema.validate(self.yaml, schema) + + self.attr_sets = collections.OrderedDict() + self.msgs = collections.OrderedDict() + self.req_by_value = collections.OrderedDict() + self.rsp_by_value = collections.OrderedDict() + self.ops = collections.OrderedDict() + + last_exception = None + while len(self._resolution_list) > 0: + resolved = [] + unresolved = self._resolution_list + self._resolution_list = [] + + for elem in unresolved: + try: + elem.resolve() + except (KeyError, AttributeError) as e: + self._resolution_list.append(elem) + last_exception = e + continue + + resolved.append(elem) + + if len(resolved) == 0: + traceback.print_exception(last_exception) + raise Exception("Could not resolve any spec element, infinite loop?") + + def new_attr_set(self, elem): + return SpecAttrSet(self, elem) + + def new_operation(self, elem, req_val, rsp_val): + return SpecOperation(self, elem, req_val, rsp_val) + + def add_unresolved(self, elem): + self._resolution_list.append(elem) + + def _dictify_ops_unified(self): + val = 0 + for elem in self.yaml['operations']['list']: + if 'value' in elem: + val = elem['value'] + + op = self.new_operation(elem, val, val) + val += 1 + + self.msgs[op.name] = op + + def _dictify_ops_directional(self): + req_val = rsp_val = 0 + for elem in self.yaml['operations']['list']: + if 'notify' in elem: + if 'value' in elem: + rsp_val = elem['value'] + req_val_next = req_val + rsp_val_next = rsp_val + 1 + req_val = None + elif 'do' in elem or 'dump' in elem: + mode = elem['do'] if 'do' in elem else elem['dump'] + + v = mode.get('request', {}).get('value', None) + if v: + req_val = v + v = mode.get('reply', {}).get('value', None) + if v: + rsp_val = v + + rsp_inc = 1 if 'reply' in mode else 0 + req_val_next = req_val + 1 + rsp_val_next = rsp_val + rsp_inc + else: + raise Exception("Can't parse directional ops") + + op = self.new_operation(elem, req_val, rsp_val) + req_val = req_val_next + rsp_val = rsp_val_next + + self.msgs[op.name] = op + + def resolve(self): + self.resolve_up(super()) + + for elem in self.yaml['attribute-sets']: + attr_set = self.new_attr_set(elem) + self.attr_sets[elem['name']] = attr_set + + msg_id_model = self.yaml['operations'].get('enum-model', 'unified') + if msg_id_model == 'unified': + self._dictify_ops_unified() + elif msg_id_model == 'directional': + self._dictify_ops_directional() + + for op in self.msgs.values(): + if op.req_value is not None: + self.req_by_value[op.req_value] = op + if op.rsp_value is not None: + self.rsp_by_value[op.rsp_value] = op + if not op.is_async and 'attribute-set' in op: + self.ops[op.name] = op diff --git a/tools/net/ynl/samples/ynl.py b/tools/net/ynl/lib/ynl.py index b71523d71d46..1c7411ee04dc 100644 --- a/tools/net/ynl/samples/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -1,13 +1,14 @@ # SPDX-License-Identifier: BSD-3-Clause import functools -import jsonschema import os import random import socket import struct import yaml +from .nlspec import SpecFamily + # # Generic Netlink code which should really be in some library, but I can't quickly find one. # @@ -74,6 +75,9 @@ class NlAttr: self.full_len = (self.payload_len + 3) & ~3 self.raw = raw[offset + 4:offset + self.payload_len] + def as_u8(self): + return struct.unpack("B", self.raw)[0] + def as_u16(self): return struct.unpack("H", self.raw)[0] @@ -158,8 +162,8 @@ class NlMsg: # We don't have the ability to parse nests yet, so only do global if 'miss-type' in self.extack and 'miss-nest' not in self.extack: miss_type = self.extack['miss-type'] - if len(attr_space.attr_list) > miss_type: - spec = attr_space.attr_list[miss_type] + if miss_type in attr_space.attrs_by_val: + spec = attr_space.attrs_by_val[miss_type] desc = spec['name'] if 'doc' in spec: desc += f" ({spec['doc']})" @@ -289,100 +293,31 @@ class GenlFamily: # -class YnlAttrSpace: - def __init__(self, family, yaml): - self.yaml = yaml - - self.attrs = dict() - self.name = self.yaml['name'] - self.subspace_of = self.yaml['subset-of'] if 'subspace-of' in self.yaml else None - - val = 0 - max_val = 0 - for elem in self.yaml['attributes']: - if 'value' in elem: - val = elem['value'] - else: - elem['value'] = val - if val > max_val: - max_val = val - val += 1 - - self.attrs[elem['name']] = elem - - self.attr_list = [None] * (max_val + 1) - for elem in self.yaml['attributes']: - self.attr_list[elem['value']] = elem - - def __getitem__(self, key): - return self.attrs[key] - - def __contains__(self, key): - return key in self.yaml - - def __iter__(self): - yield from self.attrs - - def items(self): - return self.attrs.items() - - -class YnlFamily: +class YnlFamily(SpecFamily): def __init__(self, def_path, schema=None): - self.include_raw = False + super().__init__(def_path, schema) - with open(def_path, "r") as stream: - self.yaml = yaml.safe_load(stream) - - if schema: - with open(schema, "r") as stream: - schema = yaml.safe_load(stream) - - jsonschema.validate(self.yaml, schema) + self.include_raw = False self.sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, Netlink.NETLINK_GENERIC) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_EXT_ACK, 1) - self._ops = dict() - self._spaces = dict() self._types = dict() - for elem in self.yaml['attribute-sets']: - self._spaces[elem['name']] = YnlAttrSpace(self, elem) - - for elem in self.yaml['definitions']: + for elem in self.yaml.get('definitions', []): self._types[elem['name']] = elem - async_separation = 'async-prefix' in self.yaml['operations'] self.async_msg_ids = set() self.async_msg_queue = [] - val = 0 - max_val = 0 - for elem in self.yaml['operations']['list']: - if not (async_separation and ('notify' in elem or 'event' in elem)): - if 'value' in elem: - val = elem['value'] - else: - elem['value'] = val - val += 1 - max_val = max(val, max_val) - - if 'notify' in elem or 'event' in elem: - self.async_msg_ids.add(elem['value']) - - self._ops[elem['name']] = elem - - op_name = elem['name'].replace('-', '_') - bound_f = functools.partial(self._op, elem['name']) - setattr(self, op_name, bound_f) + for msg in self.msgs.values(): + if msg.is_async: + self.async_msg_ids.add(msg.rsp_value) - self._op_array = [None] * max_val - for _, op in self._ops.items(): - self._op_array[op['value']] = op - if 'notify' in op: - op['attribute-set'] = self._ops[op['notify']]['attribute-set'] + for op_name, op in self.ops.items(): + bound_f = functools.partial(self._op, op_name) + setattr(self, op.ident_name, bound_f) self.family = GenlFamily(self.yaml['name']) @@ -395,13 +330,15 @@ class YnlFamily: self.family.genl_family['mcast'][mcast_name]) def _add_attr(self, space, name, value): - attr = self._spaces[space][name] - nl_type = attr['value'] + attr = self.attr_sets[space][name] + nl_type = attr.value if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED attr_payload = b'' for subname, subvalue in value.items(): attr_payload += self._add_attr(attr['nested-attributes'], subname, subvalue) + elif attr["type"] == 'flag': + attr_payload = b'' elif attr["type"] == 'u32': attr_payload = struct.pack("I", int(value)) elif attr["type"] == 'string': @@ -430,36 +367,81 @@ class YnlFamily: rsp[attr_spec['name']] = value def _decode(self, attrs, space): - attr_space = self._spaces[space] + attr_space = self.attr_sets[space] rsp = dict() for attr in attrs: - attr_spec = attr_space.attr_list[attr.type] + attr_spec = attr_space.attrs_by_val[attr.type] if attr_spec["type"] == 'nest': subdict = self._decode(NlAttrs(attr.raw), attr_spec['nested-attributes']) - rsp[attr_spec['name']] = subdict + decoded = subdict + elif attr_spec['type'] == 'u8': + decoded = attr.as_u8() elif attr_spec['type'] == 'u32': - rsp[attr_spec['name']] = attr.as_u32() + decoded = attr.as_u32() elif attr_spec['type'] == 'u64': - rsp[attr_spec['name']] = attr.as_u64() + decoded = attr.as_u64() elif attr_spec["type"] == 'string': - rsp[attr_spec['name']] = attr.as_strz() + decoded = attr.as_strz() elif attr_spec["type"] == 'binary': - rsp[attr_spec['name']] = attr.as_bin() + decoded = attr.as_bin() + elif attr_spec["type"] == 'flag': + decoded = True else: raise Exception(f'Unknown {attr.type} {attr_spec["name"]} {attr_spec["type"]}') + if not attr_spec.is_multi: + rsp[attr_spec['name']] = decoded + elif attr_spec.name in rsp: + rsp[attr_spec.name].append(decoded) + else: + rsp[attr_spec.name] = [decoded] + if 'enum' in attr_spec: self._decode_enum(rsp, attr_spec) return rsp + def _decode_extack_path(self, attrs, attr_set, offset, target): + for attr in attrs: + attr_spec = attr_set.attrs_by_val[attr.type] + if offset > target: + break + if offset == target: + return '.' + attr_spec.name + + if offset + attr.full_len <= target: + offset += attr.full_len + continue + if attr_spec['type'] != 'nest': + raise Exception(f"Can't dive into {attr.type} ({attr_spec['name']}) for extack") + offset += 4 + subpath = self._decode_extack_path(NlAttrs(attr.raw), + self.attr_sets[attr_spec['nested-attributes']], + offset, target) + if subpath is None: + return None + return '.' + attr_spec.name + subpath + + return None + + def _decode_extack(self, request, attr_space, extack): + if 'bad-attr-offs' not in extack: + return + + genl_req = GenlMsg(NlMsg(request, 0, attr_space=attr_space)) + path = self._decode_extack_path(genl_req.raw_attrs, attr_space, + 20, extack['bad-attr-offs']) + if path: + del extack['bad-attr-offs'] + extack['bad-attr'] = path + def handle_ntf(self, nl_msg, genl_msg): msg = dict() if self.include_raw: msg['nlmsg'] = nl_msg msg['genlmsg'] = genl_msg - op = self._op_array[genl_msg.genl_cmd] + op = self.rsp_by_value[genl_msg.genl_cmd] msg['name'] = op['name'] - msg['msg'] = self._decode(genl_msg.raw_attrs, op['attribute-set']) + msg['msg'] = self._decode(genl_msg.raw_attrs, op.attr_set.name) self.async_msg_queue.append(msg) def check_ntf(self): @@ -487,16 +469,16 @@ class YnlFamily: self.handle_ntf(nl_msg, gm) def _op(self, method, vals, dump=False): - op = self._ops[method] + op = self.ops[method] nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK if dump: nl_flags |= Netlink.NLM_F_DUMP req_seq = random.randint(1024, 65535) - msg = _genl_msg(self.family.family_id, nl_flags, op['value'], 1, req_seq) + msg = _genl_msg(self.family.family_id, nl_flags, op.req_value, 1, req_seq) for name, value in vals.items(): - msg += self._add_attr(op['attribute-set'], name, value) + msg += self._add_attr(op.attr_set.name, name, value) msg = _genl_msg_finalize(msg) self.sock.send(msg, 0) @@ -505,19 +487,25 @@ class YnlFamily: rsp = [] while not done: reply = self.sock.recv(128 * 1024) - nms = NlMsgs(reply, attr_space=self._spaces[op['attribute-set']]) + nms = NlMsgs(reply, attr_space=op.attr_set) for nl_msg in nms: + if nl_msg.extack: + self._decode_extack(msg, op.attr_set, nl_msg.extack) + if nl_msg.error: print("Netlink error:", os.strerror(-nl_msg.error)) print(nl_msg) return if nl_msg.done: + if nl_msg.extack: + print("Netlink warning:") + print(nl_msg) done = True break gm = GenlMsg(nl_msg) # Check if this is a reply to our request - if nl_msg.nl_seq != req_seq or gm.genl_cmd != op['value']: + if nl_msg.nl_seq != req_seq or gm.genl_cmd != op.rsp_value: if gm.genl_cmd in self.async_msg_ids: self.handle_ntf(nl_msg, gm) continue @@ -525,10 +513,16 @@ class YnlFamily: print('Unexpected message: ' + repr(gm)) continue - rsp.append(self._decode(gm.raw_attrs, op['attribute-set'])) + rsp.append(self._decode(gm.raw_attrs, op.attr_set.name)) if not rsp: return None if not dump and len(rsp) == 1: return rsp[0] return rsp + + def do(self, method, vals): + return self._op(method, vals) + + def dump(self, method, vals): + return self._op(method, vals, dump=True) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 1aa872e582ab..3942f24b9163 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1,11 +1,12 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import argparse import collections -import jsonschema import os import yaml +from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation + def c_upper(name): return name.upper().replace('-', '_') @@ -28,12 +29,12 @@ class BaseNlLib: "ynl_cb_array, NLMSG_MIN_TYPE)" -class Type: - def __init__(self, family, attr_set, attr): - self.family = family +class Type(SpecAttr): + def __init__(self, family, attr_set, attr, value): + super().__init__(family, attr_set, attr, value) + self.attr = attr - self.value = attr['value'] - self.name = c_lower(attr['name']) + self.attr_set = attr_set self.type = attr['type'] self.checks = attr.get('checks', {}) @@ -46,17 +47,17 @@ class Type: else: self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}" - self.enum_name = f"{attr_set.name_prefix}{self.name}" - self.enum_name = c_upper(self.enum_name) self.c_name = c_lower(self.name) if self.c_name in _C_KW: self.c_name += '_' - def __getitem__(self, key): - return self.attr[key] + # Added by resolve(): + self.enum_name = None + delattr(self, "enum_name") - def __contains__(self, key): - return key in self.attr + def resolve(self): + self.enum_name = f"{self.attr_set.name_prefix}{self.name}" + self.enum_name = c_upper(self.enum_name) def is_multi_val(self): return None @@ -214,24 +215,34 @@ class TypePad(Type): class TypeScalar(Type): - def __init__(self, family, attr_set, attr): - super().__init__(family, attr_set, attr) + def __init__(self, family, attr_set, attr, value): + super().__init__(family, attr_set, attr, value) + + self.byte_order_comment = '' + if 'byte-order' in attr: + self.byte_order_comment = f" /* {attr['byte-order']} */" + + # Added by resolve(): + self.is_bitfield = None + delattr(self, "is_bitfield") + self.type_name = None + delattr(self, "type_name") + + def resolve(self): + self.resolve_up(super()) - self.is_bitfield = False - if 'enum' in self.attr: - self.is_bitfield = family.consts[self.attr['enum']]['type'] == 'flags' if 'enum-as-flags' in self.attr and self.attr['enum-as-flags']: self.is_bitfield = True + elif 'enum' in self.attr: + self.is_bitfield = self.family.consts[self.attr['enum']]['type'] == 'flags' + else: + self.is_bitfield = False if 'enum' in self.attr and not self.is_bitfield: - self.type_name = f"enum {family.name}_{c_lower(self.attr['enum'])}" + self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}" else: self.type_name = '__' + self.type - self.byte_order_comment = '' - if 'byte-order' in attr: - self.byte_order_comment = f" /* {attr['byte-order']} */" - def _mnl_type(self): t = self.type # mnl does not have a helper for signed types @@ -648,14 +659,11 @@ class EnumSet: return mask -class AttrSet: +class AttrSet(SpecAttrSet): def __init__(self, family, yaml): - self.yaml = yaml + super().__init__(family, yaml) - self.attrs = dict() - self.name = self.yaml['name'] - if 'subset-of' not in yaml: - self.subset_of = None + if self.subset_of is None: if 'name-prefix' in yaml: pfx = yaml['name-prefix'] elif self.name == family.name: @@ -665,83 +673,68 @@ class AttrSet: self.name_prefix = c_upper(pfx) self.max_name = c_upper(self.yaml.get('attr-max-name', f"{self.name_prefix}max")) else: - self.subset_of = self.yaml['subset-of'] self.name_prefix = family.attr_sets[self.subset_of].name_prefix self.max_name = family.attr_sets[self.subset_of].max_name + # Added by resolve: + self.c_name = None + delattr(self, "c_name") + + def resolve(self): self.c_name = c_lower(self.name) if self.c_name in _C_KW: self.c_name += '_' - if self.c_name == family.c_name: + if self.c_name == self.family.c_name: self.c_name = '' - val = 0 - for elem in self.yaml['attributes']: - if 'value' in elem: - val = elem['value'] - else: - elem['value'] = val - val += 1 - - if 'multi-attr' in elem and elem['multi-attr']: - attr = TypeMultiAttr(family, self, elem) - elif elem['type'] in scalars: - attr = TypeScalar(family, self, elem) - elif elem['type'] == 'unused': - attr = TypeUnused(family, self, elem) - elif elem['type'] == 'pad': - attr = TypePad(family, self, elem) - elif elem['type'] == 'flag': - attr = TypeFlag(family, self, elem) - elif elem['type'] == 'string': - attr = TypeString(family, self, elem) - elif elem['type'] == 'binary': - attr = TypeBinary(family, self, elem) - elif elem['type'] == 'nest': - attr = TypeNest(family, self, elem) - elif elem['type'] == 'array-nest': - attr = TypeArrayNest(family, self, elem) - elif elem['type'] == 'nest-type-value': - attr = TypeNestTypeValue(family, self, elem) - else: - raise Exception(f"No typed class for type {elem['type']}") - - self.attrs[elem['name']] = attr - - def __getitem__(self, key): - return self.attrs[key] - - def __contains__(self, key): - return key in self.yaml - - def __iter__(self): - yield from self.attrs + def new_attr(self, elem, value): + if 'multi-attr' in elem and elem['multi-attr']: + return TypeMultiAttr(self.family, self, elem, value) + elif elem['type'] in scalars: + return TypeScalar(self.family, self, elem, value) + elif elem['type'] == 'unused': + return TypeUnused(self.family, self, elem, value) + elif elem['type'] == 'pad': + return TypePad(self.family, self, elem, value) + elif elem['type'] == 'flag': + return TypeFlag(self.family, self, elem, value) + elif elem['type'] == 'string': + return TypeString(self.family, self, elem, value) + elif elem['type'] == 'binary': + return TypeBinary(self.family, self, elem, value) + elif elem['type'] == 'nest': + return TypeNest(self.family, self, elem, value) + elif elem['type'] == 'array-nest': + return TypeArrayNest(self.family, self, elem, value) + elif elem['type'] == 'nest-type-value': + return TypeNestTypeValue(self.family, self, elem, value) + else: + raise Exception(f"No typed class for type {elem['type']}") - def items(self): - return self.attrs.items() +class Operation(SpecOperation): + def __init__(self, family, yaml, req_value, rsp_value): + super().__init__(family, yaml, req_value, rsp_value) -class Operation: - def __init__(self, family, yaml, value): - self.yaml = yaml - self.value = value + if req_value != rsp_value: + raise Exception("Directional messages not supported by codegen") - self.name = self.yaml['name'] self.render_name = family.name + '_' + c_lower(self.name) - self.is_async = 'notify' in yaml or 'event' in yaml - if not self.is_async: - self.enum_name = family.op_prefix + c_upper(self.name) - else: - self.enum_name = family.async_op_prefix + c_upper(self.name) self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \ ('dump' in yaml and 'request' in yaml['dump']) - def __getitem__(self, key): - return self.yaml[key] + # Added by resolve: + self.enum_name = None + delattr(self, "enum_name") - def __contains__(self, key): - return key in self.yaml + def resolve(self): + self.resolve_up(super()) + + if not self.is_async: + self.enum_name = self.family.op_prefix + c_upper(self.name) + else: + self.enum_name = self.family.async_op_prefix + c_upper(self.name) def add_notification(self, op): if 'notify' not in self.yaml: @@ -751,21 +744,23 @@ class Operation: self.yaml['notify']['cmds'].append(op) -class Family: +class Family(SpecFamily): def __init__(self, file_name): - with open(file_name, "r") as stream: - self.yaml = yaml.safe_load(stream) - - self.proto = self.yaml.get('protocol', 'genetlink') - - with open(os.path.dirname(os.path.dirname(file_name)) + - f'/{self.proto}.yaml', "r") as stream: - schema = yaml.safe_load(stream) - - jsonschema.validate(self.yaml, schema) - - if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}: - raise Exception("Codegen only supported for genetlink") + # Added by resolve: + self.c_name = None + delattr(self, "c_name") + self.op_prefix = None + delattr(self, "op_prefix") + self.async_op_prefix = None + delattr(self, "async_op_prefix") + self.mcgrps = None + delattr(self, "mcgrps") + self.consts = None + delattr(self, "consts") + self.hooks = None + delattr(self, "hooks") + + super().__init__(file_name) self.fam_key = c_upper(self.yaml.get('c-family-name', self.yaml["name"] + '_FAMILY_NAME')) self.ver_key = c_upper(self.yaml.get('c-version-name', self.yaml["name"] + '_FAMILY_VERSION')) @@ -773,12 +768,18 @@ class Family: if 'definitions' not in self.yaml: self.yaml['definitions'] = [] - self.name = self.yaml['name'] - self.c_name = c_lower(self.name) if 'uapi-header' in self.yaml: self.uapi_header = self.yaml['uapi-header'] else: self.uapi_header = f"linux/{self.name}.h" + + def resolve(self): + self.resolve_up(super()) + + if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}: + raise Exception("Codegen only supported for genetlink") + + self.c_name = c_lower(self.name) if 'name-prefix' in self.yaml['operations']: self.op_prefix = c_upper(self.yaml['operations']['name-prefix']) else: @@ -791,12 +792,6 @@ class Family: self.mcgrps = self.yaml.get('mcast-groups', {'list': []}) self.consts = dict() - # list of all operations - self.msg_list = [] - # dict of operations which have their own message type (have attributes) - self.ops = collections.OrderedDict() - self.attr_sets = dict() - self.attr_sets_list = [] self.hooks = dict() for when in ['pre', 'post']: @@ -824,11 +819,11 @@ class Family: if self.kernel_policy == 'global': self._load_global_policy() - def __getitem__(self, key): - return self.yaml[key] + def new_attr_set(self, elem): + return AttrSet(self, elem) - def get(self, key, default=None): - return self.yaml.get(key, default) + def new_operation(self, elem, req_value, rsp_value): + return Operation(self, elem, req_value, rsp_value) # Fake a 'do' equivalent of all events, so that we can render their response parsing def _mock_up_events(self): @@ -847,27 +842,10 @@ class Family: else: self.consts[elem['name']] = elem - for elem in self.yaml['attribute-sets']: - attr_set = AttrSet(self, elem) - self.attr_sets[elem['name']] = attr_set - self.attr_sets_list.append((elem['name'], attr_set), ) - ntf = [] - val = 0 - for elem in self.yaml['operations']['list']: - if 'value' in elem: - val = elem['value'] - - op = Operation(self, elem, val) - val += 1 - - self.msg_list.append(op) - if 'notify' in elem: - ntf.append(op) - continue - if 'attribute-set' not in elem: - continue - self.ops[elem['name']] = op + for msg in self.msgs.values(): + if 'notify' in msg: + ntf.append(msg) for n in ntf: self.ops[n['notify']].add_notification(n) @@ -933,7 +911,7 @@ class Family: if attr_set_name != op['attribute-set']: raise Exception('For a global policy all ops must use the same set') - for op_mode in {'do', 'dump'}: + for op_mode in ['do', 'dump']: if op_mode in op: global_set.update(op[op_mode].get('request', [])) @@ -2033,7 +2011,7 @@ def render_uapi(family, cw): max_by_define = family.get('max-by-define', False) - for _, attr_set in family.attr_sets_list: + for _, attr_set in family.attr_sets.items(): if attr_set.subset_of: continue @@ -2044,9 +2022,9 @@ def render_uapi(family, cw): uapi_enum_start(family, cw, attr_set.yaml, 'enum-name') for _, attr in attr_set.items(): suffix = ',' - if attr['value'] != val: - suffix = f" = {attr['value']}," - val = attr['value'] + if attr.value != val: + suffix = f" = {attr.value}," + val = attr.value val += 1 cw.p(attr.enum_name + suffix) cw.nl() @@ -2066,7 +2044,7 @@ def render_uapi(family, cw): max_value = f"({cnt_name} - 1)" uapi_enum_start(family, cw, family['operations'], 'enum-name') - for op in family.msg_list: + for op in family.msgs.values(): if separate_ntf and ('notify' in op or 'event' in op): continue @@ -2085,7 +2063,7 @@ def render_uapi(family, cw): if separate_ntf: uapi_enum_start(family, cw, family['operations'], enum_name='async-enum') - for op in family.msg_list: + for op in family.msgs.values(): if separate_ntf and not ('notify' in op or 'event' in op): continue @@ -2244,7 +2222,7 @@ def main(): for op_name, op in parsed.ops.items(): if parsed.kernel_policy in {'per-op', 'split'}: - for op_mode in {'do', 'dump'}: + for op_mode in ['do', 'dump']: if op_mode in op and 'request' in op[op_mode]: cw.p(f"/* {op.enum_name} - {op_mode} */") ri = RenderInfo(cw, parsed, args.mode, op, op_name, op_mode) diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_defprio.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_defprio.sh index 71066bc4b886..5492fa5550d7 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_defprio.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_defprio.sh @@ -5,18 +5,18 @@ # prioritized according to the default priority specified at the port. # rx_octets_prio_* counters are used to verify the prioritization. # -# +-----------------------+ -# | H1 | -# | + $h1 | -# | | 192.0.2.1/28 | -# +----|------------------+ +# +----------------------------------+ +# | H1 | +# | + $h1 | +# | | 192.0.2.1/28 | +# +----|-----------------------------+ # | -# +----|------------------+ -# | SW | | -# | + $swp1 | -# | 192.0.2.2/28 | -# | APP=<prio>,1,0 | -# +-----------------------+ +# +----|-----------------------------+ +# | SW | | +# | + $swp1 | +# | 192.0.2.2/28 | +# | dcb app default-prio <prio> | +# +----------------------------------+ ALL_TESTS=" ping_ipv4 @@ -29,42 +29,6 @@ NUM_NETIFS=2 : ${HIT_TIMEOUT:=1000} # ms source $lib_dir/lib.sh -declare -a APP - -defprio_install() -{ - local dev=$1; shift - local prio=$1; shift - local app="app=$prio,1,0" - - lldptool -T -i $dev -V APP $app >/dev/null - lldpad_app_wait_set $dev - APP[$prio]=$app -} - -defprio_uninstall() -{ - local dev=$1; shift - local prio=$1; shift - local app=${APP[$prio]} - - lldptool -T -i $dev -V APP -d $app >/dev/null - lldpad_app_wait_del - unset APP[$prio] -} - -defprio_flush() -{ - local dev=$1; shift - local prio - - if ((${#APP[@]})); then - lldptool -T -i $dev -V APP -d ${APP[@]} >/dev/null - fi - lldpad_app_wait_del - APP=() -} - h1_create() { simple_if_init $h1 192.0.2.1/28 @@ -83,7 +47,7 @@ switch_create() switch_destroy() { - defprio_flush $swp1 + dcb app flush dev $swp1 default-prio ip addr del dev $swp1 192.0.2.2/28 ip link set dev $swp1 down } @@ -124,7 +88,7 @@ __test_defprio() RET=0 - defprio_install $swp1 $prio_install + dcb app add dev $swp1 default-prio $prio_install local t0=$(ethtool_stats_get $swp1 rx_frames_prio_$prio_observe) mausezahn -q $h1 -d 100m -c 10 -t arp reply @@ -134,7 +98,7 @@ __test_defprio() check_err $? "Default priority $prio_install/$prio_observe: Expected to capture 10 packets, got $((t1 - t0))." log_test "Default priority $prio_install/$prio_observe" - defprio_uninstall $swp1 $prio_install + dcb app del dev $swp1 default-prio $prio_install } test_defprio() @@ -145,7 +109,7 @@ test_defprio() __test_defprio $prio $prio done - defprio_install $swp1 3 + dcb app add dev $swp1 default-prio 3 __test_defprio 0 3 __test_defprio 1 3 __test_defprio 2 3 @@ -153,7 +117,7 @@ test_defprio() __test_defprio 5 5 __test_defprio 6 6 __test_defprio 7 7 - defprio_uninstall $swp1 3 + dcb app del dev $swp1 default-prio 3 } trap cleanup EXIT diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh index 28a570006d4d..87c41f5727c9 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh @@ -20,7 +20,7 @@ # | SW | | | # | +-|----------------------------------------------------------------|-+ | # | | + $swp1 BR $swp2 + | | -# | | APP=0,5,10 .. 7,5,17 APP=0,5,20 .. 7,5,27 | | +# | | dcb dscp-prio 10:0...17:7 dcb dscp-prio 20:0...27:7 | | # | +--------------------------------------------------------------------+ | # +---------------------------------------------------------------------------+ @@ -62,16 +62,6 @@ h2_destroy() simple_if_fini $h2 192.0.2.2/28 } -dscp_map() -{ - local base=$1; shift - local prio - - for prio in {0..7}; do - echo app=$prio,5,$((base + prio)) - done -} - switch_create() { ip link add name br1 type bridge vlan_filtering 1 @@ -81,17 +71,14 @@ switch_create() ip link set dev $swp2 master br1 ip link set dev $swp2 up - lldptool -T -i $swp1 -V APP $(dscp_map 10) >/dev/null - lldptool -T -i $swp2 -V APP $(dscp_map 20) >/dev/null - lldpad_app_wait_set $swp1 - lldpad_app_wait_set $swp2 + dcb app add dev $swp1 dscp-prio 10:0 11:1 12:2 13:3 14:4 15:5 16:6 17:7 + dcb app add dev $swp2 dscp-prio 20:0 21:1 22:2 23:3 24:4 25:5 26:6 27:7 } switch_destroy() { - lldptool -T -i $swp2 -V APP -d $(dscp_map 20) >/dev/null - lldptool -T -i $swp1 -V APP -d $(dscp_map 10) >/dev/null - lldpad_app_wait_del + dcb app del dev $swp2 dscp-prio 20:0 21:1 22:2 23:3 24:4 25:5 26:6 27:7 + dcb app del dev $swp1 dscp-prio 10:0 11:1 12:2 13:3 14:4 15:5 16:6 17:7 ip link set dev $swp2 down ip link set dev $swp2 nomaster diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh index 4cb2aa65278a..f6c23f84423e 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh @@ -94,16 +94,6 @@ h2_destroy() simple_if_fini $h2 192.0.2.18/28 } -dscp_map() -{ - local base=$1; shift - local prio - - for prio in {0..7}; do - echo app=$prio,5,$((base + prio)) - done -} - switch_create() { simple_if_init $swp1 192.0.2.2/28 @@ -112,17 +102,14 @@ switch_create() tc qdisc add dev $swp1 clsact tc qdisc add dev $swp2 clsact - lldptool -T -i $swp1 -V APP $(dscp_map 0) >/dev/null - lldptool -T -i $swp2 -V APP $(dscp_map 0) >/dev/null - lldpad_app_wait_set $swp1 - lldpad_app_wait_set $swp2 + dcb app add dev $swp1 dscp-prio 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 + dcb app add dev $swp2 dscp-prio 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 } switch_destroy() { - lldptool -T -i $swp2 -V APP -d $(dscp_map 0) >/dev/null - lldptool -T -i $swp1 -V APP -d $(dscp_map 0) >/dev/null - lldpad_app_wait_del + dcb app del dev $swp2 dscp-prio 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 + dcb app del dev $swp1 dscp-prio 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 tc qdisc del dev $swp2 clsact tc qdisc del dev $swp1 clsact @@ -265,13 +252,11 @@ test_dscp_leftover() { echo "Test that last removed DSCP rule is deconfigured correctly" - lldptool -T -i $swp2 -V APP -d $(dscp_map 0) >/dev/null - lldpad_app_wait_del + dcb app del dev $swp2 dscp-prio 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 __test_update 0 zero - lldptool -T -i $swp2 -V APP $(dscp_map 0) >/dev/null - lldpad_app_wait_set $swp2 + dcb app add dev $swp2 dscp-prio 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 } trap cleanup EXIT diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 1c4f866de7d7..29cd4705c752 100755 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -524,27 +524,6 @@ cmd_jq() [ ! -z "$output" ] } -lldpad_app_wait_set() -{ - local dev=$1; shift - - while lldptool -t -i $dev -V APP -c app | grep -Eq "pending|unknown"; do - echo "$dev: waiting for lldpad to push pending APP updates" - sleep 5 - done -} - -lldpad_app_wait_del() -{ - # Give lldpad a chance to push down the changes. If the device is downed - # too soon, the updates will be left pending. However, they will have - # been struck off the lldpad's DB already, so we won't be able to tell - # they are pending. Then on next test iteration this would cause - # weirdness as newly-added APP rules conflict with the old ones, - # sometimes getting stuck in an "unknown" state. - sleep 5 -} - pre_cleanup() { if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then |