Pull networking fixes from Jakub Kicinski. "Including fixes from bpf and netfilter. Current release - regressions: - sock: fix parameter order in sock_setsockopt() Current release - new code bugs: - netfilter: nft_last: - fix incorrect arithmetic when restoring last used - honor NFTA_LAST_SET on restoration Previous releases - regressions: - udp: properly flush normal packet at GRO time - sfc: ensure correct number of XDP queues; don't allow enabling the feature if there isn't sufficient resources to Tx from any CPU - dsa: sja1105: fix address learning getting disabled on the CPU port - mptcp: addresses a rmem accounting issue that could keep packets in subflow receive buffers longer than necessary, delaying MPTCP-level ACKs - ip_tunnel: fix mtu calculation for ETHER tunnel devices - do not reuse skbs allocated from skbuff_fclone_cache in the napi skb cache, we'd try to return them to the wrong slab cache - tcp: consistently disable header prediction for mptcp Previous releases - always broken: - bpf: fix subprog poke descriptor tracking use-after-free - ipv6: - allocate enough headroom in ip6_finish_output2() in case iptables TEE is used - tcp: drop silly ICMPv6 packet too big messages to avoid expensive and pointless lookups (which may serve as a DDOS vector) - make sure fwmark is copied in SYNACK packets - fix 'disable_policy' for forwarded packets (align with IPv4) - netfilter: conntrack: - do not renew entry stuck in tcp SYN_SENT state - do not mark RST in the reply direction coming after SYN packet for an out-of-sync entry - mptcp: cleanly handle error conditions with MP_JOIN and syncookies - mptcp: fix double free when rejecting a join due to port mismatch - validate lwtstate->data before returning from skb_tunnel_info() - tcp: call sk_wmem_schedule before sk_mem_charge in zerocopy path - mt76: mt7921: continue to probe driver when fw already downloaded - bonding: fix multiple issues with offloading IPsec to (thru?) bond - stmmac: ptp: fix issues around Qbv support and setting time back - bcmgenet: always clear wake-up based on energy detection Misc: - sctp: move 198 addresses from unusable to private scope - ptp: support virtual clocks and timestamping - openvswitch: optimize operation for key comparison" * tag 'net-5.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (158 commits) net: dsa: properly check for the bridge_leave methods in dsa_switch_bridge_leave() sfc: add logs explaining XDP_TX/REDIRECT is not available sfc: ensure correct number of XDP queues sfc: fix lack of XDP TX queues - error XDP TX failed (-22) net: fddi: fix UAF in fza_probe net: dsa: sja1105: fix address learning getting disabled on the CPU port net: ocelot: fix switchdev objects synced for wrong netdev with LAG offload net: Use nlmsg_unicast() instead of netlink_unicast() octeontx2-pf: Fix uninitialized boolean variable pps ipv6: allocate enough headroom in ip6_finish_output2() net: hdlc: rename 'mod_init' & 'mod_exit' functions to be module-specific net: bridge: multicast: fix MRD advertisement router port marking race net: bridge: multicast: fix PIM hello router port marking race net: phy: marvell10g: fix differentiation of 88X3310 from 88X3340 dsa: fix for_each_child.cocci warnings virtio_net: check virtqueue_add_sgs() return value mptcp: properly account bulk freed memory selftests: mptcp: fix case multiple subflows limited by server mptcp: avoid processing packet if a subflow reset mptcp: fix syncookie process if mptcp can not_accept new subflow ...
Unified · Split
| @@ -33,6 +33,13 @@ Description: · 32 unmodified lines | ||
| 33 | 33 | frequency adjustment value (a positive integer) in |
| 34 | 34 | parts per billion. |
| 35 | 35 | |
| 36 | +What: /sys/class/ptp/ptpN/max_vclocks | |
| 37 | +Date: May 2021 | |
| 38 | +Contact: Yangbo Lu <yangbo.lu@nxp.com> | |
| 39 | +Description: | |
| 40 | + This file contains the maximum number of ptp vclocks. | |
| 41 | + Write integer to re-configure it. | |
| 42 | + | |
| 36 | 43 | What: /sys/class/ptp/ptpN/n_alarms |
| 37 | 44 | Date: September 2010 |
| 38 | 45 | Contact: Richard Cochran <richardcochran@gmail.com> |
| @@ -61,6 +68,19 @@ Description: · 22 unmodified lines | ||
| 61 | 68 | This file contains the number of programmable pins |
| 62 | 69 | offered by the PTP hardware clock. |
| 63 | 70 | |
| 71 | +What: /sys/class/ptp/ptpN/n_vclocks | |
| 72 | +Date: May 2021 | |
| 73 | +Contact: Yangbo Lu <yangbo.lu@nxp.com> | |
| 74 | +Description: | |
| 75 | + This file contains the number of virtual PTP clocks in | |
| 76 | + use. By default, the value is 0 meaning that only the | |
| 77 | + physical clock is in use. Setting the value creates | |
| 78 | + the corresponding number of virtual clocks and causes | |
| 79 | + the physical clock to become free running. Setting the | |
| 80 | + value back to 0 deletes the virtual clocks and | |
| 81 | + switches the physical clock back to normal, adjustable | |
| 82 | + operation. | |
| 83 | + | |
| 64 | 84 | What: /sys/class/ptp/ptpN/pins |
| 65 | 85 | Date: March 2014 |
| 66 | 86 | Contact: Richard Cochran <richardcochran@gmail.com> |
| @@ -13,7 +13,7 @@ Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | For the properties relevant to the ethernet controller connected to the GPMC |
| 15 | 15 | refer to the binding documentation of the device. For example, the documentation |
| 16 | −for the SMSC 911x is Documentation/devicetree/bindings/net/smsc911x.txt | |
| 16 | +for the SMSC 911x is Documentation/devicetree/bindings/net/smsc,lan9115.yaml | |
| 17 | 17 | |
| 18 | 18 | Child nodes need to specify the GPMC bus address width using the "bank-width" |
| 19 | 19 | property but is possible that an ethernet controller also has a property to |
| @@ -0,0 +1,110 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/smsc,lan9115.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Smart Mixed-Signal Connectivity (SMSC) LAN911x/912x Controller | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Shawn Guo <shawnguo@kernel.org> | |
| 11 | + | |
| 12 | +allOf: | |
| 13 | + - $ref: ethernet-controller.yaml# | |
| 14 | + | |
| 15 | +properties: | |
| 16 | + compatible: | |
| 17 | + oneOf: | |
| 18 | + - const: smsc,lan9115 | |
| 19 | + - items: | |
| 20 | + - enum: | |
| 21 | + - smsc,lan89218 | |
| 22 | + - smsc,lan9117 | |
| 23 | + - smsc,lan9118 | |
| 24 | + - smsc,lan9220 | |
| 25 | + - smsc,lan9221 | |
| 26 | + - const: smsc,lan9115 | |
| 27 | + | |
| 28 | + reg: | |
| 29 | + maxItems: 1 | |
| 30 | + | |
| 31 | + reg-shift: true | |
| 32 | + | |
| 33 | + reg-io-width: | |
| 34 | + enum: [ 2, 4 ] | |
| 35 | + default: 2 | |
| 36 | + | |
| 37 | + interrupts: | |
| 38 | + minItems: 1 | |
| 39 | + items: | |
| 40 | + - description: | |
| 41 | + LAN interrupt line | |
| 42 | + - description: | |
| 43 | + Optional PME (power management event) interrupt that is able to wake | |
| 44 | + up the host system with a 50ms pulse on network activity | |
| 45 | + | |
| 46 | + clocks: | |
| 47 | + maxItems: 1 | |
| 48 | + | |
| 49 | + phy-mode: true | |
| 50 | + | |
| 51 | + smsc,irq-active-high: | |
| 52 | + type: boolean | |
| 53 | + description: Indicates the IRQ polarity is active-high | |
| 54 | + | |
| 55 | + smsc,irq-push-pull: | |
| 56 | + type: boolean | |
| 57 | + description: Indicates the IRQ type is push-pull | |
| 58 | + | |
| 59 | + smsc,force-internal-phy: | |
| 60 | + type: boolean | |
| 61 | + description: Forces SMSC LAN controller to use internal PHY | |
| 62 | + | |
| 63 | + smsc,force-external-phy: | |
| 64 | + type: boolean | |
| 65 | + description: Forces SMSC LAN controller to use external PHY | |
| 66 | + | |
| 67 | + smsc,save-mac-address: | |
| 68 | + type: boolean | |
| 69 | + description: | |
| 70 | + Indicates that MAC address needs to be saved before resetting the | |
| 71 | + controller | |
| 72 | + | |
| 73 | + reset-gpios: | |
| 74 | + maxItems: 1 | |
| 75 | + description: | |
| 76 | + A GPIO line connected to the RESET (active low) signal of the device. | |
| 77 | + On many systems this is wired high so the device goes out of reset at | |
| 78 | + power-on, but if it is under program control, this optional GPIO can | |
| 79 | + wake up in response to it. | |
| 80 | + | |
| 81 | + vdd33a-supply: | |
| 82 | + description: 3.3V analog power supply | |
| 83 | + | |
| 84 | + vddvario-supply: | |
| 85 | + description: IO logic power supply | |
| 86 | + | |
| 87 | +required: | |
| 88 | + - compatible | |
| 89 | + - reg | |
| 90 | + - interrupts | |
| 91 | + | |
| 92 | +# There are lots of bus-specific properties ("qcom,*", "samsung,*", "fsl,*", | |
| 93 | +# "gpmc,*", ...) to be found, that actually depend on the compatible value of | |
| 94 | +# the parent node. | |
| 95 | +additionalProperties: true | |
| 96 | + | |
| 97 | +examples: | |
| 98 | + - | | |
| 99 | + #include <dt-bindings/gpio/gpio.h> | |
| 100 | + | |
| 101 | + ethernet@f4000000 { | |
| 102 | + compatible = "smsc,lan9220", "smsc,lan9115"; | |
| 103 | + reg = <0xf4000000 0x2000000>; | |
| 104 | + phy-mode = "mii"; | |
| 105 | + interrupt-parent = <&gpio1>; | |
| 106 | + interrupts = <31>, <32>; | |
| 107 | + reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>; | |
| 108 | + reg-io-width = <4>; | |
| 109 | + smsc,irq-push-pull; | |
| 110 | + }; | |
| @@ -1,43 +0,0 @@ | ||
| 1 | −* Smart Mixed-Signal Connectivity (SMSC) LAN911x/912x Controller | |
| 2 | − | |
| 3 | −Required properties: | |
| 4 | −- compatible : Should be "smsc,lan<model>", "smsc,lan9115" | |
| 5 | −- reg : Address and length of the io space for SMSC LAN | |
| 6 | −- interrupts : one or two interrupt specifiers | |
| 7 | − - The first interrupt is the SMSC LAN interrupt line | |
| 8 | − - The second interrupt (if present) is the PME (power | |
| 9 | − management event) interrupt that is able to wake up the host | |
| 10 | − system with a 50ms pulse on network activity | |
| 11 | −- phy-mode : See ethernet.txt file in the same directory | |
| 12 | − | |
| 13 | −Optional properties: | |
| 14 | −- reg-shift : Specify the quantity to shift the register offsets by | |
| 15 | −- reg-io-width : Specify the size (in bytes) of the IO accesses that | |
| 16 | − should be performed on the device. Valid value for SMSC LAN is | |
| 17 | − 2 or 4. If it's omitted or invalid, the size would be 2. | |
| 18 | −- smsc,irq-active-high : Indicates the IRQ polarity is active-high | |
| 19 | −- smsc,irq-push-pull : Indicates the IRQ type is push-pull | |
| 20 | −- smsc,force-internal-phy : Forces SMSC LAN controller to use | |
| 21 | − internal PHY | |
| 22 | −- smsc,force-external-phy : Forces SMSC LAN controller to use | |
| 23 | − external PHY | |
| 24 | −- smsc,save-mac-address : Indicates that mac address needs to be saved | |
| 25 | − before resetting the controller | |
| 26 | −- reset-gpios : a GPIO line connected to the RESET (active low) signal | |
| 27 | − of the device. On many systems this is wired high so the device goes | |
| 28 | − out of reset at power-on, but if it is under program control, this | |
| 29 | − optional GPIO can wake up in response to it. | |
| 30 | −- vdd33a-supply, vddvario-supply : 3.3V analog and IO logic power supplies | |
| 31 | − | |
| 32 | −Examples: | |
| 33 | − | |
| 34 | −lan9220@f4000000 { | |
| 35 | − compatible = "smsc,lan9220", "smsc,lan9115"; | |
| 36 | − reg = <0xf4000000 0x2000000>; | |
| 37 | − phy-mode = "mii"; | |
| 38 | − interrupt-parent = <&gpio1>; | |
| 39 | − interrupts = <31>, <32>; | |
| 40 | − reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>; | |
| 41 | − reg-io-width = <4>; | |
| 42 | − smsc,irq-push-pull; | |
| 43 | −}; | |
| @@ -212,6 +212,7 @@ Userspace to kernel: · 211 unmodified lines | ||
| 212 | 212 | ``ETHTOOL_MSG_FEC_SET`` set FEC settings |
| 213 | 213 | ``ETHTOOL_MSG_MODULE_EEPROM_GET`` read SFP module EEPROM |
| 214 | 214 | ``ETHTOOL_MSG_STATS_GET`` get standard statistics |
| 215 | + ``ETHTOOL_MSG_PHC_VCLOCKS_GET`` get PHC virtual clocks info | |
| 215 | 216 | ===================================== ================================ |
| 216 | 217 | |
| 217 | 218 | Kernel to userspace: |
| @@ -250,6 +251,7 @@ Kernel to userspace: · 32 unmodified lines | ||
| 250 | 251 | ``ETHTOOL_MSG_FEC_NTF`` FEC settings |
| 251 | 252 | ``ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY`` read SFP module EEPROM |
| 252 | 253 | ``ETHTOOL_MSG_STATS_GET_REPLY`` standard statistics |
| 254 | + ``ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY`` PHC virtual clocks info | |
| 253 | 255 | ======================================== ================================= |
| 254 | 256 | |
| 255 | 257 | ``GET`` requests are sent by userspace applications to retrieve device |
| @@ -1477,6 +1479,25 @@ Low and high bounds are inclusive, for example: · 1221 unmodified lines | ||
| 1477 | 1479 | etherStatsPkts512to1023Octets 512 1023 |
| 1478 | 1480 | ============================= ==== ==== |
| 1479 | 1481 | |
| 1482 | +PHC_VCLOCKS_GET | |
| 1483 | +=============== | |
| 1484 | + | |
| 1485 | +Query device PHC virtual clocks information. | |
| 1486 | + | |
| 1487 | +Request contents: | |
| 1488 | + | |
| 1489 | + ==================================== ====== ========================== | |
| 1490 | + ``ETHTOOL_A_PHC_VCLOCKS_HEADER`` nested request header | |
| 1491 | + ==================================== ====== ========================== | |
| 1492 | + | |
| 1493 | +Kernel response contents: | |
| 1494 | + | |
| 1495 | + ==================================== ====== ========================== | |
| 1496 | + ``ETHTOOL_A_PHC_VCLOCKS_HEADER`` nested reply header | |
| 1497 | + ``ETHTOOL_A_PHC_VCLOCKS_NUM`` u32 PHC virtual clocks number | |
| 1498 | + ``ETHTOOL_A_PHC_VCLOCKS_INDEX`` s32 PHC index array | |
| 1499 | + ==================================== ====== ========================== | |
| 1500 | + | |
| 1480 | 1501 | Request translation |
| 1481 | 1502 | =================== |
| 1482 | 1503 | |
| @@ -1575,4 +1596,5 @@ are netlink only. · 92 unmodified lines | ||
| 1575 | 1596 | n/a ``ETHTOOL_MSG_CABLE_TEST_ACT`` |
| 1576 | 1597 | n/a ``ETHTOOL_MSG_CABLE_TEST_TDR_ACT`` |
| 1577 | 1598 | n/a ``ETHTOOL_MSG_TUNNEL_INFO_GET`` |
| 1599 | + n/a ``ETHTOOL_MSG_PHC_VCLOCKS_GET`` | |
| 1578 | 1600 | =================================== ===================================== |
| @@ -110,6 +110,12 @@ nf_conntrack_tcp_be_liberal - BOOLEAN · 109 unmodified lines | ||
| 110 | 110 | Be conservative in what you do, be liberal in what you accept from others. |
| 111 | 111 | If it's non-zero, we mark only out of window RST segments as INVALID. |
| 112 | 112 | |
| 113 | +nf_conntrack_tcp_ignore_invalid_rst - BOOLEAN | |
| 114 | + - 0 - disabled (default) | |
| 115 | + - 1 - enabled | |
| 116 | + | |
| 117 | + If it's 1, we don't mark out of window RST segments as INVALID. | |
| 118 | + | |
| 113 | 119 | nf_conntrack_tcp_loose - BOOLEAN |
| 114 | 120 | - 0 - disabled |
| 115 | 121 | - not 0 - enabled (default) |
| @@ -4,10 +4,125 @@ · 3 unmodified lines | ||
| 4 | 4 | Linux Kernel TIPC |
| 5 | 5 | ================= |
| 6 | 6 | |
| 7 | −TIPC (Transparent Inter Process Communication) is a protocol that is | |
| 8 | −specially designed for intra-cluster communication. | |
| 7 | +Introduction | |
| 8 | +============ | |
| 9 | 9 | |
| 10 | −For more information about TIPC, see http://tipc.sourceforge.net. | |
| 10 | +TIPC (Transparent Inter Process Communication) is a protocol that is specially | |
| 11 | +designed for intra-cluster communication. It can be configured to transmit | |
| 12 | +messages either on UDP or directly across Ethernet. Message delivery is | |
| 13 | +sequence guaranteed, loss free and flow controlled. Latency times are shorter | |
| 14 | +than with any other known protocol, while maximal throughput is comparable to | |
| 15 | +that of TCP. | |
| 16 | + | |
| 17 | +TIPC Features | |
| 18 | +------------- | |
| 19 | + | |
| 20 | +- Cluster wide IPC service | |
| 21 | + | |
| 22 | + Have you ever wished you had the convenience of Unix Domain Sockets even when | |
| 23 | + transmitting data between cluster nodes? Where you yourself determine the | |
| 24 | + addresses you want to bind to and use? Where you don't have to perform DNS | |
| 25 | + lookups and worry about IP addresses? Where you don't have to start timers | |
| 26 | + to monitor the continuous existence of peer sockets? And yet without the | |
| 27 | + downsides of that socket type, such as the risk of lingering inodes? | |
| 28 | + | |
| 29 | + Welcome to the Transparent Inter Process Communication service, TIPC in short, | |
| 30 | + which gives you all of this, and a lot more. | |
| 31 | + | |
| 32 | +- Service Addressing | |
| 33 | + | |
| 34 | + A fundamental concept in TIPC is that of Service Addressing which makes it | |
| 35 | + possible for a programmer to chose his own address, bind it to a server | |
| 36 | + socket and let client programs use only that address for sending messages. | |
| 37 | + | |
| 38 | +- Service Tracking | |
| 39 | + | |
| 40 | + A client wanting to wait for the availability of a server, uses the Service | |
| 41 | + Tracking mechanism to subscribe for binding and unbinding/close events for | |
| 42 | + sockets with the associated service address. | |
| 43 | + | |
| 44 | + The service tracking mechanism can also be used for Cluster Topology Tracking, | |
| 45 | + i.e., subscribing for availability/non-availability of cluster nodes. | |
| 46 | + | |
| 47 | + Likewise, the service tracking mechanism can be used for Cluster Connectivity | |
| 48 | + Tracking, i.e., subscribing for up/down events for individual links between | |
| 49 | + cluster nodes. | |
| 50 | + | |
| 51 | +- Transmission Modes | |
| 52 | + | |
| 53 | + Using a service address, a client can send datagram messages to a server socket. | |
| 54 | + | |
| 55 | + Using the same address type, it can establish a connection towards an accepting | |
| 56 | + server socket. | |
| 57 | + | |
| 58 | + It can also use a service address to create and join a Communication Group, | |
| 59 | + which is the TIPC manifestation of a brokerless message bus. | |
| 60 | + | |
| 61 | + Multicast with very good performance and scalability is available both in | |
| 62 | + datagram mode and in communication group mode. | |
| 63 | + | |
| 64 | +- Inter Node Links | |
| 65 | + | |
| 66 | + Communication between any two nodes in a cluster is maintained by one or two | |
| 67 | + Inter Node Links, which both guarantee data traffic integrity and monitor | |
| 68 | + the peer node's availability. | |
| 69 | + | |
| 70 | +- Cluster Scalability | |
| 71 | + | |
| 72 | + By applying the Overlapping Ring Monitoring algorithm on the inter node links | |
| 73 | + it is possible to scale TIPC clusters up to 1000 nodes with a maintained | |
| 74 | + neighbor failure discovery time of 1-2 seconds. For smaller clusters this | |
| 75 | + time can be made much shorter. | |
| 76 | + | |
| 77 | +- Neighbor Discovery | |
| 78 | + | |
| 79 | + Neighbor Node Discovery in the cluster is done by Ethernet broadcast or UDP | |
| 80 | + multicast, when any of those services are available. If not, configured peer | |
| 81 | + IP addresses can be used. | |
| 82 | + | |
| 83 | +- Configuration | |
| 84 | + | |
| 85 | + When running TIPC in single node mode no configuration whatsoever is needed. | |
| 86 | + When running in cluster mode TIPC must as a minimum be given a node address | |
| 87 | + (before Linux 4.17) and told which interface to attach to. The "tipc" | |
| 88 | + configuration tool makes is possible to add and maintain many more | |
| 89 | + configuration parameters. | |
| 90 | + | |
| 91 | +- Performance | |
| 92 | + | |
| 93 | + TIPC message transfer latency times are better than in any other known protocol. | |
| 94 | + Maximal byte throughput for inter-node connections is still somewhat lower than | |
| 95 | + for TCP, while they are superior for intra-node and inter-container throughput | |
| 96 | + on the same host. | |
| 97 | + | |
| 98 | +- Language Support | |
| 99 | + | |
| 100 | + The TIPC user API has support for C, Python, Perl, Ruby, D and Go. | |
| 101 | + | |
| 102 | +More Information | |
| 103 | +---------------- | |
| 104 | + | |
| 105 | +- How to set up TIPC: | |
| 106 | + | |
| 107 | + http://tipc.io/getting_started.html | |
| 108 | + | |
| 109 | +- How to program with TIPC: | |
| 110 | + | |
| 111 | + http://tipc.io/programming.html | |
| 112 | + | |
| 113 | +- How to contribute to TIPC: | |
| 114 | + | |
| 115 | +- http://tipc.io/contacts.html | |
| 116 | + | |
| 117 | +- More details about TIPC specification: | |
| 118 | + | |
| 119 | + http://tipc.io/protocol.html | |
| 120 | + | |
| 121 | + | |
| 122 | +Implementation | |
| 123 | +============== | |
| 124 | + | |
| 125 | +TIPC is implemented as a kernel module in net/tipc/ directory. | |
| 11 | 126 | |
| 12 | 127 | TIPC Base Types |
| 13 | 128 | --------------- |
| @@ -15009,6 +15009,13 @@ F: drivers/net/phy/dp83640* · 15008 unmodified lines | ||
| 15009 | 15009 | F: drivers/ptp/* |
| 15010 | 15010 | F: include/linux/ptp_cl* |
| 15011 | 15011 | |
| 15012 | +PTP VIRTUAL CLOCK SUPPORT | |
| 15013 | +M: Yangbo Lu <yangbo.lu@nxp.com> | |
| 15014 | +L: netdev@vger.kernel.org | |
| 15015 | +S: Maintained | |
| 15016 | +F: drivers/ptp/ptp_vclock.c | |
| 15017 | +F: net/ethtool/phc_vclocks.c | |
| 15018 | + | |
| 15012 | 15019 | PTRACE SUPPORT |
| 15013 | 15020 | M: Oleg Nesterov <oleg@redhat.com> |
| 15014 | 15021 | S: Maintained |
| @@ -581,7 +581,7 @@ · 580 unmodified lines | ||
| 581 | 581 | * EBI2. This has a 25MHz chrystal next to it, so no |
| 582 | 582 | * clocking is needed. |
| 583 | 583 | */ |
| 584 | − ethernet-ebi2@2,0 { | |
| 584 | + ethernet@2,0 { | |
| 585 | 585 | compatible = "smsc,lan9221", "smsc,lan9115"; |
| 586 | 586 | reg = <2 0x0 0x100>; |
| 587 | 587 | /* |
| @@ -598,8 +598,6 @@ · 10 unmodified lines | ||
| 598 | 598 | phy-mode = "mii"; |
| 599 | 599 | reg-io-width = <2>; |
| 600 | 600 | smsc,force-external-phy; |
| 601 | − /* IRQ on edge falling = active low */ | |
| 602 | − smsc,irq-active-low; | |
| 603 | 601 | smsc,irq-push-pull; |
| 604 | 602 | |
| 605 | 603 | /* |
| @@ -570,6 +570,9 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog) · 569 unmodified lines | ||
| 570 | 570 | |
| 571 | 571 | for (i = 0; i < prog->aux->size_poke_tab; i++) { |
| 572 | 572 | poke = &prog->aux->poke_tab[i]; |
| 573 | + if (poke->aux && poke->aux != prog->aux) | |
| 574 | + continue; | |
| 575 | + | |
| 573 | 576 | WARN_ON_ONCE(READ_ONCE(poke->tailcall_target_stable)); |
| 574 | 577 | |
| 575 | 578 | if (poke->reason != BPF_POKE_REASON_TAIL_CALL) |
| @@ -401,24 +401,85 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, · 400 unmodified lines | ||
| 401 | 401 | static int bond_ipsec_add_sa(struct xfrm_state *xs) |
| 402 | 402 | { |
| 403 | 403 | struct net_device *bond_dev = xs->xso.dev; |
| 404 | + struct bond_ipsec *ipsec; | |
| 404 | 405 | struct bonding *bond; |
| 405 | 406 | struct slave *slave; |
| 407 | + int err; | |
| 406 | 408 | |
| 407 | 409 | if (!bond_dev) |
| 408 | 410 | return -EINVAL; |
| 409 | 411 | |
| 412 | + rcu_read_lock(); | |
| 410 | 413 | bond = netdev_priv(bond_dev); |
| 411 | 414 | slave = rcu_dereference(bond->curr_active_slave); |
| 412 | − xs->xso.real_dev = slave->dev; | |
| 413 | − bond->xs = xs; | |
| 415 | + if (!slave) { | |
| 416 | + rcu_read_unlock(); | |
| 417 | + return -ENODEV; | |
| 418 | + } | |
| 414 | 419 | |
| 415 | − if (!(slave->dev->xfrmdev_ops | |
| 416 | − && slave->dev->xfrmdev_ops->xdo_dev_state_add)) { | |
| 420 | + if (!slave->dev->xfrmdev_ops || | |
| 421 | + !slave->dev->xfrmdev_ops->xdo_dev_state_add || | |
| 422 | + netif_is_bond_master(slave->dev)) { | |
| 417 | 423 | slave_warn(bond_dev, slave->dev, "Slave does not support ipsec offload\n"); |
| 424 | + rcu_read_unlock(); | |
| 418 | 425 | return -EINVAL; |
| 419 | 426 | } |
| 420 | 427 | |
| 421 | − return slave->dev->xfrmdev_ops->xdo_dev_state_add(xs); | |
| 428 | + ipsec = kmalloc(sizeof(*ipsec), GFP_ATOMIC); | |
| 429 | + if (!ipsec) { | |
| 430 | + rcu_read_unlock(); | |
| 431 | + return -ENOMEM; | |
| 432 | + } | |
| 433 | + xs->xso.real_dev = slave->dev; | |
| 434 | + | |
| 435 | + err = slave->dev->xfrmdev_ops->xdo_dev_state_add(xs); | |
| 436 | + if (!err) { | |
| 437 | + ipsec->xs = xs; | |
| 438 | + INIT_LIST_HEAD(&ipsec->list); | |
| 439 | + spin_lock_bh(&bond->ipsec_lock); | |
| 440 | + list_add(&ipsec->list, &bond->ipsec_list); | |
| 441 | + spin_unlock_bh(&bond->ipsec_lock); | |
| 442 | + } else { | |
| 443 | + kfree(ipsec); | |
| 444 | + } | |
| 445 | + rcu_read_unlock(); | |
| 446 | + return err; | |
| 447 | +} | |
| 448 | + | |
| 449 | +static void bond_ipsec_add_sa_all(struct bonding *bond) | |
| 450 | +{ | |
| 451 | + struct net_device *bond_dev = bond->dev; | |
| 452 | + struct bond_ipsec *ipsec; | |
| 453 | + struct slave *slave; | |
| 454 | + | |
| 455 | + rcu_read_lock(); | |
| 456 | + slave = rcu_dereference(bond->curr_active_slave); | |
| 457 | + if (!slave) | |
| 458 | + goto out; | |
| 459 | + | |
| 460 | + if (!slave->dev->xfrmdev_ops || | |
| 461 | + !slave->dev->xfrmdev_ops->xdo_dev_state_add || | |
| 462 | + netif_is_bond_master(slave->dev)) { | |
| 463 | + spin_lock_bh(&bond->ipsec_lock); | |
| 464 | + if (!list_empty(&bond->ipsec_list)) | |
| 465 | + slave_warn(bond_dev, slave->dev, | |
| 466 | + "%s: no slave xdo_dev_state_add\n", | |
| 467 | + __func__); | |
| 468 | + spin_unlock_bh(&bond->ipsec_lock); | |
| 469 | + goto out; | |
| 470 | + } | |
| 471 | + | |
| 472 | + spin_lock_bh(&bond->ipsec_lock); | |
| 473 | + list_for_each_entry(ipsec, &bond->ipsec_list, list) { | |
| 474 | + ipsec->xs->xso.real_dev = slave->dev; | |
| 475 | + if (slave->dev->xfrmdev_ops->xdo_dev_state_add(ipsec->xs)) { | |
| 476 | + slave_warn(bond_dev, slave->dev, "%s: failed to add SA\n", __func__); | |
| 477 | + ipsec->xs->xso.real_dev = NULL; | |
| 478 | + } | |
| 479 | + } | |
| 480 | + spin_unlock_bh(&bond->ipsec_lock); | |
| 481 | +out: | |
| 482 | + rcu_read_unlock(); | |
| 422 | 483 | } |
| 423 | 484 | |
| 424 | 485 | /** |
| @@ -428,27 +489,77 @@ static int bond_ipsec_add_sa(struct xfrm_state *xs) · 3 unmodified lines | ||
| 428 | 489 | static void bond_ipsec_del_sa(struct xfrm_state *xs) |
| 429 | 490 | { |
| 430 | 491 | struct net_device *bond_dev = xs->xso.dev; |
| 492 | + struct bond_ipsec *ipsec; | |
| 431 | 493 | struct bonding *bond; |
| 432 | 494 | struct slave *slave; |
| 433 | 495 | |
| 434 | 496 | if (!bond_dev) |
| 435 | 497 | return; |
| 436 | 498 | |
| 499 | + rcu_read_lock(); | |
| 437 | 500 | bond = netdev_priv(bond_dev); |
| 438 | 501 | slave = rcu_dereference(bond->curr_active_slave); |
| 439 | 502 | |
| 440 | 503 | if (!slave) |
| 441 | − return; | |
| 504 | + goto out; | |
| 442 | 505 | |
| 443 | − xs->xso.real_dev = slave->dev; | |
| 506 | + if (!xs->xso.real_dev) | |
| 507 | + goto out; | |
| 508 | + | |
| 509 | + WARN_ON(xs->xso.real_dev != slave->dev); | |
| 444 | 510 | |
| 445 | − if (!(slave->dev->xfrmdev_ops | |
| 446 | − && slave->dev->xfrmdev_ops->xdo_dev_state_delete)) { | |
| 511 | + if (!slave->dev->xfrmdev_ops || | |
| 512 | + !slave->dev->xfrmdev_ops->xdo_dev_state_delete || | |
| 513 | + netif_is_bond_master(slave->dev)) { | |
| 447 | 514 | slave_warn(bond_dev, slave->dev, "%s: no slave xdo_dev_state_delete\n", __func__); |
| 448 | − return; | |
| 515 | + goto out; | |
| 449 | 516 | } |
| 450 | 517 | |
| 451 | 518 | slave->dev->xfrmdev_ops->xdo_dev_state_delete(xs); |
| 519 | +out: | |
| 520 | + spin_lock_bh(&bond->ipsec_lock); | |
| 521 | + list_for_each_entry(ipsec, &bond->ipsec_list, list) { | |
| 522 | + if (ipsec->xs == xs) { | |
| 523 | + list_del(&ipsec->list); | |
| 524 | + kfree(ipsec); | |
| 525 | + break; | |
| 526 | + } | |
| 527 | + } | |
| 528 | + spin_unlock_bh(&bond->ipsec_lock); | |
| 529 | + rcu_read_unlock(); | |
| 530 | +} | |
| 531 | + | |
| 532 | +static void bond_ipsec_del_sa_all(struct bonding *bond) | |
| 533 | +{ | |
| 534 | + struct net_device *bond_dev = bond->dev; | |
| 535 | + struct bond_ipsec *ipsec; | |
| 536 | + struct slave *slave; | |
| 537 | + | |
| 538 | + rcu_read_lock(); | |
| 539 | + slave = rcu_dereference(bond->curr_active_slave); | |
| 540 | + if (!slave) { | |
| 541 | + rcu_read_unlock(); | |
| 542 | + return; | |
| 543 | + } | |
| 544 | + | |
| 545 | + spin_lock_bh(&bond->ipsec_lock); | |
| 546 | + list_for_each_entry(ipsec, &bond->ipsec_list, list) { | |
| 547 | + if (!ipsec->xs->xso.real_dev) | |
| 548 | + continue; | |
| 549 | + | |
| 550 | + if (!slave->dev->xfrmdev_ops || | |
| 551 | + !slave->dev->xfrmdev_ops->xdo_dev_state_delete || | |
| 552 | + netif_is_bond_master(slave->dev)) { | |
| 553 | + slave_warn(bond_dev, slave->dev, | |
| 554 | + "%s: no slave xdo_dev_state_delete\n", | |
| 555 | + __func__); | |
| 556 | + } else { | |
| 557 | + slave->dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs); | |
| 558 | + } | |
| 559 | + ipsec->xs->xso.real_dev = NULL; | |
| 560 | + } | |
| 561 | + spin_unlock_bh(&bond->ipsec_lock); | |
| 562 | + rcu_read_unlock(); | |
| 452 | 563 | } |
| 453 | 564 | |
| 454 | 565 | /** |
| @@ -459,21 +570,37 @@ static void bond_ipsec_del_sa(struct xfrm_state *xs) · 4 unmodified lines | ||
| 459 | 570 | static bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) |
| 460 | 571 | { |
| 461 | 572 | struct net_device *bond_dev = xs->xso.dev; |
| 462 | − struct bonding *bond = netdev_priv(bond_dev); | |
| 463 | − struct slave *curr_active = rcu_dereference(bond->curr_active_slave); | |
| 464 | − struct net_device *slave_dev = curr_active->dev; | |
| 573 | + struct net_device *real_dev; | |
| 574 | + struct slave *curr_active; | |
| 575 | + struct bonding *bond; | |
| 576 | + int err; | |
| 465 | 577 | |
| 466 | − if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) | |
| 467 | − return true; | |
| 578 | + bond = netdev_priv(bond_dev); | |
| 579 | + rcu_read_lock(); | |
| 580 | + curr_active = rcu_dereference(bond->curr_active_slave); | |
| 581 | + real_dev = curr_active->dev; | |
| 468 | 582 | |
| 469 | − if (!(slave_dev->xfrmdev_ops | |
| 470 | − && slave_dev->xfrmdev_ops->xdo_dev_offload_ok)) { | |
| 471 | − slave_warn(bond_dev, slave_dev, "%s: no slave xdo_dev_offload_ok\n", __func__); | |
| 472 | − return false; | |
| 583 | + if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { | |
| 584 | + err = false; | |
| 585 | + goto out; | |
| 473 | 586 | } |
| 474 | 587 | |
| 475 | − xs->xso.real_dev = slave_dev; | |
| 476 | − return slave_dev->xfrmdev_ops->xdo_dev_offload_ok(skb, xs); | |
| 588 | + if (!xs->xso.real_dev) { | |
| 589 | + err = false; | |
| 590 | + goto out; | |
| 591 | + } | |
| 592 | + | |
| 593 | + if (!real_dev->xfrmdev_ops || | |
| 594 | + !real_dev->xfrmdev_ops->xdo_dev_offload_ok || | |
| 595 | + netif_is_bond_master(real_dev)) { | |
| 596 | + err = false; | |
| 597 | + goto out; | |
| 598 | + } | |
| 599 | + | |
| 600 | + err = real_dev->xfrmdev_ops->xdo_dev_offload_ok(skb, xs); | |
| 601 | +out: | |
| 602 | + rcu_read_unlock(); | |
| 603 | + return err; | |
| 477 | 604 | } |
| 478 | 605 | |
| 479 | 606 | static const struct xfrmdev_ops bond_xfrmdev_ops = { |
| @@ -990,8 +1117,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) · 510 unmodified lines | ||
| 990 | 1117 | return; |
| 991 | 1118 | |
| 992 | 1119 | #ifdef CONFIG_XFRM_OFFLOAD |
| 993 | − if (old_active && bond->xs) | |
| 994 | − bond_ipsec_del_sa(bond->xs); | |
| 1120 | + bond_ipsec_del_sa_all(bond); | |
| 995 | 1121 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 996 | 1122 | |
| 997 | 1123 | if (new_active) { |
| @@ -1066,10 +1192,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) · 68 unmodified lines | ||
| 1066 | 1192 | } |
| 1067 | 1193 | |
| 1068 | 1194 | #ifdef CONFIG_XFRM_OFFLOAD |
| 1069 | − if (new_active && bond->xs) { | |
| 1070 | − xfrm_dev_state_flush(dev_net(bond->dev), bond->dev, true); | |
| 1071 | − bond_ipsec_add_sa(bond->xs); | |
| 1072 | − } | |
| 1195 | + bond_ipsec_add_sa_all(bond); | |
| 1073 | 1196 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 1074 | 1197 | |
| 1075 | 1198 | /* resend IGMP joins since active slave has changed or |
| @@ -3327,6 +3450,7 @@ static int bond_master_netdev_event(unsigned long event, · 2251 unmodified lines | ||
| 3327 | 3450 | return bond_event_changename(event_bond); |
| 3328 | 3451 | case NETDEV_UNREGISTER: |
| 3329 | 3452 | bond_remove_proc_entry(event_bond); |
| 3453 | + xfrm_dev_state_flush(dev_net(bond_dev), bond_dev, true); | |
| 3330 | 3454 | break; |
| 3331 | 3455 | case NETDEV_REGISTER: |
| 3332 | 3456 | bond_create_proc_entry(event_bond); |
| @@ -4894,7 +5018,8 @@ void bond_setup(struct net_device *bond_dev) · 1561 unmodified lines | ||
| 4894 | 5018 | #ifdef CONFIG_XFRM_OFFLOAD |
| 4895 | 5019 | /* set up xfrm device ops (only supported in active-backup right now) */ |
| 4896 | 5020 | bond_dev->xfrmdev_ops = &bond_xfrmdev_ops; |
| 4897 | − bond->xs = NULL; | |
| 5021 | + INIT_LIST_HEAD(&bond->ipsec_list); | |
| 5022 | + spin_lock_init(&bond->ipsec_lock); | |
| 4898 | 5023 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 4899 | 5024 | |
| 4900 | 5025 | /* don't acquire bond device's netif_tx_lock when transmitting */ |
| @@ -20,15 +20,6 @@ config CAIF_TTY · 19 unmodified lines | ||
| 20 | 20 | identified as N_CAIF. When this ldisc is opened from user space |
| 21 | 21 | it will redirect the TTY's traffic into the CAIF stack. |
| 22 | 22 | |
| 23 | −config CAIF_HSI | |
| 24 | − tristate "CAIF HSI transport driver" | |
| 25 | − depends on CAIF | |
| 26 | − default n | |
| 27 | − help | |
| 28 | − The CAIF low level driver for CAIF over HSI. | |
| 29 | − Be aware that if you enable this then you also need to | |
| 30 | − enable a low-level HSI driver. | |
| 31 | − | |
| 32 | 23 | config CAIF_VIRTIO |
| 33 | 24 | tristate "CAIF virtio transport driver" |
| 34 | 25 | depends on CAIF && HAS_DMA |
| @@ -4,8 +4,5 @@ ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG · 3 unmodified lines | ||
| 4 | 4 | # Serial interface |
| 5 | 5 | obj-$(CONFIG_CAIF_TTY) += caif_serial.o |
| 6 | 6 | |
| 7 | −# HSI interface | |
| 8 | −obj-$(CONFIG_CAIF_HSI) += caif_hsi.o | |
| 9 | − | |
| 10 | 7 | # Virtio interface |
| 11 | 8 | obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o |
| @@ -1,1454 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Copyright (C) ST-Ericsson AB 2010 | |
| 4 | − * Author: Daniel Martensson | |
| 5 | − * Dmitry.Tarnyagin / dmitry.tarnyagin@lockless.no | |
| 6 | − */ | |
| 7 | − | |
| 8 | −#define pr_fmt(fmt) KBUILD_MODNAME fmt | |
| 9 | − | |
| 10 | −#include <linux/init.h> | |
| 11 | −#include <linux/module.h> | |
| 12 | −#include <linux/device.h> | |
| 13 | −#include <linux/netdevice.h> | |
| 14 | −#include <linux/string.h> | |
| 15 | −#include <linux/list.h> | |
| 16 | −#include <linux/interrupt.h> | |
| 17 | −#include <linux/delay.h> | |
| 18 | −#include <linux/sched.h> | |
| 19 | −#include <linux/if_arp.h> | |
| 20 | −#include <linux/timer.h> | |
| 21 | −#include <net/rtnetlink.h> | |
| 22 | −#include <linux/pkt_sched.h> | |
| 23 | −#include <net/caif/caif_layer.h> | |
| 24 | −#include <net/caif/caif_hsi.h> | |
| 25 | − | |
| 26 | −MODULE_LICENSE("GPL"); | |
| 27 | −MODULE_AUTHOR("Daniel Martensson"); | |
| 28 | −MODULE_DESCRIPTION("CAIF HSI driver"); | |
| 29 | − | |
| 30 | −/* Returns the number of padding bytes for alignment. */ | |
| 31 | −#define PAD_POW2(x, pow) ((((x)&((pow)-1)) == 0) ? 0 :\ | |
| 32 | − (((pow)-((x)&((pow)-1))))) | |
| 33 | − | |
| 34 | −static const struct cfhsi_config hsi_default_config = { | |
| 35 | − | |
| 36 | − /* Inactivity timeout on HSI, ms */ | |
| 37 | − .inactivity_timeout = HZ, | |
| 38 | − | |
| 39 | − /* Aggregation timeout (ms) of zero means no aggregation is done*/ | |
| 40 | − .aggregation_timeout = 1, | |
| 41 | − | |
| 42 | − /* | |
| 43 | − * HSI link layer flow-control thresholds. | |
| 44 | − * Threshold values for the HSI packet queue. Flow-control will be | |
| 45 | − * asserted when the number of packets exceeds q_high_mark. It will | |
| 46 | − * not be de-asserted before the number of packets drops below | |
| 47 | − * q_low_mark. | |
| 48 | − * Warning: A high threshold value might increase throughput but it | |
| 49 | − * will at the same time prevent channel prioritization and increase | |
| 50 | − * the risk of flooding the modem. The high threshold should be above | |
| 51 | − * the low. | |
| 52 | − */ | |
| 53 | − .q_high_mark = 100, | |
| 54 | − .q_low_mark = 50, | |
| 55 | − | |
| 56 | − /* | |
| 57 | − * HSI padding options. | |
| 58 | − * Warning: must be a base of 2 (& operation used) and can not be zero ! | |
| 59 | − */ | |
| 60 | − .head_align = 4, | |
| 61 | − .tail_align = 4, | |
| 62 | −}; | |
| 63 | − | |
| 64 | −#define ON 1 | |
| 65 | −#define OFF 0 | |
| 66 | − | |
| 67 | −static LIST_HEAD(cfhsi_list); | |
| 68 | − | |
| 69 | −static void cfhsi_inactivity_tout(struct timer_list *t) | |
| 70 | −{ | |
| 71 | − struct cfhsi *cfhsi = from_timer(cfhsi, t, inactivity_timer); | |
| 72 | − | |
| 73 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 74 | − __func__); | |
| 75 | − | |
| 76 | − /* Schedule power down work queue. */ | |
| 77 | − if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 78 | − queue_work(cfhsi->wq, &cfhsi->wake_down_work); | |
| 79 | −} | |
| 80 | − | |
| 81 | −static void cfhsi_update_aggregation_stats(struct cfhsi *cfhsi, | |
| 82 | − const struct sk_buff *skb, | |
| 83 | − int direction) | |
| 84 | −{ | |
| 85 | − struct caif_payload_info *info; | |
| 86 | − int hpad, tpad, len; | |
| 87 | − | |
| 88 | − info = (struct caif_payload_info *)&skb->cb; | |
| 89 | − hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align); | |
| 90 | − tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align); | |
| 91 | − len = skb->len + hpad + tpad; | |
| 92 | − | |
| 93 | − if (direction > 0) | |
| 94 | − cfhsi->aggregation_len += len; | |
| 95 | − else if (direction < 0) | |
| 96 | − cfhsi->aggregation_len -= len; | |
| 97 | −} | |
| 98 | − | |
| 99 | −static bool cfhsi_can_send_aggregate(struct cfhsi *cfhsi) | |
| 100 | −{ | |
| 101 | − int i; | |
| 102 | − | |
| 103 | − if (cfhsi->cfg.aggregation_timeout == 0) | |
| 104 | − return true; | |
| 105 | − | |
| 106 | − for (i = 0; i < CFHSI_PRIO_BEBK; ++i) { | |
| 107 | − if (cfhsi->qhead[i].qlen) | |
| 108 | − return true; | |
| 109 | − } | |
| 110 | − | |
| 111 | − /* TODO: Use aggregation_len instead */ | |
| 112 | − if (cfhsi->qhead[CFHSI_PRIO_BEBK].qlen >= CFHSI_MAX_PKTS) | |
| 113 | − return true; | |
| 114 | − | |
| 115 | − return false; | |
| 116 | −} | |
| 117 | − | |
| 118 | −static struct sk_buff *cfhsi_dequeue(struct cfhsi *cfhsi) | |
| 119 | −{ | |
| 120 | − struct sk_buff *skb; | |
| 121 | − int i; | |
| 122 | − | |
| 123 | − for (i = 0; i < CFHSI_PRIO_LAST; ++i) { | |
| 124 | − skb = skb_dequeue(&cfhsi->qhead[i]); | |
| 125 | − if (skb) | |
| 126 | − break; | |
| 127 | − } | |
| 128 | − | |
| 129 | − return skb; | |
| 130 | −} | |
| 131 | − | |
| 132 | −static int cfhsi_tx_queue_len(struct cfhsi *cfhsi) | |
| 133 | −{ | |
| 134 | − int i, len = 0; | |
| 135 | − for (i = 0; i < CFHSI_PRIO_LAST; ++i) | |
| 136 | − len += skb_queue_len(&cfhsi->qhead[i]); | |
| 137 | − return len; | |
| 138 | −} | |
| 139 | − | |
| 140 | −static void cfhsi_abort_tx(struct cfhsi *cfhsi) | |
| 141 | −{ | |
| 142 | − struct sk_buff *skb; | |
| 143 | − | |
| 144 | − for (;;) { | |
| 145 | − spin_lock_bh(&cfhsi->lock); | |
| 146 | − skb = cfhsi_dequeue(cfhsi); | |
| 147 | − if (!skb) | |
| 148 | − break; | |
| 149 | − | |
| 150 | − cfhsi->ndev->stats.tx_errors++; | |
| 151 | − cfhsi->ndev->stats.tx_dropped++; | |
| 152 | − cfhsi_update_aggregation_stats(cfhsi, skb, -1); | |
| 153 | − spin_unlock_bh(&cfhsi->lock); | |
| 154 | − kfree_skb(skb); | |
| 155 | − } | |
| 156 | − cfhsi->tx_state = CFHSI_TX_STATE_IDLE; | |
| 157 | − if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 158 | − mod_timer(&cfhsi->inactivity_timer, | |
| 159 | − jiffies + cfhsi->cfg.inactivity_timeout); | |
| 160 | − spin_unlock_bh(&cfhsi->lock); | |
| 161 | −} | |
| 162 | − | |
| 163 | −static int cfhsi_flush_fifo(struct cfhsi *cfhsi) | |
| 164 | −{ | |
| 165 | − char buffer[32]; /* Any reasonable value */ | |
| 166 | − size_t fifo_occupancy; | |
| 167 | − int ret; | |
| 168 | − | |
| 169 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 170 | − __func__); | |
| 171 | − | |
| 172 | − do { | |
| 173 | − ret = cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops, | |
| 174 | − &fifo_occupancy); | |
| 175 | − if (ret) { | |
| 176 | − netdev_warn(cfhsi->ndev, | |
| 177 | − "%s: can't get FIFO occupancy: %d.\n", | |
| 178 | − __func__, ret); | |
| 179 | − break; | |
| 180 | − } else if (!fifo_occupancy) | |
| 181 | − /* No more data, exitting normally */ | |
| 182 | − break; | |
| 183 | − | |
| 184 | − fifo_occupancy = min(sizeof(buffer), fifo_occupancy); | |
| 185 | − set_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits); | |
| 186 | − ret = cfhsi->ops->cfhsi_rx(buffer, fifo_occupancy, | |
| 187 | − cfhsi->ops); | |
| 188 | − if (ret) { | |
| 189 | − clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits); | |
| 190 | − netdev_warn(cfhsi->ndev, | |
| 191 | − "%s: can't read data: %d.\n", | |
| 192 | − __func__, ret); | |
| 193 | − break; | |
| 194 | − } | |
| 195 | − | |
| 196 | − ret = 5 * HZ; | |
| 197 | − ret = wait_event_interruptible_timeout(cfhsi->flush_fifo_wait, | |
| 198 | − !test_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits), ret); | |
| 199 | − | |
| 200 | − if (ret < 0) { | |
| 201 | − netdev_warn(cfhsi->ndev, | |
| 202 | − "%s: can't wait for flush complete: %d.\n", | |
| 203 | − __func__, ret); | |
| 204 | − break; | |
| 205 | − } else if (!ret) { | |
| 206 | − ret = -ETIMEDOUT; | |
| 207 | − netdev_warn(cfhsi->ndev, | |
| 208 | − "%s: timeout waiting for flush complete.\n", | |
| 209 | − __func__); | |
| 210 | − break; | |
| 211 | − } | |
| 212 | − } while (1); | |
| 213 | − | |
| 214 | − return ret; | |
| 215 | −} | |
| 216 | − | |
| 217 | −static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi) | |
| 218 | −{ | |
| 219 | − int nfrms = 0; | |
| 220 | − int pld_len = 0; | |
| 221 | − struct sk_buff *skb; | |
| 222 | − u8 *pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ; | |
| 223 | − | |
| 224 | − skb = cfhsi_dequeue(cfhsi); | |
| 225 | − if (!skb) | |
| 226 | − return 0; | |
| 227 | − | |
| 228 | − /* Clear offset. */ | |
| 229 | − desc->offset = 0; | |
| 230 | − | |
| 231 | − /* Check if we can embed a CAIF frame. */ | |
| 232 | − if (skb->len < CFHSI_MAX_EMB_FRM_SZ) { | |
| 233 | − struct caif_payload_info *info; | |
| 234 | − int hpad; | |
| 235 | − int tpad; | |
| 236 | − | |
| 237 | − /* Calculate needed head alignment and tail alignment. */ | |
| 238 | − info = (struct caif_payload_info *)&skb->cb; | |
| 239 | − | |
| 240 | − hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align); | |
| 241 | − tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align); | |
| 242 | − | |
| 243 | − /* Check if frame still fits with added alignment. */ | |
| 244 | − if ((skb->len + hpad + tpad) <= CFHSI_MAX_EMB_FRM_SZ) { | |
| 245 | − u8 *pemb = desc->emb_frm; | |
| 246 | − desc->offset = CFHSI_DESC_SHORT_SZ; | |
| 247 | − *pemb = (u8)(hpad - 1); | |
| 248 | − pemb += hpad; | |
| 249 | − | |
| 250 | − /* Update network statistics. */ | |
| 251 | − spin_lock_bh(&cfhsi->lock); | |
| 252 | − cfhsi->ndev->stats.tx_packets++; | |
| 253 | − cfhsi->ndev->stats.tx_bytes += skb->len; | |
| 254 | − cfhsi_update_aggregation_stats(cfhsi, skb, -1); | |
| 255 | − spin_unlock_bh(&cfhsi->lock); | |
| 256 | − | |
| 257 | − /* Copy in embedded CAIF frame. */ | |
| 258 | − skb_copy_bits(skb, 0, pemb, skb->len); | |
| 259 | − | |
| 260 | − /* Consume the SKB */ | |
| 261 | − consume_skb(skb); | |
| 262 | − skb = NULL; | |
| 263 | − } | |
| 264 | − } | |
| 265 | − | |
| 266 | − /* Create payload CAIF frames. */ | |
| 267 | − while (nfrms < CFHSI_MAX_PKTS) { | |
| 268 | − struct caif_payload_info *info; | |
| 269 | − int hpad; | |
| 270 | − int tpad; | |
| 271 | − | |
| 272 | − if (!skb) | |
| 273 | − skb = cfhsi_dequeue(cfhsi); | |
| 274 | − | |
| 275 | − if (!skb) | |
| 276 | − break; | |
| 277 | − | |
| 278 | − /* Calculate needed head alignment and tail alignment. */ | |
| 279 | − info = (struct caif_payload_info *)&skb->cb; | |
| 280 | − | |
| 281 | − hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align); | |
| 282 | − tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align); | |
| 283 | − | |
| 284 | − /* Fill in CAIF frame length in descriptor. */ | |
| 285 | − desc->cffrm_len[nfrms] = hpad + skb->len + tpad; | |
| 286 | − | |
| 287 | − /* Fill head padding information. */ | |
| 288 | − *pfrm = (u8)(hpad - 1); | |
| 289 | − pfrm += hpad; | |
| 290 | − | |
| 291 | − /* Update network statistics. */ | |
| 292 | − spin_lock_bh(&cfhsi->lock); | |
| 293 | − cfhsi->ndev->stats.tx_packets++; | |
| 294 | − cfhsi->ndev->stats.tx_bytes += skb->len; | |
| 295 | − cfhsi_update_aggregation_stats(cfhsi, skb, -1); | |
| 296 | − spin_unlock_bh(&cfhsi->lock); | |
| 297 | − | |
| 298 | − /* Copy in CAIF frame. */ | |
| 299 | − skb_copy_bits(skb, 0, pfrm, skb->len); | |
| 300 | − | |
| 301 | − /* Update payload length. */ | |
| 302 | − pld_len += desc->cffrm_len[nfrms]; | |
| 303 | − | |
| 304 | − /* Update frame pointer. */ | |
| 305 | − pfrm += skb->len + tpad; | |
| 306 | − | |
| 307 | − /* Consume the SKB */ | |
| 308 | − consume_skb(skb); | |
| 309 | − skb = NULL; | |
| 310 | − | |
| 311 | − /* Update number of frames. */ | |
| 312 | − nfrms++; | |
| 313 | − } | |
| 314 | − | |
| 315 | − /* Unused length fields should be zero-filled (according to SPEC). */ | |
| 316 | − while (nfrms < CFHSI_MAX_PKTS) { | |
| 317 | − desc->cffrm_len[nfrms] = 0x0000; | |
| 318 | − nfrms++; | |
| 319 | − } | |
| 320 | − | |
| 321 | − /* Check if we can piggy-back another descriptor. */ | |
| 322 | − if (cfhsi_can_send_aggregate(cfhsi)) | |
| 323 | − desc->header |= CFHSI_PIGGY_DESC; | |
| 324 | − else | |
| 325 | − desc->header &= ~CFHSI_PIGGY_DESC; | |
| 326 | − | |
| 327 | − return CFHSI_DESC_SZ + pld_len; | |
| 328 | −} | |
| 329 | − | |
| 330 | −static void cfhsi_start_tx(struct cfhsi *cfhsi) | |
| 331 | −{ | |
| 332 | − struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf; | |
| 333 | − int len, res; | |
| 334 | − | |
| 335 | − netdev_dbg(cfhsi->ndev, "%s.\n", __func__); | |
| 336 | − | |
| 337 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 338 | − return; | |
| 339 | − | |
| 340 | − do { | |
| 341 | − /* Create HSI frame. */ | |
| 342 | − len = cfhsi_tx_frm(desc, cfhsi); | |
| 343 | − if (!len) { | |
| 344 | − spin_lock_bh(&cfhsi->lock); | |
| 345 | − if (unlikely(cfhsi_tx_queue_len(cfhsi))) { | |
| 346 | − spin_unlock_bh(&cfhsi->lock); | |
| 347 | − res = -EAGAIN; | |
| 348 | − continue; | |
| 349 | − } | |
| 350 | − cfhsi->tx_state = CFHSI_TX_STATE_IDLE; | |
| 351 | − /* Start inactivity timer. */ | |
| 352 | − mod_timer(&cfhsi->inactivity_timer, | |
| 353 | − jiffies + cfhsi->cfg.inactivity_timeout); | |
| 354 | − spin_unlock_bh(&cfhsi->lock); | |
| 355 | − break; | |
| 356 | − } | |
| 357 | − | |
| 358 | − /* Set up new transfer. */ | |
| 359 | − res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops); | |
| 360 | − if (WARN_ON(res < 0)) | |
| 361 | − netdev_err(cfhsi->ndev, "%s: TX error %d.\n", | |
| 362 | − __func__, res); | |
| 363 | − } while (res < 0); | |
| 364 | −} | |
| 365 | − | |
| 366 | −static void cfhsi_tx_done(struct cfhsi *cfhsi) | |
| 367 | −{ | |
| 368 | − netdev_dbg(cfhsi->ndev, "%s.\n", __func__); | |
| 369 | − | |
| 370 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 371 | − return; | |
| 372 | − | |
| 373 | − /* | |
| 374 | − * Send flow on if flow off has been previously signalled | |
| 375 | − * and number of packets is below low water mark. | |
| 376 | − */ | |
| 377 | − spin_lock_bh(&cfhsi->lock); | |
| 378 | − if (cfhsi->flow_off_sent && | |
| 379 | − cfhsi_tx_queue_len(cfhsi) <= cfhsi->cfg.q_low_mark && | |
| 380 | − cfhsi->cfdev.flowctrl) { | |
| 381 | − | |
| 382 | − cfhsi->flow_off_sent = 0; | |
| 383 | − cfhsi->cfdev.flowctrl(cfhsi->ndev, ON); | |
| 384 | − } | |
| 385 | − | |
| 386 | − if (cfhsi_can_send_aggregate(cfhsi)) { | |
| 387 | − spin_unlock_bh(&cfhsi->lock); | |
| 388 | − cfhsi_start_tx(cfhsi); | |
| 389 | − } else { | |
| 390 | − mod_timer(&cfhsi->aggregation_timer, | |
| 391 | − jiffies + cfhsi->cfg.aggregation_timeout); | |
| 392 | − spin_unlock_bh(&cfhsi->lock); | |
| 393 | − } | |
| 394 | − | |
| 395 | − return; | |
| 396 | −} | |
| 397 | − | |
| 398 | −static void cfhsi_tx_done_cb(struct cfhsi_cb_ops *cb_ops) | |
| 399 | −{ | |
| 400 | − struct cfhsi *cfhsi; | |
| 401 | − | |
| 402 | − cfhsi = container_of(cb_ops, struct cfhsi, cb_ops); | |
| 403 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 404 | − __func__); | |
| 405 | − | |
| 406 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 407 | − return; | |
| 408 | − cfhsi_tx_done(cfhsi); | |
| 409 | −} | |
| 410 | − | |
| 411 | −static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi) | |
| 412 | −{ | |
| 413 | − int xfer_sz = 0; | |
| 414 | − int nfrms = 0; | |
| 415 | − u16 *plen = NULL; | |
| 416 | − u8 *pfrm = NULL; | |
| 417 | − | |
| 418 | − if ((desc->header & ~CFHSI_PIGGY_DESC) || | |
| 419 | − (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) { | |
| 420 | − netdev_err(cfhsi->ndev, "%s: Invalid descriptor.\n", | |
| 421 | − __func__); | |
| 422 | − return -EPROTO; | |
| 423 | − } | |
| 424 | − | |
| 425 | − /* Check for embedded CAIF frame. */ | |
| 426 | − if (desc->offset) { | |
| 427 | − struct sk_buff *skb; | |
| 428 | − int len = 0; | |
| 429 | − pfrm = ((u8 *)desc) + desc->offset; | |
| 430 | − | |
| 431 | − /* Remove offset padding. */ | |
| 432 | − pfrm += *pfrm + 1; | |
| 433 | − | |
| 434 | − /* Read length of CAIF frame (little endian). */ | |
| 435 | − len = *pfrm; | |
| 436 | − len |= ((*(pfrm+1)) << 8) & 0xFF00; | |
| 437 | − len += 2; /* Add FCS fields. */ | |
| 438 | − | |
| 439 | − /* Sanity check length of CAIF frame. */ | |
| 440 | − if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) { | |
| 441 | − netdev_err(cfhsi->ndev, "%s: Invalid length.\n", | |
| 442 | − __func__); | |
| 443 | − return -EPROTO; | |
| 444 | − } | |
| 445 | − | |
| 446 | − /* Allocate SKB (OK even in IRQ context). */ | |
| 447 | − skb = alloc_skb(len + 1, GFP_ATOMIC); | |
| 448 | − if (!skb) { | |
| 449 | − netdev_err(cfhsi->ndev, "%s: Out of memory !\n", | |
| 450 | − __func__); | |
| 451 | − return -ENOMEM; | |
| 452 | − } | |
| 453 | − caif_assert(skb != NULL); | |
| 454 | − | |
| 455 | − skb_put_data(skb, pfrm, len); | |
| 456 | − | |
| 457 | − skb->protocol = htons(ETH_P_CAIF); | |
| 458 | − skb_reset_mac_header(skb); | |
| 459 | − skb->dev = cfhsi->ndev; | |
| 460 | − | |
| 461 | − netif_rx_any_context(skb); | |
| 462 | − | |
| 463 | − /* Update network statistics. */ | |
| 464 | − cfhsi->ndev->stats.rx_packets++; | |
| 465 | − cfhsi->ndev->stats.rx_bytes += len; | |
| 466 | − } | |
| 467 | − | |
| 468 | − /* Calculate transfer length. */ | |
| 469 | − plen = desc->cffrm_len; | |
| 470 | − while (nfrms < CFHSI_MAX_PKTS && *plen) { | |
| 471 | − xfer_sz += *plen; | |
| 472 | − plen++; | |
| 473 | − nfrms++; | |
| 474 | − } | |
| 475 | − | |
| 476 | − /* Check for piggy-backed descriptor. */ | |
| 477 | − if (desc->header & CFHSI_PIGGY_DESC) | |
| 478 | − xfer_sz += CFHSI_DESC_SZ; | |
| 479 | − | |
| 480 | − if ((xfer_sz % 4) || (xfer_sz > (CFHSI_BUF_SZ_RX - CFHSI_DESC_SZ))) { | |
| 481 | − netdev_err(cfhsi->ndev, | |
| 482 | − "%s: Invalid payload len: %d, ignored.\n", | |
| 483 | − __func__, xfer_sz); | |
| 484 | − return -EPROTO; | |
| 485 | − } | |
| 486 | − return xfer_sz; | |
| 487 | −} | |
| 488 | − | |
| 489 | −static int cfhsi_rx_desc_len(struct cfhsi_desc *desc) | |
| 490 | −{ | |
| 491 | − int xfer_sz = 0; | |
| 492 | − int nfrms = 0; | |
| 493 | − u16 *plen; | |
| 494 | − | |
| 495 | − if ((desc->header & ~CFHSI_PIGGY_DESC) || | |
| 496 | − (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) { | |
| 497 | − | |
| 498 | − pr_err("Invalid descriptor. %x %x\n", desc->header, | |
| 499 | − desc->offset); | |
| 500 | − return -EPROTO; | |
| 501 | − } | |
| 502 | − | |
| 503 | − /* Calculate transfer length. */ | |
| 504 | − plen = desc->cffrm_len; | |
| 505 | − while (nfrms < CFHSI_MAX_PKTS && *plen) { | |
| 506 | − xfer_sz += *plen; | |
| 507 | − plen++; | |
| 508 | − nfrms++; | |
| 509 | − } | |
| 510 | − | |
| 511 | − if (xfer_sz % 4) { | |
| 512 | − pr_err("Invalid payload len: %d, ignored.\n", xfer_sz); | |
| 513 | − return -EPROTO; | |
| 514 | − } | |
| 515 | − return xfer_sz; | |
| 516 | −} | |
| 517 | − | |
| 518 | −static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) | |
| 519 | −{ | |
| 520 | − int rx_sz = 0; | |
| 521 | − int nfrms = 0; | |
| 522 | − u16 *plen = NULL; | |
| 523 | − u8 *pfrm = NULL; | |
| 524 | − | |
| 525 | − /* Sanity check header and offset. */ | |
| 526 | − if (WARN_ON((desc->header & ~CFHSI_PIGGY_DESC) || | |
| 527 | − (desc->offset > CFHSI_MAX_EMB_FRM_SZ))) { | |
| 528 | − netdev_err(cfhsi->ndev, "%s: Invalid descriptor.\n", | |
| 529 | − __func__); | |
| 530 | − return -EPROTO; | |
| 531 | − } | |
| 532 | − | |
| 533 | − /* Set frame pointer to start of payload. */ | |
| 534 | − pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ; | |
| 535 | − plen = desc->cffrm_len; | |
| 536 | − | |
| 537 | − /* Skip already processed frames. */ | |
| 538 | − while (nfrms < cfhsi->rx_state.nfrms) { | |
| 539 | − pfrm += *plen; | |
| 540 | − rx_sz += *plen; | |
| 541 | − plen++; | |
| 542 | − nfrms++; | |
| 543 | − } | |
| 544 | − | |
| 545 | − /* Parse payload. */ | |
| 546 | − while (nfrms < CFHSI_MAX_PKTS && *plen) { | |
| 547 | − struct sk_buff *skb; | |
| 548 | − u8 *pcffrm = NULL; | |
| 549 | − int len; | |
| 550 | − | |
| 551 | − /* CAIF frame starts after head padding. */ | |
| 552 | − pcffrm = pfrm + *pfrm + 1; | |
| 553 | − | |
| 554 | − /* Read length of CAIF frame (little endian). */ | |
| 555 | − len = *pcffrm; | |
| 556 | − len |= ((*(pcffrm + 1)) << 8) & 0xFF00; | |
| 557 | − len += 2; /* Add FCS fields. */ | |
| 558 | − | |
| 559 | − /* Sanity check length of CAIF frames. */ | |
| 560 | − if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) { | |
| 561 | − netdev_err(cfhsi->ndev, "%s: Invalid length.\n", | |
| 562 | − __func__); | |
| 563 | − return -EPROTO; | |
| 564 | − } | |
| 565 | − | |
| 566 | − /* Allocate SKB (OK even in IRQ context). */ | |
| 567 | − skb = alloc_skb(len + 1, GFP_ATOMIC); | |
| 568 | − if (!skb) { | |
| 569 | − netdev_err(cfhsi->ndev, "%s: Out of memory !\n", | |
| 570 | − __func__); | |
| 571 | − cfhsi->rx_state.nfrms = nfrms; | |
| 572 | − return -ENOMEM; | |
| 573 | − } | |
| 574 | − caif_assert(skb != NULL); | |
| 575 | − | |
| 576 | − skb_put_data(skb, pcffrm, len); | |
| 577 | − | |
| 578 | − skb->protocol = htons(ETH_P_CAIF); | |
| 579 | − skb_reset_mac_header(skb); | |
| 580 | − skb->dev = cfhsi->ndev; | |
| 581 | − | |
| 582 | − netif_rx_any_context(skb); | |
| 583 | − | |
| 584 | − /* Update network statistics. */ | |
| 585 | − cfhsi->ndev->stats.rx_packets++; | |
| 586 | − cfhsi->ndev->stats.rx_bytes += len; | |
| 587 | − | |
| 588 | − pfrm += *plen; | |
| 589 | − rx_sz += *plen; | |
| 590 | − plen++; | |
| 591 | − nfrms++; | |
| 592 | − } | |
| 593 | − | |
| 594 | − return rx_sz; | |
| 595 | −} | |
| 596 | − | |
| 597 | −static void cfhsi_rx_done(struct cfhsi *cfhsi) | |
| 598 | −{ | |
| 599 | − int res; | |
| 600 | − int desc_pld_len = 0, rx_len, rx_state; | |
| 601 | − struct cfhsi_desc *desc = NULL; | |
| 602 | − u8 *rx_ptr, *rx_buf; | |
| 603 | − struct cfhsi_desc *piggy_desc = NULL; | |
| 604 | − | |
| 605 | − desc = (struct cfhsi_desc *)cfhsi->rx_buf; | |
| 606 | − | |
| 607 | − netdev_dbg(cfhsi->ndev, "%s\n", __func__); | |
| 608 | − | |
| 609 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 610 | − return; | |
| 611 | − | |
| 612 | − /* Update inactivity timer if pending. */ | |
| 613 | − spin_lock_bh(&cfhsi->lock); | |
| 614 | − mod_timer_pending(&cfhsi->inactivity_timer, | |
| 615 | − jiffies + cfhsi->cfg.inactivity_timeout); | |
| 616 | − spin_unlock_bh(&cfhsi->lock); | |
| 617 | − | |
| 618 | − if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) { | |
| 619 | − desc_pld_len = cfhsi_rx_desc_len(desc); | |
| 620 | − | |
| 621 | − if (desc_pld_len < 0) | |
| 622 | − goto out_of_sync; | |
| 623 | − | |
| 624 | − rx_buf = cfhsi->rx_buf; | |
| 625 | − rx_len = desc_pld_len; | |
| 626 | − if (desc_pld_len > 0 && (desc->header & CFHSI_PIGGY_DESC)) | |
| 627 | − rx_len += CFHSI_DESC_SZ; | |
| 628 | − if (desc_pld_len == 0) | |
| 629 | − rx_buf = cfhsi->rx_flip_buf; | |
| 630 | − } else { | |
| 631 | − rx_buf = cfhsi->rx_flip_buf; | |
| 632 | − | |
| 633 | − rx_len = CFHSI_DESC_SZ; | |
| 634 | − if (cfhsi->rx_state.pld_len > 0 && | |
| 635 | − (desc->header & CFHSI_PIGGY_DESC)) { | |
| 636 | − | |
| 637 | − piggy_desc = (struct cfhsi_desc *) | |
| 638 | − (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ + | |
| 639 | − cfhsi->rx_state.pld_len); | |
| 640 | − | |
| 641 | − cfhsi->rx_state.piggy_desc = true; | |
| 642 | − | |
| 643 | − /* Extract payload len from piggy-backed descriptor. */ | |
| 644 | − desc_pld_len = cfhsi_rx_desc_len(piggy_desc); | |
| 645 | − if (desc_pld_len < 0) | |
| 646 | − goto out_of_sync; | |
| 647 | − | |
| 648 | − if (desc_pld_len > 0) { | |
| 649 | − rx_len = desc_pld_len; | |
| 650 | − if (piggy_desc->header & CFHSI_PIGGY_DESC) | |
| 651 | − rx_len += CFHSI_DESC_SZ; | |
| 652 | − } | |
| 653 | − | |
| 654 | − /* | |
| 655 | − * Copy needed information from the piggy-backed | |
| 656 | − * descriptor to the descriptor in the start. | |
| 657 | − */ | |
| 658 | − memcpy(rx_buf, (u8 *)piggy_desc, | |
| 659 | − CFHSI_DESC_SHORT_SZ); | |
| 660 | − } | |
| 661 | − } | |
| 662 | − | |
| 663 | − if (desc_pld_len) { | |
| 664 | − rx_state = CFHSI_RX_STATE_PAYLOAD; | |
| 665 | − rx_ptr = rx_buf + CFHSI_DESC_SZ; | |
| 666 | − } else { | |
| 667 | − rx_state = CFHSI_RX_STATE_DESC; | |
| 668 | − rx_ptr = rx_buf; | |
| 669 | − rx_len = CFHSI_DESC_SZ; | |
| 670 | − } | |
| 671 | − | |
| 672 | − /* Initiate next read */ | |
| 673 | − if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) { | |
| 674 | − /* Set up new transfer. */ | |
| 675 | − netdev_dbg(cfhsi->ndev, "%s: Start RX.\n", | |
| 676 | − __func__); | |
| 677 | − | |
| 678 | − res = cfhsi->ops->cfhsi_rx(rx_ptr, rx_len, | |
| 679 | − cfhsi->ops); | |
| 680 | − if (WARN_ON(res < 0)) { | |
| 681 | − netdev_err(cfhsi->ndev, "%s: RX error %d.\n", | |
| 682 | − __func__, res); | |
| 683 | − cfhsi->ndev->stats.rx_errors++; | |
| 684 | − cfhsi->ndev->stats.rx_dropped++; | |
| 685 | − } | |
| 686 | − } | |
| 687 | − | |
| 688 | − if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) { | |
| 689 | − /* Extract payload from descriptor */ | |
| 690 | − if (cfhsi_rx_desc(desc, cfhsi) < 0) | |
| 691 | − goto out_of_sync; | |
| 692 | − } else { | |
| 693 | − /* Extract payload */ | |
| 694 | − if (cfhsi_rx_pld(desc, cfhsi) < 0) | |
| 695 | − goto out_of_sync; | |
| 696 | − if (piggy_desc) { | |
| 697 | − /* Extract any payload in piggyback descriptor. */ | |
| 698 | − if (cfhsi_rx_desc(piggy_desc, cfhsi) < 0) | |
| 699 | − goto out_of_sync; | |
| 700 | − /* Mark no embedded frame after extracting it */ | |
| 701 | − piggy_desc->offset = 0; | |
| 702 | − } | |
| 703 | − } | |
| 704 | − | |
| 705 | − /* Update state info */ | |
| 706 | − memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state)); | |
| 707 | − cfhsi->rx_state.state = rx_state; | |
| 708 | − cfhsi->rx_ptr = rx_ptr; | |
| 709 | − cfhsi->rx_len = rx_len; | |
| 710 | − cfhsi->rx_state.pld_len = desc_pld_len; | |
| 711 | − cfhsi->rx_state.piggy_desc = desc->header & CFHSI_PIGGY_DESC; | |
| 712 | − | |
| 713 | − if (rx_buf != cfhsi->rx_buf) | |
| 714 | − swap(cfhsi->rx_buf, cfhsi->rx_flip_buf); | |
| 715 | − return; | |
| 716 | − | |
| 717 | −out_of_sync: | |
| 718 | − netdev_err(cfhsi->ndev, "%s: Out of sync.\n", __func__); | |
| 719 | − print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE, | |
| 720 | − cfhsi->rx_buf, CFHSI_DESC_SZ); | |
| 721 | − schedule_work(&cfhsi->out_of_sync_work); | |
| 722 | −} | |
| 723 | − | |
| 724 | −static void cfhsi_rx_slowpath(struct timer_list *t) | |
| 725 | −{ | |
| 726 | − struct cfhsi *cfhsi = from_timer(cfhsi, t, rx_slowpath_timer); | |
| 727 | − | |
| 728 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 729 | − __func__); | |
| 730 | − | |
| 731 | − cfhsi_rx_done(cfhsi); | |
| 732 | −} | |
| 733 | − | |
| 734 | −static void cfhsi_rx_done_cb(struct cfhsi_cb_ops *cb_ops) | |
| 735 | −{ | |
| 736 | − struct cfhsi *cfhsi; | |
| 737 | − | |
| 738 | − cfhsi = container_of(cb_ops, struct cfhsi, cb_ops); | |
| 739 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 740 | − __func__); | |
| 741 | − | |
| 742 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 743 | − return; | |
| 744 | − | |
| 745 | − if (test_and_clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits)) | |
| 746 | − wake_up_interruptible(&cfhsi->flush_fifo_wait); | |
| 747 | − else | |
| 748 | − cfhsi_rx_done(cfhsi); | |
| 749 | −} | |
| 750 | − | |
| 751 | −static void cfhsi_wake_up(struct work_struct *work) | |
| 752 | −{ | |
| 753 | − struct cfhsi *cfhsi = NULL; | |
| 754 | − int res; | |
| 755 | − int len; | |
| 756 | − long ret; | |
| 757 | − | |
| 758 | − cfhsi = container_of(work, struct cfhsi, wake_up_work); | |
| 759 | − | |
| 760 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 761 | − return; | |
| 762 | − | |
| 763 | − if (unlikely(test_bit(CFHSI_AWAKE, &cfhsi->bits))) { | |
| 764 | − /* It happenes when wakeup is requested by | |
| 765 | − * both ends at the same time. */ | |
| 766 | − clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); | |
| 767 | − clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); | |
| 768 | − return; | |
| 769 | − } | |
| 770 | − | |
| 771 | − /* Activate wake line. */ | |
| 772 | − cfhsi->ops->cfhsi_wake_up(cfhsi->ops); | |
| 773 | − | |
| 774 | − netdev_dbg(cfhsi->ndev, "%s: Start waiting.\n", | |
| 775 | − __func__); | |
| 776 | − | |
| 777 | − /* Wait for acknowledge. */ | |
| 778 | − ret = CFHSI_WAKE_TOUT; | |
| 779 | − ret = wait_event_interruptible_timeout(cfhsi->wake_up_wait, | |
| 780 | − test_and_clear_bit(CFHSI_WAKE_UP_ACK, | |
| 781 | − &cfhsi->bits), ret); | |
| 782 | − if (unlikely(ret < 0)) { | |
| 783 | − /* Interrupted by signal. */ | |
| 784 | − netdev_err(cfhsi->ndev, "%s: Signalled: %ld.\n", | |
| 785 | − __func__, ret); | |
| 786 | − | |
| 787 | − clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); | |
| 788 | − cfhsi->ops->cfhsi_wake_down(cfhsi->ops); | |
| 789 | − return; | |
| 790 | − } else if (!ret) { | |
| 791 | − bool ca_wake = false; | |
| 792 | − size_t fifo_occupancy = 0; | |
| 793 | − | |
| 794 | − /* Wakeup timeout */ | |
| 795 | − netdev_dbg(cfhsi->ndev, "%s: Timeout.\n", | |
| 796 | − __func__); | |
| 797 | − | |
| 798 | − /* Check FIFO to check if modem has sent something. */ | |
| 799 | − WARN_ON(cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops, | |
| 800 | − &fifo_occupancy)); | |
| 801 | − | |
| 802 | − netdev_dbg(cfhsi->ndev, "%s: Bytes in FIFO: %u.\n", | |
| 803 | − __func__, (unsigned) fifo_occupancy); | |
| 804 | − | |
| 805 | − /* Check if we misssed the interrupt. */ | |
| 806 | − WARN_ON(cfhsi->ops->cfhsi_get_peer_wake(cfhsi->ops, | |
| 807 | − &ca_wake)); | |
| 808 | − | |
| 809 | − if (ca_wake) { | |
| 810 | − netdev_err(cfhsi->ndev, "%s: CA Wake missed !.\n", | |
| 811 | − __func__); | |
| 812 | − | |
| 813 | − /* Clear the CFHSI_WAKE_UP_ACK bit to prevent race. */ | |
| 814 | − clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); | |
| 815 | − | |
| 816 | − /* Continue execution. */ | |
| 817 | − goto wake_ack; | |
| 818 | − } | |
| 819 | − | |
| 820 | − clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); | |
| 821 | − cfhsi->ops->cfhsi_wake_down(cfhsi->ops); | |
| 822 | − return; | |
| 823 | − } | |
| 824 | −wake_ack: | |
| 825 | − netdev_dbg(cfhsi->ndev, "%s: Woken.\n", | |
| 826 | − __func__); | |
| 827 | − | |
| 828 | − /* Clear power up bit. */ | |
| 829 | − set_bit(CFHSI_AWAKE, &cfhsi->bits); | |
| 830 | − clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); | |
| 831 | − | |
| 832 | − /* Resume read operation. */ | |
| 833 | − netdev_dbg(cfhsi->ndev, "%s: Start RX.\n", __func__); | |
| 834 | − res = cfhsi->ops->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, cfhsi->ops); | |
| 835 | − | |
| 836 | − if (WARN_ON(res < 0)) | |
| 837 | − netdev_err(cfhsi->ndev, "%s: RX err %d.\n", __func__, res); | |
| 838 | − | |
| 839 | − /* Clear power up acknowledment. */ | |
| 840 | − clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); | |
| 841 | − | |
| 842 | − spin_lock_bh(&cfhsi->lock); | |
| 843 | − | |
| 844 | − /* Resume transmit if queues are not empty. */ | |
| 845 | − if (!cfhsi_tx_queue_len(cfhsi)) { | |
| 846 | − netdev_dbg(cfhsi->ndev, "%s: Peer wake, start timer.\n", | |
| 847 | − __func__); | |
| 848 | − /* Start inactivity timer. */ | |
| 849 | − mod_timer(&cfhsi->inactivity_timer, | |
| 850 | − jiffies + cfhsi->cfg.inactivity_timeout); | |
| 851 | − spin_unlock_bh(&cfhsi->lock); | |
| 852 | − return; | |
| 853 | − } | |
| 854 | − | |
| 855 | − netdev_dbg(cfhsi->ndev, "%s: Host wake.\n", | |
| 856 | − __func__); | |
| 857 | − | |
| 858 | − spin_unlock_bh(&cfhsi->lock); | |
| 859 | − | |
| 860 | − /* Create HSI frame. */ | |
| 861 | − len = cfhsi_tx_frm((struct cfhsi_desc *)cfhsi->tx_buf, cfhsi); | |
| 862 | − | |
| 863 | − if (likely(len > 0)) { | |
| 864 | − /* Set up new transfer. */ | |
| 865 | − res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops); | |
| 866 | − if (WARN_ON(res < 0)) { | |
| 867 | − netdev_err(cfhsi->ndev, "%s: TX error %d.\n", | |
| 868 | − __func__, res); | |
| 869 | − cfhsi_abort_tx(cfhsi); | |
| 870 | − } | |
| 871 | − } else { | |
| 872 | − netdev_err(cfhsi->ndev, | |
| 873 | − "%s: Failed to create HSI frame: %d.\n", | |
| 874 | − __func__, len); | |
| 875 | − } | |
| 876 | −} | |
| 877 | − | |
| 878 | −static void cfhsi_wake_down(struct work_struct *work) | |
| 879 | −{ | |
| 880 | − long ret; | |
| 881 | − struct cfhsi *cfhsi = NULL; | |
| 882 | − size_t fifo_occupancy = 0; | |
| 883 | − int retry = CFHSI_WAKE_TOUT; | |
| 884 | − | |
| 885 | − cfhsi = container_of(work, struct cfhsi, wake_down_work); | |
| 886 | − netdev_dbg(cfhsi->ndev, "%s.\n", __func__); | |
| 887 | − | |
| 888 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 889 | − return; | |
| 890 | − | |
| 891 | − /* Deactivate wake line. */ | |
| 892 | − cfhsi->ops->cfhsi_wake_down(cfhsi->ops); | |
| 893 | − | |
| 894 | − /* Wait for acknowledge. */ | |
| 895 | − ret = CFHSI_WAKE_TOUT; | |
| 896 | − ret = wait_event_interruptible_timeout(cfhsi->wake_down_wait, | |
| 897 | − test_and_clear_bit(CFHSI_WAKE_DOWN_ACK, | |
| 898 | − &cfhsi->bits), ret); | |
| 899 | − if (ret < 0) { | |
| 900 | − /* Interrupted by signal. */ | |
| 901 | − netdev_err(cfhsi->ndev, "%s: Signalled: %ld.\n", | |
| 902 | − __func__, ret); | |
| 903 | − return; | |
| 904 | − } else if (!ret) { | |
| 905 | − bool ca_wake = true; | |
| 906 | − | |
| 907 | − /* Timeout */ | |
| 908 | − netdev_err(cfhsi->ndev, "%s: Timeout.\n", __func__); | |
| 909 | − | |
| 910 | − /* Check if we misssed the interrupt. */ | |
| 911 | − WARN_ON(cfhsi->ops->cfhsi_get_peer_wake(cfhsi->ops, | |
| 912 | − &ca_wake)); | |
| 913 | − if (!ca_wake) | |
| 914 | − netdev_err(cfhsi->ndev, "%s: CA Wake missed !.\n", | |
| 915 | − __func__); | |
| 916 | − } | |
| 917 | − | |
| 918 | − /* Check FIFO occupancy. */ | |
| 919 | − while (retry) { | |
| 920 | − WARN_ON(cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops, | |
| 921 | − &fifo_occupancy)); | |
| 922 | − | |
| 923 | − if (!fifo_occupancy) | |
| 924 | − break; | |
| 925 | − | |
| 926 | − set_current_state(TASK_INTERRUPTIBLE); | |
| 927 | − schedule_timeout(1); | |
| 928 | − retry--; | |
| 929 | − } | |
| 930 | − | |
| 931 | − if (!retry) | |
| 932 | − netdev_err(cfhsi->ndev, "%s: FIFO Timeout.\n", __func__); | |
| 933 | − | |
| 934 | − /* Clear AWAKE condition. */ | |
| 935 | − clear_bit(CFHSI_AWAKE, &cfhsi->bits); | |
| 936 | − | |
| 937 | − /* Cancel pending RX requests. */ | |
| 938 | − cfhsi->ops->cfhsi_rx_cancel(cfhsi->ops); | |
| 939 | −} | |
| 940 | − | |
| 941 | −static void cfhsi_out_of_sync(struct work_struct *work) | |
| 942 | −{ | |
| 943 | − struct cfhsi *cfhsi = NULL; | |
| 944 | − | |
| 945 | − cfhsi = container_of(work, struct cfhsi, out_of_sync_work); | |
| 946 | − | |
| 947 | − rtnl_lock(); | |
| 948 | − dev_close(cfhsi->ndev); | |
| 949 | − rtnl_unlock(); | |
| 950 | −} | |
| 951 | − | |
| 952 | −static void cfhsi_wake_up_cb(struct cfhsi_cb_ops *cb_ops) | |
| 953 | −{ | |
| 954 | − struct cfhsi *cfhsi = NULL; | |
| 955 | − | |
| 956 | − cfhsi = container_of(cb_ops, struct cfhsi, cb_ops); | |
| 957 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 958 | − __func__); | |
| 959 | − | |
| 960 | − set_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); | |
| 961 | − wake_up_interruptible(&cfhsi->wake_up_wait); | |
| 962 | − | |
| 963 | − if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) | |
| 964 | − return; | |
| 965 | − | |
| 966 | − /* Schedule wake up work queue if the peer initiates. */ | |
| 967 | − if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits)) | |
| 968 | − queue_work(cfhsi->wq, &cfhsi->wake_up_work); | |
| 969 | −} | |
| 970 | − | |
| 971 | −static void cfhsi_wake_down_cb(struct cfhsi_cb_ops *cb_ops) | |
| 972 | −{ | |
| 973 | − struct cfhsi *cfhsi = NULL; | |
| 974 | − | |
| 975 | − cfhsi = container_of(cb_ops, struct cfhsi, cb_ops); | |
| 976 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 977 | − __func__); | |
| 978 | − | |
| 979 | − /* Initiating low power is only permitted by the host (us). */ | |
| 980 | − set_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits); | |
| 981 | − wake_up_interruptible(&cfhsi->wake_down_wait); | |
| 982 | −} | |
| 983 | − | |
| 984 | −static void cfhsi_aggregation_tout(struct timer_list *t) | |
| 985 | −{ | |
| 986 | − struct cfhsi *cfhsi = from_timer(cfhsi, t, aggregation_timer); | |
| 987 | − | |
| 988 | − netdev_dbg(cfhsi->ndev, "%s.\n", | |
| 989 | − __func__); | |
| 990 | − | |
| 991 | − cfhsi_start_tx(cfhsi); | |
| 992 | −} | |
| 993 | − | |
| 994 | −static netdev_tx_t cfhsi_xmit(struct sk_buff *skb, struct net_device *dev) | |
| 995 | −{ | |
| 996 | − struct cfhsi *cfhsi = NULL; | |
| 997 | − int start_xfer = 0; | |
| 998 | − int timer_active; | |
| 999 | − int prio; | |
| 1000 | − | |
| 1001 | − if (!dev) | |
| 1002 | − return -EINVAL; | |
| 1003 | − | |
| 1004 | − cfhsi = netdev_priv(dev); | |
| 1005 | − | |
| 1006 | − switch (skb->priority) { | |
| 1007 | − case TC_PRIO_BESTEFFORT: | |
| 1008 | − case TC_PRIO_FILLER: | |
| 1009 | − case TC_PRIO_BULK: | |
| 1010 | − prio = CFHSI_PRIO_BEBK; | |
| 1011 | − break; | |
| 1012 | − case TC_PRIO_INTERACTIVE_BULK: | |
| 1013 | − prio = CFHSI_PRIO_VI; | |
| 1014 | − break; | |
| 1015 | − case TC_PRIO_INTERACTIVE: | |
| 1016 | − prio = CFHSI_PRIO_VO; | |
| 1017 | − break; | |
| 1018 | − case TC_PRIO_CONTROL: | |
| 1019 | − default: | |
| 1020 | − prio = CFHSI_PRIO_CTL; | |
| 1021 | − break; | |
| 1022 | − } | |
| 1023 | − | |
| 1024 | − spin_lock_bh(&cfhsi->lock); | |
| 1025 | − | |
| 1026 | − /* Update aggregation statistics */ | |
| 1027 | − cfhsi_update_aggregation_stats(cfhsi, skb, 1); | |
| 1028 | − | |
| 1029 | − /* Queue the SKB */ | |
| 1030 | − skb_queue_tail(&cfhsi->qhead[prio], skb); | |
| 1031 | − | |
| 1032 | − /* Sanity check; xmit should not be called after unregister_netdev */ | |
| 1033 | − if (WARN_ON(test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))) { | |
| 1034 | − spin_unlock_bh(&cfhsi->lock); | |
| 1035 | − cfhsi_abort_tx(cfhsi); | |
| 1036 | − return -EINVAL; | |
| 1037 | − } | |
| 1038 | − | |
| 1039 | − /* Send flow off if number of packets is above high water mark. */ | |
| 1040 | − if (!cfhsi->flow_off_sent && | |
| 1041 | − cfhsi_tx_queue_len(cfhsi) > cfhsi->cfg.q_high_mark && | |
| 1042 | − cfhsi->cfdev.flowctrl) { | |
| 1043 | − cfhsi->flow_off_sent = 1; | |
| 1044 | − cfhsi->cfdev.flowctrl(cfhsi->ndev, OFF); | |
| 1045 | − } | |
| 1046 | − | |
| 1047 | − if (cfhsi->tx_state == CFHSI_TX_STATE_IDLE) { | |
| 1048 | − cfhsi->tx_state = CFHSI_TX_STATE_XFER; | |
| 1049 | − start_xfer = 1; | |
| 1050 | − } | |
| 1051 | − | |
| 1052 | − if (!start_xfer) { | |
| 1053 | − /* Send aggregate if it is possible */ | |
| 1054 | − bool aggregate_ready = | |
| 1055 | − cfhsi_can_send_aggregate(cfhsi) && | |
| 1056 | − del_timer(&cfhsi->aggregation_timer) > 0; | |
| 1057 | − spin_unlock_bh(&cfhsi->lock); | |
| 1058 | − if (aggregate_ready) | |
| 1059 | − cfhsi_start_tx(cfhsi); | |
| 1060 | − return NETDEV_TX_OK; | |
| 1061 | − } | |
| 1062 | − | |
| 1063 | − /* Delete inactivity timer if started. */ | |
| 1064 | − timer_active = del_timer_sync(&cfhsi->inactivity_timer); | |
| 1065 | − | |
| 1066 | − spin_unlock_bh(&cfhsi->lock); | |
| 1067 | − | |
| 1068 | − if (timer_active) { | |
| 1069 | − struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf; | |
| 1070 | − int len; | |
| 1071 | − int res; | |
| 1072 | − | |
| 1073 | − /* Create HSI frame. */ | |
| 1074 | − len = cfhsi_tx_frm(desc, cfhsi); | |
| 1075 | − WARN_ON(!len); | |
| 1076 | − | |
| 1077 | − /* Set up new transfer. */ | |
| 1078 | − res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops); | |
| 1079 | − if (WARN_ON(res < 0)) { | |
| 1080 | − netdev_err(cfhsi->ndev, "%s: TX error %d.\n", | |
| 1081 | − __func__, res); | |
| 1082 | − cfhsi_abort_tx(cfhsi); | |
| 1083 | − } | |
| 1084 | − } else { | |
| 1085 | − /* Schedule wake up work queue if the we initiate. */ | |
| 1086 | − if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits)) | |
| 1087 | − queue_work(cfhsi->wq, &cfhsi->wake_up_work); | |
| 1088 | − } | |
| 1089 | − | |
| 1090 | − return NETDEV_TX_OK; | |
| 1091 | −} | |
| 1092 | − | |
| 1093 | −static const struct net_device_ops cfhsi_netdevops; | |
| 1094 | − | |
| 1095 | −static void cfhsi_setup(struct net_device *dev) | |
| 1096 | −{ | |
| 1097 | − int i; | |
| 1098 | − struct cfhsi *cfhsi = netdev_priv(dev); | |
| 1099 | − dev->features = 0; | |
| 1100 | − dev->type = ARPHRD_CAIF; | |
| 1101 | − dev->flags = IFF_POINTOPOINT | IFF_NOARP; | |
| 1102 | − dev->mtu = CFHSI_MAX_CAIF_FRAME_SZ; | |
| 1103 | − dev->priv_flags |= IFF_NO_QUEUE; | |
| 1104 | − dev->needs_free_netdev = true; | |
| 1105 | − dev->netdev_ops = &cfhsi_netdevops; | |
| 1106 | − for (i = 0; i < CFHSI_PRIO_LAST; ++i) | |
| 1107 | − skb_queue_head_init(&cfhsi->qhead[i]); | |
| 1108 | − cfhsi->cfdev.link_select = CAIF_LINK_HIGH_BANDW; | |
| 1109 | − cfhsi->cfdev.use_frag = false; | |
| 1110 | − cfhsi->cfdev.use_stx = false; | |
| 1111 | − cfhsi->cfdev.use_fcs = false; | |
| 1112 | − cfhsi->ndev = dev; | |
| 1113 | − cfhsi->cfg = hsi_default_config; | |
| 1114 | −} | |
| 1115 | − | |
| 1116 | −static int cfhsi_open(struct net_device *ndev) | |
| 1117 | −{ | |
| 1118 | − struct cfhsi *cfhsi = netdev_priv(ndev); | |
| 1119 | − int res; | |
| 1120 | − | |
| 1121 | − clear_bit(CFHSI_SHUTDOWN, &cfhsi->bits); | |
| 1122 | − | |
| 1123 | − /* Initialize state vaiables. */ | |
| 1124 | − cfhsi->tx_state = CFHSI_TX_STATE_IDLE; | |
| 1125 | − cfhsi->rx_state.state = CFHSI_RX_STATE_DESC; | |
| 1126 | − | |
| 1127 | − /* Set flow info */ | |
| 1128 | − cfhsi->flow_off_sent = 0; | |
| 1129 | − | |
| 1130 | − /* | |
| 1131 | − * Allocate a TX buffer with the size of a HSI packet descriptors | |
| 1132 | − * and the necessary room for CAIF payload frames. | |
| 1133 | − */ | |
| 1134 | − cfhsi->tx_buf = kzalloc(CFHSI_BUF_SZ_TX, GFP_KERNEL); | |
| 1135 | − if (!cfhsi->tx_buf) { | |
| 1136 | − res = -ENODEV; | |
| 1137 | − goto err_alloc_tx; | |
| 1138 | − } | |
| 1139 | − | |
| 1140 | − /* | |
| 1141 | − * Allocate a RX buffer with the size of two HSI packet descriptors and | |
| 1142 | − * the necessary room for CAIF payload frames. | |
| 1143 | − */ | |
| 1144 | − cfhsi->rx_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL); | |
| 1145 | − if (!cfhsi->rx_buf) { | |
| 1146 | − res = -ENODEV; | |
| 1147 | − goto err_alloc_rx; | |
| 1148 | − } | |
| 1149 | − | |
| 1150 | − cfhsi->rx_flip_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL); | |
| 1151 | − if (!cfhsi->rx_flip_buf) { | |
| 1152 | − res = -ENODEV; | |
| 1153 | − goto err_alloc_rx_flip; | |
| 1154 | − } | |
| 1155 | − | |
| 1156 | − /* Initialize aggregation timeout */ | |
| 1157 | − cfhsi->cfg.aggregation_timeout = hsi_default_config.aggregation_timeout; | |
| 1158 | − | |
| 1159 | − /* Initialize recieve vaiables. */ | |
| 1160 | − cfhsi->rx_ptr = cfhsi->rx_buf; | |
| 1161 | − cfhsi->rx_len = CFHSI_DESC_SZ; | |
| 1162 | − | |
| 1163 | − /* Initialize spin locks. */ | |
| 1164 | − spin_lock_init(&cfhsi->lock); | |
| 1165 | − | |
| 1166 | − /* Set up the driver. */ | |
| 1167 | − cfhsi->cb_ops.tx_done_cb = cfhsi_tx_done_cb; | |
| 1168 | − cfhsi->cb_ops.rx_done_cb = cfhsi_rx_done_cb; | |
| 1169 | − cfhsi->cb_ops.wake_up_cb = cfhsi_wake_up_cb; | |
| 1170 | − cfhsi->cb_ops.wake_down_cb = cfhsi_wake_down_cb; | |
| 1171 | − | |
| 1172 | − /* Initialize the work queues. */ | |
| 1173 | − INIT_WORK(&cfhsi->wake_up_work, cfhsi_wake_up); | |
| 1174 | − INIT_WORK(&cfhsi->wake_down_work, cfhsi_wake_down); | |
| 1175 | − INIT_WORK(&cfhsi->out_of_sync_work, cfhsi_out_of_sync); | |
| 1176 | − | |
| 1177 | − /* Clear all bit fields. */ | |
| 1178 | − clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); | |
| 1179 | − clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits); | |
| 1180 | − clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); | |
| 1181 | − clear_bit(CFHSI_AWAKE, &cfhsi->bits); | |
| 1182 | − | |
| 1183 | − /* Create work thread. */ | |
| 1184 | − cfhsi->wq = alloc_ordered_workqueue(cfhsi->ndev->name, WQ_MEM_RECLAIM); | |
| 1185 | − if (!cfhsi->wq) { | |
| 1186 | − netdev_err(cfhsi->ndev, "%s: Failed to create work queue.\n", | |
| 1187 | − __func__); | |
| 1188 | − res = -ENODEV; | |
| 1189 | − goto err_create_wq; | |
| 1190 | − } | |
| 1191 | − | |
| 1192 | − /* Initialize wait queues. */ | |
| 1193 | − init_waitqueue_head(&cfhsi->wake_up_wait); | |
| 1194 | − init_waitqueue_head(&cfhsi->wake_down_wait); | |
| 1195 | − init_waitqueue_head(&cfhsi->flush_fifo_wait); | |
| 1196 | − | |
| 1197 | − /* Setup the inactivity timer. */ | |
| 1198 | − timer_setup(&cfhsi->inactivity_timer, cfhsi_inactivity_tout, 0); | |
| 1199 | − /* Setup the slowpath RX timer. */ | |
| 1200 | − timer_setup(&cfhsi->rx_slowpath_timer, cfhsi_rx_slowpath, 0); | |
| 1201 | − /* Setup the aggregation timer. */ | |
| 1202 | − timer_setup(&cfhsi->aggregation_timer, cfhsi_aggregation_tout, 0); | |
| 1203 | − | |
| 1204 | − /* Activate HSI interface. */ | |
| 1205 | − res = cfhsi->ops->cfhsi_up(cfhsi->ops); | |
| 1206 | − if (res) { | |
| 1207 | − netdev_err(cfhsi->ndev, | |
| 1208 | − "%s: can't activate HSI interface: %d.\n", | |
| 1209 | − __func__, res); | |
| 1210 | − goto err_activate; | |
| 1211 | − } | |
| 1212 | − | |
| 1213 | − /* Flush FIFO */ | |
| 1214 | − res = cfhsi_flush_fifo(cfhsi); | |
| 1215 | − if (res) { | |
| 1216 | − netdev_err(cfhsi->ndev, "%s: Can't flush FIFO: %d.\n", | |
| 1217 | − __func__, res); | |
| 1218 | − goto err_net_reg; | |
| 1219 | − } | |
| 1220 | − return res; | |
| 1221 | − | |
| 1222 | − err_net_reg: | |
| 1223 | − cfhsi->ops->cfhsi_down(cfhsi->ops); | |
| 1224 | − err_activate: | |
| 1225 | − destroy_workqueue(cfhsi->wq); | |
| 1226 | − err_create_wq: | |
| 1227 | − kfree(cfhsi->rx_flip_buf); | |
| 1228 | − err_alloc_rx_flip: | |
| 1229 | − kfree(cfhsi->rx_buf); | |
| 1230 | − err_alloc_rx: | |
| 1231 | − kfree(cfhsi->tx_buf); | |
| 1232 | − err_alloc_tx: | |
| 1233 | − return res; | |
| 1234 | −} | |
| 1235 | − | |
| 1236 | −static int cfhsi_close(struct net_device *ndev) | |
| 1237 | −{ | |
| 1238 | − struct cfhsi *cfhsi = netdev_priv(ndev); | |
| 1239 | − u8 *tx_buf, *rx_buf, *flip_buf; | |
| 1240 | − | |
| 1241 | − /* going to shutdown driver */ | |
| 1242 | − set_bit(CFHSI_SHUTDOWN, &cfhsi->bits); | |
| 1243 | − | |
| 1244 | − /* Delete timers if pending */ | |
| 1245 | − del_timer_sync(&cfhsi->inactivity_timer); | |
| 1246 | − del_timer_sync(&cfhsi->rx_slowpath_timer); | |
| 1247 | − del_timer_sync(&cfhsi->aggregation_timer); | |
| 1248 | − | |
| 1249 | − /* Cancel pending RX request (if any) */ | |
| 1250 | − cfhsi->ops->cfhsi_rx_cancel(cfhsi->ops); | |
| 1251 | − | |
| 1252 | − /* Destroy workqueue */ | |
| 1253 | − destroy_workqueue(cfhsi->wq); | |
| 1254 | − | |
| 1255 | − /* Store bufferes: will be freed later. */ | |
| 1256 | − tx_buf = cfhsi->tx_buf; | |
| 1257 | − rx_buf = cfhsi->rx_buf; | |
| 1258 | − flip_buf = cfhsi->rx_flip_buf; | |
| 1259 | − /* Flush transmit queues. */ | |
| 1260 | − cfhsi_abort_tx(cfhsi); | |
| 1261 | − | |
| 1262 | − /* Deactivate interface */ | |
| 1263 | − cfhsi->ops->cfhsi_down(cfhsi->ops); | |
| 1264 | − | |
| 1265 | − /* Free buffers. */ | |
| 1266 | − kfree(tx_buf); | |
| 1267 | − kfree(rx_buf); | |
| 1268 | − kfree(flip_buf); | |
| 1269 | − return 0; | |
| 1270 | −} | |
| 1271 | − | |
| 1272 | −static void cfhsi_uninit(struct net_device *dev) | |
| 1273 | −{ | |
| 1274 | − struct cfhsi *cfhsi = netdev_priv(dev); | |
| 1275 | − ASSERT_RTNL(); | |
| 1276 | − symbol_put(cfhsi_get_device); | |
| 1277 | − list_del(&cfhsi->list); | |
| 1278 | −} | |
| 1279 | − | |
| 1280 | −static const struct net_device_ops cfhsi_netdevops = { | |
| 1281 | − .ndo_uninit = cfhsi_uninit, | |
| 1282 | − .ndo_open = cfhsi_open, | |
| 1283 | − .ndo_stop = cfhsi_close, | |
| 1284 | − .ndo_start_xmit = cfhsi_xmit | |
| 1285 | −}; | |
| 1286 | − | |
| 1287 | −static void cfhsi_netlink_parms(struct nlattr *data[], struct cfhsi *cfhsi) | |
| 1288 | −{ | |
| 1289 | − int i; | |
| 1290 | − | |
| 1291 | − if (!data) { | |
| 1292 | − pr_debug("no params data found\n"); | |
| 1293 | − return; | |
| 1294 | − } | |
| 1295 | − | |
| 1296 | − i = __IFLA_CAIF_HSI_INACTIVITY_TOUT; | |
| 1297 | − /* | |
| 1298 | − * Inactivity timeout in millisecs. Lowest possible value is 1, | |
| 1299 | − * and highest possible is NEXT_TIMER_MAX_DELTA. | |
| 1300 | − */ | |
| 1301 | − if (data[i]) { | |
| 1302 | − u32 inactivity_timeout = nla_get_u32(data[i]); | |
| 1303 | − /* Pre-calculate inactivity timeout. */ | |
| 1304 | − cfhsi->cfg.inactivity_timeout = inactivity_timeout * HZ / 1000; | |
| 1305 | − if (cfhsi->cfg.inactivity_timeout == 0) | |
| 1306 | − cfhsi->cfg.inactivity_timeout = 1; | |
| 1307 | − else if (cfhsi->cfg.inactivity_timeout > NEXT_TIMER_MAX_DELTA) | |
| 1308 | − cfhsi->cfg.inactivity_timeout = NEXT_TIMER_MAX_DELTA; | |
| 1309 | − } | |
| 1310 | − | |
| 1311 | − i = __IFLA_CAIF_HSI_AGGREGATION_TOUT; | |
| 1312 | − if (data[i]) | |
| 1313 | − cfhsi->cfg.aggregation_timeout = nla_get_u32(data[i]); | |
| 1314 | − | |
| 1315 | − i = __IFLA_CAIF_HSI_HEAD_ALIGN; | |
| 1316 | − if (data[i]) | |
| 1317 | − cfhsi->cfg.head_align = nla_get_u32(data[i]); | |
| 1318 | − | |
| 1319 | − i = __IFLA_CAIF_HSI_TAIL_ALIGN; | |
| 1320 | − if (data[i]) | |
| 1321 | − cfhsi->cfg.tail_align = nla_get_u32(data[i]); | |
| 1322 | − | |
| 1323 | − i = __IFLA_CAIF_HSI_QHIGH_WATERMARK; | |
| 1324 | − if (data[i]) | |
| 1325 | − cfhsi->cfg.q_high_mark = nla_get_u32(data[i]); | |
| 1326 | − | |
| 1327 | − i = __IFLA_CAIF_HSI_QLOW_WATERMARK; | |
| 1328 | − if (data[i]) | |
| 1329 | − cfhsi->cfg.q_low_mark = nla_get_u32(data[i]); | |
| 1330 | −} | |
| 1331 | − | |
| 1332 | −static int caif_hsi_changelink(struct net_device *dev, struct nlattr *tb[], | |
| 1333 | − struct nlattr *data[], | |
| 1334 | − struct netlink_ext_ack *extack) | |
| 1335 | −{ | |
| 1336 | − cfhsi_netlink_parms(data, netdev_priv(dev)); | |
| 1337 | − netdev_state_change(dev); | |
| 1338 | − return 0; | |
| 1339 | −} | |
| 1340 | − | |
| 1341 | −static const struct nla_policy caif_hsi_policy[__IFLA_CAIF_HSI_MAX + 1] = { | |
| 1342 | − [__IFLA_CAIF_HSI_INACTIVITY_TOUT] = { .type = NLA_U32, .len = 4 }, | |
| 1343 | − [__IFLA_CAIF_HSI_AGGREGATION_TOUT] = { .type = NLA_U32, .len = 4 }, | |
| 1344 | − [__IFLA_CAIF_HSI_HEAD_ALIGN] = { .type = NLA_U32, .len = 4 }, | |
| 1345 | − [__IFLA_CAIF_HSI_TAIL_ALIGN] = { .type = NLA_U32, .len = 4 }, | |
| 1346 | − [__IFLA_CAIF_HSI_QHIGH_WATERMARK] = { .type = NLA_U32, .len = 4 }, | |
| 1347 | − [__IFLA_CAIF_HSI_QLOW_WATERMARK] = { .type = NLA_U32, .len = 4 }, | |
| 1348 | −}; | |
| 1349 | − | |
| 1350 | −static size_t caif_hsi_get_size(const struct net_device *dev) | |
| 1351 | −{ | |
| 1352 | − int i; | |
| 1353 | − size_t s = 0; | |
| 1354 | − for (i = __IFLA_CAIF_HSI_UNSPEC + 1; i < __IFLA_CAIF_HSI_MAX; i++) | |
| 1355 | − s += nla_total_size(caif_hsi_policy[i].len); | |
| 1356 | − return s; | |
| 1357 | −} | |
| 1358 | − | |
| 1359 | −static int caif_hsi_fill_info(struct sk_buff *skb, const struct net_device *dev) | |
| 1360 | −{ | |
| 1361 | − struct cfhsi *cfhsi = netdev_priv(dev); | |
| 1362 | − | |
| 1363 | − if (nla_put_u32(skb, __IFLA_CAIF_HSI_INACTIVITY_TOUT, | |
| 1364 | − cfhsi->cfg.inactivity_timeout) || | |
| 1365 | − nla_put_u32(skb, __IFLA_CAIF_HSI_AGGREGATION_TOUT, | |
| 1366 | − cfhsi->cfg.aggregation_timeout) || | |
| 1367 | − nla_put_u32(skb, __IFLA_CAIF_HSI_HEAD_ALIGN, | |
| 1368 | − cfhsi->cfg.head_align) || | |
| 1369 | − nla_put_u32(skb, __IFLA_CAIF_HSI_TAIL_ALIGN, | |
| 1370 | − cfhsi->cfg.tail_align) || | |
| 1371 | − nla_put_u32(skb, __IFLA_CAIF_HSI_QHIGH_WATERMARK, | |
| 1372 | − cfhsi->cfg.q_high_mark) || | |
| 1373 | − nla_put_u32(skb, __IFLA_CAIF_HSI_QLOW_WATERMARK, | |
| 1374 | − cfhsi->cfg.q_low_mark)) | |
| 1375 | − return -EMSGSIZE; | |
| 1376 | − | |
| 1377 | − return 0; | |
| 1378 | −} | |
| 1379 | − | |
| 1380 | −static int caif_hsi_newlink(struct net *src_net, struct net_device *dev, | |
| 1381 | − struct nlattr *tb[], struct nlattr *data[], | |
| 1382 | − struct netlink_ext_ack *extack) | |
| 1383 | −{ | |
| 1384 | − struct cfhsi *cfhsi = NULL; | |
| 1385 | − struct cfhsi_ops *(*get_ops)(void); | |
| 1386 | − | |
| 1387 | − ASSERT_RTNL(); | |
| 1388 | − | |
| 1389 | − cfhsi = netdev_priv(dev); | |
| 1390 | − cfhsi_netlink_parms(data, cfhsi); | |
| 1391 | − | |
| 1392 | − get_ops = symbol_get(cfhsi_get_ops); | |
| 1393 | − if (!get_ops) { | |
| 1394 | − pr_err("%s: failed to get the cfhsi_ops\n", __func__); | |
| 1395 | − return -ENODEV; | |
| 1396 | − } | |
| 1397 | − | |
| 1398 | − /* Assign the HSI device. */ | |
| 1399 | − cfhsi->ops = (*get_ops)(); | |
| 1400 | − if (!cfhsi->ops) { | |
| 1401 | − pr_err("%s: failed to get the cfhsi_ops\n", __func__); | |
| 1402 | − goto err; | |
| 1403 | − } | |
| 1404 | − | |
| 1405 | − /* Assign the driver to this HSI device. */ | |
| 1406 | − cfhsi->ops->cb_ops = &cfhsi->cb_ops; | |
| 1407 | − if (register_netdevice(dev)) { | |
| 1408 | − pr_warn("%s: caif_hsi device registration failed\n", __func__); | |
| 1409 | − goto err; | |
| 1410 | − } | |
| 1411 | − /* Add CAIF HSI device to list. */ | |
| 1412 | − list_add_tail(&cfhsi->list, &cfhsi_list); | |
| 1413 | − | |
| 1414 | − return 0; | |
| 1415 | −err: | |
| 1416 | − symbol_put(cfhsi_get_ops); | |
| 1417 | − return -ENODEV; | |
| 1418 | −} | |
| 1419 | − | |
| 1420 | −static struct rtnl_link_ops caif_hsi_link_ops __read_mostly = { | |
| 1421 | − .kind = "cfhsi", | |
| 1422 | − .priv_size = sizeof(struct cfhsi), | |
| 1423 | − .setup = cfhsi_setup, | |
| 1424 | − .maxtype = __IFLA_CAIF_HSI_MAX, | |
| 1425 | − .policy = caif_hsi_policy, | |
| 1426 | − .newlink = caif_hsi_newlink, | |
| 1427 | − .changelink = caif_hsi_changelink, | |
| 1428 | − .get_size = caif_hsi_get_size, | |
| 1429 | − .fill_info = caif_hsi_fill_info, | |
| 1430 | −}; | |
| 1431 | − | |
| 1432 | −static void __exit cfhsi_exit_module(void) | |
| 1433 | −{ | |
| 1434 | − struct list_head *list_node; | |
| 1435 | − struct list_head *n; | |
| 1436 | − struct cfhsi *cfhsi; | |
| 1437 | − | |
| 1438 | − rtnl_link_unregister(&caif_hsi_link_ops); | |
| 1439 | − | |
| 1440 | − rtnl_lock(); | |
| 1441 | − list_for_each_safe(list_node, n, &cfhsi_list) { | |
| 1442 | − cfhsi = list_entry(list_node, struct cfhsi, list); | |
| 1443 | − unregister_netdevice(cfhsi->ndev); | |
| 1444 | − } | |
| 1445 | − rtnl_unlock(); | |
| 1446 | −} | |
| 1447 | − | |
| 1448 | −static int __init cfhsi_init_module(void) | |
| 1449 | −{ | |
| 1450 | − return rtnl_link_register(&caif_hsi_link_ops); | |
| 1451 | −} | |
| 1452 | − | |
| 1453 | −module_init(cfhsi_init_module); | |
| 1454 | −module_exit(cfhsi_exit_module); | |
| @@ -419,8 +419,10 @@ int ksz_switch_register(struct ksz_device *dev, · 418 unmodified lines | ||
| 419 | 419 | if (of_property_read_u32(port, "reg", |
| 420 | 420 | &port_num)) |
| 421 | 421 | continue; |
| 422 | − if (!(dev->port_mask & BIT(port_num))) | |
| 422 | + if (!(dev->port_mask & BIT(port_num))) { | |
| 423 | + of_node_put(port); | |
| 423 | 424 | return -EINVAL; |
| 425 | + } | |
| 424 | 426 | of_get_phy_mode(port, |
| 425 | 427 | &dev->ports[port_num].interface); |
| 426 | 428 | } |
| @@ -3583,6 +3583,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { · 3582 unmodified lines | ||
| 3583 | 3583 | .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, |
| 3584 | 3584 | .port_max_speed_mode = mv88e6341_port_max_speed_mode, |
| 3585 | 3585 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 3586 | + .port_set_policy = mv88e6352_port_set_policy, | |
| 3586 | 3587 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 3587 | 3588 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 3588 | 3589 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, |
| @@ -3596,7 +3597,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { · 7 unmodified lines | ||
| 3596 | 3597 | .port_set_cmode = mv88e6341_port_set_cmode, |
| 3597 | 3598 | .port_setup_message_port = mv88e6xxx_setup_message_port, |
| 3598 | 3599 | .stats_snapshot = mv88e6390_g1_stats_snapshot, |
| 3599 | − .stats_set_histogram = mv88e6095_g1_stats_set_histogram, | |
| 3600 | + .stats_set_histogram = mv88e6390_g1_stats_set_histogram, | |
| 3600 | 3601 | .stats_get_sset_count = mv88e6320_stats_get_sset_count, |
| 3601 | 3602 | .stats_get_strings = mv88e6320_stats_get_strings, |
| 3602 | 3603 | .stats_get_stats = mv88e6390_stats_get_stats, |
| @@ -3606,6 +3607,9 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { · 3 unmodified lines | ||
| 3606 | 3607 | .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, |
| 3607 | 3608 | .pot_clear = mv88e6xxx_g2_pot_clear, |
| 3608 | 3609 | .reset = mv88e6352_g1_reset, |
| 3610 | + .rmu_disable = mv88e6390_g1_rmu_disable, | |
| 3611 | + .atu_get_hash = mv88e6165_g1_atu_get_hash, | |
| 3612 | + .atu_set_hash = mv88e6165_g1_atu_set_hash, | |
| 3609 | 3613 | .vtu_getnext = mv88e6352_g1_vtu_getnext, |
| 3610 | 3614 | .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, |
| 3611 | 3615 | .serdes_power = mv88e6390_serdes_power, |
| @@ -3619,6 +3623,11 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { · 7 unmodified lines | ||
| 3619 | 3623 | .serdes_irq_enable = mv88e6390_serdes_irq_enable, |
| 3620 | 3624 | .serdes_irq_status = mv88e6390_serdes_irq_status, |
| 3621 | 3625 | .gpio_ops = &mv88e6352_gpio_ops, |
| 3626 | + .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, | |
| 3627 | + .serdes_get_strings = mv88e6390_serdes_get_strings, | |
| 3628 | + .serdes_get_stats = mv88e6390_serdes_get_stats, | |
| 3629 | + .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, | |
| 3630 | + .serdes_get_regs = mv88e6390_serdes_get_regs, | |
| 3622 | 3631 | .phylink_validate = mv88e6341_phylink_validate, |
| 3623 | 3632 | }; |
| 3624 | 3633 | |
| @@ -4383,6 +4392,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { · 758 unmodified lines | ||
| 4383 | 4392 | .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, |
| 4384 | 4393 | .port_max_speed_mode = mv88e6341_port_max_speed_mode, |
| 4385 | 4394 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 4395 | + .port_set_policy = mv88e6352_port_set_policy, | |
| 4386 | 4396 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 4387 | 4397 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 4388 | 4398 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, |
| @@ -4396,7 +4406,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { · 7 unmodified lines | ||
| 4396 | 4406 | .port_set_cmode = mv88e6341_port_set_cmode, |
| 4397 | 4407 | .port_setup_message_port = mv88e6xxx_setup_message_port, |
| 4398 | 4408 | .stats_snapshot = mv88e6390_g1_stats_snapshot, |
| 4399 | − .stats_set_histogram = mv88e6095_g1_stats_set_histogram, | |
| 4409 | + .stats_set_histogram = mv88e6390_g1_stats_set_histogram, | |
| 4400 | 4410 | .stats_get_sset_count = mv88e6320_stats_get_sset_count, |
| 4401 | 4411 | .stats_get_strings = mv88e6320_stats_get_strings, |
| 4402 | 4412 | .stats_get_stats = mv88e6390_stats_get_stats, |
| @@ -4406,6 +4416,9 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { · 3 unmodified lines | ||
| 4406 | 4416 | .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, |
| 4407 | 4417 | .pot_clear = mv88e6xxx_g2_pot_clear, |
| 4408 | 4418 | .reset = mv88e6352_g1_reset, |
| 4419 | + .rmu_disable = mv88e6390_g1_rmu_disable, | |
| 4420 | + .atu_get_hash = mv88e6165_g1_atu_get_hash, | |
| 4421 | + .atu_set_hash = mv88e6165_g1_atu_set_hash, | |
| 4409 | 4422 | .vtu_getnext = mv88e6352_g1_vtu_getnext, |
| 4410 | 4423 | .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, |
| 4411 | 4424 | .serdes_power = mv88e6390_serdes_power, |
| @@ -4421,6 +4434,11 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { · 9 unmodified lines | ||
| 4421 | 4434 | .gpio_ops = &mv88e6352_gpio_ops, |
| 4422 | 4435 | .avb_ops = &mv88e6390_avb_ops, |
| 4423 | 4436 | .ptp_ops = &mv88e6352_ptp_ops, |
| 4437 | + .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, | |
| 4438 | + .serdes_get_strings = mv88e6390_serdes_get_strings, | |
| 4439 | + .serdes_get_stats = mv88e6390_serdes_get_stats, | |
| 4440 | + .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, | |
| 4441 | + .serdes_get_regs = mv88e6390_serdes_get_regs, | |
| 4424 | 4442 | .phylink_validate = mv88e6341_phylink_validate, |
| 4425 | 4443 | }; |
| 4426 | 4444 | |
| @@ -722,7 +722,7 @@ static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = { · 721 unmodified lines | ||
| 722 | 722 | |
| 723 | 723 | int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) |
| 724 | 724 | { |
| 725 | − if (mv88e6390_serdes_get_lane(chip, port) < 0) | |
| 725 | + if (mv88e6xxx_serdes_get_lane(chip, port) < 0) | |
| 726 | 726 | return 0; |
| 727 | 727 | |
| 728 | 728 | return ARRAY_SIZE(mv88e6390_serdes_hw_stats); |
| @@ -734,7 +734,7 @@ int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, · 5 unmodified lines | ||
| 734 | 734 | struct mv88e6390_serdes_hw_stat *stat; |
| 735 | 735 | int i; |
| 736 | 736 | |
| 737 | − if (mv88e6390_serdes_get_lane(chip, port) < 0) | |
| 737 | + if (mv88e6xxx_serdes_get_lane(chip, port) < 0) | |
| 738 | 738 | return 0; |
| 739 | 739 | |
| 740 | 740 | for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { |
| @@ -770,7 +770,7 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, · 29 unmodified lines | ||
| 770 | 770 | int lane; |
| 771 | 771 | int i; |
| 772 | 772 | |
| 773 | − lane = mv88e6390_serdes_get_lane(chip, port); | |
| 773 | + lane = mv88e6xxx_serdes_get_lane(chip, port); | |
| 774 | 774 | if (lane < 0) |
| 775 | 775 | return 0; |
| 776 | 776 | |
| @@ -122,14 +122,12 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) · 121 unmodified lines | ||
| 122 | 122 | |
| 123 | 123 | for (i = 0; i < ds->num_ports; i++) { |
| 124 | 124 | mac[i] = default_mac; |
| 125 | − if (i == dsa_upstream_port(priv->ds, i)) { | |
| 126 | − /* STP doesn't get called for CPU port, so we need to | |
| 127 | − * set the I/O parameters statically. | |
| 128 | − */ | |
| 129 | − mac[i].dyn_learn = true; | |
| 130 | − mac[i].ingress = true; | |
| 131 | − mac[i].egress = true; | |
| 132 | − } | |
| 125 | + | |
| 126 | + /* Let sja1105_bridge_stp_state_set() keep address learning | |
| 127 | + * enabled for the CPU port. | |
| 128 | + */ | |
| 129 | + if (dsa_is_cpu_port(ds, i)) | |
| 130 | + priv->learn_ena |= BIT(i); | |
| 133 | 131 | } |
| 134 | 132 | |
| 135 | 133 | return 0; |
| @@ -594,6 +594,11 @@ int atl1c_phy_init(struct atl1c_hw *hw) · 593 unmodified lines | ||
| 594 | 594 | int ret_val; |
| 595 | 595 | u16 mii_bmcr_data = BMCR_RESET; |
| 596 | 596 | |
| 597 | + if (hw->nic_type == athr_mt) { | |
| 598 | + hw->phy_configured = true; | |
| 599 | + return 0; | |
| 600 | + } | |
| 601 | + | |
| 597 | 602 | if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) || |
| 598 | 603 | (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) { |
| 599 | 604 | dev_err(&pdev->dev, "Error get phy ID\n"); |
| @@ -1640,7 +1640,8 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, · 1639 unmodified lines | ||
| 1640 | 1640 | |
| 1641 | 1641 | switch (mode) { |
| 1642 | 1642 | case GENET_POWER_PASSIVE: |
| 1643 | − reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS); | |
| 1643 | + reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS | | |
| 1644 | + EXT_ENERGY_DET_MASK); | |
| 1644 | 1645 | if (GENET_IS_V5(priv)) { |
| 1645 | 1646 | reg &= ~(EXT_PWR_DOWN_PHY_EN | |
| 1646 | 1647 | EXT_PWR_DOWN_PHY_RD | |
| @@ -3237,15 +3238,21 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, · 1590 unmodified lines | ||
| 3237 | 3238 | /* Returns a reusable dma control register value */ |
| 3238 | 3239 | static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) |
| 3239 | 3240 | { |
| 3241 | + unsigned int i; | |
| 3240 | 3242 | u32 reg; |
| 3241 | 3243 | u32 dma_ctrl; |
| 3242 | 3244 | |
| 3243 | 3245 | /* disable DMA */ |
| 3244 | 3246 | dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; |
| 3247 | + for (i = 0; i < priv->hw_params->tx_queues; i++) | |
| 3248 | + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); | |
| 3245 | 3249 | reg = bcmgenet_tdma_readl(priv, DMA_CTRL); |
| 3246 | 3250 | reg &= ~dma_ctrl; |
| 3247 | 3251 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); |
| 3248 | 3252 | |
| 3253 | + dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; | |
| 3254 | + for (i = 0; i < priv->hw_params->rx_queues; i++) | |
| 3255 | + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); | |
| 3249 | 3256 | reg = bcmgenet_rdma_readl(priv, DMA_CTRL); |
| 3250 | 3257 | reg &= ~dma_ctrl; |
| 3251 | 3258 | bcmgenet_rdma_writel(priv, reg, DMA_CTRL); |
| @@ -3292,7 +3299,6 @@ static int bcmgenet_open(struct net_device *dev) · 40 unmodified lines | ||
| 3292 | 3299 | { |
| 3293 | 3300 | struct bcmgenet_priv *priv = netdev_priv(dev); |
| 3294 | 3301 | unsigned long dma_ctrl; |
| 3295 | − u32 reg; | |
| 3296 | 3302 | int ret; |
| 3297 | 3303 | |
| 3298 | 3304 | netif_dbg(priv, ifup, dev, "bcmgenet_open\n"); |
| @@ -3318,12 +3324,6 @@ static int bcmgenet_open(struct net_device *dev) · 19 unmodified lines | ||
| 3318 | 3324 | |
| 3319 | 3325 | bcmgenet_set_hw_addr(priv, dev->dev_addr); |
| 3320 | 3326 | |
| 3321 | − if (priv->internal_phy) { | |
| 3322 | − reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); | |
| 3323 | − reg |= EXT_ENERGY_DET_MASK; | |
| 3324 | − bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); | |
| 3325 | − } | |
| 3326 | − | |
| 3327 | 3327 | /* Disable RX/TX DMA and flush TX queues */ |
| 3328 | 3328 | dma_ctrl = bcmgenet_dma_disable(priv); |
| 3329 | 3329 | |
| @@ -4139,7 +4139,6 @@ static int bcmgenet_resume(struct device *d) · 809 unmodified lines | ||
| 4139 | 4139 | struct bcmgenet_priv *priv = netdev_priv(dev); |
| 4140 | 4140 | struct bcmgenet_rxnfc_rule *rule; |
| 4141 | 4141 | unsigned long dma_ctrl; |
| 4142 | − u32 reg; | |
| 4143 | 4142 | int ret; |
| 4144 | 4143 | |
| 4145 | 4144 | if (!netif_running(dev)) |
| @@ -4176,12 +4175,6 @@ static int bcmgenet_resume(struct device *d) · 30 unmodified lines | ||
| 4176 | 4175 | if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) |
| 4177 | 4176 | bcmgenet_hfb_create_rxnfc_filter(priv, rule); |
| 4178 | 4177 | |
| 4179 | − if (priv->internal_phy) { | |
| 4180 | − reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); | |
| 4181 | − reg |= EXT_ENERGY_DET_MASK; | |
| 4182 | − bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); | |
| 4183 | − } | |
| 4184 | − | |
| 4185 | 4178 | /* Disable RX/TX DMA and flush TX queues */ |
| 4186 | 4179 | dma_ctrl = bcmgenet_dma_disable(priv); |
| 4187 | 4180 | |
| @@ -186,12 +186,6 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, · 185 unmodified lines | ||
| 186 | 186 | reg |= CMD_RX_EN; |
| 187 | 187 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); |
| 188 | 188 | |
| 189 | − if (priv->hw_params->flags & GENET_HAS_EXT) { | |
| 190 | − reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); | |
| 191 | − reg &= ~EXT_ENERGY_DET_MASK; | |
| 192 | − bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); | |
| 193 | − } | |
| 194 | − | |
| 195 | 189 | reg = UMAC_IRQ_MPD_R; |
| 196 | 190 | if (hfb_enable) |
| 197 | 191 | reg |= UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM; |
| @@ -2643,6 +2643,9 @@ static void detach_ulds(struct adapter *adap) · 2642 unmodified lines | ||
| 2643 | 2643 | { |
| 2644 | 2644 | unsigned int i; |
| 2645 | 2645 | |
| 2646 | + if (!is_uld(adap)) | |
| 2647 | + return; | |
| 2648 | + | |
| 2646 | 2649 | mutex_lock(&uld_mutex); |
| 2647 | 2650 | list_del(&adap->list_node); |
| 2648 | 2651 | |
| @@ -7141,10 +7144,13 @@ static void remove_one(struct pci_dev *pdev) · 4492 unmodified lines | ||
| 7141 | 7144 | */ |
| 7142 | 7145 | destroy_workqueue(adapter->workq); |
| 7143 | 7146 | |
| 7144 | − if (is_uld(adapter)) { | |
| 7145 | − detach_ulds(adapter); | |
| 7146 | − t4_uld_clean_up(adapter); | |
| 7147 | − } | |
| 7147 | + detach_ulds(adapter); | |
| 7148 | + | |
| 7149 | + for_each_port(adapter, i) | |
| 7150 | + if (adapter->port[i]->reg_state == NETREG_REGISTERED) | |
| 7151 | + unregister_netdev(adapter->port[i]); | |
| 7152 | + | |
| 7153 | + t4_uld_clean_up(adapter); | |
| 7148 | 7154 | |
| 7149 | 7155 | adap_free_hma_mem(adapter); |
| 7150 | 7156 | |
| @@ -7152,10 +7158,6 @@ static void remove_one(struct pci_dev *pdev) · 1 unmodified line | ||
| 7152 | 7158 | |
| 7153 | 7159 | cxgb4_free_mps_ref_entries(adapter); |
| 7154 | 7160 | |
| 7155 | − for_each_port(adapter, i) | |
| 7156 | − if (adapter->port[i]->reg_state == NETREG_REGISTERED) | |
| 7157 | − unregister_netdev(adapter->port[i]); | |
| 7158 | − | |
| 7159 | 7161 | debugfs_remove_recursive(adapter->debugfs_root); |
| 7160 | 7162 | |
| 7161 | 7163 | if (!is_t4(adapter->params.chip)) |
| @@ -581,6 +581,9 @@ void t4_uld_clean_up(struct adapter *adap) · 580 unmodified lines | ||
| 581 | 581 | { |
| 582 | 582 | unsigned int i; |
| 583 | 583 | |
| 584 | + if (!is_uld(adap)) | |
| 585 | + return; | |
| 586 | + | |
| 584 | 587 | mutex_lock(&uld_mutex); |
| 585 | 588 | for (i = 0; i < CXGB4_ULD_MAX; i++) { |
| 586 | 589 | if (!adap->uld[i].handle) |
| @@ -1469,7 +1469,7 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 1468 unmodified lines | ||
| 1469 | 1469 | |
| 1470 | 1470 | err = pci_enable_device(pdev); |
| 1471 | 1471 | if (err) |
| 1472 | − return -ENXIO; | |
| 1472 | + return err; | |
| 1473 | 1473 | |
| 1474 | 1474 | err = pci_request_regions(pdev, "gvnic-cfg"); |
| 1475 | 1475 | if (err) |
| @@ -1477,19 +1477,12 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 1 unmodified line | ||
| 1477 | 1477 | |
| 1478 | 1478 | pci_set_master(pdev); |
| 1479 | 1479 | |
| 1480 | − err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | |
| 1480 | + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); | |
| 1481 | 1481 | if (err) { |
| 1482 | 1482 | dev_err(&pdev->dev, "Failed to set dma mask: err=%d\n", err); |
| 1483 | 1483 | goto abort_with_pci_region; |
| 1484 | 1484 | } |
| 1485 | 1485 | |
| 1486 | − err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); | |
| 1487 | − if (err) { | |
| 1488 | − dev_err(&pdev->dev, | |
| 1489 | − "Failed to set consistent dma mask: err=%d\n", err); | |
| 1490 | − goto abort_with_pci_region; | |
| 1491 | − } | |
| 1492 | − | |
| 1493 | 1486 | reg_bar = pci_iomap(pdev, GVE_REGISTER_BAR, 0); |
| 1494 | 1487 | if (!reg_bar) { |
| 1495 | 1488 | dev_err(&pdev->dev, "Failed to map pci bar!\n"); |
| @@ -1512,6 +1505,7 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 16 unmodified lines | ||
| 1512 | 1505 | dev = alloc_etherdev_mqs(sizeof(*priv), max_tx_queues, max_rx_queues); |
| 1513 | 1506 | if (!dev) { |
| 1514 | 1507 | dev_err(&pdev->dev, "could not allocate netdev\n"); |
| 1508 | + err = -ENOMEM; | |
| 1515 | 1509 | goto abort_with_db_bar; |
| 1516 | 1510 | } |
| 1517 | 1511 | SET_NETDEV_DEV(dev, &pdev->dev); |
| @@ -1565,7 +1559,7 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 47 unmodified lines | ||
| 1565 | 1559 | |
| 1566 | 1560 | err = register_netdev(dev); |
| 1567 | 1561 | if (err) |
| 1568 | − goto abort_with_wq; | |
| 1562 | + goto abort_with_gve_init; | |
| 1569 | 1563 | |
| 1570 | 1564 | dev_info(&pdev->dev, "GVE version %s\n", gve_version_str); |
| 1571 | 1565 | dev_info(&pdev->dev, "GVE queue format %d\n", (int)priv->queue_format); |
| @@ -1573,6 +1567,9 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 1 unmodified line | ||
| 1573 | 1567 | queue_work(priv->gve_wq, &priv->service_task); |
| 1574 | 1568 | return 0; |
| 1575 | 1569 | |
| 1570 | +abort_with_gve_init: | |
| 1571 | + gve_teardown_priv_resources(priv); | |
| 1572 | + | |
| 1576 | 1573 | abort_with_wq: |
| 1577 | 1574 | destroy_workqueue(priv->gve_wq); |
| 1578 | 1575 | |
| @@ -1590,7 +1587,7 @@ abort_with_pci_region: · 11 unmodified lines | ||
| 1590 | 1587 | |
| 1591 | 1588 | abort_with_enabled: |
| 1592 | 1589 | pci_disable_device(pdev); |
| 1593 | − return -ENXIO; | |
| 1590 | + return err; | |
| 1594 | 1591 | } |
| 1595 | 1592 | |
| 1596 | 1593 | static void gve_remove(struct pci_dev *pdev) |
| @@ -566,13 +566,6 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, · 565 unmodified lines | ||
| 566 | 566 | return 0; |
| 567 | 567 | } |
| 568 | 568 | |
| 569 | − /* Prefetch the payload header. */ | |
| 570 | − prefetch((char *)buf_state->addr + buf_state->page_info.page_offset); | |
| 571 | −#if L1_CACHE_BYTES < 128 | |
| 572 | − prefetch((char *)buf_state->addr + buf_state->page_info.page_offset + | |
| 573 | − L1_CACHE_BYTES); | |
| 574 | −#endif | |
| 575 | − | |
| 576 | 569 | if (eop && buf_len <= priv->rx_copybreak) { |
| 577 | 570 | rx->skb_head = gve_rx_copy(priv->dev, napi, |
| 578 | 571 | &buf_state->page_info, buf_len, 0); |
| @@ -2420,9 +2420,10 @@ out: · 2419 unmodified lines | ||
| 2420 | 2420 | |
| 2421 | 2421 | static void __ibmvnic_reset(struct work_struct *work) |
| 2422 | 2422 | { |
| 2423 | − struct ibmvnic_rwi *rwi; | |
| 2424 | 2423 | struct ibmvnic_adapter *adapter; |
| 2425 | 2424 | bool saved_state = false; |
| 2425 | + struct ibmvnic_rwi *tmprwi; | |
| 2426 | + struct ibmvnic_rwi *rwi; | |
| 2426 | 2427 | unsigned long flags; |
| 2427 | 2428 | u32 reset_state; |
| 2428 | 2429 | int rc = 0; |
| @@ -2489,7 +2490,7 @@ static void __ibmvnic_reset(struct work_struct *work) · 60 unmodified lines | ||
| 2489 | 2490 | } else { |
| 2490 | 2491 | rc = do_reset(adapter, rwi, reset_state); |
| 2491 | 2492 | } |
| 2492 | − kfree(rwi); | |
| 2493 | + tmprwi = rwi; | |
| 2493 | 2494 | adapter->last_reset_time = jiffies; |
| 2494 | 2495 | |
| 2495 | 2496 | if (rc) |
| @@ -2497,8 +2498,23 @@ static void __ibmvnic_reset(struct work_struct *work) · 1 unmodified line | ||
| 2497 | 2498 | |
| 2498 | 2499 | rwi = get_next_rwi(adapter); |
| 2499 | 2500 | |
| 2501 | + /* | |
| 2502 | + * If there is another reset queued, free the previous rwi | |
| 2503 | + * and process the new reset even if previous reset failed | |
| 2504 | + * (the previous reset could have failed because of a fail | |
| 2505 | + * over for instance, so process the fail over). | |
| 2506 | + * | |
| 2507 | + * If there are no resets queued and the previous reset failed, | |
| 2508 | + * the adapter would be in an undefined state. So retry the | |
| 2509 | + * previous reset as a hard reset. | |
| 2510 | + */ | |
| 2511 | + if (rwi) | |
| 2512 | + kfree(tmprwi); | |
| 2513 | + else if (rc) | |
| 2514 | + rwi = tmprwi; | |
| 2515 | + | |
| 2500 | 2516 | if (rwi && (rwi->reset_reason == VNIC_RESET_FAILOVER || |
| 2501 | − rwi->reset_reason == VNIC_RESET_MOBILITY)) | |
| 2517 | + rwi->reset_reason == VNIC_RESET_MOBILITY || rc)) | |
| 2502 | 2518 | adapter->force_reset_recovery = true; |
| 2503 | 2519 | } |
| 2504 | 2520 | |
| @@ -7664,6 +7664,7 @@ err_flashmap: · 7663 unmodified lines | ||
| 7664 | 7664 | err_ioremap: |
| 7665 | 7665 | free_netdev(netdev); |
| 7666 | 7666 | err_alloc_etherdev: |
| 7667 | + pci_disable_pcie_error_reporting(pdev); | |
| 7667 | 7668 | pci_release_mem_regions(pdev); |
| 7668 | 7669 | err_pci_reg: |
| 7669 | 7670 | err_dma: |
| @@ -2227,6 +2227,7 @@ err_sw_init: · 2226 unmodified lines | ||
| 2227 | 2227 | err_ioremap: |
| 2228 | 2228 | free_netdev(netdev); |
| 2229 | 2229 | err_alloc_netdev: |
| 2230 | + pci_disable_pcie_error_reporting(pdev); | |
| 2230 | 2231 | pci_release_mem_regions(pdev); |
| 2231 | 2232 | err_pci_reg: |
| 2232 | 2233 | err_dma: |
| @@ -3798,6 +3798,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 3797 unmodified lines | ||
| 3798 | 3798 | err_ioremap: |
| 3799 | 3799 | free_netdev(netdev); |
| 3800 | 3800 | err_alloc_etherdev: |
| 3801 | + pci_disable_pcie_error_reporting(pdev); | |
| 3801 | 3802 | pci_release_regions(pdev); |
| 3802 | 3803 | err_pci_reg: |
| 3803 | 3804 | err_dma: |
| @@ -931,6 +931,7 @@ static void igb_configure_msix(struct igb_adapter *adapter) · 930 unmodified lines | ||
| 931 | 931 | **/ |
| 932 | 932 | static int igb_request_msix(struct igb_adapter *adapter) |
| 933 | 933 | { |
| 934 | + unsigned int num_q_vectors = adapter->num_q_vectors; | |
| 934 | 935 | struct net_device *netdev = adapter->netdev; |
| 935 | 936 | int i, err = 0, vector = 0, free_vector = 0; |
| 936 | 937 | |
| @@ -939,7 +940,13 @@ static int igb_request_msix(struct igb_adapter *adapter) · 2 unmodified lines | ||
| 939 | 940 | if (err) |
| 940 | 941 | goto err_out; |
| 941 | 942 | |
| 942 | − for (i = 0; i < adapter->num_q_vectors; i++) { | |
| 943 | + if (num_q_vectors > MAX_Q_VECTORS) { | |
| 944 | + num_q_vectors = MAX_Q_VECTORS; | |
| 945 | + dev_warn(&adapter->pdev->dev, | |
| 946 | + "The number of queue vectors (%d) is higher than max allowed (%d)\n", | |
| 947 | + adapter->num_q_vectors, MAX_Q_VECTORS); | |
| 948 | + } | |
| 949 | + for (i = 0; i < num_q_vectors; i++) { | |
| 943 | 950 | struct igb_q_vector *q_vector = adapter->q_vector[i]; |
| 944 | 951 | |
| 945 | 952 | vector++; |
| @@ -1678,14 +1685,15 @@ static bool is_any_txtime_enabled(struct igb_adapter *adapter) · 732 unmodified lines | ||
| 1678 | 1685 | **/ |
| 1679 | 1686 | static void igb_config_tx_modes(struct igb_adapter *adapter, int queue) |
| 1680 | 1687 | { |
| 1681 | − struct igb_ring *ring = adapter->tx_ring[queue]; | |
| 1682 | 1688 | struct net_device *netdev = adapter->netdev; |
| 1683 | 1689 | struct e1000_hw *hw = &adapter->hw; |
| 1690 | + struct igb_ring *ring; | |
| 1684 | 1691 | u32 tqavcc, tqavctrl; |
| 1685 | 1692 | u16 value; |
| 1686 | 1693 | |
| 1687 | 1694 | WARN_ON(hw->mac.type != e1000_i210); |
| 1688 | 1695 | WARN_ON(queue < 0 || queue > 1); |
| 1696 | + ring = adapter->tx_ring[queue]; | |
| 1689 | 1697 | |
| 1690 | 1698 | /* If any of the Qav features is enabled, configure queues as SR and |
| 1691 | 1699 | * with HIGH PRIO. If none is, then configure them with LOW PRIO and |
| @@ -3615,6 +3623,7 @@ err_sw_init: · 1923 unmodified lines | ||
| 3615 | 3623 | err_ioremap: |
| 3616 | 3624 | free_netdev(netdev); |
| 3617 | 3625 | err_alloc_etherdev: |
| 3626 | + pci_disable_pcie_error_reporting(pdev); | |
| 3618 | 3627 | pci_release_mem_regions(pdev); |
| 3619 | 3628 | err_pci_reg: |
| 3620 | 3629 | err_dma: |
| @@ -4835,6 +4844,8 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring) · 1214 unmodified lines | ||
| 4835 | 4844 | DMA_TO_DEVICE); |
| 4836 | 4845 | } |
| 4837 | 4846 | |
| 4847 | + tx_buffer->next_to_watch = NULL; | |
| 4848 | + | |
| 4838 | 4849 | /* move us one more past the eop_desc for start of next pkt */ |
| 4839 | 4850 | tx_buffer++; |
| 4840 | 4851 | i++; |
| @@ -578,7 +578,7 @@ static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data) · 577 unmodified lines | ||
| 578 | 578 | if (hw->phy.ops.read_reg) |
| 579 | 579 | return hw->phy.ops.read_reg(hw, offset, data); |
| 580 | 580 | |
| 581 | − return 0; | |
| 581 | + return -EOPNOTSUPP; | |
| 582 | 582 | } |
| 583 | 583 | |
| 584 | 584 | void igc_reinit_locked(struct igc_adapter *); |
| @@ -232,6 +232,8 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring) · 231 unmodified lines | ||
| 232 | 232 | igc_unmap_tx_buffer(tx_ring->dev, tx_buffer); |
| 233 | 233 | } |
| 234 | 234 | |
| 235 | + tx_buffer->next_to_watch = NULL; | |
| 236 | + | |
| 235 | 237 | /* move us one more past the eop_desc for start of next pkt */ |
| 236 | 238 | tx_buffer++; |
| 237 | 239 | i++; |
| @@ -6054,6 +6056,7 @@ err_sw_init: · 5816 unmodified lines | ||
| 6054 | 6056 | err_ioremap: |
| 6055 | 6057 | free_netdev(netdev); |
| 6056 | 6058 | err_alloc_etherdev: |
| 6059 | + pci_disable_pcie_error_reporting(pdev); | |
| 6057 | 6060 | pci_release_mem_regions(pdev); |
| 6058 | 6061 | err_pci_reg: |
| 6059 | 6062 | err_dma: |
| @@ -11067,6 +11067,7 @@ err_ioremap: · 11066 unmodified lines | ||
| 11067 | 11067 | disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); |
| 11068 | 11068 | free_netdev(netdev); |
| 11069 | 11069 | err_alloc_etherdev: |
| 11070 | + pci_disable_pcie_error_reporting(pdev); | |
| 11070 | 11071 | pci_release_mem_regions(pdev); |
| 11071 | 11072 | err_pci_reg: |
| 11072 | 11073 | err_dma: |
| @@ -211,7 +211,7 @@ struct xfrm_state *ixgbevf_ipsec_find_rx_state(struct ixgbevf_ipsec *ipsec, · 210 unmodified lines | ||
| 211 | 211 | static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs, |
| 212 | 212 | u32 *mykey, u32 *mysalt) |
| 213 | 213 | { |
| 214 | − struct net_device *dev = xs->xso.dev; | |
| 214 | + struct net_device *dev = xs->xso.real_dev; | |
| 215 | 215 | unsigned char *key_data; |
| 216 | 216 | char *alg_name = NULL; |
| 217 | 217 | int key_len; |
| @@ -260,12 +260,15 @@ static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs, · 42 unmodified lines | ||
| 260 | 260 | **/ |
| 261 | 261 | static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs) |
| 262 | 262 | { |
| 263 | − struct net_device *dev = xs->xso.dev; | |
| 264 | − struct ixgbevf_adapter *adapter = netdev_priv(dev); | |
| 265 | − struct ixgbevf_ipsec *ipsec = adapter->ipsec; | |
| 263 | + struct net_device *dev = xs->xso.real_dev; | |
| 264 | + struct ixgbevf_adapter *adapter; | |
| 265 | + struct ixgbevf_ipsec *ipsec; | |
| 266 | 266 | u16 sa_idx; |
| 267 | 267 | int ret; |
| 268 | 268 | |
| 269 | + adapter = netdev_priv(dev); | |
| 270 | + ipsec = adapter->ipsec; | |
| 271 | + | |
| 269 | 272 | if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) { |
| 270 | 273 | netdev_err(dev, "Unsupported protocol 0x%04x for IPsec offload\n", |
| 271 | 274 | xs->id.proto); |
| @@ -383,11 +386,14 @@ static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs) · 111 unmodified lines | ||
| 383 | 386 | **/ |
| 384 | 387 | static void ixgbevf_ipsec_del_sa(struct xfrm_state *xs) |
| 385 | 388 | { |
| 386 | − struct net_device *dev = xs->xso.dev; | |
| 387 | − struct ixgbevf_adapter *adapter = netdev_priv(dev); | |
| 388 | − struct ixgbevf_ipsec *ipsec = adapter->ipsec; | |
| 389 | + struct net_device *dev = xs->xso.real_dev; | |
| 390 | + struct ixgbevf_adapter *adapter; | |
| 391 | + struct ixgbevf_ipsec *ipsec; | |
| 389 | 392 | u16 sa_idx; |
| 390 | 393 | |
| 394 | + adapter = netdev_priv(dev); | |
| 395 | + ipsec = adapter->ipsec; | |
| 396 | + | |
| 391 | 397 | if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) { |
| 392 | 398 | sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX; |
| 393 | 399 | |
| @@ -2299,19 +2299,19 @@ mvneta_swbm_add_rx_fragment(struct mvneta_port *pp, · 2298 unmodified lines | ||
| 2299 | 2299 | skb_frag_off_set(frag, pp->rx_offset_correction); |
| 2300 | 2300 | skb_frag_size_set(frag, data_len); |
| 2301 | 2301 | __skb_frag_set_page(frag, page); |
| 2302 | − | |
| 2303 | − /* last fragment */ | |
| 2304 | − if (len == *size) { | |
| 2305 | − struct skb_shared_info *sinfo; | |
| 2306 | − | |
| 2307 | − sinfo = xdp_get_shared_info_from_buff(xdp); | |
| 2308 | − sinfo->nr_frags = xdp_sinfo->nr_frags; | |
| 2309 | − memcpy(sinfo->frags, xdp_sinfo->frags, | |
| 2310 | − sinfo->nr_frags * sizeof(skb_frag_t)); | |
| 2311 | − } | |
| 2312 | 2302 | } else { |
| 2313 | 2303 | page_pool_put_full_page(rxq->page_pool, page, true); |
| 2314 | 2304 | } |
| 2305 | + | |
| 2306 | + /* last fragment */ | |
| 2307 | + if (len == *size) { | |
| 2308 | + struct skb_shared_info *sinfo; | |
| 2309 | + | |
| 2310 | + sinfo = xdp_get_shared_info_from_buff(xdp); | |
| 2311 | + sinfo->nr_frags = xdp_sinfo->nr_frags; | |
| 2312 | + memcpy(sinfo->frags, xdp_sinfo->frags, | |
| 2313 | + sinfo->nr_frags * sizeof(skb_frag_t)); | |
| 2314 | + } | |
| 2315 | 2315 | *size -= len; |
| 2316 | 2316 | } |
| 2317 | 2317 | |
| @@ -86,6 +86,22 @@ bool is_lmac_valid(struct cgx *cgx, int lmac_id) · 85 unmodified lines | ||
| 86 | 86 | return test_bit(lmac_id, &cgx->lmac_bmap); |
| 87 | 87 | } |
| 88 | 88 | |
| 89 | +/* Helper function to get sequential index | |
| 90 | + * given the enabled LMAC of a CGX | |
| 91 | + */ | |
| 92 | +static int get_sequence_id_of_lmac(struct cgx *cgx, int lmac_id) | |
| 93 | +{ | |
| 94 | + int tmp, id = 0; | |
| 95 | + | |
| 96 | + for_each_set_bit(tmp, &cgx->lmac_bmap, MAX_LMAC_PER_CGX) { | |
| 97 | + if (tmp == lmac_id) | |
| 98 | + break; | |
| 99 | + id++; | |
| 100 | + } | |
| 101 | + | |
| 102 | + return id; | |
| 103 | +} | |
| 104 | + | |
| 89 | 105 | struct mac_ops *get_mac_ops(void *cgxd) |
| 90 | 106 | { |
| 91 | 107 | if (!cgxd) |
| @@ -211,37 +227,257 @@ static u64 mac2u64 (u8 *mac_addr) · 119 unmodified lines | ||
| 211 | 227 | return mac; |
| 212 | 228 | } |
| 213 | 229 | |
| 230 | +static void cfg2mac(u64 cfg, u8 *mac_addr) | |
| 231 | +{ | |
| 232 | + int i, index = 0; | |
| 233 | + | |
| 234 | + for (i = ETH_ALEN - 1; i >= 0; i--, index++) | |
| 235 | + mac_addr[i] = (cfg >> (8 * index)) & 0xFF; | |
| 236 | +} | |
| 237 | + | |
| 214 | 238 | int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr) |
| 215 | 239 | { |
| 216 | 240 | struct cgx *cgx_dev = cgx_get_pdata(cgx_id); |
| 241 | + struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | |
| 217 | 242 | struct mac_ops *mac_ops; |
| 243 | + int index, id; | |
| 218 | 244 | u64 cfg; |
| 219 | 245 | |
| 246 | + /* access mac_ops to know csr_offset */ | |
| 220 | 247 | mac_ops = cgx_dev->mac_ops; |
| 248 | + | |
| 221 | 249 | /* copy 6bytes from macaddr */ |
| 222 | 250 | /* memcpy(&cfg, mac_addr, 6); */ |
| 223 | 251 | |
| 224 | 252 | cfg = mac2u64 (mac_addr); |
| 225 | 253 | |
| 226 | − cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (lmac_id * 0x8)), | |
| 254 | + id = get_sequence_id_of_lmac(cgx_dev, lmac_id); | |
| 255 | + | |
| 256 | + index = id * lmac->mac_to_index_bmap.max; | |
| 257 | + | |
| 258 | + cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), | |
| 227 | 259 | cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64)lmac_id << 49)); |
| 228 | 260 | |
| 229 | 261 | cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); |
| 230 | − cfg |= CGX_DMAC_CTL0_CAM_ENABLE; | |
| 262 | + cfg |= (CGX_DMAC_CTL0_CAM_ENABLE | CGX_DMAC_BCAST_MODE | | |
| 263 | + CGX_DMAC_MCAST_MODE); | |
| 231 | 264 | cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); |
| 232 | 265 | |
| 233 | 266 | return 0; |
| 234 | 267 | } |
| 235 | 268 | |
| 269 | +u64 cgx_read_dmac_ctrl(void *cgxd, int lmac_id) | |
| 270 | +{ | |
| 271 | + struct mac_ops *mac_ops; | |
| 272 | + struct cgx *cgx = cgxd; | |
| 273 | + | |
| 274 | + if (!cgxd || !is_lmac_valid(cgxd, lmac_id)) | |
| 275 | + return 0; | |
| 276 | + | |
| 277 | + cgx = cgxd; | |
| 278 | + /* Get mac_ops to know csr offset */ | |
| 279 | + mac_ops = cgx->mac_ops; | |
| 280 | + | |
| 281 | + return cgx_read(cgxd, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); | |
| 282 | +} | |
| 283 | + | |
| 284 | +u64 cgx_read_dmac_entry(void *cgxd, int index) | |
| 285 | +{ | |
| 286 | + struct mac_ops *mac_ops; | |
| 287 | + struct cgx *cgx; | |
| 288 | + | |
| 289 | + if (!cgxd) | |
| 290 | + return 0; | |
| 291 | + | |
| 292 | + cgx = cgxd; | |
| 293 | + mac_ops = cgx->mac_ops; | |
| 294 | + return cgx_read(cgx, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 8))); | |
| 295 | +} | |
| 296 | + | |
| 297 | +int cgx_lmac_addr_add(u8 cgx_id, u8 lmac_id, u8 *mac_addr) | |
| 298 | +{ | |
| 299 | + struct cgx *cgx_dev = cgx_get_pdata(cgx_id); | |
| 300 | + struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | |
| 301 | + struct mac_ops *mac_ops; | |
| 302 | + int index, idx; | |
| 303 | + u64 cfg = 0; | |
| 304 | + int id; | |
| 305 | + | |
| 306 | + if (!lmac) | |
| 307 | + return -ENODEV; | |
| 308 | + | |
| 309 | + mac_ops = cgx_dev->mac_ops; | |
| 310 | + /* Get available index where entry is to be installed */ | |
| 311 | + idx = rvu_alloc_rsrc(&lmac->mac_to_index_bmap); | |
| 312 | + if (idx < 0) | |
| 313 | + return idx; | |
| 314 | + | |
| 315 | + id = get_sequence_id_of_lmac(cgx_dev, lmac_id); | |
| 316 | + | |
| 317 | + index = id * lmac->mac_to_index_bmap.max + idx; | |
| 318 | + | |
| 319 | + cfg = mac2u64 (mac_addr); | |
| 320 | + cfg |= CGX_DMAC_CAM_ADDR_ENABLE; | |
| 321 | + cfg |= ((u64)lmac_id << 49); | |
| 322 | + cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg); | |
| 323 | + | |
| 324 | + cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); | |
| 325 | + cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_CAM_ACCEPT); | |
| 326 | + | |
| 327 | + if (is_multicast_ether_addr(mac_addr)) { | |
| 328 | + cfg &= ~GENMASK_ULL(2, 1); | |
| 329 | + cfg |= CGX_DMAC_MCAST_MODE_CAM; | |
| 330 | + lmac->mcast_filters_count++; | |
| 331 | + } else if (!lmac->mcast_filters_count) { | |
| 332 | + cfg |= CGX_DMAC_MCAST_MODE; | |
| 333 | + } | |
| 334 | + | |
| 335 | + cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); | |
| 336 | + | |
| 337 | + return idx; | |
| 338 | +} | |
| 339 | + | |
| 340 | +int cgx_lmac_addr_reset(u8 cgx_id, u8 lmac_id) | |
| 341 | +{ | |
| 342 | + struct cgx *cgx_dev = cgx_get_pdata(cgx_id); | |
| 343 | + struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | |
| 344 | + struct mac_ops *mac_ops; | |
| 345 | + u8 index = 0, id; | |
| 346 | + u64 cfg; | |
| 347 | + | |
| 348 | + if (!lmac) | |
| 349 | + return -ENODEV; | |
| 350 | + | |
| 351 | + mac_ops = cgx_dev->mac_ops; | |
| 352 | + /* Restore index 0 to its default init value as done during | |
| 353 | + * cgx_lmac_init | |
| 354 | + */ | |
| 355 | + set_bit(0, lmac->mac_to_index_bmap.bmap); | |
| 356 | + | |
| 357 | + id = get_sequence_id_of_lmac(cgx_dev, lmac_id); | |
| 358 | + | |
| 359 | + index = id * lmac->mac_to_index_bmap.max + index; | |
| 360 | + cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), 0); | |
| 361 | + | |
| 362 | + /* Reset CGXX_CMRX_RX_DMAC_CTL0 register to default state */ | |
| 363 | + cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); | |
| 364 | + cfg &= ~CGX_DMAC_CAM_ACCEPT; | |
| 365 | + cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_MCAST_MODE); | |
| 366 | + cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); | |
| 367 | + | |
| 368 | + return 0; | |
| 369 | +} | |
| 370 | + | |
| 371 | +/* Allows caller to change macaddress associated with index | |
| 372 | + * in dmac filter table including index 0 reserved for | |
| 373 | + * interface mac address | |
| 374 | + */ | |
| 375 | +int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index) | |
| 376 | +{ | |
| 377 | + struct cgx *cgx_dev = cgx_get_pdata(cgx_id); | |
| 378 | + struct mac_ops *mac_ops; | |
| 379 | + struct lmac *lmac; | |
| 380 | + u64 cfg; | |
| 381 | + int id; | |
| 382 | + | |
| 383 | + lmac = lmac_pdata(lmac_id, cgx_dev); | |
| 384 | + if (!lmac) | |
| 385 | + return -ENODEV; | |
| 386 | + | |
| 387 | + mac_ops = cgx_dev->mac_ops; | |
| 388 | + /* Validate the index */ | |
| 389 | + if (index >= lmac->mac_to_index_bmap.max) | |
| 390 | + return -EINVAL; | |
| 391 | + | |
| 392 | + /* ensure index is already set */ | |
| 393 | + if (!test_bit(index, lmac->mac_to_index_bmap.bmap)) | |
| 394 | + return -EINVAL; | |
| 395 | + | |
| 396 | + id = get_sequence_id_of_lmac(cgx_dev, lmac_id); | |
| 397 | + | |
| 398 | + index = id * lmac->mac_to_index_bmap.max + index; | |
| 399 | + | |
| 400 | + cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8))); | |
| 401 | + cfg &= ~CGX_RX_DMAC_ADR_MASK; | |
| 402 | + cfg |= mac2u64 (mac_addr); | |
| 403 | + | |
| 404 | + cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg); | |
| 405 | + return 0; | |
| 406 | +} | |
| 407 | + | |
| 408 | +int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index) | |
| 409 | +{ | |
| 410 | + struct cgx *cgx_dev = cgx_get_pdata(cgx_id); | |
| 411 | + struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | |
| 412 | + struct mac_ops *mac_ops; | |
| 413 | + u8 mac[ETH_ALEN]; | |
| 414 | + u64 cfg; | |
| 415 | + int id; | |
| 416 | + | |
| 417 | + if (!lmac) | |
| 418 | + return -ENODEV; | |
| 419 | + | |
| 420 | + mac_ops = cgx_dev->mac_ops; | |
| 421 | + /* Validate the index */ | |
| 422 | + if (index >= lmac->mac_to_index_bmap.max) | |
| 423 | + return -EINVAL; | |
| 424 | + | |
| 425 | + /* Skip deletion for reserved index i.e. index 0 */ | |
| 426 | + if (index == 0) | |
| 427 | + return 0; | |
| 428 | + | |
| 429 | + rvu_free_rsrc(&lmac->mac_to_index_bmap, index); | |
| 430 | + | |
| 431 | + id = get_sequence_id_of_lmac(cgx_dev, lmac_id); | |
| 432 | + | |
| 433 | + index = id * lmac->mac_to_index_bmap.max + index; | |
| 434 | + | |
| 435 | + /* Read MAC address to check whether it is ucast or mcast */ | |
| 436 | + cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8))); | |
| 437 | + | |
| 438 | + cfg2mac(cfg, mac); | |
| 439 | + if (is_multicast_ether_addr(mac)) | |
| 440 | + lmac->mcast_filters_count--; | |
| 441 | + | |
| 442 | + if (!lmac->mcast_filters_count) { | |
| 443 | + cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); | |
| 444 | + cfg &= ~GENMASK_ULL(2, 1); | |
| 445 | + cfg |= CGX_DMAC_MCAST_MODE; | |
| 446 | + cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); | |
| 447 | + } | |
| 448 | + | |
| 449 | + cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), 0); | |
| 450 | + | |
| 451 | + return 0; | |
| 452 | +} | |
| 453 | + | |
| 454 | +int cgx_lmac_addr_max_entries_get(u8 cgx_id, u8 lmac_id) | |
| 455 | +{ | |
| 456 | + struct cgx *cgx_dev = cgx_get_pdata(cgx_id); | |
| 457 | + struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | |
| 458 | + | |
| 459 | + if (lmac) | |
| 460 | + return lmac->mac_to_index_bmap.max; | |
| 461 | + | |
| 462 | + return 0; | |
| 463 | +} | |
| 464 | + | |
| 236 | 465 | u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) |
| 237 | 466 | { |
| 238 | 467 | struct cgx *cgx_dev = cgx_get_pdata(cgx_id); |
| 468 | + struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | |
| 239 | 469 | struct mac_ops *mac_ops; |
| 470 | + int index; | |
| 240 | 471 | u64 cfg; |
| 472 | + int id; | |
| 241 | 473 | |
| 242 | 474 | mac_ops = cgx_dev->mac_ops; |
| 243 | 475 | |
| 244 | − cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8); | |
| 476 | + id = get_sequence_id_of_lmac(cgx_dev, lmac_id); | |
| 477 | + | |
| 478 | + index = id * lmac->mac_to_index_bmap.max; | |
| 479 | + | |
| 480 | + cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8); | |
| 245 | 481 | return cfg & CGX_RX_DMAC_ADR_MASK; |
| 246 | 482 | } |
| 247 | 483 | |
| @@ -297,35 +533,51 @@ int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable) · 49 unmodified lines | ||
| 297 | 533 | void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) |
| 298 | 534 | { |
| 299 | 535 | struct cgx *cgx = cgx_get_pdata(cgx_id); |
| 536 | + struct lmac *lmac = lmac_pdata(lmac_id, cgx); | |
| 537 | + u16 max_dmac = lmac->mac_to_index_bmap.max; | |
| 300 | 538 | struct mac_ops *mac_ops; |
| 539 | + int index, i; | |
| 301 | 540 | u64 cfg = 0; |
| 541 | + int id; | |
| 302 | 542 | |
| 303 | 543 | if (!cgx) |
| 304 | 544 | return; |
| 305 | 545 | |
| 546 | + id = get_sequence_id_of_lmac(cgx, lmac_id); | |
| 547 | + | |
| 306 | 548 | mac_ops = cgx->mac_ops; |
| 307 | 549 | if (enable) { |
| 308 | 550 | /* Enable promiscuous mode on LMAC */ |
| 309 | 551 | cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); |
| 310 | − cfg &= ~(CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE); | |
| 311 | − cfg |= CGX_DMAC_BCAST_MODE; | |
| 552 | + cfg &= ~CGX_DMAC_CAM_ACCEPT; | |
| 553 | + cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_MCAST_MODE); | |
| 312 | 554 | cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); |
| 313 | 555 | |
| 314 | − cfg = cgx_read(cgx, 0, | |
| 315 | − (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); | |
| 316 | − cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE; | |
| 317 | − cgx_write(cgx, 0, | |
| 318 | − (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); | |
| 556 | + for (i = 0; i < max_dmac; i++) { | |
| 557 | + index = id * max_dmac + i; | |
| 558 | + cfg = cgx_read(cgx, 0, | |
| 559 | + (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8)); | |
| 560 | + cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE; | |
| 561 | + cgx_write(cgx, 0, | |
| 562 | + (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8), cfg); | |
| 563 | + } | |
| 319 | 564 | } else { |
| 320 | 565 | /* Disable promiscuous mode */ |
| 321 | 566 | cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); |
| 322 | 567 | cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE; |
| 323 | 568 | cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); |
| 324 | − cfg = cgx_read(cgx, 0, | |
| 325 | − (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); | |
| 326 | − cfg |= CGX_DMAC_CAM_ADDR_ENABLE; | |
| 327 | − cgx_write(cgx, 0, | |
| 328 | − (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); | |
| 569 | + for (i = 0; i < max_dmac; i++) { | |
| 570 | + index = id * max_dmac + i; | |
| 571 | + cfg = cgx_read(cgx, 0, | |
| 572 | + (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8)); | |
| 573 | + if ((cfg & CGX_RX_DMAC_ADR_MASK) != 0) { | |
| 574 | + cfg |= CGX_DMAC_CAM_ADDR_ENABLE; | |
| 575 | + cgx_write(cgx, 0, | |
| 576 | + (CGXX_CMRX_RX_DMAC_CAM0 + | |
| 577 | + index * 0x8), | |
| 578 | + cfg); | |
| 579 | + } | |
| 580 | + } | |
| 329 | 581 | } |
| 330 | 582 | } |
| 331 | 583 | |
| @@ -1234,6 +1486,15 @@ static int cgx_lmac_init(struct cgx *cgx) · 902 unmodified lines | ||
| 1234 | 1486 | } |
| 1235 | 1487 | |
| 1236 | 1488 | lmac->cgx = cgx; |
| 1489 | + lmac->mac_to_index_bmap.max = | |
| 1490 | + MAX_DMAC_ENTRIES_PER_CGX / cgx->lmac_count; | |
| 1491 | + err = rvu_alloc_bitmap(&lmac->mac_to_index_bmap); | |
| 1492 | + if (err) | |
| 1493 | + return err; | |
| 1494 | + | |
| 1495 | + /* Reserve first entry for default MAC address */ | |
| 1496 | + set_bit(0, lmac->mac_to_index_bmap.bmap); | |
| 1497 | + | |
| 1237 | 1498 | init_waitqueue_head(&lmac->wq_cmd_cmplt); |
| 1238 | 1499 | mutex_init(&lmac->cmd_lock); |
| 1239 | 1500 | spin_lock_init(&lmac->event_cb_lock); |
| @@ -1274,6 +1535,7 @@ static int cgx_lmac_exit(struct cgx *cgx) · 34 unmodified lines | ||
| 1274 | 1535 | continue; |
| 1275 | 1536 | cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, false); |
| 1276 | 1537 | cgx_configure_interrupt(cgx, lmac, lmac->lmac_id, true); |
| 1538 | + kfree(lmac->mac_to_index_bmap.bmap); | |
| 1277 | 1539 | kfree(lmac->name); |
| 1278 | 1540 | kfree(lmac); |
| 1279 | 1541 | } |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | #define CGX_ID_MASK 0x7 |
| 25 | 25 | #define MAX_LMAC_PER_CGX 4 |
| 26 | +#define MAX_DMAC_ENTRIES_PER_CGX 32 | |
| 26 | 27 | #define CGX_FIFO_LEN 65536 /* 64K for both Rx & Tx */ |
| 27 | 28 | #define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX) |
| 28 | 29 | |
| @@ -46,10 +47,12 @@ · 17 unmodified lines | ||
| 46 | 47 | #define CGXX_CMRX_RX_DMAC_CTL0 (0x1F8 + mac_ops->csr_offset) |
| 47 | 48 | #define CGX_DMAC_CTL0_CAM_ENABLE BIT_ULL(3) |
| 48 | 49 | #define CGX_DMAC_CAM_ACCEPT BIT_ULL(3) |
| 50 | +#define CGX_DMAC_MCAST_MODE_CAM BIT_ULL(2) | |
| 49 | 51 | #define CGX_DMAC_MCAST_MODE BIT_ULL(1) |
| 50 | 52 | #define CGX_DMAC_BCAST_MODE BIT_ULL(0) |
| 51 | 53 | #define CGXX_CMRX_RX_DMAC_CAM0 (0x200 + mac_ops->csr_offset) |
| 52 | 54 | #define CGX_DMAC_CAM_ADDR_ENABLE BIT_ULL(48) |
| 55 | +#define CGX_DMAC_CAM_ENTRY_LMACID GENMASK_ULL(50, 49) | |
| 53 | 56 | #define CGXX_CMRX_RX_DMAC_CAM1 0x400 |
| 54 | 57 | #define CGX_RX_DMAC_ADR_MASK GENMASK_ULL(47, 0) |
| 55 | 58 | #define CGXX_CMRX_TX_STAT0 0x700 |
| @@ -139,7 +142,11 @@ int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat); · 83 unmodified lines | ||
| 139 | 142 | int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); |
| 140 | 143 | int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable); |
| 141 | 144 | int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr); |
| 145 | +int cgx_lmac_addr_reset(u8 cgx_id, u8 lmac_id); | |
| 142 | 146 | u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id); |
| 147 | +int cgx_lmac_addr_add(u8 cgx_id, u8 lmac_id, u8 *mac_addr); | |
| 148 | +int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index); | |
| 149 | +int cgx_lmac_addr_max_entries_get(u8 cgx_id, u8 lmac_id); | |
| 143 | 150 | void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable); |
| 144 | 151 | void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable); |
| 145 | 152 | int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable); |
| @@ -165,4 +172,7 @@ u8 cgx_get_lmacid(void *cgxd, u8 lmac_index); · 19 unmodified lines | ||
| 165 | 172 | unsigned long cgx_get_lmac_bmap(void *cgxd); |
| 166 | 173 | void cgx_lmac_write(int cgx_id, int lmac_id, u64 offset, u64 val); |
| 167 | 174 | u64 cgx_lmac_read(int cgx_id, int lmac_id, u64 offset); |
| 175 | +int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index); | |
| 176 | +u64 cgx_read_dmac_ctrl(void *cgxd, int lmac_id); | |
| 177 | +u64 cgx_read_dmac_entry(void *cgxd, int index); | |
| 168 | 178 | #endif /* CGX_H */ |
| @@ -10,17 +10,19 @@ · 9 unmodified lines | ||
| 10 | 10 | #include "rvu.h" |
| 11 | 11 | #include "cgx.h" |
| 12 | 12 | /** |
| 13 | − * struct lmac | |
| 13 | + * struct lmac - per lmac locks and properties | |
| 14 | 14 | * @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion |
| 15 | 15 | * @cmd_lock: Lock to serialize the command interface |
| 16 | 16 | * @resp: command response |
| 17 | 17 | * @link_info: link related information |
| 18 | + * @mac_to_index_bmap: Mac address to CGX table index mapping | |
| 18 | 19 | * @event_cb: callback for linkchange events |
| 19 | 20 | * @event_cb_lock: lock for serializing callback with unregister |
| 20 | − * @cmd_pend: flag set before new command is started | |
| 21 | − * flag cleared after command response is received | |
| 22 | 21 | * @cgx: parent cgx port |
| 22 | + * @mcast_filters_count: Number of multicast filters installed | |
| 23 | 23 | * @lmac_id: lmac port id |
| 24 | + * @cmd_pend: flag set before new command is started | |
| 25 | + * flag cleared after command response is received | |
| 24 | 26 | * @name: lmac port name |
| 25 | 27 | */ |
| 26 | 28 | struct lmac { |
| @@ -29,12 +31,14 @@ struct lmac { · 2 unmodified lines | ||
| 29 | 31 | struct mutex cmd_lock; |
| 30 | 32 | u64 resp; |
| 31 | 33 | struct cgx_link_user_info link_info; |
| 34 | + struct rsrc_bmap mac_to_index_bmap; | |
| 32 | 35 | struct cgx_event_cb event_cb; |
| 33 | 36 | /* lock for serializing callback with unregister */ |
| 34 | 37 | spinlock_t event_cb_lock; |
| 35 | − bool cmd_pend; | |
| 36 | 38 | struct cgx *cgx; |
| 39 | + u8 mcast_filters_count; | |
| 37 | 40 | u8 lmac_id; |
| 41 | + bool cmd_pend; | |
| 38 | 42 | char *name; |
| 39 | 43 | }; |
| 40 | 44 | |
| @@ -134,6 +134,8 @@ M(MSIX_OFFSET, 0x005, msix_offset, msg_req, msix_offset_rsp) \ · 133 unmodified lines | ||
| 134 | 134 | M(VF_FLR, 0x006, vf_flr, msg_req, msg_rsp) \ |
| 135 | 135 | M(PTP_OP, 0x007, ptp_op, ptp_req, ptp_rsp) \ |
| 136 | 136 | M(GET_HW_CAP, 0x008, get_hw_cap, msg_req, get_hw_cap_rsp) \ |
| 137 | +M(LMTST_TBL_SETUP, 0x00a, lmtst_tbl_setup, lmtst_tbl_setup_req, \ | |
| 138 | + msg_rsp) \ | |
| 137 | 139 | M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \ |
| 138 | 140 | /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ |
| 139 | 141 | M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \ |
| @@ -163,7 +165,15 @@ M(CGX_SET_LINK_MODE, 0x214, cgx_set_link_mode, cgx_set_link_mode_req,\ · 23 unmodified lines | ||
| 163 | 165 | M(CGX_FEATURES_GET, 0x215, cgx_features_get, msg_req, \ |
| 164 | 166 | cgx_features_info_msg) \ |
| 165 | 167 | M(RPM_STATS, 0x216, rpm_stats, msg_req, rpm_stats_rsp) \ |
| 166 | − /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ | |
| 168 | +M(CGX_MAC_ADDR_ADD, 0x217, cgx_mac_addr_add, cgx_mac_addr_add_req, \ | |
| 169 | + cgx_mac_addr_add_rsp) \ | |
| 170 | +M(CGX_MAC_ADDR_DEL, 0x218, cgx_mac_addr_del, cgx_mac_addr_del_req, \ | |
| 171 | + msg_rsp) \ | |
| 172 | +M(CGX_MAC_MAX_ENTRIES_GET, 0x219, cgx_mac_max_entries_get, msg_req, \ | |
| 173 | + cgx_max_dmac_entries_get_rsp) \ | |
| 174 | +M(CGX_MAC_ADDR_RESET, 0x21A, cgx_mac_addr_reset, msg_req, msg_rsp) \ | |
| 175 | +M(CGX_MAC_ADDR_UPDATE, 0x21B, cgx_mac_addr_update, cgx_mac_addr_update_req, \ | |
| 176 | + msg_rsp) \ | |
| 167 | 177 | /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ |
| 168 | 178 | M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \ |
| 169 | 179 | npa_lf_alloc_req, npa_lf_alloc_rsp) \ |
| @@ -401,6 +411,38 @@ struct cgx_mac_addr_set_or_get { · 231 unmodified lines | ||
| 401 | 411 | u8 mac_addr[ETH_ALEN]; |
| 402 | 412 | }; |
| 403 | 413 | |
| 414 | +/* Structure for requesting the operation to | |
| 415 | + * add DMAC filter entry into CGX interface | |
| 416 | + */ | |
| 417 | +struct cgx_mac_addr_add_req { | |
| 418 | + struct mbox_msghdr hdr; | |
| 419 | + u8 mac_addr[ETH_ALEN]; | |
| 420 | +}; | |
| 421 | + | |
| 422 | +/* Structure for response against the operation to | |
| 423 | + * add DMAC filter entry into CGX interface | |
| 424 | + */ | |
| 425 | +struct cgx_mac_addr_add_rsp { | |
| 426 | + struct mbox_msghdr hdr; | |
| 427 | + u8 index; | |
| 428 | +}; | |
| 429 | + | |
| 430 | +/* Structure for requesting the operation to | |
| 431 | + * delete DMAC filter entry from CGX interface | |
| 432 | + */ | |
| 433 | +struct cgx_mac_addr_del_req { | |
| 434 | + struct mbox_msghdr hdr; | |
| 435 | + u8 index; | |
| 436 | +}; | |
| 437 | + | |
| 438 | +/* Structure for response against the operation to | |
| 439 | + * get maximum supported DMAC filter entries | |
| 440 | + */ | |
| 441 | +struct cgx_max_dmac_entries_get_rsp { | |
| 442 | + struct mbox_msghdr hdr; | |
| 443 | + u8 max_dmac_filters; | |
| 444 | +}; | |
| 445 | + | |
| 404 | 446 | struct cgx_link_user_info { |
| 405 | 447 | uint64_t link_up:1; |
| 406 | 448 | uint64_t full_duplex:1; |
| @@ -499,6 +541,12 @@ struct cgx_set_link_mode_rsp { · 92 unmodified lines | ||
| 499 | 541 | int status; |
| 500 | 542 | }; |
| 501 | 543 | |
| 544 | +struct cgx_mac_addr_update_req { | |
| 545 | + struct mbox_msghdr hdr; | |
| 546 | + u8 mac_addr[ETH_ALEN]; | |
| 547 | + u8 index; | |
| 548 | +}; | |
| 549 | + | |
| 502 | 550 | #define RVU_LMAC_FEAT_FC BIT_ULL(0) /* pause frames */ |
| 503 | 551 | #define RVU_LMAC_FEAT_PTP BIT_ULL(1) /* precision time protocol */ |
| 504 | 552 | #define RVU_MAC_VERSION BIT_ULL(2) |
| @@ -1278,6 +1326,14 @@ struct set_vf_perm { · 773 unmodified lines | ||
| 1278 | 1326 | u64 flags; |
| 1279 | 1327 | }; |
| 1280 | 1328 | |
| 1329 | +struct lmtst_tbl_setup_req { | |
| 1330 | + struct mbox_msghdr hdr; | |
| 1331 | + u16 base_pcifunc; | |
| 1332 | + u8 use_local_lmt_region; | |
| 1333 | + u64 lmt_iova; | |
| 1334 | + u64 rsvd[4]; | |
| 1335 | +}; | |
| 1336 | + | |
| 1281 | 1337 | /* CPT mailbox error codes |
| 1282 | 1338 | * Range 901 - 1000. |
| 1283 | 1339 | */ |
| @@ -2333,6 +2333,7 @@ static void __rvu_flr_handler(struct rvu *rvu, u16 pcifunc) · 2332 unmodified lines | ||
| 2333 | 2333 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSOW); |
| 2334 | 2334 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSO); |
| 2335 | 2335 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NPA); |
| 2336 | + rvu_reset_lmt_map_tbl(rvu, pcifunc); | |
| 2336 | 2337 | rvu_detach_rsrcs(rvu, NULL, pcifunc); |
| 2337 | 2338 | mutex_unlock(&rvu->flr_lock); |
| 2338 | 2339 | } |
| @@ -243,6 +243,7 @@ struct rvu_pfvf { · 242 unmodified lines | ||
| 243 | 243 | u8 nix_blkaddr; /* BLKADDR_NIX0/1 assigned to this PF */ |
| 244 | 244 | u8 nix_rx_intf; /* NIX0_RX/NIX1_RX interface to NPC */ |
| 245 | 245 | u8 nix_tx_intf; /* NIX0_TX/NIX1_TX interface to NPC */ |
| 246 | + u64 lmt_base_addr; /* Preseving the pcifunc's lmtst base addr*/ | |
| 246 | 247 | unsigned long flags; |
| 247 | 248 | }; |
| 248 | 249 | |
| @@ -656,6 +657,8 @@ void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable); · 407 unmodified lines | ||
| 656 | 657 | int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start); |
| 657 | 658 | int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index, |
| 658 | 659 | int rxtxflag, u64 *stat); |
| 660 | +void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc); | |
| 661 | + | |
| 659 | 662 | /* NPA APIs */ |
| 660 | 663 | int rvu_npa_init(struct rvu *rvu); |
| 661 | 664 | void rvu_npa_freemem(struct rvu *rvu); |
| @@ -741,6 +744,7 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, · 79 unmodified lines | ||
| 741 | 744 | bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature); |
| 742 | 745 | u32 rvu_cgx_get_fifolen(struct rvu *rvu); |
| 743 | 746 | void *rvu_first_cgx_pdata(struct rvu *rvu); |
| 747 | +int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id); | |
| 744 | 748 | |
| 745 | 749 | int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf, |
| 746 | 750 | int type); |
| @@ -754,6 +758,9 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot); · 7 unmodified lines | ||
| 754 | 758 | int rvu_set_channels_base(struct rvu *rvu); |
| 755 | 759 | void rvu_program_channels(struct rvu *rvu); |
| 756 | 760 | |
| 761 | +/* CN10K RVU - LMT*/ | |
| 762 | +void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc); | |
| 763 | + | |
| 757 | 764 | #ifdef CONFIG_DEBUG_FS |
| 758 | 765 | void rvu_dbg_init(struct rvu *rvu); |
| 759 | 766 | void rvu_dbg_exit(struct rvu *rvu); |
| @@ -63,7 +63,7 @@ static u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id) · 62 unmodified lines | ||
| 63 | 63 | return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id]; |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | −static int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id) | |
| 66 | +int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id) | |
| 67 | 67 | { |
| 68 | 68 | unsigned long pfmap; |
| 69 | 69 | |
| @@ -454,6 +454,31 @@ int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start) · 384 unmodified lines | ||
| 454 | 454 | return 0; |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | +void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc) | |
| 458 | +{ | |
| 459 | + int pf = rvu_get_pf(pcifunc); | |
| 460 | + int i = 0, lmac_count = 0; | |
| 461 | + u8 max_dmac_filters; | |
| 462 | + u8 cgx_id, lmac_id; | |
| 463 | + void *cgx_dev; | |
| 464 | + | |
| 465 | + if (!is_cgx_config_permitted(rvu, pcifunc)) | |
| 466 | + return; | |
| 467 | + | |
| 468 | + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); | |
| 469 | + cgx_dev = cgx_get_pdata(cgx_id); | |
| 470 | + lmac_count = cgx_get_lmac_cnt(cgx_dev); | |
| 471 | + max_dmac_filters = MAX_DMAC_ENTRIES_PER_CGX / lmac_count; | |
| 472 | + | |
| 473 | + for (i = 0; i < max_dmac_filters; i++) | |
| 474 | + cgx_lmac_addr_del(cgx_id, lmac_id, i); | |
| 475 | + | |
| 476 | + /* As cgx_lmac_addr_del does not clear entry for index 0 | |
| 477 | + * so it needs to be done explicitly | |
| 478 | + */ | |
| 479 | + cgx_lmac_addr_reset(cgx_id, lmac_id); | |
| 480 | +} | |
| 481 | + | |
| 457 | 482 | int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req, |
| 458 | 483 | struct msg_rsp *rsp) |
| 459 | 484 | { |
| @@ -557,6 +582,63 @@ int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu, · 97 unmodified lines | ||
| 557 | 582 | return 0; |
| 558 | 583 | } |
| 559 | 584 | |
| 585 | +int rvu_mbox_handler_cgx_mac_addr_add(struct rvu *rvu, | |
| 586 | + struct cgx_mac_addr_add_req *req, | |
| 587 | + struct cgx_mac_addr_add_rsp *rsp) | |
| 588 | +{ | |
| 589 | + int pf = rvu_get_pf(req->hdr.pcifunc); | |
| 590 | + u8 cgx_id, lmac_id; | |
| 591 | + int rc = 0; | |
| 592 | + | |
| 593 | + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) | |
| 594 | + return -EPERM; | |
| 595 | + | |
| 596 | + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); | |
| 597 | + rc = cgx_lmac_addr_add(cgx_id, lmac_id, req->mac_addr); | |
| 598 | + if (rc >= 0) { | |
| 599 | + rsp->index = rc; | |
| 600 | + return 0; | |
| 601 | + } | |
| 602 | + | |
| 603 | + return rc; | |
| 604 | +} | |
| 605 | + | |
| 606 | +int rvu_mbox_handler_cgx_mac_addr_del(struct rvu *rvu, | |
| 607 | + struct cgx_mac_addr_del_req *req, | |
| 608 | + struct msg_rsp *rsp) | |
| 609 | +{ | |
| 610 | + int pf = rvu_get_pf(req->hdr.pcifunc); | |
| 611 | + u8 cgx_id, lmac_id; | |
| 612 | + | |
| 613 | + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) | |
| 614 | + return -EPERM; | |
| 615 | + | |
| 616 | + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); | |
| 617 | + return cgx_lmac_addr_del(cgx_id, lmac_id, req->index); | |
| 618 | +} | |
| 619 | + | |
| 620 | +int rvu_mbox_handler_cgx_mac_max_entries_get(struct rvu *rvu, | |
| 621 | + struct msg_req *req, | |
| 622 | + struct cgx_max_dmac_entries_get_rsp | |
| 623 | + *rsp) | |
| 624 | +{ | |
| 625 | + int pf = rvu_get_pf(req->hdr.pcifunc); | |
| 626 | + u8 cgx_id, lmac_id; | |
| 627 | + | |
| 628 | + /* If msg is received from PFs(which are not mapped to CGX LMACs) | |
| 629 | + * or VF then no entries are allocated for DMAC filters at CGX level. | |
| 630 | + * So returning zero. | |
| 631 | + */ | |
| 632 | + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) { | |
| 633 | + rsp->max_dmac_filters = 0; | |
| 634 | + return 0; | |
| 635 | + } | |
| 636 | + | |
| 637 | + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); | |
| 638 | + rsp->max_dmac_filters = cgx_lmac_addr_max_entries_get(cgx_id, lmac_id); | |
| 639 | + return 0; | |
| 640 | +} | |
| 641 | + | |
| 560 | 642 | int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu, |
| 561 | 643 | struct cgx_mac_addr_set_or_get *req, |
| 562 | 644 | struct cgx_mac_addr_set_or_get *rsp) |
| @@ -953,3 +1035,30 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu, · 390 unmodified lines | ||
| 953 | 1035 | rsp->status = cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac); |
| 954 | 1036 | return 0; |
| 955 | 1037 | } |
| 1038 | + | |
| 1039 | +int rvu_mbox_handler_cgx_mac_addr_reset(struct rvu *rvu, struct msg_req *req, | |
| 1040 | + struct msg_rsp *rsp) | |
| 1041 | +{ | |
| 1042 | + int pf = rvu_get_pf(req->hdr.pcifunc); | |
| 1043 | + u8 cgx_id, lmac_id; | |
| 1044 | + | |
| 1045 | + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) | |
| 1046 | + return -EPERM; | |
| 1047 | + | |
| 1048 | + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); | |
| 1049 | + return cgx_lmac_addr_reset(cgx_id, lmac_id); | |
| 1050 | +} | |
| 1051 | + | |
| 1052 | +int rvu_mbox_handler_cgx_mac_addr_update(struct rvu *rvu, | |
| 1053 | + struct cgx_mac_addr_update_req *req, | |
| 1054 | + struct msg_rsp *rsp) | |
| 1055 | +{ | |
| 1056 | + int pf = rvu_get_pf(req->hdr.pcifunc); | |
| 1057 | + u8 cgx_id, lmac_id; | |
| 1058 | + | |
| 1059 | + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) | |
| 1060 | + return -EPERM; | |
| 1061 | + | |
| 1062 | + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); | |
| 1063 | + return cgx_lmac_addr_update(cgx_id, lmac_id, req->mac_addr, req->index); | |
| 1064 | +} | |
| @@ -10,6 +10,206 @@ · 9 unmodified lines | ||
| 10 | 10 | #include "cgx.h" |
| 11 | 11 | #include "rvu_reg.h" |
| 12 | 12 | |
| 13 | +/* RVU LMTST */ | |
| 14 | +#define LMT_TBL_OP_READ 0 | |
| 15 | +#define LMT_TBL_OP_WRITE 1 | |
| 16 | +#define LMT_MAP_TABLE_SIZE (128 * 1024) | |
| 17 | +#define LMT_MAPTBL_ENTRY_SIZE 16 | |
| 18 | + | |
| 19 | +/* Function to perform operations (read/write) on lmtst map table */ | |
| 20 | +static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val, | |
| 21 | + int lmt_tbl_op) | |
| 22 | +{ | |
| 23 | + void __iomem *lmt_map_base; | |
| 24 | + u64 tbl_base; | |
| 25 | + | |
| 26 | + tbl_base = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_MAP_BASE); | |
| 27 | + | |
| 28 | + lmt_map_base = ioremap_wc(tbl_base, LMT_MAP_TABLE_SIZE); | |
| 29 | + if (!lmt_map_base) { | |
| 30 | + dev_err(rvu->dev, "Failed to setup lmt map table mapping!!\n"); | |
| 31 | + return -ENOMEM; | |
| 32 | + } | |
| 33 | + | |
| 34 | + if (lmt_tbl_op == LMT_TBL_OP_READ) { | |
| 35 | + *val = readq(lmt_map_base + index); | |
| 36 | + } else { | |
| 37 | + writeq((*val), (lmt_map_base + index)); | |
| 38 | + /* Flushing the AP interceptor cache to make APR_LMT_MAP_ENTRY_S | |
| 39 | + * changes effective. Write 1 for flush and read is being used as a | |
| 40 | + * barrier and sets up a data dependency. Write to 0 after a write | |
| 41 | + * to 1 to complete the flush. | |
| 42 | + */ | |
| 43 | + rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CTL, BIT_ULL(0)); | |
| 44 | + rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CTL); | |
| 45 | + rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CTL, 0x00); | |
| 46 | + } | |
| 47 | + | |
| 48 | + iounmap(lmt_map_base); | |
| 49 | + return 0; | |
| 50 | +} | |
| 51 | + | |
| 52 | +static u32 rvu_get_lmtst_tbl_index(struct rvu *rvu, u16 pcifunc) | |
| 53 | +{ | |
| 54 | + return ((rvu_get_pf(pcifunc) * rvu->hw->total_vfs) + | |
| 55 | + (pcifunc & RVU_PFVF_FUNC_MASK)) * LMT_MAPTBL_ENTRY_SIZE; | |
| 56 | +} | |
| 57 | + | |
| 58 | +static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc, | |
| 59 | + u64 iova, u64 *lmt_addr) | |
| 60 | +{ | |
| 61 | + u64 pa, val, pf; | |
| 62 | + int err; | |
| 63 | + | |
| 64 | + if (!iova) { | |
| 65 | + dev_err(rvu->dev, "%s Requested Null address for transulation\n", __func__); | |
| 66 | + return -EINVAL; | |
| 67 | + } | |
| 68 | + | |
| 69 | + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_REQ, iova); | |
| 70 | + pf = rvu_get_pf(pcifunc) & 0x1F; | |
| 71 | + val = BIT_ULL(63) | BIT_ULL(14) | BIT_ULL(13) | pf << 8 | | |
| 72 | + ((pcifunc & RVU_PFVF_FUNC_MASK) & 0xFF); | |
| 73 | + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TXN_REQ, val); | |
| 74 | + | |
| 75 | + err = rvu_poll_reg(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS, BIT_ULL(0), false); | |
| 76 | + if (err) { | |
| 77 | + dev_err(rvu->dev, "%s LMTLINE iova transulation failed\n", __func__); | |
| 78 | + return err; | |
| 79 | + } | |
| 80 | + val = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS); | |
| 81 | + if (val & ~0x1ULL) { | |
| 82 | + dev_err(rvu->dev, "%s LMTLINE iova transulation failed err:%llx\n", __func__, val); | |
| 83 | + return -EIO; | |
| 84 | + } | |
| 85 | + /* PA[51:12] = RVU_AF_SMMU_TLN_FLIT1[60:21] | |
| 86 | + * PA[11:0] = IOVA[11:0] | |
| 87 | + */ | |
| 88 | + pa = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TLN_FLIT1) >> 21; | |
| 89 | + pa &= GENMASK_ULL(39, 0); | |
| 90 | + *lmt_addr = (pa << 12) | (iova & 0xFFF); | |
| 91 | + | |
| 92 | + return 0; | |
| 93 | +} | |
| 94 | + | |
| 95 | +static int rvu_update_lmtaddr(struct rvu *rvu, u16 pcifunc, u64 lmt_addr) | |
| 96 | +{ | |
| 97 | + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); | |
| 98 | + u32 tbl_idx; | |
| 99 | + int err = 0; | |
| 100 | + u64 val; | |
| 101 | + | |
| 102 | + /* Read the current lmt addr of pcifunc */ | |
| 103 | + tbl_idx = rvu_get_lmtst_tbl_index(rvu, pcifunc); | |
| 104 | + err = lmtst_map_table_ops(rvu, tbl_idx, &val, LMT_TBL_OP_READ); | |
| 105 | + if (err) { | |
| 106 | + dev_err(rvu->dev, | |
| 107 | + "Failed to read LMT map table: index 0x%x err %d\n", | |
| 108 | + tbl_idx, err); | |
| 109 | + return err; | |
| 110 | + } | |
| 111 | + | |
| 112 | + /* Storing the seondary's lmt base address as this needs to be | |
| 113 | + * reverted in FLR. Also making sure this default value doesn't | |
| 114 | + * get overwritten on multiple calls to this mailbox. | |
| 115 | + */ | |
| 116 | + if (!pfvf->lmt_base_addr) | |
| 117 | + pfvf->lmt_base_addr = val; | |
| 118 | + | |
| 119 | + /* Update the LMT table with new addr */ | |
| 120 | + err = lmtst_map_table_ops(rvu, tbl_idx, &lmt_addr, LMT_TBL_OP_WRITE); | |
| 121 | + if (err) { | |
| 122 | + dev_err(rvu->dev, | |
| 123 | + "Failed to update LMT map table: index 0x%x err %d\n", | |
| 124 | + tbl_idx, err); | |
| 125 | + return err; | |
| 126 | + } | |
| 127 | + return 0; | |
| 128 | +} | |
| 129 | + | |
| 130 | +int rvu_mbox_handler_lmtst_tbl_setup(struct rvu *rvu, | |
| 131 | + struct lmtst_tbl_setup_req *req, | |
| 132 | + struct msg_rsp *rsp) | |
| 133 | +{ | |
| 134 | + u64 lmt_addr, val; | |
| 135 | + u32 pri_tbl_idx; | |
| 136 | + int err = 0; | |
| 137 | + | |
| 138 | + /* Check if PF_FUNC wants to use it's own local memory as LMTLINE | |
| 139 | + * region, if so, convert that IOVA to physical address and | |
| 140 | + * populate LMT table with that address | |
| 141 | + */ | |
| 142 | + if (req->use_local_lmt_region) { | |
| 143 | + err = rvu_get_lmtaddr(rvu, req->hdr.pcifunc, | |
| 144 | + req->lmt_iova, &lmt_addr); | |
| 145 | + if (err < 0) | |
| 146 | + return err; | |
| 147 | + | |
| 148 | + /* Update the lmt addr for this PFFUNC in the LMT table */ | |
| 149 | + err = rvu_update_lmtaddr(rvu, req->hdr.pcifunc, lmt_addr); | |
| 150 | + if (err) | |
| 151 | + return err; | |
| 152 | + } | |
| 153 | + | |
| 154 | + /* Reconfiguring lmtst map table in lmt region shared mode i.e. make | |
| 155 | + * multiple PF_FUNCs to share an LMTLINE region, so primary/base | |
| 156 | + * pcifunc (which is passed as an argument to mailbox) is the one | |
| 157 | + * whose lmt base address will be shared among other secondary | |
| 158 | + * pcifunc (will be the one who is calling this mailbox). | |
| 159 | + */ | |
| 160 | + if (req->base_pcifunc) { | |
| 161 | + /* Calculating the LMT table index equivalent to primary | |
| 162 | + * pcifunc. | |
| 163 | + */ | |
| 164 | + pri_tbl_idx = rvu_get_lmtst_tbl_index(rvu, req->base_pcifunc); | |
| 165 | + | |
| 166 | + /* Read the base lmt addr of the primary pcifunc */ | |
| 167 | + err = lmtst_map_table_ops(rvu, pri_tbl_idx, &val, | |
| 168 | + LMT_TBL_OP_READ); | |
| 169 | + if (err) { | |
| 170 | + dev_err(rvu->dev, | |
| 171 | + "Failed to read LMT map table: index 0x%x err %d\n", | |
| 172 | + pri_tbl_idx, err); | |
| 173 | + return err; | |
| 174 | + } | |
| 175 | + | |
| 176 | + /* Update the base lmt addr of secondary with primary's base | |
| 177 | + * lmt addr. | |
| 178 | + */ | |
| 179 | + err = rvu_update_lmtaddr(rvu, req->hdr.pcifunc, val); | |
| 180 | + if (err) | |
| 181 | + return err; | |
| 182 | + } | |
| 183 | + | |
| 184 | + return 0; | |
| 185 | +} | |
| 186 | + | |
| 187 | +/* Resetting the lmtst map table to original base addresses */ | |
| 188 | +void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc) | |
| 189 | +{ | |
| 190 | + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); | |
| 191 | + u32 tbl_idx; | |
| 192 | + int err; | |
| 193 | + | |
| 194 | + if (is_rvu_otx2(rvu)) | |
| 195 | + return; | |
| 196 | + | |
| 197 | + if (pfvf->lmt_base_addr) { | |
| 198 | + /* This corresponds to lmt map table index */ | |
| 199 | + tbl_idx = rvu_get_lmtst_tbl_index(rvu, pcifunc); | |
| 200 | + /* Reverting back original lmt base addr for respective | |
| 201 | + * pcifunc. | |
| 202 | + */ | |
| 203 | + err = lmtst_map_table_ops(rvu, tbl_idx, &pfvf->lmt_base_addr, | |
| 204 | + LMT_TBL_OP_WRITE); | |
| 205 | + if (err) | |
| 206 | + dev_err(rvu->dev, | |
| 207 | + "Failed to update LMT map table: index 0x%x err %d\n", | |
| 208 | + tbl_idx, err); | |
| 209 | + pfvf->lmt_base_addr = 0; | |
| 210 | + } | |
| 211 | +} | |
| 212 | + | |
| 13 | 213 | int rvu_set_channels_base(struct rvu *rvu) |
| 14 | 214 | { |
| 15 | 215 | struct rvu_hwinfo *hw = rvu->hw; |
| @@ -1971,10 +1971,9 @@ static int cgx_print_stats(struct seq_file *s, int lmac_id) · 1970 unmodified lines | ||
| 1971 | 1971 | return err; |
| 1972 | 1972 | } |
| 1973 | 1973 | |
| 1974 | −static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused) | |
| 1974 | +static int rvu_dbg_derive_lmacid(struct seq_file *filp, int *lmac_id) | |
| 1975 | 1975 | { |
| 1976 | 1976 | struct dentry *current_dir; |
| 1977 | − int err, lmac_id; | |
| 1978 | 1977 | char *buf; |
| 1979 | 1978 | |
| 1980 | 1979 | current_dir = filp->file->f_path.dentry->d_parent; |
| @@ -1982,17 +1981,87 @@ static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused) · 1 unmodified line | ||
| 1982 | 1981 | if (!buf) |
| 1983 | 1982 | return -EINVAL; |
| 1984 | 1983 | |
| 1985 | − err = kstrtoint(buf + 1, 10, &lmac_id); | |
| 1986 | − if (!err) { | |
| 1987 | − err = cgx_print_stats(filp, lmac_id); | |
| 1988 | − if (err) | |
| 1989 | − return err; | |
| 1990 | − } | |
| 1984 | + return kstrtoint(buf + 1, 10, lmac_id); | |
| 1985 | +} | |
| 1986 | + | |
| 1987 | +static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused) | |
| 1988 | +{ | |
| 1989 | + int lmac_id, err; | |
| 1990 | + | |
| 1991 | + err = rvu_dbg_derive_lmacid(filp, &lmac_id); | |
| 1992 | + if (!err) | |
| 1993 | + return cgx_print_stats(filp, lmac_id); | |
| 1994 | + | |
| 1991 | 1995 | return err; |
| 1992 | 1996 | } |
| 1993 | 1997 | |
| 1994 | 1998 | RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL); |
| 1995 | 1999 | |
| 2000 | +static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id) | |
| 2001 | +{ | |
| 2002 | + struct pci_dev *pdev = NULL; | |
| 2003 | + void *cgxd = s->private; | |
| 2004 | + char *bcast, *mcast; | |
| 2005 | + u16 index, domain; | |
| 2006 | + u8 dmac[ETH_ALEN]; | |
| 2007 | + struct rvu *rvu; | |
| 2008 | + u64 cfg, mac; | |
| 2009 | + int pf; | |
| 2010 | + | |
| 2011 | + rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, | |
| 2012 | + PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); | |
| 2013 | + if (!rvu) | |
| 2014 | + return -ENODEV; | |
| 2015 | + | |
| 2016 | + pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id); | |
| 2017 | + domain = 2; | |
| 2018 | + | |
| 2019 | + pdev = pci_get_domain_bus_and_slot(domain, pf + 1, 0); | |
| 2020 | + if (!pdev) | |
| 2021 | + return 0; | |
| 2022 | + | |
| 2023 | + cfg = cgx_read_dmac_ctrl(cgxd, lmac_id); | |
| 2024 | + bcast = cfg & CGX_DMAC_BCAST_MODE ? "ACCEPT" : "REJECT"; | |
| 2025 | + mcast = cfg & CGX_DMAC_MCAST_MODE ? "ACCEPT" : "REJECT"; | |
| 2026 | + | |
| 2027 | + seq_puts(s, | |
| 2028 | + "PCI dev RVUPF BROADCAST MULTICAST FILTER-MODE\n"); | |
| 2029 | + seq_printf(s, "%s PF%d %9s %9s", | |
| 2030 | + dev_name(&pdev->dev), pf, bcast, mcast); | |
| 2031 | + if (cfg & CGX_DMAC_CAM_ACCEPT) | |
| 2032 | + seq_printf(s, "%12s\n\n", "UNICAST"); | |
| 2033 | + else | |
| 2034 | + seq_printf(s, "%16s\n\n", "PROMISCUOUS"); | |
| 2035 | + | |
| 2036 | + seq_puts(s, "\nDMAC-INDEX ADDRESS\n"); | |
| 2037 | + | |
| 2038 | + for (index = 0 ; index < 32 ; index++) { | |
| 2039 | + cfg = cgx_read_dmac_entry(cgxd, index); | |
| 2040 | + /* Display enabled dmac entries associated with current lmac */ | |
| 2041 | + if (lmac_id == FIELD_GET(CGX_DMAC_CAM_ENTRY_LMACID, cfg) && | |
| 2042 | + FIELD_GET(CGX_DMAC_CAM_ADDR_ENABLE, cfg)) { | |
| 2043 | + mac = FIELD_GET(CGX_RX_DMAC_ADR_MASK, cfg); | |
| 2044 | + u64_to_ether_addr(mac, dmac); | |
| 2045 | + seq_printf(s, "%7d %pM\n", index, dmac); | |
| 2046 | + } | |
| 2047 | + } | |
| 2048 | + | |
| 2049 | + return 0; | |
| 2050 | +} | |
| 2051 | + | |
| 2052 | +static int rvu_dbg_cgx_dmac_flt_display(struct seq_file *filp, void *unused) | |
| 2053 | +{ | |
| 2054 | + int err, lmac_id; | |
| 2055 | + | |
| 2056 | + err = rvu_dbg_derive_lmacid(filp, &lmac_id); | |
| 2057 | + if (!err) | |
| 2058 | + return cgx_print_dmac_flt(filp, lmac_id); | |
| 2059 | + | |
| 2060 | + return err; | |
| 2061 | +} | |
| 2062 | + | |
| 2063 | +RVU_DEBUG_SEQ_FOPS(cgx_dmac_flt, cgx_dmac_flt_display, NULL); | |
| 2064 | + | |
| 1996 | 2065 | static void rvu_dbg_cgx_init(struct rvu *rvu) |
| 1997 | 2066 | { |
| 1998 | 2067 | struct mac_ops *mac_ops; |
| @@ -2029,6 +2098,9 @@ static void rvu_dbg_cgx_init(struct rvu *rvu) · 30 unmodified lines | ||
| 2029 | 2098 | |
| 2030 | 2099 | debugfs_create_file("stats", 0600, rvu->rvu_dbg.lmac, |
| 2031 | 2100 | cgx, &rvu_dbg_cgx_stat_fops); |
| 2101 | + debugfs_create_file("mac_filter", 0600, | |
| 2102 | + rvu->rvu_dbg.lmac, cgx, | |
| 2103 | + &rvu_dbg_cgx_dmac_flt_fops); | |
| 2032 | 2104 | } |
| 2033 | 2105 | } |
| 2034 | 2106 | } |
| @@ -346,6 +346,9 @@ static void nix_interface_deinit(struct rvu *rvu, u16 pcifunc, u8 nixlf) · 345 unmodified lines | ||
| 346 | 346 | |
| 347 | 347 | /* Free and disable any MCAM entries used by this NIX LF */ |
| 348 | 348 | rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf); |
| 349 | + | |
| 350 | + /* Disable DMAC filters used */ | |
| 351 | + rvu_cgx_disable_dmac_entries(rvu, pcifunc); | |
| 349 | 352 | } |
| 350 | 353 | |
| 351 | 354 | int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, |
| @@ -49,6 +49,11 @@ · 48 unmodified lines | ||
| 49 | 49 | #define RVU_AF_PFX_VF_BAR4_ADDR (0x5400 | (a) << 4) |
| 50 | 50 | #define RVU_AF_PFX_VF_BAR4_CFG (0x5600 | (a) << 4) |
| 51 | 51 | #define RVU_AF_PFX_LMTLINE_ADDR (0x5800 | (a) << 4) |
| 52 | +#define RVU_AF_SMMU_ADDR_REQ (0x6000) | |
| 53 | +#define RVU_AF_SMMU_TXN_REQ (0x6008) | |
| 54 | +#define RVU_AF_SMMU_ADDR_RSP_STS (0x6010) | |
| 55 | +#define RVU_AF_SMMU_ADDR_TLN (0x6018) | |
| 56 | +#define RVU_AF_SMMU_TLN_FLIT1 (0x6030) | |
| 52 | 57 | |
| 53 | 58 | /* Admin function's privileged PF/VF registers */ |
| 54 | 59 | #define RVU_PRIV_CONST (0x8000000) |
| @@ -692,4 +697,9 @@ · 637 unmodified lines | ||
| 692 | 697 | #define LBK_LINK_CFG_ID_MASK GENMASK_ULL(11, 6) |
| 693 | 698 | #define LBK_LINK_CFG_BASE_MASK GENMASK_ULL(5, 0) |
| 694 | 699 | |
| 700 | +/* APR */ | |
| 701 | +#define APR_AF_LMT_CFG (0x000ull) | |
| 702 | +#define APR_AF_LMT_MAP_BASE (0x008ull) | |
| 703 | +#define APR_AF_LMT_CTL (0x010ull) | |
| 704 | + | |
| 695 | 705 | #endif /* RVU_REG_H */ |
| @@ -35,7 +35,8 @@ enum rvu_block_addr_e { · 34 unmodified lines | ||
| 35 | 35 | BLKADDR_NDC_NPA0 = 0xeULL, |
| 36 | 36 | BLKADDR_NDC_NIX1_RX = 0x10ULL, |
| 37 | 37 | BLKADDR_NDC_NIX1_TX = 0x11ULL, |
| 38 | − BLK_COUNT = 0x12ULL, | |
| 38 | + BLKADDR_APR = 0x16ULL, | |
| 39 | + BLK_COUNT = 0x17ULL, | |
| 39 | 40 | }; |
| 40 | 41 | |
| 41 | 42 | /* RVU Block Type Enumeration */ |
| @@ -7,7 +7,7 @@ obj-$(CONFIG_OCTEONTX2_PF) += rvu_nicpf.o · 6 unmodified lines | ||
| 7 | 7 | obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o |
| 8 | 8 | |
| 9 | 9 | rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \ |
| 10 | − otx2_ptp.o otx2_flows.o otx2_tc.o cn10k.o | |
| 10 | + otx2_ptp.o otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o | |
| 11 | 11 | rvu_nicvf-y := otx2_vf.o |
| 12 | 12 | |
| 13 | 13 | ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af |
| @@ -22,69 +22,52 @@ static struct dev_hw_ops cn10k_hw_ops = { · 21 unmodified lines | ||
| 22 | 22 | .refill_pool_ptrs = cn10k_refill_pool_ptrs, |
| 23 | 23 | }; |
| 24 | 24 | |
| 25 | −int cn10k_pf_lmtst_init(struct otx2_nic *pf) | |
| 25 | +int cn10k_lmtst_init(struct otx2_nic *pfvf) | |
| 26 | 26 | { |
| 27 | − int size, num_lines; | |
| 28 | − u64 base; | |
| 29 | 27 | |
| 30 | − if (!test_bit(CN10K_LMTST, &pf->hw.cap_flag)) { | |
| 31 | − pf->hw_ops = &otx2_hw_ops; | |
| 28 | + struct lmtst_tbl_setup_req *req; | |
| 29 | + int qcount, err; | |
| 30 | + | |
| 31 | + if (!test_bit(CN10K_LMTST, &pfvf->hw.cap_flag)) { | |
| 32 | + pfvf->hw_ops = &otx2_hw_ops; | |
| 32 | 33 | return 0; |
| 33 | 34 | } |
| 34 | 35 | |
| 35 | − pf->hw_ops = &cn10k_hw_ops; | |
| 36 | − base = pci_resource_start(pf->pdev, PCI_MBOX_BAR_NUM) + | |
| 37 | − (MBOX_SIZE * (pf->total_vfs + 1)); | |
| 38 | − | |
| 39 | − size = pci_resource_len(pf->pdev, PCI_MBOX_BAR_NUM) - | |
| 40 | − (MBOX_SIZE * (pf->total_vfs + 1)); | |
| 41 | − | |
| 42 | − pf->hw.lmt_base = ioremap(base, size); | |
| 36 | + pfvf->hw_ops = &cn10k_hw_ops; | |
| 37 | + qcount = pfvf->hw.max_queues; | |
| 38 | + /* LMTST lines allocation | |
| 39 | + * qcount = num_online_cpus(); | |
| 40 | + * NPA = TX + RX + XDP. | |
| 41 | + * NIX = TX * 32 (For Burst SQE flush). | |
| 42 | + */ | |
| 43 | + pfvf->tot_lmt_lines = (qcount * 3) + (qcount * 32); | |
| 44 | + pfvf->npa_lmt_lines = qcount * 3; | |
| 45 | + pfvf->nix_lmt_size = LMT_BURST_SIZE * LMT_LINE_SIZE; | |
| 43 | 46 | |
| 44 | − if (!pf->hw.lmt_base) { | |
| 45 | − dev_err(pf->dev, "Unable to map PF LMTST region\n"); | |
| 47 | + mutex_lock(&pfvf->mbox.lock); | |
| 48 | + req = otx2_mbox_alloc_msg_lmtst_tbl_setup(&pfvf->mbox); | |
| 49 | + if (!req) { | |
| 50 | + mutex_unlock(&pfvf->mbox.lock); | |
| 46 | 51 | return -ENOMEM; |
| 47 | 52 | } |
| 48 | 53 | |
| 49 | − /* FIXME: Get the num of LMTST lines from LMT table */ | |
| 50 | − pf->tot_lmt_lines = size / LMT_LINE_SIZE; | |
| 51 | − num_lines = (pf->tot_lmt_lines - NIX_LMTID_BASE) / | |
| 52 | − pf->hw.tx_queues; | |
| 53 | − /* Number of LMT lines per SQ queues */ | |
| 54 | − pf->nix_lmt_lines = num_lines > 32 ? 32 : num_lines; | |
| 55 | − | |
| 56 | − pf->nix_lmt_size = pf->nix_lmt_lines * LMT_LINE_SIZE; | |
| 57 | − return 0; | |
| 58 | −} | |
| 54 | + req->use_local_lmt_region = true; | |
| 59 | 55 | |
| 60 | −int cn10k_vf_lmtst_init(struct otx2_nic *vf) | |
| 61 | −{ | |
| 62 | − int size, num_lines; | |
| 63 | − | |
| 64 | − if (!test_bit(CN10K_LMTST, &vf->hw.cap_flag)) { | |
| 65 | − vf->hw_ops = &otx2_hw_ops; | |
| 66 | − return 0; | |
| 56 | + err = qmem_alloc(pfvf->dev, &pfvf->dync_lmt, pfvf->tot_lmt_lines, | |
| 57 | + LMT_LINE_SIZE); | |
| 58 | + if (err) { | |
| 59 | + mutex_unlock(&pfvf->mbox.lock); | |
| 60 | + return err; | |
| 67 | 61 | } |
| 62 | + pfvf->hw.lmt_base = (u64 *)pfvf->dync_lmt->base; | |
| 63 | + req->lmt_iova = (u64)pfvf->dync_lmt->iova; | |
| 68 | 64 | |
| 69 | − vf->hw_ops = &cn10k_hw_ops; | |
| 70 | − size = pci_resource_len(vf->pdev, PCI_MBOX_BAR_NUM); | |
| 71 | − vf->hw.lmt_base = ioremap_wc(pci_resource_start(vf->pdev, | |
| 72 | − PCI_MBOX_BAR_NUM), | |
| 73 | − size); | |
| 74 | − if (!vf->hw.lmt_base) { | |
| 75 | − dev_err(vf->dev, "Unable to map VF LMTST region\n"); | |
| 76 | − return -ENOMEM; | |
| 77 | − } | |
| 65 | + err = otx2_sync_mbox_msg(&pfvf->mbox); | |
| 66 | + mutex_unlock(&pfvf->mbox.lock); | |
| 78 | 67 | |
| 79 | − vf->tot_lmt_lines = size / LMT_LINE_SIZE; | |
| 80 | − /* LMTST lines per SQ */ | |
| 81 | − num_lines = (vf->tot_lmt_lines - NIX_LMTID_BASE) / | |
| 82 | − vf->hw.tx_queues; | |
| 83 | − vf->nix_lmt_lines = num_lines > 32 ? 32 : num_lines; | |
| 84 | − vf->nix_lmt_size = vf->nix_lmt_lines * LMT_LINE_SIZE; | |
| 85 | 68 | return 0; |
| 86 | 69 | } |
| 87 | −EXPORT_SYMBOL(cn10k_vf_lmtst_init); | |
| 70 | +EXPORT_SYMBOL(cn10k_lmtst_init); | |
| 88 | 71 | |
| 89 | 72 | int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) |
| 90 | 73 | { |
| @@ -93,9 +76,11 @@ int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) · 2 unmodified lines | ||
| 93 | 76 | struct otx2_snd_queue *sq; |
| 94 | 77 | |
| 95 | 78 | sq = &pfvf->qset.sq[qidx]; |
| 96 | − sq->lmt_addr = (__force u64 *)((u64)pfvf->hw.nix_lmt_base + | |
| 79 | + sq->lmt_addr = (u64 *)((u64)pfvf->hw.nix_lmt_base + | |
| 97 | 80 | (qidx * pfvf->nix_lmt_size)); |
| 98 | 81 | |
| 82 | + sq->lmt_id = pfvf->npa_lmt_lines + (qidx * LMT_BURST_SIZE); | |
| 83 | + | |
| 99 | 84 | /* Get memory to put this msg */ |
| 100 | 85 | aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox); |
| 101 | 86 | if (!aq) |
| @@ -158,15 +143,13 @@ void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) · 56 unmodified lines | ||
| 158 | 143 | |
| 159 | 144 | void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx) |
| 160 | 145 | { |
| 161 | − struct otx2_nic *pfvf = dev; | |
| 162 | − int lmt_id = NIX_LMTID_BASE + (qidx * pfvf->nix_lmt_lines); | |
| 163 | 146 | u64 val = 0, tar_addr = 0; |
| 164 | 147 | |
| 165 | 148 | /* FIXME: val[0:10] LMT_ID. |
| 166 | 149 | * [12:15] no of LMTST - 1 in the burst. |
| 167 | 150 | * [19:63] data size of each LMTST in the burst except first. |
| 168 | 151 | */ |
| 169 | − val = (lmt_id & 0x7FF); | |
| 152 | + val = (sq->lmt_id & 0x7FF); | |
| 170 | 153 | /* Target address for LMTST flush tells HW how many 128bit |
| 171 | 154 | * words are present. |
| 172 | 155 | * tar_addr[6:4] size of first LMTST - 1 in units of 128b. |
| @@ -12,8 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); |
| 13 | 13 | void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); |
| 14 | 14 | int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); |
| 15 | −int cn10k_pf_lmtst_init(struct otx2_nic *pf); | |
| 16 | −int cn10k_vf_lmtst_init(struct otx2_nic *vf); | |
| 15 | +int cn10k_lmtst_init(struct otx2_nic *pfvf); | |
| 17 | 16 | int cn10k_free_all_ipolicers(struct otx2_nic *pfvf); |
| 18 | 17 | int cn10k_alloc_matchall_ipolicer(struct otx2_nic *pfvf); |
| 19 | 18 | int cn10k_free_matchall_ipolicer(struct otx2_nic *pfvf); |
| @@ -210,6 +210,9 @@ int otx2_set_mac_address(struct net_device *netdev, void *p) · 209 unmodified lines | ||
| 210 | 210 | /* update dmac field in vlan offload rule */ |
| 211 | 211 | if (pfvf->flags & OTX2_FLAG_RX_VLAN_SUPPORT) |
| 212 | 212 | otx2_install_rxvlan_offload_flow(pfvf); |
| 213 | + /* update dmac address in ntuple and DMAC filter list */ | |
| 214 | + if (pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT) | |
| 215 | + otx2_dmacflt_update_pfmac_flow(pfvf); | |
| 213 | 216 | } else { |
| 214 | 217 | return -EPERM; |
| 215 | 218 | } |
| @@ -218,8 +218,8 @@ struct otx2_hw { · 217 unmodified lines | ||
| 218 | 218 | unsigned long cap_flag; |
| 219 | 219 | |
| 220 | 220 | #define LMT_LINE_SIZE 128 |
| 221 | −#define NIX_LMTID_BASE 72 /* RX + TX + XDP */ | |
| 222 | − void __iomem *lmt_base; | |
| 221 | +#define LMT_BURST_SIZE 32 /* 32 LMTST lines for burst SQE flush */ | |
| 222 | + u64 *lmt_base; | |
| 223 | 223 | u64 *npa_lmt_base; |
| 224 | 224 | u64 *nix_lmt_base; |
| 225 | 225 | }; |
| @@ -288,6 +288,9 @@ struct otx2_flow_config { · 62 unmodified lines | ||
| 288 | 288 | u16 tc_flower_offset; |
| 289 | 289 | u16 ntuple_max_flows; |
| 290 | 290 | u16 tc_max_flows; |
| 291 | + u8 dmacflt_max_flows; | |
| 292 | + u8 *bmap_to_dmacindex; | |
| 293 | + unsigned long dmacflt_bmap; | |
| 291 | 294 | struct list_head flow_list; |
| 292 | 295 | }; |
| 293 | 296 | |
| @@ -329,6 +332,7 @@ struct otx2_nic { · 35 unmodified lines | ||
| 329 | 332 | #define OTX2_FLAG_TC_FLOWER_SUPPORT BIT_ULL(11) |
| 330 | 333 | #define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED BIT_ULL(12) |
| 331 | 334 | #define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED BIT_ULL(13) |
| 335 | +#define OTX2_FLAG_DMACFLTR_SUPPORT BIT_ULL(14) | |
| 332 | 336 | u64 flags; |
| 333 | 337 | |
| 334 | 338 | struct otx2_qset qset; |
| @@ -363,8 +367,9 @@ struct otx2_nic { · 28 unmodified lines | ||
| 363 | 367 | /* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */ |
| 364 | 368 | int nix_blkaddr; |
| 365 | 369 | /* LMTST Lines info */ |
| 370 | + struct qmem *dync_lmt; | |
| 366 | 371 | u16 tot_lmt_lines; |
| 367 | − u16 nix_lmt_lines; | |
| 372 | + u16 npa_lmt_lines; | |
| 368 | 373 | u32 nix_lmt_size; |
| 369 | 374 | |
| 370 | 375 | struct otx2_ptp *ptp; |
| @@ -833,4 +838,11 @@ int otx2_init_tc(struct otx2_nic *nic); · 462 unmodified lines | ||
| 833 | 838 | void otx2_shutdown_tc(struct otx2_nic *nic); |
| 834 | 839 | int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type, |
| 835 | 840 | void *type_data); |
| 841 | +/* CGX/RPM DMAC filters support */ | |
| 842 | +int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf); | |
| 843 | +int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u8 bit_pos); | |
| 844 | +int otx2_dmacflt_remove(struct otx2_nic *pf, const u8 *mac, u8 bit_pos); | |
| 845 | +int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u8 bit_pos); | |
| 846 | +void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf); | |
| 847 | +void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf); | |
| 836 | 848 | #endif /* OTX2_COMMON_H */ |
| @@ -0,0 +1,173 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* Marvell OcteonTx2 RVU Physcial Function ethernet driver | |
| 3 | + * | |
| 4 | + * Copyright (C) 2021 Marvell. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include "otx2_common.h" | |
| 8 | + | |
| 9 | +static int otx2_dmacflt_do_add(struct otx2_nic *pf, const u8 *mac, | |
| 10 | + u8 *dmac_index) | |
| 11 | +{ | |
| 12 | + struct cgx_mac_addr_add_req *req; | |
| 13 | + struct cgx_mac_addr_add_rsp *rsp; | |
| 14 | + int err; | |
| 15 | + | |
| 16 | + mutex_lock(&pf->mbox.lock); | |
| 17 | + | |
| 18 | + req = otx2_mbox_alloc_msg_cgx_mac_addr_add(&pf->mbox); | |
| 19 | + if (!req) { | |
| 20 | + mutex_unlock(&pf->mbox.lock); | |
| 21 | + return -ENOMEM; | |
| 22 | + } | |
| 23 | + | |
| 24 | + ether_addr_copy(req->mac_addr, mac); | |
| 25 | + err = otx2_sync_mbox_msg(&pf->mbox); | |
| 26 | + | |
| 27 | + if (!err) { | |
| 28 | + rsp = (struct cgx_mac_addr_add_rsp *) | |
| 29 | + otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr); | |
| 30 | + *dmac_index = rsp->index; | |
| 31 | + } | |
| 32 | + | |
| 33 | + mutex_unlock(&pf->mbox.lock); | |
| 34 | + return err; | |
| 35 | +} | |
| 36 | + | |
| 37 | +static int otx2_dmacflt_add_pfmac(struct otx2_nic *pf) | |
| 38 | +{ | |
| 39 | + struct cgx_mac_addr_set_or_get *req; | |
| 40 | + int err; | |
| 41 | + | |
| 42 | + mutex_lock(&pf->mbox.lock); | |
| 43 | + | |
| 44 | + req = otx2_mbox_alloc_msg_cgx_mac_addr_set(&pf->mbox); | |
| 45 | + if (!req) { | |
| 46 | + mutex_unlock(&pf->mbox.lock); | |
| 47 | + return -ENOMEM; | |
| 48 | + } | |
| 49 | + | |
| 50 | + ether_addr_copy(req->mac_addr, pf->netdev->dev_addr); | |
| 51 | + err = otx2_sync_mbox_msg(&pf->mbox); | |
| 52 | + | |
| 53 | + mutex_unlock(&pf->mbox.lock); | |
| 54 | + return err; | |
| 55 | +} | |
| 56 | + | |
| 57 | +int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u8 bit_pos) | |
| 58 | +{ | |
| 59 | + u8 *dmacindex; | |
| 60 | + | |
| 61 | + /* Store dmacindex returned by CGX/RPM driver which will | |
| 62 | + * be used for macaddr update/remove | |
| 63 | + */ | |
| 64 | + dmacindex = &pf->flow_cfg->bmap_to_dmacindex[bit_pos]; | |
| 65 | + | |
| 66 | + if (ether_addr_equal(mac, pf->netdev->dev_addr)) | |
| 67 | + return otx2_dmacflt_add_pfmac(pf); | |
| 68 | + else | |
| 69 | + return otx2_dmacflt_do_add(pf, mac, dmacindex); | |
| 70 | +} | |
| 71 | + | |
| 72 | +static int otx2_dmacflt_do_remove(struct otx2_nic *pfvf, const u8 *mac, | |
| 73 | + u8 dmac_index) | |
| 74 | +{ | |
| 75 | + struct cgx_mac_addr_del_req *req; | |
| 76 | + int err; | |
| 77 | + | |
| 78 | + mutex_lock(&pfvf->mbox.lock); | |
| 79 | + req = otx2_mbox_alloc_msg_cgx_mac_addr_del(&pfvf->mbox); | |
| 80 | + if (!req) { | |
| 81 | + mutex_unlock(&pfvf->mbox.lock); | |
| 82 | + return -ENOMEM; | |
| 83 | + } | |
| 84 | + | |
| 85 | + req->index = dmac_index; | |
| 86 | + | |
| 87 | + err = otx2_sync_mbox_msg(&pfvf->mbox); | |
| 88 | + mutex_unlock(&pfvf->mbox.lock); | |
| 89 | + | |
| 90 | + return err; | |
| 91 | +} | |
| 92 | + | |
| 93 | +static int otx2_dmacflt_remove_pfmac(struct otx2_nic *pf) | |
| 94 | +{ | |
| 95 | + struct msg_req *req; | |
| 96 | + int err; | |
| 97 | + | |
| 98 | + mutex_lock(&pf->mbox.lock); | |
| 99 | + req = otx2_mbox_alloc_msg_cgx_mac_addr_reset(&pf->mbox); | |
| 100 | + if (!req) { | |
| 101 | + mutex_unlock(&pf->mbox.lock); | |
| 102 | + return -ENOMEM; | |
| 103 | + } | |
| 104 | + | |
| 105 | + err = otx2_sync_mbox_msg(&pf->mbox); | |
| 106 | + | |
| 107 | + mutex_unlock(&pf->mbox.lock); | |
| 108 | + return err; | |
| 109 | +} | |
| 110 | + | |
| 111 | +int otx2_dmacflt_remove(struct otx2_nic *pf, const u8 *mac, | |
| 112 | + u8 bit_pos) | |
| 113 | +{ | |
| 114 | + u8 dmacindex = pf->flow_cfg->bmap_to_dmacindex[bit_pos]; | |
| 115 | + | |
| 116 | + if (ether_addr_equal(mac, pf->netdev->dev_addr)) | |
| 117 | + return otx2_dmacflt_remove_pfmac(pf); | |
| 118 | + else | |
| 119 | + return otx2_dmacflt_do_remove(pf, mac, dmacindex); | |
| 120 | +} | |
| 121 | + | |
| 122 | +/* CGX/RPM blocks support max unicast entries of 32. | |
| 123 | + * on typical configuration MAC block associated | |
| 124 | + * with 4 lmacs, each lmac will have 8 dmac entries | |
| 125 | + */ | |
| 126 | +int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf) | |
| 127 | +{ | |
| 128 | + struct cgx_max_dmac_entries_get_rsp *rsp; | |
| 129 | + struct msg_req *msg; | |
| 130 | + int err; | |
| 131 | + | |
| 132 | + mutex_lock(&pf->mbox.lock); | |
| 133 | + msg = otx2_mbox_alloc_msg_cgx_mac_max_entries_get(&pf->mbox); | |
| 134 | + | |
| 135 | + if (!msg) { | |
| 136 | + mutex_unlock(&pf->mbox.lock); | |
| 137 | + return -ENOMEM; | |
| 138 | + } | |
| 139 | + | |
| 140 | + err = otx2_sync_mbox_msg(&pf->mbox); | |
| 141 | + if (err) | |
| 142 | + goto out; | |
| 143 | + | |
| 144 | + rsp = (struct cgx_max_dmac_entries_get_rsp *) | |
| 145 | + otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &msg->hdr); | |
| 146 | + pf->flow_cfg->dmacflt_max_flows = rsp->max_dmac_filters; | |
| 147 | + | |
| 148 | +out: | |
| 149 | + mutex_unlock(&pf->mbox.lock); | |
| 150 | + return err; | |
| 151 | +} | |
| 152 | + | |
| 153 | +int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u8 bit_pos) | |
| 154 | +{ | |
| 155 | + struct cgx_mac_addr_update_req *req; | |
| 156 | + int rc; | |
| 157 | + | |
| 158 | + mutex_lock(&pf->mbox.lock); | |
| 159 | + | |
| 160 | + req = otx2_mbox_alloc_msg_cgx_mac_addr_update(&pf->mbox); | |
| 161 | + | |
| 162 | + if (!req) { | |
| 163 | + mutex_unlock(&pf->mbox.lock); | |
| 164 | + return -ENOMEM; | |
| 165 | + } | |
| 166 | + | |
| 167 | + ether_addr_copy(req->mac_addr, mac); | |
| 168 | + req->index = pf->flow_cfg->bmap_to_dmacindex[bit_pos]; | |
| 169 | + rc = otx2_sync_mbox_msg(&pf->mbox); | |
| 170 | + | |
| 171 | + mutex_unlock(&pf->mbox.lock); | |
| 172 | + return rc; | |
| 173 | +} | |
| @@ -18,6 +18,12 @@ struct otx2_flow { · 17 unmodified lines | ||
| 18 | 18 | bool is_vf; |
| 19 | 19 | u8 rss_ctx_id; |
| 20 | 20 | int vf; |
| 21 | + bool dmac_filter; | |
| 22 | +}; | |
| 23 | + | |
| 24 | +enum dmac_req { | |
| 25 | + DMAC_ADDR_UPDATE, | |
| 26 | + DMAC_ADDR_DEL | |
| 21 | 27 | }; |
| 22 | 28 | |
| 23 | 29 | static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_config *flow_cfg) |
| @@ -219,6 +225,22 @@ int otx2_mcam_flow_init(struct otx2_nic *pf) · 195 unmodified lines | ||
| 219 | 225 | if (!pf->mac_table) |
| 220 | 226 | return -ENOMEM; |
| 221 | 227 | |
| 228 | + otx2_dmacflt_get_max_cnt(pf); | |
| 229 | + | |
| 230 | + /* DMAC filters are not allocated */ | |
| 231 | + if (!pf->flow_cfg->dmacflt_max_flows) | |
| 232 | + return 0; | |
| 233 | + | |
| 234 | + pf->flow_cfg->bmap_to_dmacindex = | |
| 235 | + devm_kzalloc(pf->dev, sizeof(u8) * | |
| 236 | + pf->flow_cfg->dmacflt_max_flows, | |
| 237 | + GFP_KERNEL); | |
| 238 | + | |
| 239 | + if (!pf->flow_cfg->bmap_to_dmacindex) | |
| 240 | + return -ENOMEM; | |
| 241 | + | |
| 242 | + pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT; | |
| 243 | + | |
| 222 | 244 | return 0; |
| 223 | 245 | } |
| 224 | 246 | |
| @@ -280,6 +302,12 @@ int otx2_add_macfilter(struct net_device *netdev, const u8 *mac) · 55 unmodified lines | ||
| 280 | 302 | { |
| 281 | 303 | struct otx2_nic *pf = netdev_priv(netdev); |
| 282 | 304 | |
| 305 | + if (bitmap_weight(&pf->flow_cfg->dmacflt_bmap, | |
| 306 | + pf->flow_cfg->dmacflt_max_flows)) | |
| 307 | + netdev_warn(netdev, | |
| 308 | + "Add %pM to CGX/RPM DMAC filters list as well\n", | |
| 309 | + mac); | |
| 310 | + | |
| 283 | 311 | return otx2_do_add_macfilter(pf, mac); |
| 284 | 312 | } |
| 285 | 313 | |
| @@ -351,12 +379,22 @@ static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow) · 65 unmodified lines | ||
| 351 | 379 | list_add(&flow->list, head); |
| 352 | 380 | } |
| 353 | 381 | |
| 382 | +static int otx2_get_maxflows(struct otx2_flow_config *flow_cfg) | |
| 383 | +{ | |
| 384 | + if (flow_cfg->nr_flows == flow_cfg->ntuple_max_flows || | |
| 385 | + bitmap_weight(&flow_cfg->dmacflt_bmap, | |
| 386 | + flow_cfg->dmacflt_max_flows)) | |
| 387 | + return flow_cfg->ntuple_max_flows + flow_cfg->dmacflt_max_flows; | |
| 388 | + else | |
| 389 | + return flow_cfg->ntuple_max_flows; | |
| 390 | +} | |
| 391 | + | |
| 354 | 392 | int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc, |
| 355 | 393 | u32 location) |
| 356 | 394 | { |
| 357 | 395 | struct otx2_flow *iter; |
| 358 | 396 | |
| 359 | − if (location >= pfvf->flow_cfg->ntuple_max_flows) | |
| 397 | + if (location >= otx2_get_maxflows(pfvf->flow_cfg)) | |
| 360 | 398 | return -EINVAL; |
| 361 | 399 | |
| 362 | 400 | list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) { |
| @@ -378,7 +416,7 @@ int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc, · 15 unmodified lines | ||
| 378 | 416 | int idx = 0; |
| 379 | 417 | int err = 0; |
| 380 | 418 | |
| 381 | − nfc->data = pfvf->flow_cfg->ntuple_max_flows; | |
| 419 | + nfc->data = otx2_get_maxflows(pfvf->flow_cfg); | |
| 382 | 420 | while ((!err || err == -ENOENT) && idx < rule_cnt) { |
| 383 | 421 | err = otx2_get_flow(pfvf, nfc, location); |
| 384 | 422 | if (!err) |
| @@ -760,6 +798,32 @@ int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp, · 375 unmodified lines | ||
| 760 | 798 | return 0; |
| 761 | 799 | } |
| 762 | 800 | |
| 801 | +static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf, | |
| 802 | + struct ethtool_rx_flow_spec *fsp) | |
| 803 | +{ | |
| 804 | + struct ethhdr *eth_mask = &fsp->m_u.ether_spec; | |
| 805 | + struct ethhdr *eth_hdr = &fsp->h_u.ether_spec; | |
| 806 | + u64 ring_cookie = fsp->ring_cookie; | |
| 807 | + u32 flow_type; | |
| 808 | + | |
| 809 | + if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT)) | |
| 810 | + return false; | |
| 811 | + | |
| 812 | + flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS); | |
| 813 | + | |
| 814 | + /* CGX/RPM block dmac filtering configured for white listing | |
| 815 | + * check for action other than DROP | |
| 816 | + */ | |
| 817 | + if (flow_type == ETHER_FLOW && ring_cookie != RX_CLS_FLOW_DISC && | |
| 818 | + !ethtool_get_flow_spec_ring_vf(ring_cookie)) { | |
| 819 | + if (is_zero_ether_addr(eth_mask->h_dest) && | |
| 820 | + is_valid_ether_addr(eth_hdr->h_dest)) | |
| 821 | + return true; | |
| 822 | + } | |
| 823 | + | |
| 824 | + return false; | |
| 825 | +} | |
| 826 | + | |
| 763 | 827 | static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow) |
| 764 | 828 | { |
| 765 | 829 | u64 ring_cookie = flow->flow_spec.ring_cookie; |
| @@ -818,14 +882,46 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow) · 52 unmodified lines | ||
| 818 | 882 | return err; |
| 819 | 883 | } |
| 820 | 884 | |
| 885 | +static int otx2_add_flow_with_pfmac(struct otx2_nic *pfvf, | |
| 886 | + struct otx2_flow *flow) | |
| 887 | +{ | |
| 888 | + struct otx2_flow *pf_mac; | |
| 889 | + struct ethhdr *eth_hdr; | |
| 890 | + | |
| 891 | + pf_mac = kzalloc(sizeof(*pf_mac), GFP_KERNEL); | |
| 892 | + if (!pf_mac) | |
| 893 | + return -ENOMEM; | |
| 894 | + | |
| 895 | + pf_mac->entry = 0; | |
| 896 | + pf_mac->dmac_filter = true; | |
| 897 | + pf_mac->location = pfvf->flow_cfg->ntuple_max_flows; | |
| 898 | + memcpy(&pf_mac->flow_spec, &flow->flow_spec, | |
| 899 | + sizeof(struct ethtool_rx_flow_spec)); | |
| 900 | + pf_mac->flow_spec.location = pf_mac->location; | |
| 901 | + | |
| 902 | + /* Copy PF mac address */ | |
| 903 | + eth_hdr = &pf_mac->flow_spec.h_u.ether_spec; | |
| 904 | + ether_addr_copy(eth_hdr->h_dest, pfvf->netdev->dev_addr); | |
| 905 | + | |
| 906 | + /* Install DMAC filter with PF mac address */ | |
| 907 | + otx2_dmacflt_add(pfvf, eth_hdr->h_dest, 0); | |
| 908 | + | |
| 909 | + otx2_add_flow_to_list(pfvf, pf_mac); | |
| 910 | + pfvf->flow_cfg->nr_flows++; | |
| 911 | + set_bit(0, &pfvf->flow_cfg->dmacflt_bmap); | |
| 912 | + | |
| 913 | + return 0; | |
| 914 | +} | |
| 915 | + | |
| 821 | 916 | int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) |
| 822 | 917 | { |
| 823 | 918 | struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; |
| 824 | 919 | struct ethtool_rx_flow_spec *fsp = &nfc->fs; |
| 825 | 920 | struct otx2_flow *flow; |
| 921 | + struct ethhdr *eth_hdr; | |
| 826 | 922 | bool new = false; |
| 923 | + int err = 0; | |
| 827 | 924 | u32 ring; |
| 828 | − int err; | |
| 829 | 925 | |
| 830 | 926 | ring = ethtool_get_flow_spec_ring(fsp->ring_cookie); |
| 831 | 927 | if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT)) |
| @@ -834,16 +930,15 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) · 2 unmodified lines | ||
| 834 | 930 | if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC) |
| 835 | 931 | return -EINVAL; |
| 836 | 932 | |
| 837 | − if (fsp->location >= flow_cfg->ntuple_max_flows) | |
| 933 | + if (fsp->location >= otx2_get_maxflows(flow_cfg)) | |
| 838 | 934 | return -EINVAL; |
| 839 | 935 | |
| 840 | 936 | flow = otx2_find_flow(pfvf, fsp->location); |
| 841 | 937 | if (!flow) { |
| 842 | − flow = kzalloc(sizeof(*flow), GFP_ATOMIC); | |
| 938 | + flow = kzalloc(sizeof(*flow), GFP_KERNEL); | |
| 843 | 939 | if (!flow) |
| 844 | 940 | return -ENOMEM; |
| 845 | 941 | flow->location = fsp->location; |
| 846 | − flow->entry = flow_cfg->flow_ent[flow->location]; | |
| 847 | 942 | new = true; |
| 848 | 943 | } |
| 849 | 944 | /* struct copy */ |
| @@ -852,7 +947,54 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) · 2 unmodified lines | ||
| 852 | 947 | if (fsp->flow_type & FLOW_RSS) |
| 853 | 948 | flow->rss_ctx_id = nfc->rss_context; |
| 854 | 949 | |
| 855 | − err = otx2_add_flow_msg(pfvf, flow); | |
| 950 | + if (otx2_is_flow_rule_dmacfilter(pfvf, &flow->flow_spec)) { | |
| 951 | + eth_hdr = &flow->flow_spec.h_u.ether_spec; | |
| 952 | + | |
| 953 | + /* Sync dmac filter table with updated fields */ | |
| 954 | + if (flow->dmac_filter) | |
| 955 | + return otx2_dmacflt_update(pfvf, eth_hdr->h_dest, | |
| 956 | + flow->entry); | |
| 957 | + | |
| 958 | + if (bitmap_full(&flow_cfg->dmacflt_bmap, | |
| 959 | + flow_cfg->dmacflt_max_flows)) { | |
| 960 | + netdev_warn(pfvf->netdev, | |
| 961 | + "Can't insert the rule %d as max allowed dmac filters are %d\n", | |
| 962 | + flow->location + | |
| 963 | + flow_cfg->dmacflt_max_flows, | |
| 964 | + flow_cfg->dmacflt_max_flows); | |
| 965 | + err = -EINVAL; | |
| 966 | + if (new) | |
| 967 | + kfree(flow); | |
| 968 | + return err; | |
| 969 | + } | |
| 970 | + | |
| 971 | + /* Install PF mac address to DMAC filter list */ | |
| 972 | + if (!test_bit(0, &flow_cfg->dmacflt_bmap)) | |
| 973 | + otx2_add_flow_with_pfmac(pfvf, flow); | |
| 974 | + | |
| 975 | + flow->dmac_filter = true; | |
| 976 | + flow->entry = find_first_zero_bit(&flow_cfg->dmacflt_bmap, | |
| 977 | + flow_cfg->dmacflt_max_flows); | |
| 978 | + fsp->location = flow_cfg->ntuple_max_flows + flow->entry; | |
| 979 | + flow->flow_spec.location = fsp->location; | |
| 980 | + flow->location = fsp->location; | |
| 981 | + | |
| 982 | + set_bit(flow->entry, &flow_cfg->dmacflt_bmap); | |
| 983 | + otx2_dmacflt_add(pfvf, eth_hdr->h_dest, flow->entry); | |
| 984 | + | |
| 985 | + } else { | |
| 986 | + if (flow->location >= pfvf->flow_cfg->ntuple_max_flows) { | |
| 987 | + netdev_warn(pfvf->netdev, | |
| 988 | + "Can't insert non dmac ntuple rule at %d, allowed range %d-0\n", | |
| 989 | + flow->location, | |
| 990 | + flow_cfg->ntuple_max_flows - 1); | |
| 991 | + err = -EINVAL; | |
| 992 | + } else { | |
| 993 | + flow->entry = flow_cfg->flow_ent[flow->location]; | |
| 994 | + err = otx2_add_flow_msg(pfvf, flow); | |
| 995 | + } | |
| 996 | + } | |
| 997 | + | |
| 856 | 998 | if (err) { |
| 857 | 999 | if (new) |
| 858 | 1000 | kfree(flow); |
| @@ -890,20 +1032,70 @@ static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all) · 31 unmodified lines | ||
| 890 | 1032 | return err; |
| 891 | 1033 | } |
| 892 | 1034 | |
| 1035 | +static void otx2_update_rem_pfmac(struct otx2_nic *pfvf, int req) | |
| 1036 | +{ | |
| 1037 | + struct otx2_flow *iter; | |
| 1038 | + struct ethhdr *eth_hdr; | |
| 1039 | + bool found = false; | |
| 1040 | + | |
| 1041 | + list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) { | |
| 1042 | + if (iter->dmac_filter && iter->entry == 0) { | |
| 1043 | + eth_hdr = &iter->flow_spec.h_u.ether_spec; | |
| 1044 | + if (req == DMAC_ADDR_DEL) { | |
| 1045 | + otx2_dmacflt_remove(pfvf, eth_hdr->h_dest, | |
| 1046 | + 0); | |
| 1047 | + clear_bit(0, &pfvf->flow_cfg->dmacflt_bmap); | |
| 1048 | + found = true; | |
| 1049 | + } else { | |
| 1050 | + ether_addr_copy(eth_hdr->h_dest, | |
| 1051 | + pfvf->netdev->dev_addr); | |
| 1052 | + otx2_dmacflt_update(pfvf, eth_hdr->h_dest, 0); | |
| 1053 | + } | |
| 1054 | + break; | |
| 1055 | + } | |
| 1056 | + } | |
| 1057 | + | |
| 1058 | + if (found) { | |
| 1059 | + list_del(&iter->list); | |
| 1060 | + kfree(iter); | |
| 1061 | + pfvf->flow_cfg->nr_flows--; | |
| 1062 | + } | |
| 1063 | +} | |
| 1064 | + | |
| 893 | 1065 | int otx2_remove_flow(struct otx2_nic *pfvf, u32 location) |
| 894 | 1066 | { |
| 895 | 1067 | struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; |
| 896 | 1068 | struct otx2_flow *flow; |
| 897 | 1069 | int err; |
| 898 | 1070 | |
| 899 | − if (location >= flow_cfg->ntuple_max_flows) | |
| 1071 | + if (location >= otx2_get_maxflows(flow_cfg)) | |
| 900 | 1072 | return -EINVAL; |
| 901 | 1073 | |
| 902 | 1074 | flow = otx2_find_flow(pfvf, location); |
| 903 | 1075 | if (!flow) |
| 904 | 1076 | return -ENOENT; |
| 905 | 1077 | |
| 906 | − err = otx2_remove_flow_msg(pfvf, flow->entry, false); | |
| 1078 | + if (flow->dmac_filter) { | |
| 1079 | + struct ethhdr *eth_hdr = &flow->flow_spec.h_u.ether_spec; | |
| 1080 | + | |
| 1081 | + /* user not allowed to remove dmac filter with interface mac */ | |
| 1082 | + if (ether_addr_equal(pfvf->netdev->dev_addr, eth_hdr->h_dest)) | |
| 1083 | + return -EPERM; | |
| 1084 | + | |
| 1085 | + err = otx2_dmacflt_remove(pfvf, eth_hdr->h_dest, | |
| 1086 | + flow->entry); | |
| 1087 | + clear_bit(flow->entry, &flow_cfg->dmacflt_bmap); | |
| 1088 | + /* If all dmac filters are removed delete macfilter with | |
| 1089 | + * interface mac address and configure CGX/RPM block in | |
| 1090 | + * promiscuous mode | |
| 1091 | + */ | |
| 1092 | + if (bitmap_weight(&flow_cfg->dmacflt_bmap, | |
| 1093 | + flow_cfg->dmacflt_max_flows) == 1) | |
| 1094 | + otx2_update_rem_pfmac(pfvf, DMAC_ADDR_DEL); | |
| 1095 | + } else { | |
| 1096 | + err = otx2_remove_flow_msg(pfvf, flow->entry, false); | |
| 1097 | + } | |
| 1098 | + | |
| 907 | 1099 | if (err) |
| 908 | 1100 | return err; |
| 909 | 1101 | |
| @@ -1100,3 +1292,22 @@ int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable) · 190 unmodified lines | ||
| 1100 | 1292 | mutex_unlock(&pf->mbox.lock); |
| 1101 | 1293 | return rsp_hdr->rc; |
| 1102 | 1294 | } |
| 1295 | + | |
| 1296 | +void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf) | |
| 1297 | +{ | |
| 1298 | + struct otx2_flow *iter; | |
| 1299 | + struct ethhdr *eth_hdr; | |
| 1300 | + | |
| 1301 | + list_for_each_entry(iter, &pf->flow_cfg->flow_list, list) { | |
| 1302 | + if (iter->dmac_filter) { | |
| 1303 | + eth_hdr = &iter->flow_spec.h_u.ether_spec; | |
| 1304 | + otx2_dmacflt_add(pf, eth_hdr->h_dest, | |
| 1305 | + iter->entry); | |
| 1306 | + } | |
| 1307 | + } | |
| 1308 | +} | |
| 1309 | + | |
| 1310 | +void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf) | |
| 1311 | +{ | |
| 1312 | + otx2_update_rem_pfmac(pfvf, DMAC_ADDR_UPDATE); | |
| 1313 | +} | |
| @@ -1110,6 +1110,11 @@ static int otx2_cgx_config_loopback(struct otx2_nic *pf, bool enable) · 1109 unmodified lines | ||
| 1110 | 1110 | struct msg_req *msg; |
| 1111 | 1111 | int err; |
| 1112 | 1112 | |
| 1113 | + if (enable && bitmap_weight(&pf->flow_cfg->dmacflt_bmap, | |
| 1114 | + pf->flow_cfg->dmacflt_max_flows)) | |
| 1115 | + netdev_warn(pf->netdev, | |
| 1116 | + "CGX/RPM internal loopback might not work as DMAC filters are active\n"); | |
| 1117 | + | |
| 1113 | 1118 | mutex_lock(&pf->mbox.lock); |
| 1114 | 1119 | if (enable) |
| 1115 | 1120 | msg = otx2_mbox_alloc_msg_cgx_intlbk_enable(&pf->mbox); |
| @@ -1533,10 +1538,10 @@ int otx2_open(struct net_device *netdev) · 417 unmodified lines | ||
| 1533 | 1538 | |
| 1534 | 1539 | if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) { |
| 1535 | 1540 | /* Reserve LMT lines for NPA AURA batch free */ |
| 1536 | − pf->hw.npa_lmt_base = (__force u64 *)pf->hw.lmt_base; | |
| 1541 | + pf->hw.npa_lmt_base = pf->hw.lmt_base; | |
| 1537 | 1542 | /* Reserve LMT lines for NIX TX */ |
| 1538 | − pf->hw.nix_lmt_base = (__force u64 *)((u64)pf->hw.npa_lmt_base + | |
| 1539 | − (NIX_LMTID_BASE * LMT_LINE_SIZE)); | |
| 1543 | + pf->hw.nix_lmt_base = (u64 *)((u64)pf->hw.npa_lmt_base + | |
| 1544 | + (pf->npa_lmt_lines * LMT_LINE_SIZE)); | |
| 1540 | 1545 | } |
| 1541 | 1546 | |
| 1542 | 1547 | err = otx2_init_hw_resources(pf); |
| @@ -1644,6 +1649,10 @@ int otx2_open(struct net_device *netdev) · 101 unmodified lines | ||
| 1644 | 1649 | /* Restore pause frame settings */ |
| 1645 | 1650 | otx2_config_pause_frm(pf); |
| 1646 | 1651 | |
| 1652 | + /* Install DMAC Filters */ | |
| 1653 | + if (pf->flags & OTX2_FLAG_DMACFLTR_SUPPORT) | |
| 1654 | + otx2_dmacflt_reinstall_flows(pf); | |
| 1655 | + | |
| 1647 | 1656 | err = otx2_rxtx_enable(pf, true); |
| 1648 | 1657 | if (err) |
| 1649 | 1658 | goto err_tx_stop_queues; |
| @@ -2526,7 +2535,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 876 unmodified lines | ||
| 2526 | 2535 | if (err) |
| 2527 | 2536 | goto err_detach_rsrc; |
| 2528 | 2537 | |
| 2529 | − err = cn10k_pf_lmtst_init(pf); | |
| 2538 | + err = cn10k_lmtst_init(pf); | |
| 2530 | 2539 | if (err) |
| 2531 | 2540 | goto err_detach_rsrc; |
| 2532 | 2541 | |
| @@ -2630,8 +2639,8 @@ err_del_mcam_entries: · 97 unmodified lines | ||
| 2630 | 2639 | err_ptp_destroy: |
| 2631 | 2640 | otx2_ptp_destroy(pf); |
| 2632 | 2641 | err_detach_rsrc: |
| 2633 | − if (hw->lmt_base) | |
| 2634 | − iounmap(hw->lmt_base); | |
| 2642 | + if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) | |
| 2643 | + qmem_free(pf->dev, pf->dync_lmt); | |
| 2635 | 2644 | otx2_detach_resources(&pf->mbox); |
| 2636 | 2645 | err_disable_mbox_intr: |
| 2637 | 2646 | otx2_disable_mbox_intr(pf); |
| @@ -2772,9 +2781,8 @@ static void otx2_remove(struct pci_dev *pdev) · 134 unmodified lines | ||
| 2772 | 2781 | otx2_mcam_flow_del(pf); |
| 2773 | 2782 | otx2_shutdown_tc(pf); |
| 2774 | 2783 | otx2_detach_resources(&pf->mbox); |
| 2775 | − if (pf->hw.lmt_base) | |
| 2776 | − iounmap(pf->hw.lmt_base); | |
| 2777 | − | |
| 2784 | + if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) | |
| 2785 | + qmem_free(pf->dev, pf->dync_lmt); | |
| 2778 | 2786 | otx2_disable_mbox_intr(pf); |
| 2779 | 2787 | otx2_pfaf_mbox_destroy(pf); |
| 2780 | 2788 | pci_free_irq_vectors(pf->pdev); |
| @@ -288,7 +288,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, · 287 unmodified lines | ||
| 288 | 288 | struct otx2_nic *priv; |
| 289 | 289 | u32 burst, mark = 0; |
| 290 | 290 | u8 nr_police = 0; |
| 291 | − bool pps; | |
| 291 | + bool pps = false; | |
| 292 | 292 | u64 rate; |
| 293 | 293 | int i; |
| 294 | 294 | |
| @@ -83,6 +83,7 @@ struct otx2_snd_queue { · 82 unmodified lines | ||
| 83 | 83 | u16 num_sqbs; |
| 84 | 84 | u16 sqe_thresh; |
| 85 | 85 | u8 sqe_per_sqb; |
| 86 | + u32 lmt_id; | |
| 86 | 87 | u64 io_addr; |
| 87 | 88 | u64 *aura_fc_addr; |
| 88 | 89 | u64 *lmt_addr; |
| @@ -609,7 +609,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 608 unmodified lines | ||
| 609 | 609 | if (err) |
| 610 | 610 | goto err_detach_rsrc; |
| 611 | 611 | |
| 612 | − err = cn10k_vf_lmtst_init(vf); | |
| 612 | + err = cn10k_lmtst_init(vf); | |
| 613 | 613 | if (err) |
| 614 | 614 | goto err_detach_rsrc; |
| 615 | 615 | |
| @@ -667,8 +667,8 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 51 unmodified lines | ||
| 667 | 667 | err_unreg_netdev: |
| 668 | 668 | unregister_netdev(netdev); |
| 669 | 669 | err_detach_rsrc: |
| 670 | − if (hw->lmt_base) | |
| 671 | − iounmap(hw->lmt_base); | |
| 670 | + if (test_bit(CN10K_LMTST, &vf->hw.cap_flag)) | |
| 671 | + qmem_free(vf->dev, vf->dync_lmt); | |
| 672 | 672 | otx2_detach_resources(&vf->mbox); |
| 673 | 673 | err_disable_mbox_intr: |
| 674 | 674 | otx2vf_disable_mbox_intr(vf); |
| @@ -700,10 +700,8 @@ static void otx2vf_remove(struct pci_dev *pdev) · 25 unmodified lines | ||
| 700 | 700 | destroy_workqueue(vf->otx2_wq); |
| 701 | 701 | otx2vf_disable_mbox_intr(vf); |
| 702 | 702 | otx2_detach_resources(&vf->mbox); |
| 703 | − | |
| 704 | − if (vf->hw.lmt_base) | |
| 705 | − iounmap(vf->hw.lmt_base); | |
| 706 | − | |
| 703 | + if (test_bit(CN10K_LMTST, &vf->hw.cap_flag)) | |
| 704 | + qmem_free(vf->dev, vf->dync_lmt); | |
| 707 | 705 | otx2vf_vfaf_mbox_destroy(vf); |
| 708 | 706 | pci_free_irq_vectors(vf->pdev); |
| 709 | 707 | pci_set_drvdata(pdev, NULL); |
| @@ -2,6 +2,7 @@ config SPARX5_SWITCH · 1 unmodified line | ||
| 2 | 2 | tristate "Sparx5 switch driver" |
| 3 | 3 | depends on NET_SWITCHDEV |
| 4 | 4 | depends on HAS_IOMEM |
| 5 | + depends on OF | |
| 5 | 6 | select PHYLINK |
| 6 | 7 | select PHY_SPARX5_SERDES |
| 7 | 8 | select RESET_CONTROLLER |
| @@ -540,10 +540,8 @@ static int moxart_mac_probe(struct platform_device *pdev) · 539 unmodified lines | ||
| 540 | 540 | SET_NETDEV_DEV(ndev, &pdev->dev); |
| 541 | 541 | |
| 542 | 542 | ret = register_netdev(ndev); |
| 543 | − if (ret) { | |
| 544 | − free_netdev(ndev); | |
| 543 | + if (ret) | |
| 545 | 544 | goto init_fail; |
| 546 | − } | |
| 547 | 545 | |
| 548 | 546 | netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n", |
| 549 | 547 | __func__, ndev->irq, ndev->dev_addr); |
| @@ -1298,6 +1298,7 @@ static int ocelot_netdevice_lag_leave(struct net_device *dev, · 1297 unmodified lines | ||
| 1298 | 1298 | } |
| 1299 | 1299 | |
| 1300 | 1300 | static int ocelot_netdevice_changeupper(struct net_device *dev, |
| 1301 | + struct net_device *brport_dev, | |
| 1301 | 1302 | struct netdev_notifier_changeupper_info *info) |
| 1302 | 1303 | { |
| 1303 | 1304 | struct netlink_ext_ack *extack; |
| @@ -1307,11 +1308,11 @@ static int ocelot_netdevice_changeupper(struct net_device *dev, · 3 unmodified lines | ||
| 1307 | 1308 | |
| 1308 | 1309 | if (netif_is_bridge_master(info->upper_dev)) { |
| 1309 | 1310 | if (info->linking) |
| 1310 | − err = ocelot_netdevice_bridge_join(dev, dev, | |
| 1311 | + err = ocelot_netdevice_bridge_join(dev, brport_dev, | |
| 1311 | 1312 | info->upper_dev, |
| 1312 | 1313 | extack); |
| 1313 | 1314 | else |
| 1314 | − err = ocelot_netdevice_bridge_leave(dev, dev, | |
| 1315 | + err = ocelot_netdevice_bridge_leave(dev, brport_dev, | |
| 1315 | 1316 | info->upper_dev); |
| 1316 | 1317 | } |
| 1317 | 1318 | if (netif_is_lag_master(info->upper_dev)) { |
| @@ -1346,7 +1347,7 @@ ocelot_netdevice_lag_changeupper(struct net_device *dev, · 28 unmodified lines | ||
| 1346 | 1347 | if (ocelot_port->bond != dev) |
| 1347 | 1348 | return NOTIFY_OK; |
| 1348 | 1349 | |
| 1349 | − err = ocelot_netdevice_changeupper(lower, info); | |
| 1350 | + err = ocelot_netdevice_changeupper(lower, dev, info); | |
| 1350 | 1351 | if (err) |
| 1351 | 1352 | return notifier_from_errno(err); |
| 1352 | 1353 | } |
| @@ -1385,7 +1386,7 @@ static int ocelot_netdevice_event(struct notifier_block *unused, · 32 unmodified lines | ||
| 1385 | 1386 | struct netdev_notifier_changeupper_info *info = ptr; |
| 1386 | 1387 | |
| 1387 | 1388 | if (ocelot_netdevice_dev_check(dev)) |
| 1388 | − return ocelot_netdevice_changeupper(dev, info); | |
| 1389 | + return ocelot_netdevice_changeupper(dev, dev, info); | |
| 1389 | 1390 | |
| 1390 | 1391 | if (netif_is_lag_master(dev)) |
| 1391 | 1392 | return ocelot_netdevice_lag_changeupper(dev, info); |
| @@ -1141,20 +1141,7 @@ int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent) · 1140 unmodified lines | ||
| 1141 | 1141 | nfp_fl_ct_clean_flow_entry(ct_entry); |
| 1142 | 1142 | kfree(ct_map_ent); |
| 1143 | 1143 | |
| 1144 | − /* If this is the last pre_ct_rule it means that it is | |
| 1145 | − * very likely that the nft table will be cleaned up next, | |
| 1146 | − * as this happens on the removal of the last act_ct flow. | |
| 1147 | − * However we cannot deregister the callback on the removal | |
| 1148 | − * of the last nft flow as this runs into a deadlock situation. | |
| 1149 | − * So deregister the callback on removal of the last pre_ct flow | |
| 1150 | − * and remove any remaining nft flow entries. We also cannot | |
| 1151 | − * save this state and delete the callback later since the | |
| 1152 | − * nft table would already have been freed at that time. | |
| 1153 | − */ | |
| 1154 | 1144 | if (!zt->pre_ct_count) { |
| 1155 | − nf_flow_table_offload_del_cb(zt->nft, | |
| 1156 | − nfp_fl_ct_handle_nft_flow, | |
| 1157 | − zt); | |
| 1158 | 1145 | zt->nft = NULL; |
| 1159 | 1146 | nfp_fl_ct_clean_nft_entries(zt); |
| 1160 | 1147 | } |
| @@ -735,12 +735,13 @@ static int emac_remove(struct platform_device *pdev) · 734 unmodified lines | ||
| 735 | 735 | |
| 736 | 736 | put_device(&adpt->phydev->mdio.dev); |
| 737 | 737 | mdiobus_unregister(adpt->mii_bus); |
| 738 | − free_netdev(netdev); | |
| 739 | 738 | |
| 740 | 739 | if (adpt->phy.digital) |
| 741 | 740 | iounmap(adpt->phy.digital); |
| 742 | 741 | iounmap(adpt->phy.base); |
| 743 | 742 | |
| 743 | + free_netdev(netdev); | |
| 744 | + | |
| 744 | 745 | return 0; |
| 745 | 746 | } |
| 746 | 747 | |
| @@ -152,6 +152,7 @@ static int efx_allocate_msix_channels(struct efx_nic *efx, · 151 unmodified lines | ||
| 152 | 152 | * maximum size. |
| 153 | 153 | */ |
| 154 | 154 | tx_per_ev = EFX_MAX_EVQ_SIZE / EFX_TXQ_MAX_ENT(efx); |
| 155 | + tx_per_ev = min(tx_per_ev, EFX_MAX_TXQ_PER_CHANNEL); | |
| 155 | 156 | n_xdp_tx = num_possible_cpus(); |
| 156 | 157 | n_xdp_ev = DIV_ROUND_UP(n_xdp_tx, tx_per_ev); |
| 157 | 158 | |
| @@ -169,6 +170,8 @@ static int efx_allocate_msix_channels(struct efx_nic *efx, · 11 unmodified lines | ||
| 169 | 170 | netif_err(efx, drv, efx->net_dev, |
| 170 | 171 | "Insufficient resources for %d XDP event queues (%d other channels, max %d)\n", |
| 171 | 172 | n_xdp_ev, n_channels, max_channels); |
| 173 | + netif_err(efx, drv, efx->net_dev, | |
| 174 | + "XDP_TX and XDP_REDIRECT will not work on this interface"); | |
| 172 | 175 | efx->n_xdp_channels = 0; |
| 173 | 176 | efx->xdp_tx_per_channel = 0; |
| 174 | 177 | efx->xdp_tx_queue_count = 0; |
| @@ -176,12 +179,14 @@ static int efx_allocate_msix_channels(struct efx_nic *efx, · 1 unmodified line | ||
| 176 | 179 | netif_err(efx, drv, efx->net_dev, |
| 177 | 180 | "Insufficient resources for %d XDP TX queues (%d other channels, max VIs %d)\n", |
| 178 | 181 | n_xdp_tx, n_channels, efx->max_vis); |
| 182 | + netif_err(efx, drv, efx->net_dev, | |
| 183 | + "XDP_TX and XDP_REDIRECT will not work on this interface"); | |
| 179 | 184 | efx->n_xdp_channels = 0; |
| 180 | 185 | efx->xdp_tx_per_channel = 0; |
| 181 | 186 | efx->xdp_tx_queue_count = 0; |
| 182 | 187 | } else { |
| 183 | 188 | efx->n_xdp_channels = n_xdp_ev; |
| 184 | − efx->xdp_tx_per_channel = EFX_MAX_TXQ_PER_CHANNEL; | |
| 189 | + efx->xdp_tx_per_channel = tx_per_ev; | |
| 185 | 190 | efx->xdp_tx_queue_count = n_xdp_tx; |
| 186 | 191 | n_channels += n_xdp_ev; |
| 187 | 192 | netif_dbg(efx, drv, efx->net_dev, |
| @@ -891,18 +896,20 @@ int efx_set_channels(struct efx_nic *efx) · 703 unmodified lines | ||
| 891 | 896 | if (efx_channel_is_xdp_tx(channel)) { |
| 892 | 897 | efx_for_each_channel_tx_queue(tx_queue, channel) { |
| 893 | 898 | tx_queue->queue = next_queue++; |
| 894 | − netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n", | |
| 895 | − channel->channel, tx_queue->label, | |
| 896 | − xdp_queue_number, tx_queue->queue); | |
| 899 | + | |
| 897 | 900 | /* We may have a few left-over XDP TX |
| 898 | 901 | * queues owing to xdp_tx_queue_count |
| 899 | 902 | * not dividing evenly by EFX_MAX_TXQ_PER_CHANNEL. |
| 900 | 903 | * We still allocate and probe those |
| 901 | 904 | * TXQs, but never use them. |
| 902 | 905 | */ |
| 903 | − if (xdp_queue_number < efx->xdp_tx_queue_count) | |
| 906 | + if (xdp_queue_number < efx->xdp_tx_queue_count) { | |
| 907 | + netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n", | |
| 908 | + channel->channel, tx_queue->label, | |
| 909 | + xdp_queue_number, tx_queue->queue); | |
| 904 | 910 | efx->xdp_tx_queues[xdp_queue_number] = tx_queue; |
| 905 | − xdp_queue_number++; | |
| 911 | + xdp_queue_number++; | |
| 912 | + } | |
| 906 | 913 | } |
| 907 | 914 | } else { |
| 908 | 915 | efx_for_each_channel_tx_queue(tx_queue, channel) { |
| @@ -914,8 +921,7 @@ int efx_set_channels(struct efx_nic *efx) · 5 unmodified lines | ||
| 914 | 921 | } |
| 915 | 922 | } |
| 916 | 923 | } |
| 917 | − if (xdp_queue_number) | |
| 918 | − efx->xdp_tx_queue_count = xdp_queue_number; | |
| 924 | + WARN_ON(xdp_queue_number != efx->xdp_tx_queue_count); | |
| 919 | 925 | |
| 920 | 926 | rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); |
| 921 | 927 | if (rc) |
| @@ -49,9 +49,9 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id · 48 unmodified lines | ||
| 49 | 49 | { |
| 50 | 50 | struct plat_stmmacenet_data *plat; |
| 51 | 51 | struct stmmac_resources res; |
| 52 | − bool mdio = false; | |
| 53 | − int ret, i; | |
| 54 | 52 | struct device_node *np; |
| 53 | + int ret, i, phy_mode; | |
| 54 | + bool mdio = false; | |
| 55 | 55 | |
| 56 | 56 | np = dev_of_node(&pdev->dev); |
| 57 | 57 | |
| @@ -108,10 +108,11 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id · 50 unmodified lines | ||
| 108 | 108 | if (plat->bus_id < 0) |
| 109 | 109 | plat->bus_id = pci_dev_id(pdev); |
| 110 | 110 | |
| 111 | − plat->phy_interface = device_get_phy_mode(&pdev->dev); | |
| 112 | − if (plat->phy_interface < 0) | |
| 111 | + phy_mode = device_get_phy_mode(&pdev->dev); | |
| 112 | + if (phy_mode < 0) | |
| 113 | 113 | dev_err(&pdev->dev, "phy_mode not found\n"); |
| 114 | 114 | |
| 115 | + plat->phy_interface = phy_mode; | |
| 115 | 116 | plat->interface = PHY_INTERFACE_MODE_GMII; |
| 116 | 117 | |
| 117 | 118 | pci_set_master(pdev); |
| @@ -349,6 +349,9 @@ void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue); · 348 unmodified lines | ||
| 349 | 349 | void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue); |
| 350 | 350 | void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue); |
| 351 | 351 | int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags); |
| 352 | +struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time, | |
| 353 | + ktime_t current_time, | |
| 354 | + u64 cycle_time); | |
| 352 | 355 | |
| 353 | 356 | #if IS_ENABLED(CONFIG_STMMAC_SELFTESTS) |
| 354 | 357 | void stmmac_selftest_run(struct net_device *dev, |
| @@ -7171,6 +7171,7 @@ int stmmac_suspend(struct device *dev) · 7170 unmodified lines | ||
| 7171 | 7171 | priv->plat->rx_queues_to_use, false); |
| 7172 | 7172 | |
| 7173 | 7173 | stmmac_fpe_handshake(priv, false); |
| 7174 | + stmmac_fpe_stop_wq(priv); | |
| 7174 | 7175 | } |
| 7175 | 7176 | |
| 7176 | 7177 | priv->speed = SPEED_UNKNOWN; |
| @@ -397,6 +397,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) · 396 unmodified lines | ||
| 397 | 397 | struct device_node *np = pdev->dev.of_node; |
| 398 | 398 | struct plat_stmmacenet_data *plat; |
| 399 | 399 | struct stmmac_dma_cfg *dma_cfg; |
| 400 | + int phy_mode; | |
| 400 | 401 | void *ret; |
| 401 | 402 | int rc; |
| 402 | 403 | |
| @@ -412,10 +413,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) · 9 unmodified lines | ||
| 412 | 413 | eth_zero_addr(mac); |
| 413 | 414 | } |
| 414 | 415 | |
| 415 | − plat->phy_interface = device_get_phy_mode(&pdev->dev); | |
| 416 | − if (plat->phy_interface < 0) | |
| 417 | − return ERR_PTR(plat->phy_interface); | |
| 416 | + phy_mode = device_get_phy_mode(&pdev->dev); | |
| 417 | + if (phy_mode < 0) | |
| 418 | + return ERR_PTR(phy_mode); | |
| 418 | 419 | |
| 420 | + plat->phy_interface = phy_mode; | |
| 419 | 421 | plat->interface = stmmac_of_get_mac_mode(np); |
| 420 | 422 | if (plat->interface < 0) |
| 421 | 423 | plat->interface = plat->phy_interface; |
| @@ -62,7 +62,8 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) · 61 unmodified lines | ||
| 62 | 62 | u32 sec, nsec; |
| 63 | 63 | u32 quotient, reminder; |
| 64 | 64 | int neg_adj = 0; |
| 65 | − bool xmac; | |
| 65 | + bool xmac, est_rst = false; | |
| 66 | + int ret; | |
| 66 | 67 | |
| 67 | 68 | xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; |
| 68 | 69 | |
| @@ -75,10 +76,48 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) · 6 unmodified lines | ||
| 75 | 76 | sec = quotient; |
| 76 | 77 | nsec = reminder; |
| 77 | 78 | |
| 79 | + /* If EST is enabled, disabled it before adjust ptp time. */ | |
| 80 | + if (priv->plat->est && priv->plat->est->enable) { | |
| 81 | + est_rst = true; | |
| 82 | + mutex_lock(&priv->plat->est->lock); | |
| 83 | + priv->plat->est->enable = false; | |
| 84 | + stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, | |
| 85 | + priv->plat->clk_ptp_rate); | |
| 86 | + mutex_unlock(&priv->plat->est->lock); | |
| 87 | + } | |
| 88 | + | |
| 78 | 89 | spin_lock_irqsave(&priv->ptp_lock, flags); |
| 79 | 90 | stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac); |
| 80 | 91 | spin_unlock_irqrestore(&priv->ptp_lock, flags); |
| 81 | 92 | |
| 93 | + /* Caculate new basetime and re-configured EST after PTP time adjust. */ | |
| 94 | + if (est_rst) { | |
| 95 | + struct timespec64 current_time, time; | |
| 96 | + ktime_t current_time_ns, basetime; | |
| 97 | + u64 cycle_time; | |
| 98 | + | |
| 99 | + mutex_lock(&priv->plat->est->lock); | |
| 100 | + priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, ¤t_time); | |
| 101 | + current_time_ns = timespec64_to_ktime(current_time); | |
| 102 | + time.tv_nsec = priv->plat->est->btr_reserve[0]; | |
| 103 | + time.tv_sec = priv->plat->est->btr_reserve[1]; | |
| 104 | + basetime = timespec64_to_ktime(time); | |
| 105 | + cycle_time = priv->plat->est->ctr[1] * NSEC_PER_SEC + | |
| 106 | + priv->plat->est->ctr[0]; | |
| 107 | + time = stmmac_calc_tas_basetime(basetime, | |
| 108 | + current_time_ns, | |
| 109 | + cycle_time); | |
| 110 | + | |
| 111 | + priv->plat->est->btr[0] = (u32)time.tv_nsec; | |
| 112 | + priv->plat->est->btr[1] = (u32)time.tv_sec; | |
| 113 | + priv->plat->est->enable = true; | |
| 114 | + ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, | |
| 115 | + priv->plat->clk_ptp_rate); | |
| 116 | + mutex_unlock(&priv->plat->est->lock); | |
| 117 | + if (ret) | |
| 118 | + netdev_err(priv->dev, "failed to configure EST\n"); | |
| 119 | + } | |
| 120 | + | |
| 82 | 121 | return 0; |
| 83 | 122 | } |
| 84 | 123 | |
| @@ -711,12 +711,35 @@ static int tc_setup_cls(struct stmmac_priv *priv, · 710 unmodified lines | ||
| 711 | 711 | return ret; |
| 712 | 712 | } |
| 713 | 713 | |
| 714 | +struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time, | |
| 715 | + ktime_t current_time, | |
| 716 | + u64 cycle_time) | |
| 717 | +{ | |
| 718 | + struct timespec64 time; | |
| 719 | + | |
| 720 | + if (ktime_after(old_base_time, current_time)) { | |
| 721 | + time = ktime_to_timespec64(old_base_time); | |
| 722 | + } else { | |
| 723 | + s64 n; | |
| 724 | + ktime_t base_time; | |
| 725 | + | |
| 726 | + n = div64_s64(ktime_sub_ns(current_time, old_base_time), | |
| 727 | + cycle_time); | |
| 728 | + base_time = ktime_add_ns(old_base_time, | |
| 729 | + (n + 1) * cycle_time); | |
| 730 | + | |
| 731 | + time = ktime_to_timespec64(base_time); | |
| 732 | + } | |
| 733 | + | |
| 734 | + return time; | |
| 735 | +} | |
| 736 | + | |
| 714 | 737 | static int tc_setup_taprio(struct stmmac_priv *priv, |
| 715 | 738 | struct tc_taprio_qopt_offload *qopt) |
| 716 | 739 | { |
| 717 | 740 | u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep; |
| 718 | 741 | struct plat_stmmacenet_data *plat = priv->plat; |
| 719 | − struct timespec64 time, current_time; | |
| 742 | + struct timespec64 time, current_time, qopt_time; | |
| 720 | 743 | ktime_t current_time_ns; |
| 721 | 744 | bool fpe = false; |
| 722 | 745 | int i, ret = 0; |
| @@ -773,14 +796,18 @@ static int tc_setup_taprio(struct stmmac_priv *priv, · 50 unmodified lines | ||
| 773 | 796 | GFP_KERNEL); |
| 774 | 797 | if (!plat->est) |
| 775 | 798 | return -ENOMEM; |
| 799 | + | |
| 800 | + mutex_init(&priv->plat->est->lock); | |
| 776 | 801 | } else { |
| 777 | 802 | memset(plat->est, 0, sizeof(*plat->est)); |
| 778 | 803 | } |
| 779 | 804 | |
| 780 | 805 | size = qopt->num_entries; |
| 781 | 806 | |
| 807 | + mutex_lock(&priv->plat->est->lock); | |
| 782 | 808 | priv->plat->est->gcl_size = size; |
| 783 | 809 | priv->plat->est->enable = qopt->enable; |
| 810 | + mutex_unlock(&priv->plat->est->lock); | |
| 784 | 811 | |
| 785 | 812 | for (i = 0; i < size; i++) { |
| 786 | 813 | s64 delta_ns = qopt->entries[i].interval; |
| @@ -811,32 +838,28 @@ static int tc_setup_taprio(struct stmmac_priv *priv, · 24 unmodified lines | ||
| 811 | 838 | priv->plat->est->gcl[i] = delta_ns | (gates << wid); |
| 812 | 839 | } |
| 813 | 840 | |
| 841 | + mutex_lock(&priv->plat->est->lock); | |
| 814 | 842 | /* Adjust for real system time */ |
| 815 | 843 | priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, ¤t_time); |
| 816 | 844 | current_time_ns = timespec64_to_ktime(current_time); |
| 817 | − if (ktime_after(qopt->base_time, current_time_ns)) { | |
| 818 | − time = ktime_to_timespec64(qopt->base_time); | |
| 819 | − } else { | |
| 820 | − ktime_t base_time; | |
| 821 | − s64 n; | |
| 822 | − | |
| 823 | − n = div64_s64(ktime_sub_ns(current_time_ns, qopt->base_time), | |
| 824 | − qopt->cycle_time); | |
| 825 | − base_time = ktime_add_ns(qopt->base_time, | |
| 826 | − (n + 1) * qopt->cycle_time); | |
| 827 | − | |
| 828 | − time = ktime_to_timespec64(base_time); | |
| 829 | − } | |
| 845 | + time = stmmac_calc_tas_basetime(qopt->base_time, current_time_ns, | |
| 846 | + qopt->cycle_time); | |
| 830 | 847 | |
| 831 | 848 | priv->plat->est->btr[0] = (u32)time.tv_nsec; |
| 832 | 849 | priv->plat->est->btr[1] = (u32)time.tv_sec; |
| 833 | 850 | |
| 851 | + qopt_time = ktime_to_timespec64(qopt->base_time); | |
| 852 | + priv->plat->est->btr_reserve[0] = (u32)qopt_time.tv_nsec; | |
| 853 | + priv->plat->est->btr_reserve[1] = (u32)qopt_time.tv_sec; | |
| 854 | + | |
| 834 | 855 | ctr = qopt->cycle_time; |
| 835 | 856 | priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC); |
| 836 | 857 | priv->plat->est->ctr[1] = (u32)ctr; |
| 837 | 858 | |
| 838 | − if (fpe && !priv->dma_cap.fpesel) | |
| 859 | + if (fpe && !priv->dma_cap.fpesel) { | |
| 860 | + mutex_unlock(&priv->plat->est->lock); | |
| 839 | 861 | return -EOPNOTSUPP; |
| 862 | + } | |
| 840 | 863 | |
| 841 | 864 | /* Actual FPE register configuration will be done after FPE handshake |
| 842 | 865 | * is success. |
| @@ -845,6 +868,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv, · 2 unmodified lines | ||
| 845 | 868 | |
| 846 | 869 | ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, |
| 847 | 870 | priv->plat->clk_ptp_rate); |
| 871 | + mutex_unlock(&priv->plat->est->lock); | |
| 848 | 872 | if (ret) { |
| 849 | 873 | netdev_err(priv->dev, "failed to configure EST\n"); |
| 850 | 874 | goto disable; |
| @@ -860,9 +884,11 @@ static int tc_setup_taprio(struct stmmac_priv *priv, · 9 unmodified lines | ||
| 860 | 884 | return 0; |
| 861 | 885 | |
| 862 | 886 | disable: |
| 887 | + mutex_lock(&priv->plat->est->lock); | |
| 863 | 888 | priv->plat->est->enable = false; |
| 864 | 889 | stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, |
| 865 | 890 | priv->plat->clk_ptp_rate); |
| 891 | + mutex_unlock(&priv->plat->est->lock); | |
| 866 | 892 | |
| 867 | 893 | priv->plat->fpe_cfg->enable = false; |
| 868 | 894 | stmmac_fpe_configure(priv, priv->ioaddr, |
| @@ -313,9 +313,8 @@ static void tlan_remove_one(struct pci_dev *pdev) · 312 unmodified lines | ||
| 313 | 313 | pci_release_regions(pdev); |
| 314 | 314 | #endif |
| 315 | 315 | |
| 316 | − free_netdev(dev); | |
| 317 | − | |
| 318 | 316 | cancel_work_sync(&priv->tlan_tqueue); |
| 317 | + free_netdev(dev); | |
| 319 | 318 | } |
| 320 | 319 | |
| 321 | 320 | static void tlan_start(struct net_device *dev) |
| @@ -1504,9 +1504,8 @@ err_out_resource: · 1503 unmodified lines | ||
| 1504 | 1504 | release_mem_region(start, len); |
| 1505 | 1505 | |
| 1506 | 1506 | err_out_kfree: |
| 1507 | − free_netdev(dev); | |
| 1508 | − | |
| 1509 | 1507 | pr_err("%s: initialization failure, aborting!\n", fp->name); |
| 1508 | + free_netdev(dev); | |
| 1510 | 1509 | return ret; |
| 1511 | 1510 | } |
| 1512 | 1511 | |
| @@ -85,7 +85,7 @@ static int nsim_ipsec_parse_proto_keys(struct xfrm_state *xs, · 84 unmodified lines | ||
| 85 | 85 | u32 *mykey, u32 *mysalt) |
| 86 | 86 | { |
| 87 | 87 | const char aes_gcm_name[] = "rfc4106(gcm(aes))"; |
| 88 | − struct net_device *dev = xs->xso.dev; | |
| 88 | + struct net_device *dev = xs->xso.real_dev; | |
| 89 | 89 | unsigned char *key_data; |
| 90 | 90 | char *alg_name = NULL; |
| 91 | 91 | int key_len; |
| @@ -134,7 +134,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs) · 42 unmodified lines | ||
| 134 | 134 | u16 sa_idx; |
| 135 | 135 | int ret; |
| 136 | 136 | |
| 137 | − dev = xs->xso.dev; | |
| 137 | + dev = xs->xso.real_dev; | |
| 138 | 138 | ns = netdev_priv(dev); |
| 139 | 139 | ipsec = &ns->ipsec; |
| 140 | 140 | |
| @@ -194,7 +194,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs) · 53 unmodified lines | ||
| 194 | 194 | |
| 195 | 195 | static void nsim_ipsec_del_sa(struct xfrm_state *xs) |
| 196 | 196 | { |
| 197 | − struct netdevsim *ns = netdev_priv(xs->xso.dev); | |
| 197 | + struct netdevsim *ns = netdev_priv(xs->xso.real_dev); | |
| 198 | 198 | struct nsim_ipsec *ipsec = &ns->ipsec; |
| 199 | 199 | u16 sa_idx; |
| 200 | 200 | |
| @@ -211,7 +211,7 @@ static void nsim_ipsec_del_sa(struct xfrm_state *xs) · 10 unmodified lines | ||
| 211 | 211 | |
| 212 | 212 | static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) |
| 213 | 213 | { |
| 214 | − struct netdevsim *ns = netdev_priv(xs->xso.dev); | |
| 214 | + struct netdevsim *ns = netdev_priv(xs->xso.real_dev); | |
| 215 | 215 | struct nsim_ipsec *ipsec = &ns->ipsec; |
| 216 | 216 | |
| 217 | 217 | ipsec->ok++; |
| @@ -78,6 +78,11 @@ enum { · 77 unmodified lines | ||
| 78 | 78 | /* Temperature read register (88E2110 only) */ |
| 79 | 79 | MV_PCS_TEMP = 0x8042, |
| 80 | 80 | |
| 81 | + /* Number of ports on the device */ | |
| 82 | + MV_PCS_PORT_INFO = 0xd00d, | |
| 83 | + MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380, | |
| 84 | + MV_PCS_PORT_INFO_NPORTS_SHIFT = 7, | |
| 85 | + | |
| 81 | 86 | /* These registers appear at 0x800X and 0xa00X - the 0xa00X control |
| 82 | 87 | * registers appear to set themselves to the 0x800X when AN is |
| 83 | 88 | * restarted, but status registers appear readable from either. |
| @@ -966,6 +971,30 @@ static const struct mv3310_chip mv2111_type = { · 882 unmodified lines | ||
| 966 | 971 | #endif |
| 967 | 972 | }; |
| 968 | 973 | |
| 974 | +static int mv3310_get_number_of_ports(struct phy_device *phydev) | |
| 975 | +{ | |
| 976 | + int ret; | |
| 977 | + | |
| 978 | + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PORT_INFO); | |
| 979 | + if (ret < 0) | |
| 980 | + return ret; | |
| 981 | + | |
| 982 | + ret &= MV_PCS_PORT_INFO_NPORTS_MASK; | |
| 983 | + ret >>= MV_PCS_PORT_INFO_NPORTS_SHIFT; | |
| 984 | + | |
| 985 | + return ret + 1; | |
| 986 | +} | |
| 987 | + | |
| 988 | +static int mv3310_match_phy_device(struct phy_device *phydev) | |
| 989 | +{ | |
| 990 | + return mv3310_get_number_of_ports(phydev) == 1; | |
| 991 | +} | |
| 992 | + | |
| 993 | +static int mv3340_match_phy_device(struct phy_device *phydev) | |
| 994 | +{ | |
| 995 | + return mv3310_get_number_of_ports(phydev) == 4; | |
| 996 | +} | |
| 997 | + | |
| 969 | 998 | static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) |
| 970 | 999 | { |
| 971 | 1000 | int val; |
| @@ -994,7 +1023,8 @@ static int mv2111_match_phy_device(struct phy_device *phydev) · 22 unmodified lines | ||
| 994 | 1023 | static struct phy_driver mv3310_drivers[] = { |
| 995 | 1024 | { |
| 996 | 1025 | .phy_id = MARVELL_PHY_ID_88X3310, |
| 997 | − .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK, | |
| 1026 | + .phy_id_mask = MARVELL_PHY_ID_MASK, | |
| 1027 | + .match_phy_device = mv3310_match_phy_device, | |
| 998 | 1028 | .name = "mv88x3310", |
| 999 | 1029 | .driver_data = &mv3310_type, |
| 1000 | 1030 | .get_features = mv3310_get_features, |
| @@ -1011,8 +1041,9 @@ static struct phy_driver mv3310_drivers[] = { · 10 unmodified lines | ||
| 1011 | 1041 | .set_loopback = genphy_c45_loopback, |
| 1012 | 1042 | }, |
| 1013 | 1043 | { |
| 1014 | − .phy_id = MARVELL_PHY_ID_88X3340, | |
| 1015 | − .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK, | |
| 1044 | + .phy_id = MARVELL_PHY_ID_88X3310, | |
| 1045 | + .phy_id_mask = MARVELL_PHY_ID_MASK, | |
| 1046 | + .match_phy_device = mv3340_match_phy_device, | |
| 1016 | 1047 | .name = "mv88x3340", |
| 1017 | 1048 | .driver_data = &mv3340_type, |
| 1018 | 1049 | .get_features = mv3310_get_features, |
| @@ -1069,8 +1100,7 @@ static struct phy_driver mv3310_drivers[] = { · 50 unmodified lines | ||
| 1069 | 1100 | module_phy_driver(mv3310_drivers); |
| 1070 | 1101 | |
| 1071 | 1102 | static struct mdio_device_id __maybe_unused mv3310_tbl[] = { |
| 1072 | − { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_88X33X0_MASK }, | |
| 1073 | − { MARVELL_PHY_ID_88X3340, MARVELL_PHY_ID_88X33X0_MASK }, | |
| 1103 | + { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK }, | |
| 1074 | 1104 | { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK }, |
| 1075 | 1105 | { }, |
| 1076 | 1106 | }; |
| @@ -701,6 +701,7 @@ static int ax88772_init_phy(struct usbnet *dev) · 700 unmodified lines | ||
| 701 | 701 | return ret; |
| 702 | 702 | } |
| 703 | 703 | |
| 704 | + phy_suspend(priv->phydev); | |
| 704 | 705 | priv->phydev->mac_managed_pm = 1; |
| 705 | 706 | |
| 706 | 707 | phy_attached_info(priv->phydev); |
| @@ -1771,6 +1771,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, · 1770 unmodified lines | ||
| 1771 | 1771 | { |
| 1772 | 1772 | struct scatterlist *sgs[4], hdr, stat; |
| 1773 | 1773 | unsigned out_num = 0, tmp; |
| 1774 | + int ret; | |
| 1774 | 1775 | |
| 1775 | 1776 | /* Caller should know better */ |
| 1776 | 1777 | BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)); |
| @@ -1790,7 +1791,12 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, · 13 unmodified lines | ||
| 1790 | 1791 | sgs[out_num] = &stat; |
| 1791 | 1792 | |
| 1792 | 1793 | BUG_ON(out_num + 1 > ARRAY_SIZE(sgs)); |
| 1793 | − virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC); | |
| 1794 | + ret = virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC); | |
| 1795 | + if (ret < 0) { | |
| 1796 | + dev_warn(&vi->vdev->dev, | |
| 1797 | + "Failed to add sgs for command vq: %d\n.", ret); | |
| 1798 | + return false; | |
| 1799 | + } | |
| 1794 | 1800 | |
| 1795 | 1801 | if (unlikely(!virtqueue_kick(vi->cvq))) |
| 1796 | 1802 | return vi->ctrl->status == VIRTIO_NET_OK; |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Linux driver for VMware's vmxnet3 ethernet NIC. |
| 3 | 3 | * |
| 4 | − * Copyright (C) 2008-2020, VMware, Inc. All Rights Reserved. | |
| 4 | + * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved. | |
| 5 | 5 | * |
| 6 | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | 7 | * under the terms of the GNU General Public License as published by the |
| @@ -26,6 +26,10 @@ · 18 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | |
| 28 | 28 | #include "vmxnet3_int.h" |
| 29 | +#include <net/vxlan.h> | |
| 30 | +#include <net/geneve.h> | |
| 31 | + | |
| 32 | +#define VXLAN_UDP_PORT 8472 | |
| 29 | 33 | |
| 30 | 34 | struct vmxnet3_stat_desc { |
| 31 | 35 | char desc[ETH_GSTRING_LEN]; |
| @@ -262,6 +266,8 @@ netdev_features_t vmxnet3_features_check(struct sk_buff *skb, · 230 unmodified lines | ||
| 262 | 266 | if (VMXNET3_VERSION_GE_4(adapter) && |
| 263 | 267 | skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) { |
| 264 | 268 | u8 l4_proto = 0; |
| 269 | + u16 port; | |
| 270 | + struct udphdr *udph; | |
| 265 | 271 | |
| 266 | 272 | switch (vlan_get_protocol(skb)) { |
| 267 | 273 | case htons(ETH_P_IP): |
| @@ -274,8 +280,20 @@ netdev_features_t vmxnet3_features_check(struct sk_buff *skb, · 6 unmodified lines | ||
| 274 | 280 | return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); |
| 275 | 281 | } |
| 276 | 282 | |
| 277 | − if (l4_proto != IPPROTO_UDP) | |
| 283 | + switch (l4_proto) { | |
| 284 | + case IPPROTO_UDP: | |
| 285 | + udph = udp_hdr(skb); | |
| 286 | + port = be16_to_cpu(udph->dest); | |
| 287 | + /* Check if offloaded port is supported */ | |
| 288 | + if (port != GENEVE_UDP_PORT && | |
| 289 | + port != IANA_VXLAN_UDP_PORT && | |
| 290 | + port != VXLAN_UDP_PORT) { | |
| 291 | + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); | |
| 292 | + } | |
| 293 | + break; | |
| 294 | + default: | |
| 278 | 295 | return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); |
| 296 | + } | |
| 279 | 297 | } |
| 280 | 298 | return features; |
| 281 | 299 | } |
| @@ -364,19 +364,19 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) · 363 unmodified lines | ||
| 364 | 364 | return -EINVAL; |
| 365 | 365 | } |
| 366 | 366 | |
| 367 | −static int __init mod_init(void) | |
| 367 | +static int __init hdlc_cisco_init(void) | |
| 368 | 368 | { |
| 369 | 369 | register_hdlc_protocol(&proto); |
| 370 | 370 | return 0; |
| 371 | 371 | } |
| 372 | 372 | |
| 373 | −static void __exit mod_exit(void) | |
| 373 | +static void __exit hdlc_cisco_exit(void) | |
| 374 | 374 | { |
| 375 | 375 | unregister_hdlc_protocol(&proto); |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | −module_init(mod_init); | |
| 379 | −module_exit(mod_exit); | |
| 378 | +module_init(hdlc_cisco_init); | |
| 379 | +module_exit(hdlc_cisco_exit); | |
| 380 | 380 | |
| 381 | 381 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 382 | 382 | MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC"); |
| @@ -1279,19 +1279,19 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr) · 1278 unmodified lines | ||
| 1279 | 1279 | return -EINVAL; |
| 1280 | 1280 | } |
| 1281 | 1281 | |
| 1282 | −static int __init mod_init(void) | |
| 1282 | +static int __init hdlc_fr_init(void) | |
| 1283 | 1283 | { |
| 1284 | 1284 | register_hdlc_protocol(&proto); |
| 1285 | 1285 | return 0; |
| 1286 | 1286 | } |
| 1287 | 1287 | |
| 1288 | −static void __exit mod_exit(void) | |
| 1288 | +static void __exit hdlc_fr_exit(void) | |
| 1289 | 1289 | { |
| 1290 | 1290 | unregister_hdlc_protocol(&proto); |
| 1291 | 1291 | } |
| 1292 | 1292 | |
| 1293 | −module_init(mod_init); | |
| 1294 | −module_exit(mod_exit); | |
| 1293 | +module_init(hdlc_fr_init); | |
| 1294 | +module_exit(hdlc_fr_exit); | |
| 1295 | 1295 | |
| 1296 | 1296 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 1297 | 1297 | MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC"); |
| @@ -705,20 +705,20 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) · 704 unmodified lines | ||
| 705 | 705 | return -EINVAL; |
| 706 | 706 | } |
| 707 | 707 | |
| 708 | −static int __init mod_init(void) | |
| 708 | +static int __init hdlc_ppp_init(void) | |
| 709 | 709 | { |
| 710 | 710 | skb_queue_head_init(&tx_queue); |
| 711 | 711 | register_hdlc_protocol(&proto); |
| 712 | 712 | return 0; |
| 713 | 713 | } |
| 714 | 714 | |
| 715 | −static void __exit mod_exit(void) | |
| 715 | +static void __exit hdlc_ppp_exit(void) | |
| 716 | 716 | { |
| 717 | 717 | unregister_hdlc_protocol(&proto); |
| 718 | 718 | } |
| 719 | 719 | |
| 720 | −module_init(mod_init); | |
| 721 | −module_exit(mod_exit); | |
| 720 | +module_init(hdlc_ppp_init); | |
| 721 | +module_exit(hdlc_ppp_exit); | |
| 722 | 722 | |
| 723 | 723 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 724 | 724 | MODULE_DESCRIPTION("PPP protocol support for generic HDLC"); |
| @@ -90,7 +90,7 @@ static int raw_ioctl(struct net_device *dev, struct ifreq *ifr) · 89 unmodified lines | ||
| 90 | 90 | } |
| 91 | 91 | |
| 92 | 92 | |
| 93 | −static int __init mod_init(void) | |
| 93 | +static int __init hdlc_raw_init(void) | |
| 94 | 94 | { |
| 95 | 95 | register_hdlc_protocol(&proto); |
| 96 | 96 | return 0; |
| @@ -98,14 +98,14 @@ static int __init mod_init(void) · 1 unmodified line | ||
| 98 | 98 | |
| 99 | 99 | |
| 100 | 100 | |
| 101 | −static void __exit mod_exit(void) | |
| 101 | +static void __exit hdlc_raw_exit(void) | |
| 102 | 102 | { |
| 103 | 103 | unregister_hdlc_protocol(&proto); |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | |
| 107 | −module_init(mod_init); | |
| 108 | −module_exit(mod_exit); | |
| 107 | +module_init(hdlc_raw_init); | |
| 108 | +module_exit(hdlc_raw_exit); | |
| 109 | 109 | |
| 110 | 110 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 111 | 111 | MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC"); |
| @@ -110,7 +110,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) · 109 unmodified lines | ||
| 110 | 110 | } |
| 111 | 111 | |
| 112 | 112 | |
| 113 | −static int __init mod_init(void) | |
| 113 | +static int __init hdlc_eth_init(void) | |
| 114 | 114 | { |
| 115 | 115 | register_hdlc_protocol(&proto); |
| 116 | 116 | return 0; |
| @@ -118,14 +118,14 @@ static int __init mod_init(void) · 1 unmodified line | ||
| 118 | 118 | |
| 119 | 119 | |
| 120 | 120 | |
| 121 | −static void __exit mod_exit(void) | |
| 121 | +static void __exit hdlc_eth_exit(void) | |
| 122 | 122 | { |
| 123 | 123 | unregister_hdlc_protocol(&proto); |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | 126 | |
| 127 | −module_init(mod_init); | |
| 128 | −module_exit(mod_exit); | |
| 127 | +module_init(hdlc_eth_init); | |
| 128 | +module_exit(hdlc_eth_exit); | |
| 129 | 129 | |
| 130 | 130 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 131 | 131 | MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC"); |
| @@ -365,19 +365,19 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr) · 364 unmodified lines | ||
| 365 | 365 | return -EINVAL; |
| 366 | 366 | } |
| 367 | 367 | |
| 368 | −static int __init mod_init(void) | |
| 368 | +static int __init hdlc_x25_init(void) | |
| 369 | 369 | { |
| 370 | 370 | register_hdlc_protocol(&proto); |
| 371 | 371 | return 0; |
| 372 | 372 | } |
| 373 | 373 | |
| 374 | −static void __exit mod_exit(void) | |
| 374 | +static void __exit hdlc_x25_exit(void) | |
| 375 | 375 | { |
| 376 | 376 | unregister_hdlc_protocol(&proto); |
| 377 | 377 | } |
| 378 | 378 | |
| 379 | −module_init(mod_init); | |
| 380 | −module_exit(mod_exit); | |
| 379 | +module_init(hdlc_x25_init); | |
| 380 | +module_exit(hdlc_x25_exit); | |
| 381 | 381 | |
| 382 | 382 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 383 | 383 | MODULE_DESCRIPTION("X.25 protocol support for generic HDLC"); |
| @@ -931,7 +931,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) · 930 unmodified lines | ||
| 931 | 931 | ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); |
| 932 | 932 | if (ret) { |
| 933 | 933 | dev_dbg(dev->mt76.dev, "Firmware is already download\n"); |
| 934 | − return -EIO; | |
| 934 | + goto fw_loaded; | |
| 935 | 935 | } |
| 936 | 936 | |
| 937 | 937 | ret = mt7921_load_patch(dev); |
| @@ -949,6 +949,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) · 11 unmodified lines | ||
| 949 | 949 | return -EIO; |
| 950 | 950 | } |
| 951 | 951 | |
| 952 | +fw_loaded: | |
| 952 | 953 | mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); |
| 953 | 954 | |
| 954 | 955 | #ifdef CONFIG_PM |
| @@ -24,15 +24,7 @@ int ipc_imem_sys_wwan_open(struct iosm_imem *ipc_imem, int if_id) · 23 unmodified lines | ||
| 24 | 24 | return -EIO; |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | − /* check for the interafce id | |
| 28 | − * if if_id 1 to 8 then create IP MUX channel sessions. | |
| 29 | − * To start MUX session from 0 as network interface id would start | |
| 30 | − * from 1 so map it to if_id = if_id - 1 | |
| 31 | − */ | |
| 32 | − if (if_id >= IP_MUX_SESSION_START && if_id <= IP_MUX_SESSION_END) | |
| 33 | − return ipc_mux_open_session(ipc_imem->mux, if_id - 1); | |
| 34 | − | |
| 35 | − return -EINVAL; | |
| 27 | + return ipc_mux_open_session(ipc_imem->mux, if_id); | |
| 36 | 28 | } |
| 37 | 29 | |
| 38 | 30 | /* Release a net link to CP. */ |
| @@ -41,7 +33,7 @@ void ipc_imem_sys_wwan_close(struct iosm_imem *ipc_imem, int if_id, · 2 unmodified lines | ||
| 41 | 33 | { |
| 42 | 34 | if (ipc_imem->mux && if_id >= IP_MUX_SESSION_START && |
| 43 | 35 | if_id <= IP_MUX_SESSION_END) |
| 44 | − ipc_mux_close_session(ipc_imem->mux, if_id - 1); | |
| 36 | + ipc_mux_close_session(ipc_imem->mux, if_id); | |
| 45 | 37 | } |
| 46 | 38 | |
| 47 | 39 | /* Tasklet call to do uplink transfer. */ |
| @@ -83,13 +75,8 @@ int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem, · 35 unmodified lines | ||
| 83 | 75 | goto out; |
| 84 | 76 | } |
| 85 | 77 | |
| 86 | − if (if_id >= IP_MUX_SESSION_START && if_id <= IP_MUX_SESSION_END) | |
| 87 | − /* Route the UL packet through IP MUX Layer */ | |
| 88 | − ret = ipc_mux_ul_trigger_encode(ipc_imem->mux, | |
| 89 | − if_id - 1, skb); | |
| 90 | − else | |
| 91 | − dev_err(ipc_imem->dev, | |
| 92 | − "invalid if_id %d: ", if_id); | |
| 78 | + /* Route the UL packet through IP MUX Layer */ | |
| 79 | + ret = ipc_mux_ul_trigger_encode(ipc_imem->mux, if_id, skb); | |
| 93 | 80 | out: |
| 94 | 81 | return ret; |
| 95 | 82 | } |
| @@ -27,11 +27,11 @@ · 26 unmodified lines | ||
| 27 | 27 | #define BOOT_CHECK_DEFAULT_TIMEOUT 400 |
| 28 | 28 | |
| 29 | 29 | /* IP MUX channel range */ |
| 30 | −#define IP_MUX_SESSION_START 1 | |
| 31 | −#define IP_MUX_SESSION_END 8 | |
| 30 | +#define IP_MUX_SESSION_START 0 | |
| 31 | +#define IP_MUX_SESSION_END 7 | |
| 32 | 32 | |
| 33 | 33 | /* Default IP MUX channel */ |
| 34 | −#define IP_MUX_SESSION_DEFAULT 1 | |
| 34 | +#define IP_MUX_SESSION_DEFAULT 0 | |
| 35 | 35 | |
| 36 | 36 | /** |
| 37 | 37 | * ipc_imem_sys_port_open - Open a port link to CP. |
| @@ -288,7 +288,7 @@ static int ipc_mux_net_receive(struct iosm_mux *ipc_mux, int if_id, · 287 unmodified lines | ||
| 288 | 288 | /* Pass the packet to the netif layer. */ |
| 289 | 289 | dest_skb->priority = service_class; |
| 290 | 290 | |
| 291 | − return ipc_wwan_receive(wwan, dest_skb, false, if_id + 1); | |
| 291 | + return ipc_wwan_receive(wwan, dest_skb, false, if_id); | |
| 292 | 292 | } |
| 293 | 293 | |
| 294 | 294 | /* Decode Flow Credit Table in the block */ |
| @@ -37,7 +37,7 @@ void ipc_uevent_send(struct device *dev, char *uevent) · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | /* Store the device and event information */ |
| 39 | 39 | info->dev = dev; |
| 40 | − snprintf(info->uevent, MAX_UEVENT_LEN, "%s: %s", dev_name(dev), uevent); | |
| 40 | + snprintf(info->uevent, MAX_UEVENT_LEN, "IOSM_EVENT=%s", uevent); | |
| 41 | 41 | |
| 42 | 42 | /* Schedule uevent in process context using work queue */ |
| 43 | 43 | schedule_work(&info->work); |
| @@ -107,6 +107,7 @@ static int ipc_wwan_link_transmit(struct sk_buff *skb, · 106 unmodified lines | ||
| 107 | 107 | { |
| 108 | 108 | struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev); |
| 109 | 109 | struct iosm_wwan *ipc_wwan = priv->ipc_wwan; |
| 110 | + unsigned int len = skb->len; | |
| 110 | 111 | int if_id = priv->if_id; |
| 111 | 112 | int ret; |
| 112 | 113 | |
| @@ -123,6 +124,8 @@ static int ipc_wwan_link_transmit(struct sk_buff *skb, · 10 unmodified lines | ||
| 123 | 124 | |
| 124 | 125 | /* Return code of zero is success */ |
| 125 | 126 | if (ret == 0) { |
| 127 | + netdev->stats.tx_packets++; | |
| 128 | + netdev->stats.tx_bytes += len; | |
| 126 | 129 | ret = NETDEV_TX_OK; |
| 127 | 130 | } else if (ret == -EBUSY) { |
| 128 | 131 | ret = NETDEV_TX_BUSY; |
| @@ -140,7 +143,8 @@ exit: · 11 unmodified lines | ||
| 140 | 143 | ret); |
| 141 | 144 | |
| 142 | 145 | dev_kfree_skb_any(skb); |
| 143 | − return ret; | |
| 146 | + netdev->stats.tx_dropped++; | |
| 147 | + return NETDEV_TX_OK; | |
| 144 | 148 | } |
| 145 | 149 | |
| 146 | 150 | /* Ops structure for wwan net link */ |
| @@ -158,6 +162,7 @@ static void ipc_wwan_setup(struct net_device *iosm_dev) · 11 unmodified lines | ||
| 158 | 162 | iosm_dev->priv_flags |= IFF_NO_QUEUE; |
| 159 | 163 | |
| 160 | 164 | iosm_dev->type = ARPHRD_NONE; |
| 165 | + iosm_dev->mtu = ETH_DATA_LEN; | |
| 161 | 166 | iosm_dev->min_mtu = ETH_MIN_MTU; |
| 162 | 167 | iosm_dev->max_mtu = ETH_MAX_MTU; |
| 163 | 168 | |
| @@ -252,8 +257,8 @@ int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, · 88 unmodified lines | ||
| 252 | 257 | |
| 253 | 258 | skb->pkt_type = PACKET_HOST; |
| 254 | 259 | |
| 255 | − if (if_id < (IP_MUX_SESSION_START - 1) || | |
| 256 | − if_id > (IP_MUX_SESSION_END - 1)) { | |
| 260 | + if (if_id < IP_MUX_SESSION_START || | |
| 261 | + if_id > IP_MUX_SESSION_END) { | |
| 257 | 262 | ret = -EINVAL; |
| 258 | 263 | goto free; |
| 259 | 264 | } |
| @@ -3,7 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | # Makefile for PTP 1588 clock support. |
| 4 | 4 | # |
| 5 | 5 | |
| 6 | −ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o | |
| 6 | +ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o ptp_vclock.o | |
| 7 | 7 | ptp_kvm-$(CONFIG_X86) := ptp_kvm_x86.o ptp_kvm_common.o |
| 8 | 8 | ptp_kvm-$(CONFIG_HAVE_ARM_SMCCC) := ptp_kvm_arm.o ptp_kvm_common.o |
| 9 | 9 | obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o |
| @@ -24,10 +24,11 @@ · 23 unmodified lines | ||
| 24 | 24 | #define PTP_PPS_EVENT PPS_CAPTUREASSERT |
| 25 | 25 | #define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC) |
| 26 | 26 | |
| 27 | +struct class *ptp_class; | |
| 28 | + | |
| 27 | 29 | /* private globals */ |
| 28 | 30 | |
| 29 | 31 | static dev_t ptp_devt; |
| 30 | −static struct class *ptp_class; | |
| 31 | 32 | |
| 32 | 33 | static DEFINE_IDA(ptp_clocks_map); |
| 33 | 34 | |
| @@ -76,6 +77,11 @@ static int ptp_clock_settime(struct posix_clock *pc, const struct timespec64 *tp · 42 unmodified lines | ||
| 76 | 77 | { |
| 77 | 78 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); |
| 78 | 79 | |
| 80 | + if (ptp_vclock_in_use(ptp)) { | |
| 81 | + pr_err("ptp: virtual clock in use\n"); | |
| 82 | + return -EBUSY; | |
| 83 | + } | |
| 84 | + | |
| 79 | 85 | return ptp->info->settime64(ptp->info, tp); |
| 80 | 86 | } |
| 81 | 87 | |
| @@ -97,6 +103,11 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) · 15 unmodified lines | ||
| 97 | 103 | struct ptp_clock_info *ops; |
| 98 | 104 | int err = -EOPNOTSUPP; |
| 99 | 105 | |
| 106 | + if (ptp_vclock_in_use(ptp)) { | |
| 107 | + pr_err("ptp: virtual clock in use\n"); | |
| 108 | + return -EBUSY; | |
| 109 | + } | |
| 110 | + | |
| 100 | 111 | ops = ptp->info; |
| 101 | 112 | |
| 102 | 113 | if (tx->modes & ADJ_SETOFFSET) { |
| @@ -161,6 +172,7 @@ static void ptp_clock_release(struct device *dev) · 58 unmodified lines | ||
| 161 | 172 | ptp_cleanup_pin_groups(ptp); |
| 162 | 173 | mutex_destroy(&ptp->tsevq_mux); |
| 163 | 174 | mutex_destroy(&ptp->pincfg_mux); |
| 175 | + mutex_destroy(&ptp->n_vclocks_mux); | |
| 164 | 176 | ida_simple_remove(&ptp_clocks_map, ptp->index); |
| 165 | 177 | kfree(ptp); |
| 166 | 178 | } |
| @@ -185,6 +197,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, · 18 unmodified lines | ||
| 185 | 197 | { |
| 186 | 198 | struct ptp_clock *ptp; |
| 187 | 199 | int err = 0, index, major = MAJOR(ptp_devt); |
| 200 | + size_t size; | |
| 188 | 201 | |
| 189 | 202 | if (info->n_alarm > PTP_MAX_ALARMS) |
| 190 | 203 | return ERR_PTR(-EINVAL); |
| @@ -208,6 +221,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, · 17 unmodified lines | ||
| 208 | 221 | spin_lock_init(&ptp->tsevq.lock); |
| 209 | 222 | mutex_init(&ptp->tsevq_mux); |
| 210 | 223 | mutex_init(&ptp->pincfg_mux); |
| 224 | + mutex_init(&ptp->n_vclocks_mux); | |
| 211 | 225 | init_waitqueue_head(&ptp->tsev_wq); |
| 212 | 226 | |
| 213 | 227 | if (ptp->info->do_aux_work) { |
| @@ -218,7 +232,22 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, · 4 unmodified lines | ||
| 218 | 232 | pr_err("failed to create ptp aux_worker %d\n", err); |
| 219 | 233 | goto kworker_err; |
| 220 | 234 | } |
| 221 | − ptp->pps_source->lookup_cookie = ptp; | |
| 235 | + } | |
| 236 | + | |
| 237 | + /* PTP virtual clock is being registered under physical clock */ | |
| 238 | + if (parent && parent->class && parent->class->name && | |
| 239 | + strcmp(parent->class->name, "ptp") == 0) | |
| 240 | + ptp->is_virtual_clock = true; | |
| 241 | + | |
| 242 | + if (!ptp->is_virtual_clock) { | |
| 243 | + ptp->max_vclocks = PTP_DEFAULT_MAX_VCLOCKS; | |
| 244 | + | |
| 245 | + size = sizeof(int) * ptp->max_vclocks; | |
| 246 | + ptp->vclock_index = kzalloc(size, GFP_KERNEL); | |
| 247 | + if (!ptp->vclock_index) { | |
| 248 | + err = -ENOMEM; | |
| 249 | + goto no_mem_for_vclocks; | |
| 250 | + } | |
| 222 | 251 | } |
| 223 | 252 | |
| 224 | 253 | err = ptp_populate_pin_groups(ptp); |
| @@ -238,6 +267,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, · 13 unmodified lines | ||
| 238 | 267 | pr_err("failed to register pps source\n"); |
| 239 | 268 | goto no_pps; |
| 240 | 269 | } |
| 270 | + ptp->pps_source->lookup_cookie = ptp; | |
| 241 | 271 | } |
| 242 | 272 | |
| 243 | 273 | /* Initialize a new device of our class in our clock structure. */ |
| @@ -265,11 +295,14 @@ no_clock: · 21 unmodified lines | ||
| 265 | 295 | no_pps: |
| 266 | 296 | ptp_cleanup_pin_groups(ptp); |
| 267 | 297 | no_pin_groups: |
| 298 | + kfree(ptp->vclock_index); | |
| 299 | +no_mem_for_vclocks: | |
| 268 | 300 | if (ptp->kworker) |
| 269 | 301 | kthread_destroy_worker(ptp->kworker); |
| 270 | 302 | kworker_err: |
| 271 | 303 | mutex_destroy(&ptp->tsevq_mux); |
| 272 | 304 | mutex_destroy(&ptp->pincfg_mux); |
| 305 | + mutex_destroy(&ptp->n_vclocks_mux); | |
| 273 | 306 | ida_simple_remove(&ptp_clocks_map, index); |
| 274 | 307 | no_slot: |
| 275 | 308 | kfree(ptp); |
| @@ -280,9 +313,16 @@ EXPORT_SYMBOL(ptp_clock_register); · 4 unmodified lines | ||
| 280 | 313 | |
| 281 | 314 | int ptp_clock_unregister(struct ptp_clock *ptp) |
| 282 | 315 | { |
| 316 | + if (ptp_vclock_in_use(ptp)) { | |
| 317 | + pr_err("ptp: virtual clock in use\n"); | |
| 318 | + return -EBUSY; | |
| 319 | + } | |
| 320 | + | |
| 283 | 321 | ptp->defunct = 1; |
| 284 | 322 | wake_up_interruptible(&ptp->tsev_wq); |
| 285 | 323 | |
| 324 | + kfree(ptp->vclock_index); | |
| 325 | + | |
| 286 | 326 | if (ptp->kworker) { |
| 287 | 327 | kthread_cancel_delayed_work_sync(&ptp->aux_work); |
| 288 | 328 | kthread_destroy_worker(ptp->kworker); |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | #define PTP_MAX_TIMESTAMPS 128 |
| 20 | 20 | #define PTP_BUF_TIMESTAMPS 30 |
| 21 | +#define PTP_DEFAULT_MAX_VCLOCKS 20 | |
| 21 | 22 | |
| 22 | 23 | struct timestamp_event_queue { |
| 23 | 24 | struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS]; |
| @@ -46,6 +47,24 @@ struct ptp_clock { · 22 unmodified lines | ||
| 46 | 47 | const struct attribute_group *pin_attr_groups[2]; |
| 47 | 48 | struct kthread_worker *kworker; |
| 48 | 49 | struct kthread_delayed_work aux_work; |
| 50 | + unsigned int max_vclocks; | |
| 51 | + unsigned int n_vclocks; | |
| 52 | + int *vclock_index; | |
| 53 | + struct mutex n_vclocks_mux; /* protect concurrent n_vclocks access */ | |
| 54 | + bool is_virtual_clock; | |
| 55 | +}; | |
| 56 | + | |
| 57 | +#define info_to_vclock(d) container_of((d), struct ptp_vclock, info) | |
| 58 | +#define cc_to_vclock(d) container_of((d), struct ptp_vclock, cc) | |
| 59 | +#define dw_to_vclock(d) container_of((d), struct ptp_vclock, refresh_work) | |
| 60 | + | |
| 61 | +struct ptp_vclock { | |
| 62 | + struct ptp_clock *pclock; | |
| 63 | + struct ptp_clock_info info; | |
| 64 | + struct ptp_clock *clock; | |
| 65 | + struct cyclecounter cc; | |
| 66 | + struct timecounter tc; | |
| 67 | + spinlock_t lock; /* protects tc/cc */ | |
| 49 | 68 | }; |
| 50 | 69 | |
| 51 | 70 | /* |
| @@ -61,6 +80,24 @@ static inline int queue_cnt(struct timestamp_event_queue *q) · 9 unmodified lines | ||
| 61 | 80 | return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt; |
| 62 | 81 | } |
| 63 | 82 | |
| 83 | +/* Check if ptp virtual clock is in use */ | |
| 84 | +static inline bool ptp_vclock_in_use(struct ptp_clock *ptp) | |
| 85 | +{ | |
| 86 | + bool in_use = false; | |
| 87 | + | |
| 88 | + if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) | |
| 89 | + return true; | |
| 90 | + | |
| 91 | + if (!ptp->is_virtual_clock && ptp->n_vclocks) | |
| 92 | + in_use = true; | |
| 93 | + | |
| 94 | + mutex_unlock(&ptp->n_vclocks_mux); | |
| 95 | + | |
| 96 | + return in_use; | |
| 97 | +} | |
| 98 | + | |
| 99 | +extern struct class *ptp_class; | |
| 100 | + | |
| 64 | 101 | /* |
| 65 | 102 | * see ptp_chardev.c |
| 66 | 103 | */ |
| @@ -89,4 +126,6 @@ extern const struct attribute_group *ptp_groups[]; · 22 unmodified lines | ||
| 89 | 126 | int ptp_populate_pin_groups(struct ptp_clock *ptp); |
| 90 | 127 | void ptp_cleanup_pin_groups(struct ptp_clock *ptp); |
| 91 | 128 | |
| 129 | +struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock); | |
| 130 | +void ptp_vclock_unregister(struct ptp_vclock *vclock); | |
| 92 | 131 | #endif |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | * PTP 1588 clock support - sysfs interface. |
| 4 | 4 | * |
| 5 | 5 | * Copyright (C) 2010 OMICRON electronics GmbH |
| 6 | + * Copyright 2021 NXP | |
| 6 | 7 | */ |
| 7 | 8 | #include <linux/capability.h> |
| 8 | 9 | #include <linux/slab.h> |
| @@ -148,6 +149,159 @@ out: · 139 unmodified lines | ||
| 148 | 149 | } |
| 149 | 150 | static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store); |
| 150 | 151 | |
| 152 | +static int unregister_vclock(struct device *dev, void *data) | |
| 153 | +{ | |
| 154 | + struct ptp_clock *ptp = dev_get_drvdata(dev); | |
| 155 | + struct ptp_clock_info *info = ptp->info; | |
| 156 | + struct ptp_vclock *vclock; | |
| 157 | + u8 *num = data; | |
| 158 | + | |
| 159 | + vclock = info_to_vclock(info); | |
| 160 | + dev_info(dev->parent, "delete virtual clock ptp%d\n", | |
| 161 | + vclock->clock->index); | |
| 162 | + | |
| 163 | + ptp_vclock_unregister(vclock); | |
| 164 | + (*num)--; | |
| 165 | + | |
| 166 | + /* For break. Not error. */ | |
| 167 | + if (*num == 0) | |
| 168 | + return -EINVAL; | |
| 169 | + | |
| 170 | + return 0; | |
| 171 | +} | |
| 172 | + | |
| 173 | +static ssize_t n_vclocks_show(struct device *dev, | |
| 174 | + struct device_attribute *attr, char *page) | |
| 175 | +{ | |
| 176 | + struct ptp_clock *ptp = dev_get_drvdata(dev); | |
| 177 | + ssize_t size; | |
| 178 | + | |
| 179 | + if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) | |
| 180 | + return -ERESTARTSYS; | |
| 181 | + | |
| 182 | + size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->n_vclocks); | |
| 183 | + | |
| 184 | + mutex_unlock(&ptp->n_vclocks_mux); | |
| 185 | + | |
| 186 | + return size; | |
| 187 | +} | |
| 188 | + | |
| 189 | +static ssize_t n_vclocks_store(struct device *dev, | |
| 190 | + struct device_attribute *attr, | |
| 191 | + const char *buf, size_t count) | |
| 192 | +{ | |
| 193 | + struct ptp_clock *ptp = dev_get_drvdata(dev); | |
| 194 | + struct ptp_vclock *vclock; | |
| 195 | + int err = -EINVAL; | |
| 196 | + u32 num, i; | |
| 197 | + | |
| 198 | + if (kstrtou32(buf, 0, &num)) | |
| 199 | + return err; | |
| 200 | + | |
| 201 | + if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) | |
| 202 | + return -ERESTARTSYS; | |
| 203 | + | |
| 204 | + if (num > ptp->max_vclocks) { | |
| 205 | + dev_err(dev, "max value is %d\n", ptp->max_vclocks); | |
| 206 | + goto out; | |
| 207 | + } | |
| 208 | + | |
| 209 | + /* Need to create more vclocks */ | |
| 210 | + if (num > ptp->n_vclocks) { | |
| 211 | + for (i = 0; i < num - ptp->n_vclocks; i++) { | |
| 212 | + vclock = ptp_vclock_register(ptp); | |
| 213 | + if (!vclock) | |
| 214 | + goto out; | |
| 215 | + | |
| 216 | + *(ptp->vclock_index + ptp->n_vclocks + i) = | |
| 217 | + vclock->clock->index; | |
| 218 | + | |
| 219 | + dev_info(dev, "new virtual clock ptp%d\n", | |
| 220 | + vclock->clock->index); | |
| 221 | + } | |
| 222 | + } | |
| 223 | + | |
| 224 | + /* Need to delete vclocks */ | |
| 225 | + if (num < ptp->n_vclocks) { | |
| 226 | + i = ptp->n_vclocks - num; | |
| 227 | + device_for_each_child_reverse(dev, &i, | |
| 228 | + unregister_vclock); | |
| 229 | + | |
| 230 | + for (i = 1; i <= ptp->n_vclocks - num; i++) | |
| 231 | + *(ptp->vclock_index + ptp->n_vclocks - i) = -1; | |
| 232 | + } | |
| 233 | + | |
| 234 | + if (num == 0) | |
| 235 | + dev_info(dev, "only physical clock in use now\n"); | |
| 236 | + else | |
| 237 | + dev_info(dev, "guarantee physical clock free running\n"); | |
| 238 | + | |
| 239 | + ptp->n_vclocks = num; | |
| 240 | + mutex_unlock(&ptp->n_vclocks_mux); | |
| 241 | + | |
| 242 | + return count; | |
| 243 | +out: | |
| 244 | + mutex_unlock(&ptp->n_vclocks_mux); | |
| 245 | + return err; | |
| 246 | +} | |
| 247 | +static DEVICE_ATTR_RW(n_vclocks); | |
| 248 | + | |
| 249 | +static ssize_t max_vclocks_show(struct device *dev, | |
| 250 | + struct device_attribute *attr, char *page) | |
| 251 | +{ | |
| 252 | + struct ptp_clock *ptp = dev_get_drvdata(dev); | |
| 253 | + ssize_t size; | |
| 254 | + | |
| 255 | + size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->max_vclocks); | |
| 256 | + | |
| 257 | + return size; | |
| 258 | +} | |
| 259 | + | |
| 260 | +static ssize_t max_vclocks_store(struct device *dev, | |
| 261 | + struct device_attribute *attr, | |
| 262 | + const char *buf, size_t count) | |
| 263 | +{ | |
| 264 | + struct ptp_clock *ptp = dev_get_drvdata(dev); | |
| 265 | + unsigned int *vclock_index; | |
| 266 | + int err = -EINVAL; | |
| 267 | + size_t size; | |
| 268 | + u32 max; | |
| 269 | + | |
| 270 | + if (kstrtou32(buf, 0, &max) || max == 0) | |
| 271 | + return -EINVAL; | |
| 272 | + | |
| 273 | + if (max == ptp->max_vclocks) | |
| 274 | + return count; | |
| 275 | + | |
| 276 | + if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) | |
| 277 | + return -ERESTARTSYS; | |
| 278 | + | |
| 279 | + if (max < ptp->n_vclocks) | |
| 280 | + goto out; | |
| 281 | + | |
| 282 | + size = sizeof(int) * max; | |
| 283 | + vclock_index = kzalloc(size, GFP_KERNEL); | |
| 284 | + if (!vclock_index) { | |
| 285 | + err = -ENOMEM; | |
| 286 | + goto out; | |
| 287 | + } | |
| 288 | + | |
| 289 | + size = sizeof(int) * ptp->n_vclocks; | |
| 290 | + memcpy(vclock_index, ptp->vclock_index, size); | |
| 291 | + | |
| 292 | + kfree(ptp->vclock_index); | |
| 293 | + ptp->vclock_index = vclock_index; | |
| 294 | + ptp->max_vclocks = max; | |
| 295 | + | |
| 296 | + mutex_unlock(&ptp->n_vclocks_mux); | |
| 297 | + | |
| 298 | + return count; | |
| 299 | +out: | |
| 300 | + mutex_unlock(&ptp->n_vclocks_mux); | |
| 301 | + return err; | |
| 302 | +} | |
| 303 | +static DEVICE_ATTR_RW(max_vclocks); | |
| 304 | + | |
| 151 | 305 | static struct attribute *ptp_attrs[] = { |
| 152 | 306 | &dev_attr_clock_name.attr, |
| 153 | 307 | |
| @@ -162,6 +316,8 @@ static struct attribute *ptp_attrs[] = { · 8 unmodified lines | ||
| 162 | 316 | &dev_attr_fifo.attr, |
| 163 | 317 | &dev_attr_period.attr, |
| 164 | 318 | &dev_attr_pps_enable.attr, |
| 319 | + &dev_attr_n_vclocks.attr, | |
| 320 | + &dev_attr_max_vclocks.attr, | |
| 165 | 321 | NULL |
| 166 | 322 | }; |
| 167 | 323 | |
| @@ -183,6 +339,10 @@ static umode_t ptp_is_attribute_visible(struct kobject *kobj, · 15 unmodified lines | ||
| 183 | 339 | } else if (attr == &dev_attr_pps_enable.attr) { |
| 184 | 340 | if (!info->pps) |
| 185 | 341 | mode = 0; |
| 342 | + } else if (attr == &dev_attr_n_vclocks.attr || | |
| 343 | + attr == &dev_attr_max_vclocks.attr) { | |
| 344 | + if (ptp->is_virtual_clock) | |
| 345 | + mode = 0; | |
| 186 | 346 | } |
| 187 | 347 | |
| 188 | 348 | return mode; |
| @@ -0,0 +1,219 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | +/* | |
| 3 | + * PTP virtual clock driver | |
| 4 | + * | |
| 5 | + * Copyright 2021 NXP | |
| 6 | + */ | |
| 7 | +#include <linux/slab.h> | |
| 8 | +#include "ptp_private.h" | |
| 9 | + | |
| 10 | +#define PTP_VCLOCK_CC_SHIFT 31 | |
| 11 | +#define PTP_VCLOCK_CC_MULT (1 << PTP_VCLOCK_CC_SHIFT) | |
| 12 | +#define PTP_VCLOCK_FADJ_SHIFT 9 | |
| 13 | +#define PTP_VCLOCK_FADJ_DENOMINATOR 15625ULL | |
| 14 | +#define PTP_VCLOCK_REFRESH_INTERVAL (HZ * 2) | |
| 15 | + | |
| 16 | +static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) | |
| 17 | +{ | |
| 18 | + struct ptp_vclock *vclock = info_to_vclock(ptp); | |
| 19 | + unsigned long flags; | |
| 20 | + s64 adj; | |
| 21 | + | |
| 22 | + adj = (s64)scaled_ppm << PTP_VCLOCK_FADJ_SHIFT; | |
| 23 | + adj = div_s64(adj, PTP_VCLOCK_FADJ_DENOMINATOR); | |
| 24 | + | |
| 25 | + spin_lock_irqsave(&vclock->lock, flags); | |
| 26 | + timecounter_read(&vclock->tc); | |
| 27 | + vclock->cc.mult = PTP_VCLOCK_CC_MULT + adj; | |
| 28 | + spin_unlock_irqrestore(&vclock->lock, flags); | |
| 29 | + | |
| 30 | + return 0; | |
| 31 | +} | |
| 32 | + | |
| 33 | +static int ptp_vclock_adjtime(struct ptp_clock_info *ptp, s64 delta) | |
| 34 | +{ | |
| 35 | + struct ptp_vclock *vclock = info_to_vclock(ptp); | |
| 36 | + unsigned long flags; | |
| 37 | + | |
| 38 | + spin_lock_irqsave(&vclock->lock, flags); | |
| 39 | + timecounter_adjtime(&vclock->tc, delta); | |
| 40 | + spin_unlock_irqrestore(&vclock->lock, flags); | |
| 41 | + | |
| 42 | + return 0; | |
| 43 | +} | |
| 44 | + | |
| 45 | +static int ptp_vclock_gettime(struct ptp_clock_info *ptp, | |
| 46 | + struct timespec64 *ts) | |
| 47 | +{ | |
| 48 | + struct ptp_vclock *vclock = info_to_vclock(ptp); | |
| 49 | + unsigned long flags; | |
| 50 | + u64 ns; | |
| 51 | + | |
| 52 | + spin_lock_irqsave(&vclock->lock, flags); | |
| 53 | + ns = timecounter_read(&vclock->tc); | |
| 54 | + spin_unlock_irqrestore(&vclock->lock, flags); | |
| 55 | + *ts = ns_to_timespec64(ns); | |
| 56 | + | |
| 57 | + return 0; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static int ptp_vclock_settime(struct ptp_clock_info *ptp, | |
| 61 | + const struct timespec64 *ts) | |
| 62 | +{ | |
| 63 | + struct ptp_vclock *vclock = info_to_vclock(ptp); | |
| 64 | + u64 ns = timespec64_to_ns(ts); | |
| 65 | + unsigned long flags; | |
| 66 | + | |
| 67 | + spin_lock_irqsave(&vclock->lock, flags); | |
| 68 | + timecounter_init(&vclock->tc, &vclock->cc, ns); | |
| 69 | + spin_unlock_irqrestore(&vclock->lock, flags); | |
| 70 | + | |
| 71 | + return 0; | |
| 72 | +} | |
| 73 | + | |
| 74 | +static long ptp_vclock_refresh(struct ptp_clock_info *ptp) | |
| 75 | +{ | |
| 76 | + struct ptp_vclock *vclock = info_to_vclock(ptp); | |
| 77 | + struct timespec64 ts; | |
| 78 | + | |
| 79 | + ptp_vclock_gettime(&vclock->info, &ts); | |
| 80 | + | |
| 81 | + return PTP_VCLOCK_REFRESH_INTERVAL; | |
| 82 | +} | |
| 83 | + | |
| 84 | +static const struct ptp_clock_info ptp_vclock_info = { | |
| 85 | + .owner = THIS_MODULE, | |
| 86 | + .name = "ptp virtual clock", | |
| 87 | + /* The maximum ppb value that long scaled_ppm can support */ | |
| 88 | + .max_adj = 32767999, | |
| 89 | + .adjfine = ptp_vclock_adjfine, | |
| 90 | + .adjtime = ptp_vclock_adjtime, | |
| 91 | + .gettime64 = ptp_vclock_gettime, | |
| 92 | + .settime64 = ptp_vclock_settime, | |
| 93 | + .do_aux_work = ptp_vclock_refresh, | |
| 94 | +}; | |
| 95 | + | |
| 96 | +static u64 ptp_vclock_read(const struct cyclecounter *cc) | |
| 97 | +{ | |
| 98 | + struct ptp_vclock *vclock = cc_to_vclock(cc); | |
| 99 | + struct ptp_clock *ptp = vclock->pclock; | |
| 100 | + struct timespec64 ts = {}; | |
| 101 | + | |
| 102 | + if (ptp->info->gettimex64) | |
| 103 | + ptp->info->gettimex64(ptp->info, &ts, NULL); | |
| 104 | + else | |
| 105 | + ptp->info->gettime64(ptp->info, &ts); | |
| 106 | + | |
| 107 | + return timespec64_to_ns(&ts); | |
| 108 | +} | |
| 109 | + | |
| 110 | +static const struct cyclecounter ptp_vclock_cc = { | |
| 111 | + .read = ptp_vclock_read, | |
| 112 | + .mask = CYCLECOUNTER_MASK(32), | |
| 113 | + .mult = PTP_VCLOCK_CC_MULT, | |
| 114 | + .shift = PTP_VCLOCK_CC_SHIFT, | |
| 115 | +}; | |
| 116 | + | |
| 117 | +struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock) | |
| 118 | +{ | |
| 119 | + struct ptp_vclock *vclock; | |
| 120 | + | |
| 121 | + vclock = kzalloc(sizeof(*vclock), GFP_KERNEL); | |
| 122 | + if (!vclock) | |
| 123 | + return NULL; | |
| 124 | + | |
| 125 | + vclock->pclock = pclock; | |
| 126 | + vclock->info = ptp_vclock_info; | |
| 127 | + vclock->cc = ptp_vclock_cc; | |
| 128 | + | |
| 129 | + snprintf(vclock->info.name, PTP_CLOCK_NAME_LEN, "ptp%d_virt", | |
| 130 | + pclock->index); | |
| 131 | + | |
| 132 | + spin_lock_init(&vclock->lock); | |
| 133 | + | |
| 134 | + vclock->clock = ptp_clock_register(&vclock->info, &pclock->dev); | |
| 135 | + if (IS_ERR_OR_NULL(vclock->clock)) { | |
| 136 | + kfree(vclock); | |
| 137 | + return NULL; | |
| 138 | + } | |
| 139 | + | |
| 140 | + timecounter_init(&vclock->tc, &vclock->cc, 0); | |
| 141 | + ptp_schedule_worker(vclock->clock, PTP_VCLOCK_REFRESH_INTERVAL); | |
| 142 | + | |
| 143 | + return vclock; | |
| 144 | +} | |
| 145 | + | |
| 146 | +void ptp_vclock_unregister(struct ptp_vclock *vclock) | |
| 147 | +{ | |
| 148 | + ptp_clock_unregister(vclock->clock); | |
| 149 | + kfree(vclock); | |
| 150 | +} | |
| 151 | + | |
| 152 | +int ptp_get_vclocks_index(int pclock_index, int **vclock_index) | |
| 153 | +{ | |
| 154 | + char name[PTP_CLOCK_NAME_LEN] = ""; | |
| 155 | + struct ptp_clock *ptp; | |
| 156 | + struct device *dev; | |
| 157 | + int num = 0; | |
| 158 | + | |
| 159 | + if (pclock_index < 0) | |
| 160 | + return num; | |
| 161 | + | |
| 162 | + snprintf(name, PTP_CLOCK_NAME_LEN, "ptp%d", pclock_index); | |
| 163 | + dev = class_find_device_by_name(ptp_class, name); | |
| 164 | + if (!dev) | |
| 165 | + return num; | |
| 166 | + | |
| 167 | + ptp = dev_get_drvdata(dev); | |
| 168 | + | |
| 169 | + if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) { | |
| 170 | + put_device(dev); | |
| 171 | + return num; | |
| 172 | + } | |
| 173 | + | |
| 174 | + *vclock_index = kzalloc(sizeof(int) * ptp->n_vclocks, GFP_KERNEL); | |
| 175 | + if (!(*vclock_index)) | |
| 176 | + goto out; | |
| 177 | + | |
| 178 | + memcpy(*vclock_index, ptp->vclock_index, sizeof(int) * ptp->n_vclocks); | |
| 179 | + num = ptp->n_vclocks; | |
| 180 | +out: | |
| 181 | + mutex_unlock(&ptp->n_vclocks_mux); | |
| 182 | + put_device(dev); | |
| 183 | + return num; | |
| 184 | +} | |
| 185 | +EXPORT_SYMBOL(ptp_get_vclocks_index); | |
| 186 | + | |
| 187 | +void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps, | |
| 188 | + int vclock_index) | |
| 189 | +{ | |
| 190 | + char name[PTP_CLOCK_NAME_LEN] = ""; | |
| 191 | + struct ptp_vclock *vclock; | |
| 192 | + struct ptp_clock *ptp; | |
| 193 | + unsigned long flags; | |
| 194 | + struct device *dev; | |
| 195 | + u64 ns; | |
| 196 | + | |
| 197 | + snprintf(name, PTP_CLOCK_NAME_LEN, "ptp%d", vclock_index); | |
| 198 | + dev = class_find_device_by_name(ptp_class, name); | |
| 199 | + if (!dev) | |
| 200 | + return; | |
| 201 | + | |
| 202 | + ptp = dev_get_drvdata(dev); | |
| 203 | + if (!ptp->is_virtual_clock) { | |
| 204 | + put_device(dev); | |
| 205 | + return; | |
| 206 | + } | |
| 207 | + | |
| 208 | + vclock = info_to_vclock(ptp->info); | |
| 209 | + | |
| 210 | + ns = ktime_to_ns(hwtstamps->hwtstamp); | |
| 211 | + | |
| 212 | + spin_lock_irqsave(&vclock->lock, flags); | |
| 213 | + ns = timecounter_cyc2time(&vclock->tc, ns); | |
| 214 | + spin_unlock_irqrestore(&vclock->lock, flags); | |
| 215 | + | |
| 216 | + put_device(dev); | |
| 217 | + hwtstamps->hwtstamp = ns_to_ktime(ns); | |
| 218 | +} | |
| 219 | +EXPORT_SYMBOL(ptp_convert_timestamp); | |
| @@ -780,6 +780,7 @@ struct bpf_jit_poke_descriptor { · 779 unmodified lines | ||
| 780 | 780 | void *tailcall_target; |
| 781 | 781 | void *tailcall_bypass; |
| 782 | 782 | void *bypass_addr; |
| 783 | + void *aux; | |
| 783 | 784 | union { |
| 784 | 785 | struct { |
| 785 | 786 | struct bpf_map *map; |
| @@ -757,6 +757,16 @@ void · 756 unmodified lines | ||
| 757 | 757 | ethtool_params_from_link_mode(struct ethtool_link_ksettings *link_ksettings, |
| 758 | 758 | enum ethtool_link_mode_bit_indices link_mode); |
| 759 | 759 | |
| 760 | +/** | |
| 761 | + * ethtool_get_phc_vclocks - Derive phc vclocks information, and caller | |
| 762 | + * is responsible to free memory of vclock_index | |
| 763 | + * @dev: pointer to net_device structure | |
| 764 | + * @vclock_index: pointer to pointer of vclock index | |
| 765 | + * | |
| 766 | + * Return number of phc vclocks | |
| 767 | + */ | |
| 768 | +int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index); | |
| 769 | + | |
| 760 | 770 | /** |
| 761 | 771 | * ethtool_sprintf - Write formatted string to ethtool string data |
| 762 | 772 | * @data: Pointer to start of string to update |
| @@ -22,14 +22,10 @@ · 21 unmodified lines | ||
| 22 | 22 | #define MARVELL_PHY_ID_88E1545 0x01410ea0 |
| 23 | 23 | #define MARVELL_PHY_ID_88E1548P 0x01410ec0 |
| 24 | 24 | #define MARVELL_PHY_ID_88E3016 0x01410e60 |
| 25 | +#define MARVELL_PHY_ID_88X3310 0x002b09a0 | |
| 25 | 26 | #define MARVELL_PHY_ID_88E2110 0x002b09b0 |
| 26 | 27 | #define MARVELL_PHY_ID_88X2222 0x01410f10 |
| 27 | 28 | |
| 28 | −/* PHY IDs and mask for Alaska 10G PHYs */ | |
| 29 | −#define MARVELL_PHY_ID_88X33X0_MASK 0xfffffff8 | |
| 30 | −#define MARVELL_PHY_ID_88X3310 0x002b09a0 | |
| 31 | −#define MARVELL_PHY_ID_88X3340 0x002b09a8 | |
| 32 | − | |
| 33 | 29 | /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ |
| 34 | 30 | #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 |
| 35 | 31 | |
| @@ -11,7 +11,10 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/device.h> |
| 12 | 12 | #include <linux/pps_kernel.h> |
| 13 | 13 | #include <linux/ptp_clock.h> |
| 14 | +#include <linux/timecounter.h> | |
| 15 | +#include <linux/skbuff.h> | |
| 14 | 16 | |
| 17 | +#define PTP_CLOCK_NAME_LEN 32 | |
| 15 | 18 | /** |
| 16 | 19 | * struct ptp_clock_request - request PTP clock event |
| 17 | 20 | * |
| @@ -134,7 +137,7 @@ struct ptp_system_timestamp { · 116 unmodified lines | ||
| 134 | 137 | |
| 135 | 138 | struct ptp_clock_info { |
| 136 | 139 | struct module *owner; |
| 137 | − char name[16]; | |
| 140 | + char name[PTP_CLOCK_NAME_LEN]; | |
| 138 | 141 | s32 max_adj; |
| 139 | 142 | int n_alarm; |
| 140 | 143 | int n_ext_ts; |
| @@ -304,6 +307,27 @@ int ptp_schedule_worker(struct ptp_clock *ptp, unsigned long delay); · 163 unmodified lines | ||
| 304 | 307 | */ |
| 305 | 308 | void ptp_cancel_worker_sync(struct ptp_clock *ptp); |
| 306 | 309 | |
| 310 | +/** | |
| 311 | + * ptp_get_vclocks_index() - get all vclocks index on pclock, and | |
| 312 | + * caller is responsible to free memory | |
| 313 | + * of vclock_index | |
| 314 | + * | |
| 315 | + * @pclock_index: phc index of ptp pclock. | |
| 316 | + * @vclock_index: pointer to pointer of vclock index. | |
| 317 | + * | |
| 318 | + * return number of vclocks. | |
| 319 | + */ | |
| 320 | +int ptp_get_vclocks_index(int pclock_index, int **vclock_index); | |
| 321 | + | |
| 322 | +/** | |
| 323 | + * ptp_convert_timestamp() - convert timestamp to a ptp vclock time | |
| 324 | + * | |
| 325 | + * @hwtstamps: skb_shared_hwtstamps structure pointer | |
| 326 | + * @vclock_index: phc index of ptp vclock. | |
| 327 | + */ | |
| 328 | +void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps, | |
| 329 | + int vclock_index); | |
| 330 | + | |
| 307 | 331 | #else |
| 308 | 332 | static inline struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, |
| 309 | 333 | struct device *parent) |
| @@ -323,6 +347,11 @@ static inline int ptp_schedule_worker(struct ptp_clock *ptp, · 13 unmodified lines | ||
| 323 | 347 | { return -EOPNOTSUPP; } |
| 324 | 348 | static inline void ptp_cancel_worker_sync(struct ptp_clock *ptp) |
| 325 | 349 | { } |
| 350 | +static inline int ptp_get_vclocks_index(int pclock_index, int **vclock_index) | |
| 351 | +{ return 0; } | |
| 352 | +static inline void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps, | |
| 353 | + int vclock_index) | |
| 354 | +{ } | |
| 326 | 355 | |
| 327 | 356 | #endif |
| 328 | 357 | |
| @@ -115,7 +115,9 @@ struct stmmac_axi { · 114 unmodified lines | ||
| 115 | 115 | |
| 116 | 116 | #define EST_GCL 1024 |
| 117 | 117 | struct stmmac_est { |
| 118 | + struct mutex lock; | |
| 118 | 119 | int enable; |
| 120 | + u32 btr_reserve[2]; | |
| 119 | 121 | u32 btr_offset[2]; |
| 120 | 122 | u32 btr[2]; |
| 121 | 123 | u32 ctr[2]; |
| @@ -201,6 +201,11 @@ struct bond_up_slave { · 200 unmodified lines | ||
| 201 | 201 | */ |
| 202 | 202 | #define BOND_LINK_NOCHANGE -1 |
| 203 | 203 | |
| 204 | +struct bond_ipsec { | |
| 205 | + struct list_head list; | |
| 206 | + struct xfrm_state *xs; | |
| 207 | +}; | |
| 208 | + | |
| 204 | 209 | /* |
| 205 | 210 | * Here are the locking policies for the two bonding locks: |
| 206 | 211 | * Get rcu_read_lock when reading or RTNL when writing slave list. |
| @@ -249,7 +254,9 @@ struct bonding { · 42 unmodified lines | ||
| 249 | 254 | #endif /* CONFIG_DEBUG_FS */ |
| 250 | 255 | struct rtnl_link_stats64 bond_stats; |
| 251 | 256 | #ifdef CONFIG_XFRM_OFFLOAD |
| 252 | − struct xfrm_state *xs; | |
| 257 | + struct list_head ipsec_list; | |
| 258 | + /* protecting ipsec_list */ | |
| 259 | + spinlock_t ipsec_lock; | |
| 253 | 260 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 254 | 261 | }; |
| 255 | 262 | |
| @@ -38,7 +38,7 @@ static inline bool net_busy_loop_on(void) · 37 unmodified lines | ||
| 38 | 38 | |
| 39 | 39 | static inline bool sk_can_busy_loop(const struct sock *sk) |
| 40 | 40 | { |
| 41 | − return sk->sk_ll_usec && !signal_pending(current); | |
| 41 | + return READ_ONCE(sk->sk_ll_usec) && !signal_pending(current); | |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | bool sk_busy_loop_end(void *p, unsigned long start_time); |
| @@ -1,200 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | −/* | |
| 3 | − * Copyright (C) ST-Ericsson AB 2010 | |
| 4 | − * Author: Daniel Martensson / daniel.martensson@stericsson.com | |
| 5 | − * Dmitry.Tarnyagin / dmitry.tarnyagin@stericsson.com | |
| 6 | − */ | |
| 7 | − | |
| 8 | −#ifndef CAIF_HSI_H_ | |
| 9 | −#define CAIF_HSI_H_ | |
| 10 | − | |
| 11 | −#include <net/caif/caif_layer.h> | |
| 12 | −#include <net/caif/caif_device.h> | |
| 13 | −#include <linux/atomic.h> | |
| 14 | − | |
| 15 | −/* | |
| 16 | − * Maximum number of CAIF frames that can reside in the same HSI frame. | |
| 17 | − */ | |
| 18 | −#define CFHSI_MAX_PKTS 15 | |
| 19 | − | |
| 20 | −/* | |
| 21 | − * Maximum number of bytes used for the frame that can be embedded in the | |
| 22 | − * HSI descriptor. | |
| 23 | − */ | |
| 24 | −#define CFHSI_MAX_EMB_FRM_SZ 96 | |
| 25 | − | |
| 26 | −/* | |
| 27 | − * Decides if HSI buffers should be prefilled with 0xFF pattern for easier | |
| 28 | − * debugging. Both TX and RX buffers will be filled before the transfer. | |
| 29 | − */ | |
| 30 | −#define CFHSI_DBG_PREFILL 0 | |
| 31 | − | |
| 32 | −/* Structure describing a HSI packet descriptor. */ | |
| 33 | −#pragma pack(1) /* Byte alignment. */ | |
| 34 | −struct cfhsi_desc { | |
| 35 | − u8 header; | |
| 36 | − u8 offset; | |
| 37 | − u16 cffrm_len[CFHSI_MAX_PKTS]; | |
| 38 | − u8 emb_frm[CFHSI_MAX_EMB_FRM_SZ]; | |
| 39 | −}; | |
| 40 | −#pragma pack() /* Default alignment. */ | |
| 41 | − | |
| 42 | −/* Size of the complete HSI packet descriptor. */ | |
| 43 | −#define CFHSI_DESC_SZ (sizeof(struct cfhsi_desc)) | |
| 44 | − | |
| 45 | −/* | |
| 46 | − * Size of the complete HSI packet descriptor excluding the optional embedded | |
| 47 | − * CAIF frame. | |
| 48 | − */ | |
| 49 | −#define CFHSI_DESC_SHORT_SZ (CFHSI_DESC_SZ - CFHSI_MAX_EMB_FRM_SZ) | |
| 50 | − | |
| 51 | −/* | |
| 52 | − * Maximum bytes transferred in one transfer. | |
| 53 | − */ | |
| 54 | −#define CFHSI_MAX_CAIF_FRAME_SZ 4096 | |
| 55 | − | |
| 56 | −#define CFHSI_MAX_PAYLOAD_SZ (CFHSI_MAX_PKTS * CFHSI_MAX_CAIF_FRAME_SZ) | |
| 57 | − | |
| 58 | −/* Size of the complete HSI TX buffer. */ | |
| 59 | −#define CFHSI_BUF_SZ_TX (CFHSI_DESC_SZ + CFHSI_MAX_PAYLOAD_SZ) | |
| 60 | − | |
| 61 | −/* Size of the complete HSI RX buffer. */ | |
| 62 | −#define CFHSI_BUF_SZ_RX ((2 * CFHSI_DESC_SZ) + CFHSI_MAX_PAYLOAD_SZ) | |
| 63 | − | |
| 64 | −/* Bitmasks for the HSI descriptor. */ | |
| 65 | −#define CFHSI_PIGGY_DESC (0x01 << 7) | |
| 66 | − | |
| 67 | −#define CFHSI_TX_STATE_IDLE 0 | |
| 68 | −#define CFHSI_TX_STATE_XFER 1 | |
| 69 | − | |
| 70 | −#define CFHSI_RX_STATE_DESC 0 | |
| 71 | −#define CFHSI_RX_STATE_PAYLOAD 1 | |
| 72 | − | |
| 73 | −/* Bitmasks for power management. */ | |
| 74 | −#define CFHSI_WAKE_UP 0 | |
| 75 | −#define CFHSI_WAKE_UP_ACK 1 | |
| 76 | −#define CFHSI_WAKE_DOWN_ACK 2 | |
| 77 | −#define CFHSI_AWAKE 3 | |
| 78 | −#define CFHSI_WAKELOCK_HELD 4 | |
| 79 | −#define CFHSI_SHUTDOWN 5 | |
| 80 | −#define CFHSI_FLUSH_FIFO 6 | |
| 81 | − | |
| 82 | −#ifndef CFHSI_INACTIVITY_TOUT | |
| 83 | −#define CFHSI_INACTIVITY_TOUT (1 * HZ) | |
| 84 | −#endif /* CFHSI_INACTIVITY_TOUT */ | |
| 85 | − | |
| 86 | −#ifndef CFHSI_WAKE_TOUT | |
| 87 | −#define CFHSI_WAKE_TOUT (3 * HZ) | |
| 88 | −#endif /* CFHSI_WAKE_TOUT */ | |
| 89 | − | |
| 90 | −#ifndef CFHSI_MAX_RX_RETRIES | |
| 91 | −#define CFHSI_MAX_RX_RETRIES (10 * HZ) | |
| 92 | −#endif | |
| 93 | − | |
| 94 | −/* Structure implemented by the CAIF HSI driver. */ | |
| 95 | −struct cfhsi_cb_ops { | |
| 96 | − void (*tx_done_cb) (struct cfhsi_cb_ops *drv); | |
| 97 | − void (*rx_done_cb) (struct cfhsi_cb_ops *drv); | |
| 98 | − void (*wake_up_cb) (struct cfhsi_cb_ops *drv); | |
| 99 | − void (*wake_down_cb) (struct cfhsi_cb_ops *drv); | |
| 100 | −}; | |
| 101 | − | |
| 102 | −/* Structure implemented by HSI device. */ | |
| 103 | −struct cfhsi_ops { | |
| 104 | − int (*cfhsi_up) (struct cfhsi_ops *dev); | |
| 105 | − int (*cfhsi_down) (struct cfhsi_ops *dev); | |
| 106 | − int (*cfhsi_tx) (u8 *ptr, int len, struct cfhsi_ops *dev); | |
| 107 | − int (*cfhsi_rx) (u8 *ptr, int len, struct cfhsi_ops *dev); | |
| 108 | − int (*cfhsi_wake_up) (struct cfhsi_ops *dev); | |
| 109 | − int (*cfhsi_wake_down) (struct cfhsi_ops *dev); | |
| 110 | − int (*cfhsi_get_peer_wake) (struct cfhsi_ops *dev, bool *status); | |
| 111 | − int (*cfhsi_fifo_occupancy) (struct cfhsi_ops *dev, size_t *occupancy); | |
| 112 | − int (*cfhsi_rx_cancel)(struct cfhsi_ops *dev); | |
| 113 | − struct cfhsi_cb_ops *cb_ops; | |
| 114 | −}; | |
| 115 | − | |
| 116 | −/* Structure holds status of received CAIF frames processing */ | |
| 117 | −struct cfhsi_rx_state { | |
| 118 | − int state; | |
| 119 | − int nfrms; | |
| 120 | − int pld_len; | |
| 121 | − int retries; | |
| 122 | − bool piggy_desc; | |
| 123 | −}; | |
| 124 | − | |
| 125 | −/* Priority mapping */ | |
| 126 | −enum { | |
| 127 | − CFHSI_PRIO_CTL = 0, | |
| 128 | − CFHSI_PRIO_VI, | |
| 129 | − CFHSI_PRIO_VO, | |
| 130 | − CFHSI_PRIO_BEBK, | |
| 131 | − CFHSI_PRIO_LAST, | |
| 132 | −}; | |
| 133 | − | |
| 134 | −struct cfhsi_config { | |
| 135 | − u32 inactivity_timeout; | |
| 136 | − u32 aggregation_timeout; | |
| 137 | − u32 head_align; | |
| 138 | − u32 tail_align; | |
| 139 | − u32 q_high_mark; | |
| 140 | − u32 q_low_mark; | |
| 141 | −}; | |
| 142 | − | |
| 143 | −/* Structure implemented by CAIF HSI drivers. */ | |
| 144 | −struct cfhsi { | |
| 145 | − struct caif_dev_common cfdev; | |
| 146 | − struct net_device *ndev; | |
| 147 | − struct platform_device *pdev; | |
| 148 | − struct sk_buff_head qhead[CFHSI_PRIO_LAST]; | |
| 149 | − struct cfhsi_cb_ops cb_ops; | |
| 150 | − struct cfhsi_ops *ops; | |
| 151 | − int tx_state; | |
| 152 | − struct cfhsi_rx_state rx_state; | |
| 153 | − struct cfhsi_config cfg; | |
| 154 | − int rx_len; | |
| 155 | − u8 *rx_ptr; | |
| 156 | − u8 *tx_buf; | |
| 157 | − u8 *rx_buf; | |
| 158 | − u8 *rx_flip_buf; | |
| 159 | − spinlock_t lock; | |
| 160 | − int flow_off_sent; | |
| 161 | − struct list_head list; | |
| 162 | − struct work_struct wake_up_work; | |
| 163 | − struct work_struct wake_down_work; | |
| 164 | − struct work_struct out_of_sync_work; | |
| 165 | − struct workqueue_struct *wq; | |
| 166 | − wait_queue_head_t wake_up_wait; | |
| 167 | − wait_queue_head_t wake_down_wait; | |
| 168 | − wait_queue_head_t flush_fifo_wait; | |
| 169 | − struct timer_list inactivity_timer; | |
| 170 | − struct timer_list rx_slowpath_timer; | |
| 171 | − | |
| 172 | − /* TX aggregation */ | |
| 173 | − int aggregation_len; | |
| 174 | − struct timer_list aggregation_timer; | |
| 175 | − | |
| 176 | − unsigned long bits; | |
| 177 | −}; | |
| 178 | −extern struct platform_driver cfhsi_driver; | |
| 179 | − | |
| 180 | −/** | |
| 181 | − * enum ifla_caif_hsi - CAIF HSI NetlinkRT parameters. | |
| 182 | − * @IFLA_CAIF_HSI_INACTIVITY_TOUT: Inactivity timeout before | |
| 183 | − * taking the HSI wakeline down, in milliseconds. | |
| 184 | − * When using RT Netlink to create, destroy or configure a CAIF HSI interface, | |
| 185 | − * enum ifla_caif_hsi is used to specify the configuration attributes. | |
| 186 | − */ | |
| 187 | −enum ifla_caif_hsi { | |
| 188 | − __IFLA_CAIF_HSI_UNSPEC, | |
| 189 | − __IFLA_CAIF_HSI_INACTIVITY_TOUT, | |
| 190 | − __IFLA_CAIF_HSI_AGGREGATION_TOUT, | |
| 191 | − __IFLA_CAIF_HSI_HEAD_ALIGN, | |
| 192 | − __IFLA_CAIF_HSI_TAIL_ALIGN, | |
| 193 | − __IFLA_CAIF_HSI_QHIGH_WATERMARK, | |
| 194 | − __IFLA_CAIF_HSI_QLOW_WATERMARK, | |
| 195 | − __IFLA_CAIF_HSI_MAX | |
| 196 | −}; | |
| 197 | − | |
| 198 | −struct cfhsi_ops *cfhsi_get_ops(void); | |
| 199 | − | |
| 200 | −#endif /* CAIF_HSI_H_ */ | |
| @@ -45,7 +45,9 @@ skb_tunnel_info(const struct sk_buff *skb) · 44 unmodified lines | ||
| 45 | 45 | return &md_dst->u.tun_info; |
| 46 | 46 | |
| 47 | 47 | dst = skb_dst(skb); |
| 48 | − if (dst && dst->lwtstate) | |
| 48 | + if (dst && dst->lwtstate && | |
| 49 | + (dst->lwtstate->type == LWTUNNEL_ENCAP_IP || | |
| 50 | + dst->lwtstate->type == LWTUNNEL_ENCAP_IP6)) | |
| 49 | 51 | return lwt_tun_info(dst->lwtstate); |
| 50 | 52 | |
| 51 | 53 | return NULL; |
| @@ -263,7 +263,7 @@ static inline bool ipv6_anycast_destination(const struct dst_entry *dst, · 262 unmodified lines | ||
| 263 | 263 | int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, |
| 264 | 264 | int (*output)(struct net *, struct sock *, struct sk_buff *)); |
| 265 | 265 | |
| 266 | −static inline int ip6_skb_dst_mtu(struct sk_buff *skb) | |
| 266 | +static inline unsigned int ip6_skb_dst_mtu(struct sk_buff *skb) | |
| 267 | 267 | { |
| 268 | 268 | int mtu; |
| 269 | 269 | |
| @@ -105,7 +105,7 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size, · 104 unmodified lines | ||
| 105 | 105 | bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, |
| 106 | 106 | unsigned int *size, unsigned int remaining, |
| 107 | 107 | struct mptcp_out_options *opts); |
| 108 | −void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb); | |
| 108 | +bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb); | |
| 109 | 109 | |
| 110 | 110 | void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, |
| 111 | 111 | struct mptcp_out_options *opts); |
| @@ -227,9 +227,10 @@ static inline bool mptcp_established_options(struct sock *sk, · 115 unmodified lines | ||
| 227 | 227 | return false; |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | −static inline void mptcp_incoming_options(struct sock *sk, | |
| 230 | +static inline bool mptcp_incoming_options(struct sock *sk, | |
| 231 | 231 | struct sk_buff *skb) |
| 232 | 232 | { |
| 233 | + return true; | |
| 233 | 234 | } |
| 234 | 235 | |
| 235 | 236 | static inline void mptcp_skb_ext_move(struct sk_buff *to, |
| @@ -30,7 +30,6 @@ void nf_conntrack_cleanup_net(struct net *net); · 29 unmodified lines | ||
| 30 | 30 | void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list); |
| 31 | 31 | |
| 32 | 32 | void nf_conntrack_proto_pernet_init(struct net *net); |
| 33 | −void nf_conntrack_proto_pernet_fini(struct net *net); | |
| 34 | 33 | |
| 35 | 34 | int nf_conntrack_proto_init(void); |
| 36 | 35 | void nf_conntrack_proto_fini(void); |
| @@ -27,6 +27,7 @@ struct nf_tcp_net { · 26 unmodified lines | ||
| 27 | 27 | u8 tcp_loose; |
| 28 | 28 | u8 tcp_be_liberal; |
| 29 | 29 | u8 tcp_max_retrans; |
| 30 | + u8 tcp_ignore_invalid_rst; | |
| 30 | 31 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
| 31 | 32 | unsigned int offload_timeout; |
| 32 | 33 | unsigned int offload_pickup; |
| @@ -360,8 +360,7 @@ enum { · 359 unmodified lines | ||
| 360 | 360 | #define SCTP_SCOPE_POLICY_MAX SCTP_SCOPE_POLICY_LINK |
| 361 | 361 | |
| 362 | 362 | /* Based on IPv4 scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>, |
| 363 | − * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 198.18.0.0/24, | |
| 364 | − * 192.88.99.0/24. | |
| 363 | + * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 192.88.99.0/24. | |
| 365 | 364 | * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP |
| 366 | 365 | * addresses. |
| 367 | 366 | */ |
| @@ -369,7 +368,6 @@ enum { · 1 unmodified line | ||
| 369 | 368 | ((htonl(INADDR_BROADCAST) == a) || \ |
| 370 | 369 | ipv4_is_multicast(a) || \ |
| 371 | 370 | ipv4_is_zeronet(a) || \ |
| 372 | − ipv4_is_test_198(a) || \ | |
| 373 | 371 | ipv4_is_anycast_6to4(a)) |
| 374 | 372 | |
| 375 | 373 | /* Flags used for the bind address copy functions. */ |
| @@ -316,7 +316,9 @@ struct bpf_local_storage; · 315 unmodified lines | ||
| 316 | 316 | * @sk_timer: sock cleanup timer |
| 317 | 317 | * @sk_stamp: time stamp of last packet received |
| 318 | 318 | * @sk_stamp_seq: lock for accessing sk_stamp on 32 bit architectures only |
| 319 | − * @sk_tsflags: SO_TIMESTAMPING socket options | |
| 319 | + * @sk_tsflags: SO_TIMESTAMPING flags | |
| 320 | + * @sk_bind_phc: SO_TIMESTAMPING bind PHC index of PTP virtual clock | |
| 321 | + * for timestamping | |
| 320 | 322 | * @sk_tskey: counter to disambiguate concurrent tstamp requests |
| 321 | 323 | * @sk_zckey: counter to order MSG_ZEROCOPY notifications |
| 322 | 324 | * @sk_socket: Identd and reporting IO signals |
| @@ -493,6 +495,7 @@ struct sock { · 170 unmodified lines | ||
| 493 | 495 | seqlock_t sk_stamp_seq; |
| 494 | 496 | #endif |
| 495 | 497 | u16 sk_tsflags; |
| 498 | + int sk_bind_phc; | |
| 496 | 499 | u8 sk_shutdown; |
| 497 | 500 | u32 sk_tskey; |
| 498 | 501 | atomic_t sk_zckey; |
| @@ -2755,7 +2758,8 @@ void sock_def_readable(struct sock *sk); · 2256 unmodified lines | ||
| 2755 | 2758 | |
| 2756 | 2759 | int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk); |
| 2757 | 2760 | void sock_set_timestamp(struct sock *sk, int optname, bool valbool); |
| 2758 | −int sock_set_timestamping(struct sock *sk, int optname, int val); | |
| 2761 | +int sock_set_timestamping(struct sock *sk, int optname, | |
| 2762 | + struct so_timestamping timestamping); | |
| 2759 | 2763 | |
| 2760 | 2764 | void sock_enable_timestamps(struct sock *sk); |
| 2761 | 2765 | void sock_no_linger(struct sock *sk); |
| @@ -686,6 +686,10 @@ static inline u32 __tcp_set_rto(const struct tcp_sock *tp) · 685 unmodified lines | ||
| 686 | 686 | |
| 687 | 687 | static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd) |
| 688 | 688 | { |
| 689 | + /* mptcp hooks are only on the slow path */ | |
| 690 | + if (sk_is_mptcp((struct sock *)tp)) | |
| 691 | + return; | |
| 692 | + | |
| 689 | 693 | tp->pred_flags = htonl((tp->tcp_header_len << 26) | |
| 690 | 694 | ntohl(TCP_FLAG_ACK) | |
| 691 | 695 | snd_wnd); |
| @@ -46,6 +46,7 @@ enum { · 45 unmodified lines | ||
| 46 | 46 | ETHTOOL_MSG_FEC_SET, |
| 47 | 47 | ETHTOOL_MSG_MODULE_EEPROM_GET, |
| 48 | 48 | ETHTOOL_MSG_STATS_GET, |
| 49 | + ETHTOOL_MSG_PHC_VCLOCKS_GET, | |
| 49 | 50 | |
| 50 | 51 | /* add new constants above here */ |
| 51 | 52 | __ETHTOOL_MSG_USER_CNT, |
| @@ -88,6 +89,7 @@ enum { · 36 unmodified lines | ||
| 88 | 89 | ETHTOOL_MSG_FEC_NTF, |
| 89 | 90 | ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY, |
| 90 | 91 | ETHTOOL_MSG_STATS_GET_REPLY, |
| 92 | + ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY, | |
| 91 | 93 | |
| 92 | 94 | /* add new constants above here */ |
| 93 | 95 | __ETHTOOL_MSG_KERNEL_CNT, |
| @@ -440,6 +442,19 @@ enum { · 346 unmodified lines | ||
| 440 | 442 | ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1) |
| 441 | 443 | }; |
| 442 | 444 | |
| 445 | +/* PHC VCLOCKS */ | |
| 446 | + | |
| 447 | +enum { | |
| 448 | + ETHTOOL_A_PHC_VCLOCKS_UNSPEC, | |
| 449 | + ETHTOOL_A_PHC_VCLOCKS_HEADER, /* nest - _A_HEADER_* */ | |
| 450 | + ETHTOOL_A_PHC_VCLOCKS_NUM, /* u32 */ | |
| 451 | + ETHTOOL_A_PHC_VCLOCKS_INDEX, /* array, s32 */ | |
| 452 | + | |
| 453 | + /* add new constants above here */ | |
| 454 | + __ETHTOOL_A_PHC_VCLOCKS_CNT, | |
| 455 | + ETHTOOL_A_PHC_VCLOCKS_MAX = (__ETHTOOL_A_PHC_VCLOCKS_CNT - 1) | |
| 456 | +}; | |
| 457 | + | |
| 443 | 458 | /* CABLE TEST */ |
| 444 | 459 | |
| 445 | 460 | enum { |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/types.h> |
| 14 | 14 | #include <linux/socket.h> /* for SO_TIMESTAMPING */ |
| 15 | 15 | |
| 16 | −/* SO_TIMESTAMPING gets an integer bit field comprised of these values */ | |
| 16 | +/* SO_TIMESTAMPING flags */ | |
| 17 | 17 | enum { |
| 18 | 18 | SOF_TIMESTAMPING_TX_HARDWARE = (1<<0), |
| 19 | 19 | SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1), |
| @@ -30,8 +30,9 @@ enum { · 10 unmodified lines | ||
| 30 | 30 | SOF_TIMESTAMPING_OPT_STATS = (1<<12), |
| 31 | 31 | SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13), |
| 32 | 32 | SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14), |
| 33 | + SOF_TIMESTAMPING_BIND_PHC = (1 << 15), | |
| 33 | 34 | |
| 34 | − SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TX_SWHW, | |
| 35 | + SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_BIND_PHC, | |
| 35 | 36 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | |
| 36 | 37 | SOF_TIMESTAMPING_LAST |
| 37 | 38 | }; |
| @@ -46,6 +47,18 @@ enum { · 8 unmodified lines | ||
| 46 | 47 | SOF_TIMESTAMPING_TX_SCHED | \ |
| 47 | 48 | SOF_TIMESTAMPING_TX_ACK) |
| 48 | 49 | |
| 50 | +/** | |
| 51 | + * struct so_timestamping - SO_TIMESTAMPING parameter | |
| 52 | + * | |
| 53 | + * @flags: SO_TIMESTAMPING flags | |
| 54 | + * @bind_phc: Index of PTP virtual clock bound to sock. This is available | |
| 55 | + * if flag SOF_TIMESTAMPING_BIND_PHC is set. | |
| 56 | + */ | |
| 57 | +struct so_timestamping { | |
| 58 | + int flags; | |
| 59 | + int bind_phc; | |
| 60 | +}; | |
| 61 | + | |
| 49 | 62 | /** |
| 50 | 63 | * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter |
| 51 | 64 | * |
| @@ -61,7 +61,7 @@ enum nfulnl_attr_type { · 60 unmodified lines | ||
| 61 | 61 | NFULA_HWTYPE, /* hardware type */ |
| 62 | 62 | NFULA_HWHEADER, /* hardware header */ |
| 63 | 63 | NFULA_HWLEN, /* hardware header length */ |
| 64 | − NFULA_CT, /* nf_conntrack_netlink.h */ | |
| 64 | + NFULA_CT, /* nfnetlink_conntrack.h */ | |
| 65 | 65 | NFULA_CT_INFO, /* enum ip_conntrack_info */ |
| 66 | 66 | NFULA_VLAN, /* nested attribute: packet vlan info */ |
| 67 | 67 | NFULA_L2HDR, /* full L2 header */ |
| @@ -51,11 +51,11 @@ enum nfqnl_attr_type { · 50 unmodified lines | ||
| 51 | 51 | NFQA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */ |
| 52 | 52 | NFQA_HWADDR, /* nfqnl_msg_packet_hw */ |
| 53 | 53 | NFQA_PAYLOAD, /* opaque data payload */ |
| 54 | − NFQA_CT, /* nf_conntrack_netlink.h */ | |
| 54 | + NFQA_CT, /* nfnetlink_conntrack.h */ | |
| 55 | 55 | NFQA_CT_INFO, /* enum ip_conntrack_info */ |
| 56 | 56 | NFQA_CAP_LEN, /* __u32 length of captured packet */ |
| 57 | 57 | NFQA_SKB_INFO, /* __u32 skb meta information */ |
| 58 | − NFQA_EXP, /* nf_conntrack_netlink.h */ | |
| 58 | + NFQA_EXP, /* nfnetlink_conntrack.h */ | |
| 59 | 59 | NFQA_UID, /* __u32 sk uid */ |
| 60 | 60 | NFQA_GID, /* __u32 sk gid */ |
| 61 | 61 | NFQA_SECCTX, /* security context string */ |
| @@ -2236,8 +2236,14 @@ static void bpf_prog_free_deferred(struct work_struct *work) · 2235 unmodified lines | ||
| 2236 | 2236 | #endif |
| 2237 | 2237 | if (aux->dst_trampoline) |
| 2238 | 2238 | bpf_trampoline_put(aux->dst_trampoline); |
| 2239 | − for (i = 0; i < aux->func_cnt; i++) | |
| 2239 | + for (i = 0; i < aux->func_cnt; i++) { | |
| 2240 | + /* We can just unlink the subprog poke descriptor table as | |
| 2241 | + * it was originally linked to the main program and is also | |
| 2242 | + * released along with it. | |
| 2243 | + */ | |
| 2244 | + aux->func[i]->aux->poke_tab = NULL; | |
| 2240 | 2245 | bpf_jit_free(aux->func[i]); |
| 2246 | + } | |
| 2241 | 2247 | if (aux->func_cnt) { |
| 2242 | 2248 | kfree(aux->func); |
| 2243 | 2249 | bpf_prog_unlock_free(aux->prog); |
| @@ -558,7 +558,8 @@ int dev_map_enqueue_multi(struct xdp_buff *xdp, struct net_device *dev_rx, · 557 unmodified lines | ||
| 558 | 558 | |
| 559 | 559 | if (map->map_type == BPF_MAP_TYPE_DEVMAP) { |
| 560 | 560 | for (i = 0; i < map->max_entries; i++) { |
| 561 | − dst = READ_ONCE(dtab->netdev_map[i]); | |
| 561 | + dst = rcu_dereference_check(dtab->netdev_map[i], | |
| 562 | + rcu_read_lock_bh_held()); | |
| 562 | 563 | if (!is_valid_dst(dst, xdp, exclude_ifindex)) |
| 563 | 564 | continue; |
| 564 | 565 | |
| @@ -654,7 +655,8 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, · 89 unmodified lines | ||
| 654 | 655 | |
| 655 | 656 | if (map->map_type == BPF_MAP_TYPE_DEVMAP) { |
| 656 | 657 | for (i = 0; i < map->max_entries; i++) { |
| 657 | − dst = READ_ONCE(dtab->netdev_map[i]); | |
| 658 | + dst = rcu_dereference_check(dtab->netdev_map[i], | |
| 659 | + rcu_read_lock_bh_held()); | |
| 658 | 660 | if (!dst || dst->dev->ifindex == exclude_ifindex) |
| 659 | 661 | continue; |
| 660 | 662 | |
| @@ -12121,33 +12121,19 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 12120 unmodified lines | ||
| 12121 | 12121 | goto out_free; |
| 12122 | 12122 | func[i]->is_func = 1; |
| 12123 | 12123 | func[i]->aux->func_idx = i; |
| 12124 | − /* the btf and func_info will be freed only at prog->aux */ | |
| 12124 | + /* Below members will be freed only at prog->aux */ | |
| 12125 | 12125 | func[i]->aux->btf = prog->aux->btf; |
| 12126 | 12126 | func[i]->aux->func_info = prog->aux->func_info; |
| 12127 | + func[i]->aux->poke_tab = prog->aux->poke_tab; | |
| 12128 | + func[i]->aux->size_poke_tab = prog->aux->size_poke_tab; | |
| 12127 | 12129 | |
| 12128 | 12130 | for (j = 0; j < prog->aux->size_poke_tab; j++) { |
| 12129 | − u32 insn_idx = prog->aux->poke_tab[j].insn_idx; | |
| 12130 | − int ret; | |
| 12131 | + struct bpf_jit_poke_descriptor *poke; | |
| 12131 | 12132 | |
| 12132 | − if (!(insn_idx >= subprog_start && | |
| 12133 | − insn_idx <= subprog_end)) | |
| 12134 | − continue; | |
| 12135 | − | |
| 12136 | − ret = bpf_jit_add_poke_descriptor(func[i], | |
| 12137 | − &prog->aux->poke_tab[j]); | |
| 12138 | − if (ret < 0) { | |
| 12139 | − verbose(env, "adding tail call poke descriptor failed\n"); | |
| 12140 | − goto out_free; | |
| 12141 | − } | |
| 12142 | − | |
| 12143 | − func[i]->insnsi[insn_idx - subprog_start].imm = ret + 1; | |
| 12144 | − | |
| 12145 | − map_ptr = func[i]->aux->poke_tab[ret].tail_call.map; | |
| 12146 | − ret = map_ptr->ops->map_poke_track(map_ptr, func[i]->aux); | |
| 12147 | − if (ret < 0) { | |
| 12148 | − verbose(env, "tracking tail call prog failed\n"); | |
| 12149 | − goto out_free; | |
| 12150 | − } | |
| 12133 | + poke = &prog->aux->poke_tab[j]; | |
| 12134 | + if (poke->insn_idx < subprog_end && | |
| 12135 | + poke->insn_idx >= subprog_start) | |
| 12136 | + poke->aux = func[i]->aux; | |
| 12151 | 12137 | } |
| 12152 | 12138 | |
| 12153 | 12139 | /* Use bpf_prog_F_tag to indicate functions in stack traces. |
| @@ -12178,18 +12164,6 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 24 unmodified lines | ||
| 12178 | 12164 | cond_resched(); |
| 12179 | 12165 | } |
| 12180 | 12166 | |
| 12181 | − /* Untrack main program's aux structs so that during map_poke_run() | |
| 12182 | − * we will not stumble upon the unfilled poke descriptors; each | |
| 12183 | − * of the main program's poke descs got distributed across subprogs | |
| 12184 | − * and got tracked onto map, so we are sure that none of them will | |
| 12185 | − * be missed after the operation below | |
| 12186 | − */ | |
| 12187 | − for (i = 0; i < prog->aux->size_poke_tab; i++) { | |
| 12188 | − map_ptr = prog->aux->poke_tab[i].tail_call.map; | |
| 12189 | − | |
| 12190 | − map_ptr->ops->map_poke_untrack(map_ptr, prog->aux); | |
| 12191 | − } | |
| 12192 | − | |
| 12193 | 12167 | /* at this point all bpf functions were successfully JITed |
| 12194 | 12168 | * now populate all bpf_calls with correct addresses and |
| 12195 | 12169 | * run last pass of JIT |
| @@ -12267,14 +12241,22 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 71 unmodified lines | ||
| 12267 | 12241 | bpf_prog_jit_attempt_done(prog); |
| 12268 | 12242 | return 0; |
| 12269 | 12243 | out_free: |
| 12244 | + /* We failed JIT'ing, so at this point we need to unregister poke | |
| 12245 | + * descriptors from subprogs, so that kernel is not attempting to | |
| 12246 | + * patch it anymore as we're freeing the subprog JIT memory. | |
| 12247 | + */ | |
| 12248 | + for (i = 0; i < prog->aux->size_poke_tab; i++) { | |
| 12249 | + map_ptr = prog->aux->poke_tab[i].tail_call.map; | |
| 12250 | + map_ptr->ops->map_poke_untrack(map_ptr, prog->aux); | |
| 12251 | + } | |
| 12252 | + /* At this point we're guaranteed that poke descriptors are not | |
| 12253 | + * live anymore. We can just unlink its descriptor table as it's | |
| 12254 | + * released with the main prog. | |
| 12255 | + */ | |
| 12270 | 12256 | for (i = 0; i < env->subprog_cnt; i++) { |
| 12271 | 12257 | if (!func[i]) |
| 12272 | 12258 | continue; |
| 12273 | − | |
| 12274 | − for (j = 0; j < func[i]->aux->size_poke_tab; j++) { | |
| 12275 | − map_ptr = func[i]->aux->poke_tab[j].tail_call.map; | |
| 12276 | − map_ptr->ops->map_poke_untrack(map_ptr, func[i]->aux); | |
| 12277 | − } | |
| 12259 | + func[i]->aux->poke_tab = NULL; | |
| 12278 | 12260 | bpf_jit_free(func[i]); |
| 12279 | 12261 | } |
| 12280 | 12262 | kfree(func); |
| @@ -203,6 +203,19 @@ static void garp_attr_destroy(struct garp_applicant *app, struct garp_attr *attr · 202 unmodified lines | ||
| 203 | 203 | kfree(attr); |
| 204 | 204 | } |
| 205 | 205 | |
| 206 | +static void garp_attr_destroy_all(struct garp_applicant *app) | |
| 207 | +{ | |
| 208 | + struct rb_node *node, *next; | |
| 209 | + struct garp_attr *attr; | |
| 210 | + | |
| 211 | + for (node = rb_first(&app->gid); | |
| 212 | + next = node ? rb_next(node) : NULL, node != NULL; | |
| 213 | + node = next) { | |
| 214 | + attr = rb_entry(node, struct garp_attr, node); | |
| 215 | + garp_attr_destroy(app, attr); | |
| 216 | + } | |
| 217 | +} | |
| 218 | + | |
| 206 | 219 | static int garp_pdu_init(struct garp_applicant *app) |
| 207 | 220 | { |
| 208 | 221 | struct sk_buff *skb; |
| @@ -609,6 +622,7 @@ void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl · 400 unmodified lines | ||
| 609 | 622 | |
| 610 | 623 | spin_lock_bh(&app->lock); |
| 611 | 624 | garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); |
| 625 | + garp_attr_destroy_all(app); | |
| 612 | 626 | garp_pdu_queue(app); |
| 613 | 627 | spin_unlock_bh(&app->lock); |
| 614 | 628 | |
| @@ -292,6 +292,19 @@ static void mrp_attr_destroy(struct mrp_applicant *app, struct mrp_attr *attr) · 291 unmodified lines | ||
| 292 | 292 | kfree(attr); |
| 293 | 293 | } |
| 294 | 294 | |
| 295 | +static void mrp_attr_destroy_all(struct mrp_applicant *app) | |
| 296 | +{ | |
| 297 | + struct rb_node *node, *next; | |
| 298 | + struct mrp_attr *attr; | |
| 299 | + | |
| 300 | + for (node = rb_first(&app->mad); | |
| 301 | + next = node ? rb_next(node) : NULL, node != NULL; | |
| 302 | + node = next) { | |
| 303 | + attr = rb_entry(node, struct mrp_attr, node); | |
| 304 | + mrp_attr_destroy(app, attr); | |
| 305 | + } | |
| 306 | +} | |
| 307 | + | |
| 295 | 308 | static int mrp_pdu_init(struct mrp_applicant *app) |
| 296 | 309 | { |
| 297 | 310 | struct sk_buff *skb; |
| @@ -895,6 +908,7 @@ void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl) · 597 unmodified lines | ||
| 895 | 908 | |
| 896 | 909 | spin_lock_bh(&app->lock); |
| 897 | 910 | mrp_mad_event(app, MRP_EVENT_TX); |
| 911 | + mrp_attr_destroy_all(app); | |
| 898 | 912 | mrp_pdu_queue(app); |
| 899 | 913 | spin_unlock_bh(&app->lock); |
| 900 | 914 | |
| @@ -562,7 +562,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, · 561 unmodified lines | ||
| 562 | 562 | struct net_bridge_port *p; |
| 563 | 563 | int err = 0; |
| 564 | 564 | unsigned br_hr, dev_hr; |
| 565 | − bool changed_addr; | |
| 565 | + bool changed_addr, fdb_synced = false; | |
| 566 | 566 | |
| 567 | 567 | /* Don't allow bridging non-ethernet like devices. */ |
| 568 | 568 | if ((dev->flags & IFF_LOOPBACK) || |
| @@ -652,6 +652,19 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, · 83 unmodified lines | ||
| 652 | 652 | list_add_rcu(&p->list, &br->port_list); |
| 653 | 653 | |
| 654 | 654 | nbp_update_port_count(br); |
| 655 | + if (!br_promisc_port(p) && (p->dev->priv_flags & IFF_UNICAST_FLT)) { | |
| 656 | + /* When updating the port count we also update all ports' | |
| 657 | + * promiscuous mode. | |
| 658 | + * A port leaving promiscuous mode normally gets the bridge's | |
| 659 | + * fdb synced to the unicast filter (if supported), however, | |
| 660 | + * `br_port_clear_promisc` does not distinguish between | |
| 661 | + * non-promiscuous ports and *new* ports, so we need to | |
| 662 | + * sync explicitly here. | |
| 663 | + */ | |
| 664 | + fdb_synced = br_fdb_sync_static(br, p) == 0; | |
| 665 | + if (!fdb_synced) | |
| 666 | + netdev_err(dev, "failed to sync bridge static fdb addresses to this port\n"); | |
| 667 | + } | |
| 655 | 668 | |
| 656 | 669 | netdev_update_features(br->dev); |
| 657 | 670 | |
| @@ -701,6 +714,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, · 43 unmodified lines | ||
| 701 | 714 | return 0; |
| 702 | 715 | |
| 703 | 716 | err7: |
| 717 | + if (fdb_synced) | |
| 718 | + br_fdb_unsync_static(br, p); | |
| 704 | 719 | list_del_rcu(&p->list); |
| 705 | 720 | br_fdb_delete_by_port(br, p, 0, 1); |
| 706 | 721 | nbp_update_port_count(br); |
| @@ -3264,7 +3264,9 @@ static void br_multicast_pim(struct net_bridge *br, · 3263 unmodified lines | ||
| 3264 | 3264 | pim_hdr_type(pimhdr) != PIM_TYPE_HELLO) |
| 3265 | 3265 | return; |
| 3266 | 3266 | |
| 3267 | + spin_lock(&br->multicast_lock); | |
| 3267 | 3268 | br_ip4_multicast_mark_router(br, port); |
| 3269 | + spin_unlock(&br->multicast_lock); | |
| 3268 | 3270 | } |
| 3269 | 3271 | |
| 3270 | 3272 | static int br_ip4_multicast_mrd_rcv(struct net_bridge *br, |
| @@ -3275,7 +3277,9 @@ static int br_ip4_multicast_mrd_rcv(struct net_bridge *br, · 4 unmodified lines | ||
| 3275 | 3277 | igmp_hdr(skb)->type != IGMP_MRDISC_ADV) |
| 3276 | 3278 | return -ENOMSG; |
| 3277 | 3279 | |
| 3280 | + spin_lock(&br->multicast_lock); | |
| 3278 | 3281 | br_ip4_multicast_mark_router(br, port); |
| 3282 | + spin_unlock(&br->multicast_lock); | |
| 3279 | 3283 | |
| 3280 | 3284 | return 0; |
| 3281 | 3285 | } |
| @@ -3343,7 +3347,9 @@ static void br_ip6_multicast_mrd_rcv(struct net_bridge *br, · 61 unmodified lines | ||
| 3343 | 3347 | if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV) |
| 3344 | 3348 | return; |
| 3345 | 3349 | |
| 3350 | + spin_lock(&br->multicast_lock); | |
| 3346 | 3351 | br_ip6_multicast_mark_router(br, port); |
| 3352 | + spin_unlock(&br->multicast_lock); | |
| 3347 | 3353 | } |
| 3348 | 3354 | |
| 3349 | 3355 | static int br_multicast_ipv6_rcv(struct net_bridge *br, |
| @@ -6008,6 +6008,19 @@ static void gro_list_prepare(const struct list_head *head, · 6007 unmodified lines | ||
| 6008 | 6008 | diffs = memcmp(skb_mac_header(p), |
| 6009 | 6009 | skb_mac_header(skb), |
| 6010 | 6010 | maclen); |
| 6011 | + | |
| 6012 | + diffs |= skb_get_nfct(p) ^ skb_get_nfct(skb); | |
| 6013 | +#if IS_ENABLED(CONFIG_SKB_EXTENSIONS) && IS_ENABLED(CONFIG_NET_TC_SKB_EXT) | |
| 6014 | + if (!diffs) { | |
| 6015 | + struct tc_skb_ext *skb_ext = skb_ext_find(skb, TC_SKB_EXT); | |
| 6016 | + struct tc_skb_ext *p_ext = skb_ext_find(p, TC_SKB_EXT); | |
| 6017 | + | |
| 6018 | + diffs |= (!!p_ext) ^ (!!skb_ext); | |
| 6019 | + if (!diffs && unlikely(skb_ext)) | |
| 6020 | + diffs |= p_ext->chain ^ skb_ext->chain; | |
| 6021 | + } | |
| 6022 | +#endif | |
| 6023 | + | |
| 6011 | 6024 | NAPI_GRO_CB(p)->same_flow = !diffs; |
| 6012 | 6025 | } |
| 6013 | 6026 | } |
| @@ -6221,6 +6234,8 @@ static gro_result_t napi_skb_finish(struct napi_struct *napi, · 207 unmodified lines | ||
| 6221 | 6234 | case GRO_MERGED_FREE: |
| 6222 | 6235 | if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) |
| 6223 | 6236 | napi_skb_free_stolen_head(skb); |
| 6237 | + else if (skb->fclone != SKB_FCLONE_UNAVAILABLE) | |
| 6238 | + __kfree_skb(skb); | |
| 6224 | 6239 | else |
| 6225 | 6240 | __kfree_skb_defer(skb); |
| 6226 | 6241 | break; |
| @@ -6270,6 +6285,7 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) · 43 unmodified lines | ||
| 6270 | 6285 | skb_shinfo(skb)->gso_type = 0; |
| 6271 | 6286 | skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); |
| 6272 | 6287 | skb_ext_reset(skb); |
| 6288 | + nf_reset_ct(skb); | |
| 6273 | 6289 | |
| 6274 | 6290 | napi->skb = skb; |
| 6275 | 6291 | } |
| @@ -943,6 +943,7 @@ void __kfree_skb_defer(struct sk_buff *skb) · 942 unmodified lines | ||
| 943 | 943 | |
| 944 | 944 | void napi_skb_free_stolen_head(struct sk_buff *skb) |
| 945 | 945 | { |
| 946 | + nf_reset_ct(skb); | |
| 946 | 947 | skb_dst_drop(skb); |
| 947 | 948 | skb_ext_put(skb); |
| 948 | 949 | napi_skb_cache_put(skb); |
| @@ -139,6 +139,8 @@ · 138 unmodified lines | ||
| 139 | 139 | #include <net/tcp.h> |
| 140 | 140 | #include <net/busy_poll.h> |
| 141 | 141 | |
| 142 | +#include <linux/ethtool.h> | |
| 143 | + | |
| 142 | 144 | static DEFINE_MUTEX(proto_list_mutex); |
| 143 | 145 | static LIST_HEAD(proto_list); |
| 144 | 146 | |
| @@ -810,8 +812,47 @@ void sock_set_timestamp(struct sock *sk, int optname, bool valbool) · 665 unmodified lines | ||
| 810 | 812 | } |
| 811 | 813 | } |
| 812 | 814 | |
| 813 | −int sock_set_timestamping(struct sock *sk, int optname, int val) | |
| 815 | +static int sock_timestamping_bind_phc(struct sock *sk, int phc_index) | |
| 816 | +{ | |
| 817 | + struct net *net = sock_net(sk); | |
| 818 | + struct net_device *dev = NULL; | |
| 819 | + bool match = false; | |
| 820 | + int *vclock_index; | |
| 821 | + int i, num; | |
| 822 | + | |
| 823 | + if (sk->sk_bound_dev_if) | |
| 824 | + dev = dev_get_by_index(net, sk->sk_bound_dev_if); | |
| 825 | + | |
| 826 | + if (!dev) { | |
| 827 | + pr_err("%s: sock not bind to device\n", __func__); | |
| 828 | + return -EOPNOTSUPP; | |
| 829 | + } | |
| 830 | + | |
| 831 | + num = ethtool_get_phc_vclocks(dev, &vclock_index); | |
| 832 | + for (i = 0; i < num; i++) { | |
| 833 | + if (*(vclock_index + i) == phc_index) { | |
| 834 | + match = true; | |
| 835 | + break; | |
| 836 | + } | |
| 837 | + } | |
| 838 | + | |
| 839 | + if (num > 0) | |
| 840 | + kfree(vclock_index); | |
| 841 | + | |
| 842 | + if (!match) | |
| 843 | + return -EINVAL; | |
| 844 | + | |
| 845 | + sk->sk_bind_phc = phc_index; | |
| 846 | + | |
| 847 | + return 0; | |
| 848 | +} | |
| 849 | + | |
| 850 | +int sock_set_timestamping(struct sock *sk, int optname, | |
| 851 | + struct so_timestamping timestamping) | |
| 814 | 852 | { |
| 853 | + int val = timestamping.flags; | |
| 854 | + int ret; | |
| 855 | + | |
| 815 | 856 | if (val & ~SOF_TIMESTAMPING_MASK) |
| 816 | 857 | return -EINVAL; |
| 817 | 858 | |
| @@ -832,6 +873,12 @@ int sock_set_timestamping(struct sock *sk, int optname, int val) · 14 unmodified lines | ||
| 832 | 873 | !(val & SOF_TIMESTAMPING_OPT_TSONLY)) |
| 833 | 874 | return -EINVAL; |
| 834 | 875 | |
| 876 | + if (val & SOF_TIMESTAMPING_BIND_PHC) { | |
| 877 | + ret = sock_timestamping_bind_phc(sk, timestamping.bind_phc); | |
| 878 | + if (ret) | |
| 879 | + return ret; | |
| 880 | + } | |
| 881 | + | |
| 835 | 882 | sk->sk_tsflags = val; |
| 836 | 883 | sock_valbool_flag(sk, SOCK_TSTAMP_NEW, optname == SO_TIMESTAMPING_NEW); |
| 837 | 884 | |
| @@ -907,6 +954,7 @@ EXPORT_SYMBOL(sock_set_mark); · 69 unmodified lines | ||
| 907 | 954 | int sock_setsockopt(struct socket *sock, int level, int optname, |
| 908 | 955 | sockptr_t optval, unsigned int optlen) |
| 909 | 956 | { |
| 957 | + struct so_timestamping timestamping; | |
| 910 | 958 | struct sock_txtime sk_txtime; |
| 911 | 959 | struct sock *sk = sock->sk; |
| 912 | 960 | int val; |
| @@ -1068,12 +1116,22 @@ set_sndbuf: · 155 unmodified lines | ||
| 1068 | 1116 | case SO_TIMESTAMP_NEW: |
| 1069 | 1117 | case SO_TIMESTAMPNS_OLD: |
| 1070 | 1118 | case SO_TIMESTAMPNS_NEW: |
| 1071 | − sock_set_timestamp(sk, valbool, optname); | |
| 1119 | + sock_set_timestamp(sk, optname, valbool); | |
| 1072 | 1120 | break; |
| 1073 | 1121 | |
| 1074 | 1122 | case SO_TIMESTAMPING_NEW: |
| 1075 | 1123 | case SO_TIMESTAMPING_OLD: |
| 1076 | − ret = sock_set_timestamping(sk, optname, val); | |
| 1124 | + if (optlen == sizeof(timestamping)) { | |
| 1125 | + if (copy_from_sockptr(×tamping, optval, | |
| 1126 | + sizeof(timestamping))) { | |
| 1127 | + ret = -EFAULT; | |
| 1128 | + break; | |
| 1129 | + } | |
| 1130 | + } else { | |
| 1131 | + memset(×tamping, 0, sizeof(timestamping)); | |
| 1132 | + timestamping.flags = val; | |
| 1133 | + } | |
| 1134 | + ret = sock_set_timestamping(sk, optname, timestamping); | |
| 1077 | 1135 | break; |
| 1078 | 1136 | |
| 1079 | 1137 | case SO_RCVLOWAT: |
| @@ -1201,7 +1259,7 @@ set_sndbuf: · 121 unmodified lines | ||
| 1201 | 1259 | if (val < 0) |
| 1202 | 1260 | ret = -EINVAL; |
| 1203 | 1261 | else |
| 1204 | − sk->sk_ll_usec = val; | |
| 1262 | + WRITE_ONCE(sk->sk_ll_usec, val); | |
| 1205 | 1263 | } |
| 1206 | 1264 | break; |
| 1207 | 1265 | case SO_PREFER_BUSY_POLL: |
| @@ -1348,6 +1406,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 140 unmodified lines | ||
| 1348 | 1406 | struct __kernel_old_timeval tm; |
| 1349 | 1407 | struct __kernel_sock_timeval stm; |
| 1350 | 1408 | struct sock_txtime txtime; |
| 1409 | + struct so_timestamping timestamping; | |
| 1351 | 1410 | } v; |
| 1352 | 1411 | |
| 1353 | 1412 | int lv = sizeof(int); |
| @@ -1451,7 +1510,9 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 97 unmodified lines | ||
| 1451 | 1510 | break; |
| 1452 | 1511 | |
| 1453 | 1512 | case SO_TIMESTAMPING_OLD: |
| 1454 | − v.val = sk->sk_tsflags; | |
| 1513 | + lv = sizeof(v.timestamping); | |
| 1514 | + v.timestamping.flags = sk->sk_tsflags; | |
| 1515 | + v.timestamping.bind_phc = sk->sk_bind_phc; | |
| 1455 | 1516 | break; |
| 1456 | 1517 | |
| 1457 | 1518 | case SO_RCVTIMEO_OLD: |
| @@ -113,11 +113,11 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, · 112 unmodified lines | ||
| 113 | 113 | int err, port; |
| 114 | 114 | |
| 115 | 115 | if (dst->index == info->tree_index && ds->index == info->sw_index && |
| 116 | − ds->ops->port_bridge_join) | |
| 116 | + ds->ops->port_bridge_leave) | |
| 117 | 117 | ds->ops->port_bridge_leave(ds, info->port, info->br); |
| 118 | 118 | |
| 119 | 119 | if ((dst->index != info->tree_index || ds->index != info->sw_index) && |
| 120 | − ds->ops->crosschip_bridge_join) | |
| 120 | + ds->ops->crosschip_bridge_leave) | |
| 121 | 121 | ds->ops->crosschip_bridge_leave(ds, info->tree_index, |
| 122 | 122 | info->sw_index, info->port, |
| 123 | 123 | info->br); |
| @@ -427,7 +427,7 @@ static int dsa_switch_lag_join(struct dsa_switch *ds, · 303 unmodified lines | ||
| 427 | 427 | info->port, info->lag, |
| 428 | 428 | info->info); |
| 429 | 429 | |
| 430 | − return 0; | |
| 430 | + return -EOPNOTSUPP; | |
| 431 | 431 | } |
| 432 | 432 | |
| 433 | 433 | static int dsa_switch_lag_leave(struct dsa_switch *ds, |
| @@ -440,7 +440,7 @@ static int dsa_switch_lag_leave(struct dsa_switch *ds, · 6 unmodified lines | ||
| 440 | 440 | return ds->ops->crosschip_lag_leave(ds, info->sw_index, |
| 441 | 441 | info->port, info->lag); |
| 442 | 442 | |
| 443 | − return 0; | |
| 443 | + return -EOPNOTSUPP; | |
| 444 | 444 | } |
| 445 | 445 | |
| 446 | 446 | static int dsa_switch_mdb_add(struct dsa_switch *ds, |
| @@ -7,4 +7,4 @@ obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o · 6 unmodified lines | ||
| 7 | 7 | ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ |
| 8 | 8 | linkstate.o debug.o wol.o features.o privflags.o rings.o \ |
| 9 | 9 | channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ |
| 10 | − tunnels.o fec.o eeprom.o stats.o | |
| 10 | + tunnels.o fec.o eeprom.o stats.o phc_vclocks.o | |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | #include <linux/net_tstamp.h> |
| 5 | 5 | #include <linux/phy.h> |
| 6 | 6 | #include <linux/rtnetlink.h> |
| 7 | +#include <linux/ptp_clock_kernel.h> | |
| 7 | 8 | |
| 8 | 9 | #include "common.h" |
| 9 | 10 | |
| @@ -397,6 +398,7 @@ const char sof_timestamping_names[][ETH_GSTRING_LEN] = { · 387 unmodified lines | ||
| 397 | 398 | [const_ilog2(SOF_TIMESTAMPING_OPT_STATS)] = "option-stats", |
| 398 | 399 | [const_ilog2(SOF_TIMESTAMPING_OPT_PKTINFO)] = "option-pktinfo", |
| 399 | 400 | [const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw", |
| 401 | + [const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc", | |
| 400 | 402 | }; |
| 401 | 403 | static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT); |
| 402 | 404 | |
| @@ -554,6 +556,18 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) · 151 unmodified lines | ||
| 554 | 556 | return 0; |
| 555 | 557 | } |
| 556 | 558 | |
| 559 | +int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index) | |
| 560 | +{ | |
| 561 | + struct ethtool_ts_info info = { }; | |
| 562 | + int num = 0; | |
| 563 | + | |
| 564 | + if (!__ethtool_get_ts_info(dev, &info)) | |
| 565 | + num = ptp_get_vclocks_index(info.phc_index, vclock_index); | |
| 566 | + | |
| 567 | + return num; | |
| 568 | +} | |
| 569 | +EXPORT_SYMBOL(ethtool_get_phc_vclocks); | |
| 570 | + | |
| 557 | 571 | const struct ethtool_phy_ops *ethtool_phy_ops; |
| 558 | 572 | |
| 559 | 573 | void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops) |
| @@ -248,6 +248,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { · 247 unmodified lines | ||
| 248 | 248 | [ETHTOOL_MSG_TSINFO_GET] = ðnl_tsinfo_request_ops, |
| 249 | 249 | [ETHTOOL_MSG_MODULE_EEPROM_GET] = ðnl_module_eeprom_request_ops, |
| 250 | 250 | [ETHTOOL_MSG_STATS_GET] = ðnl_stats_request_ops, |
| 251 | + [ETHTOOL_MSG_PHC_VCLOCKS_GET] = ðnl_phc_vclocks_request_ops, | |
| 251 | 252 | }; |
| 252 | 253 | |
| 253 | 254 | static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) |
| @@ -958,6 +959,15 @@ static const struct genl_ops ethtool_genl_ops[] = { · 704 unmodified lines | ||
| 958 | 959 | .policy = ethnl_stats_get_policy, |
| 959 | 960 | .maxattr = ARRAY_SIZE(ethnl_stats_get_policy) - 1, |
| 960 | 961 | }, |
| 962 | + { | |
| 963 | + .cmd = ETHTOOL_MSG_PHC_VCLOCKS_GET, | |
| 964 | + .doit = ethnl_default_doit, | |
| 965 | + .start = ethnl_default_start, | |
| 966 | + .dumpit = ethnl_default_dumpit, | |
| 967 | + .done = ethnl_default_done, | |
| 968 | + .policy = ethnl_phc_vclocks_get_policy, | |
| 969 | + .maxattr = ARRAY_SIZE(ethnl_phc_vclocks_get_policy) - 1, | |
| 970 | + }, | |
| 961 | 971 | }; |
| 962 | 972 | |
| 963 | 973 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { |
| @@ -347,6 +347,7 @@ extern const struct ethnl_request_ops ethnl_tsinfo_request_ops; · 346 unmodified lines | ||
| 347 | 347 | extern const struct ethnl_request_ops ethnl_fec_request_ops; |
| 348 | 348 | extern const struct ethnl_request_ops ethnl_module_eeprom_request_ops; |
| 349 | 349 | extern const struct ethnl_request_ops ethnl_stats_request_ops; |
| 350 | +extern const struct ethnl_request_ops ethnl_phc_vclocks_request_ops; | |
| 350 | 351 | |
| 351 | 352 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; |
| 352 | 353 | extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; |
| @@ -382,6 +383,7 @@ extern const struct nla_policy ethnl_fec_get_policy[ETHTOOL_A_FEC_HEADER + 1]; · 29 unmodified lines | ||
| 382 | 383 | extern const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1]; |
| 383 | 384 | extern const struct nla_policy ethnl_module_eeprom_get_policy[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS + 1]; |
| 384 | 385 | extern const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1]; |
| 386 | +extern const struct nla_policy ethnl_phc_vclocks_get_policy[ETHTOOL_A_PHC_VCLOCKS_HEADER + 1]; | |
| 385 | 387 | |
| 386 | 388 | int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); |
| 387 | 389 | int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); |
| @@ -0,0 +1,94 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* | |
| 3 | + * Copyright 2021 NXP | |
| 4 | + */ | |
| 5 | +#include "netlink.h" | |
| 6 | +#include "common.h" | |
| 7 | + | |
| 8 | +struct phc_vclocks_req_info { | |
| 9 | + struct ethnl_req_info base; | |
| 10 | +}; | |
| 11 | + | |
| 12 | +struct phc_vclocks_reply_data { | |
| 13 | + struct ethnl_reply_data base; | |
| 14 | + int num; | |
| 15 | + int *index; | |
| 16 | +}; | |
| 17 | + | |
| 18 | +#define PHC_VCLOCKS_REPDATA(__reply_base) \ | |
| 19 | + container_of(__reply_base, struct phc_vclocks_reply_data, base) | |
| 20 | + | |
| 21 | +const struct nla_policy ethnl_phc_vclocks_get_policy[] = { | |
| 22 | + [ETHTOOL_A_PHC_VCLOCKS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), | |
| 23 | +}; | |
| 24 | + | |
| 25 | +static int phc_vclocks_prepare_data(const struct ethnl_req_info *req_base, | |
| 26 | + struct ethnl_reply_data *reply_base, | |
| 27 | + struct genl_info *info) | |
| 28 | +{ | |
| 29 | + struct phc_vclocks_reply_data *data = PHC_VCLOCKS_REPDATA(reply_base); | |
| 30 | + struct net_device *dev = reply_base->dev; | |
| 31 | + int ret; | |
| 32 | + | |
| 33 | + ret = ethnl_ops_begin(dev); | |
| 34 | + if (ret < 0) | |
| 35 | + return ret; | |
| 36 | + data->num = ethtool_get_phc_vclocks(dev, &data->index); | |
| 37 | + ethnl_ops_complete(dev); | |
| 38 | + | |
| 39 | + return ret; | |
| 40 | +} | |
| 41 | + | |
| 42 | +static int phc_vclocks_reply_size(const struct ethnl_req_info *req_base, | |
| 43 | + const struct ethnl_reply_data *reply_base) | |
| 44 | +{ | |
| 45 | + const struct phc_vclocks_reply_data *data = | |
| 46 | + PHC_VCLOCKS_REPDATA(reply_base); | |
| 47 | + int len = 0; | |
| 48 | + | |
| 49 | + if (data->num > 0) { | |
| 50 | + len += nla_total_size(sizeof(u32)); | |
| 51 | + len += nla_total_size(sizeof(s32) * data->num); | |
| 52 | + } | |
| 53 | + | |
| 54 | + return len; | |
| 55 | +} | |
| 56 | + | |
| 57 | +static int phc_vclocks_fill_reply(struct sk_buff *skb, | |
| 58 | + const struct ethnl_req_info *req_base, | |
| 59 | + const struct ethnl_reply_data *reply_base) | |
| 60 | +{ | |
| 61 | + const struct phc_vclocks_reply_data *data = | |
| 62 | + PHC_VCLOCKS_REPDATA(reply_base); | |
| 63 | + | |
| 64 | + if (data->num <= 0) | |
| 65 | + return 0; | |
| 66 | + | |
| 67 | + if (nla_put_u32(skb, ETHTOOL_A_PHC_VCLOCKS_NUM, data->num) || | |
| 68 | + nla_put(skb, ETHTOOL_A_PHC_VCLOCKS_INDEX, | |
| 69 | + sizeof(s32) * data->num, data->index)) | |
| 70 | + return -EMSGSIZE; | |
| 71 | + | |
| 72 | + return 0; | |
| 73 | +} | |
| 74 | + | |
| 75 | +static void phc_vclocks_cleanup_data(struct ethnl_reply_data *reply_base) | |
| 76 | +{ | |
| 77 | + const struct phc_vclocks_reply_data *data = | |
| 78 | + PHC_VCLOCKS_REPDATA(reply_base); | |
| 79 | + | |
| 80 | + kfree(data->index); | |
| 81 | +} | |
| 82 | + | |
| 83 | +const struct ethnl_request_ops ethnl_phc_vclocks_request_ops = { | |
| 84 | + .request_cmd = ETHTOOL_MSG_PHC_VCLOCKS_GET, | |
| 85 | + .reply_cmd = ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY, | |
| 86 | + .hdr_attr = ETHTOOL_A_PHC_VCLOCKS_HEADER, | |
| 87 | + .req_info_size = sizeof(struct phc_vclocks_req_info), | |
| 88 | + .reply_data_size = sizeof(struct phc_vclocks_reply_data), | |
| 89 | + | |
| 90 | + .prepare_data = phc_vclocks_prepare_data, | |
| 91 | + .reply_size = phc_vclocks_reply_size, | |
| 92 | + .fill_reply = phc_vclocks_fill_reply, | |
| 93 | + .cleanup_data = phc_vclocks_cleanup_data, | |
| 94 | +}; | |
| @@ -1376,7 +1376,7 @@ static void nl_fib_input(struct sk_buff *skb) · 1375 unmodified lines | ||
| 1376 | 1376 | portid = NETLINK_CB(skb).portid; /* netlink portid */ |
| 1377 | 1377 | NETLINK_CB(skb).portid = 0; /* from kernel */ |
| 1378 | 1378 | NETLINK_CB(skb).dst_group = 0; /* unicast */ |
| 1379 | − netlink_unicast(net->ipv4.fibnl, skb, portid, MSG_DONTWAIT); | |
| 1379 | + nlmsg_unicast(net->ipv4.fibnl, skb, portid); | |
| 1380 | 1380 | } |
| 1381 | 1381 | |
| 1382 | 1382 | static int __net_init nl_fib_lookup_init(struct net *net) |
| @@ -580,10 +580,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, · 579 unmodified lines | ||
| 580 | 580 | nlmsg_free(rep); |
| 581 | 581 | goto out; |
| 582 | 582 | } |
| 583 | − err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | |
| 584 | − MSG_DONTWAIT); | |
| 585 | − if (err > 0) | |
| 586 | − err = 0; | |
| 583 | + err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); | |
| 587 | 584 | |
| 588 | 585 | out: |
| 589 | 586 | if (sk) |
| @@ -317,7 +317,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev) · 316 unmodified lines | ||
| 317 | 317 | } |
| 318 | 318 | |
| 319 | 319 | dev->needed_headroom = t_hlen + hlen; |
| 320 | − mtu -= t_hlen; | |
| 320 | + mtu -= t_hlen + (dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0); | |
| 321 | 321 | |
| 322 | 322 | if (mtu < IPV4_MIN_MTU) |
| 323 | 323 | mtu = IPV4_MIN_MTU; |
| @@ -348,6 +348,9 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net, · 24 unmodified lines | ||
| 348 | 348 | t_hlen = nt->hlen + sizeof(struct iphdr); |
| 349 | 349 | dev->min_mtu = ETH_MIN_MTU; |
| 350 | 350 | dev->max_mtu = IP_MAX_MTU - t_hlen; |
| 351 | + if (dev->type == ARPHRD_ETHER) | |
| 352 | + dev->max_mtu -= dev->hard_header_len; | |
| 353 | + | |
| 351 | 354 | ip_tunnel_add(itn, nt); |
| 352 | 355 | return nt; |
| 353 | 356 | |
| @@ -489,11 +492,14 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, · 135 unmodified lines | ||
| 489 | 492 | |
| 490 | 493 | tunnel_hlen = md ? tunnel_hlen : tunnel->hlen; |
| 491 | 494 | pkt_size = skb->len - tunnel_hlen; |
| 495 | + pkt_size -= dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0; | |
| 492 | 496 | |
| 493 | − if (df) | |
| 497 | + if (df) { | |
| 494 | 498 | mtu = dst_mtu(&rt->dst) - (sizeof(struct iphdr) + tunnel_hlen); |
| 495 | − else | |
| 499 | + mtu -= dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0; | |
| 500 | + } else { | |
| 496 | 501 | mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; |
| 502 | + } | |
| 497 | 503 | |
| 498 | 504 | if (skb_valid_dst(skb)) |
| 499 | 505 | skb_dst_update_pmtu_no_confirm(skb, mtu); |
| @@ -972,6 +978,9 @@ int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict) · 472 unmodified lines | ||
| 972 | 978 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); |
| 973 | 979 | int max_mtu = IP_MAX_MTU - t_hlen; |
| 974 | 980 | |
| 981 | + if (dev->type == ARPHRD_ETHER) | |
| 982 | + max_mtu -= dev->hard_header_len; | |
| 983 | + | |
| 975 | 984 | if (new_mtu < ETH_MIN_MTU) |
| 976 | 985 | return -EINVAL; |
| 977 | 986 | |
| @@ -1149,6 +1158,9 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], · 171 unmodified lines | ||
| 1149 | 1158 | if (tb[IFLA_MTU]) { |
| 1150 | 1159 | unsigned int max = IP_MAX_MTU - (nt->hlen + sizeof(struct iphdr)); |
| 1151 | 1160 | |
| 1161 | + if (dev->type == ARPHRD_ETHER) | |
| 1162 | + max -= dev->hard_header_len; | |
| 1163 | + | |
| 1152 | 1164 | mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, max); |
| 1153 | 1165 | } |
| 1154 | 1166 | |
| @@ -2119,7 +2119,7 @@ int ip_mr_input(struct sk_buff *skb) · 2118 unmodified lines | ||
| 2119 | 2119 | raw_rcv(mroute_sk, skb); |
| 2120 | 2120 | return 0; |
| 2121 | 2121 | } |
| 2122 | − } | |
| 2122 | + } | |
| 2123 | 2123 | } |
| 2124 | 2124 | |
| 2125 | 2125 | /* already under rcu_read_lock() */ |
| @@ -119,11 +119,8 @@ static int raw_diag_dump_one(struct netlink_callback *cb, · 118 unmodified lines | ||
| 119 | 119 | return err; |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | − err = netlink_unicast(net->diag_nlsk, rep, | |
| 123 | − NETLINK_CB(in_skb).portid, | |
| 124 | − MSG_DONTWAIT); | |
| 125 | − if (err > 0) | |
| 126 | − err = 0; | |
| 122 | + err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); | |
| 123 | + | |
| 127 | 124 | return err; |
| 128 | 125 | } |
| 129 | 126 | |
| @@ -1375,6 +1375,9 @@ new_segment: · 1374 unmodified lines | ||
| 1375 | 1375 | } |
| 1376 | 1376 | pfrag->offset += copy; |
| 1377 | 1377 | } else { |
| 1378 | + if (!sk_wmem_schedule(sk, copy)) | |
| 1379 | + goto wait_for_space; | |
| 1380 | + | |
| 1378 | 1381 | err = skb_zerocopy_iter_stream(sk, skb, msg, copy, uarg); |
| 1379 | 1382 | if (err == -EMSGSIZE || err == -EEXIST) { |
| 1380 | 1383 | tcp_mark_push(tp, skb); |
| @@ -4247,6 +4247,9 @@ void tcp_reset(struct sock *sk, struct sk_buff *skb) · 4246 unmodified lines | ||
| 4247 | 4247 | { |
| 4248 | 4248 | trace_tcp_receive_reset(sk); |
| 4249 | 4249 | |
| 4250 | + /* mptcp can't tell us to ignore reset pkts, | |
| 4251 | + * so just ignore the return value of mptcp_incoming_options(). | |
| 4252 | + */ | |
| 4250 | 4253 | if (sk_is_mptcp(sk)) |
| 4251 | 4254 | mptcp_incoming_options(sk, skb); |
| 4252 | 4255 | |
| @@ -4941,8 +4944,13 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) · 688 unmodified lines | ||
| 4941 | 4944 | bool fragstolen; |
| 4942 | 4945 | int eaten; |
| 4943 | 4946 | |
| 4944 | − if (sk_is_mptcp(sk)) | |
| 4945 | − mptcp_incoming_options(sk, skb); | |
| 4947 | + /* If a subflow has been reset, the packet should not continue | |
| 4948 | + * to be processed, drop the packet. | |
| 4949 | + */ | |
| 4950 | + if (sk_is_mptcp(sk) && !mptcp_incoming_options(sk, skb)) { | |
| 4951 | + __kfree_skb(skb); | |
| 4952 | + return; | |
| 4953 | + } | |
| 4946 | 4954 | |
| 4947 | 4955 | if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { |
| 4948 | 4956 | __kfree_skb(skb); |
| @@ -5922,8 +5930,8 @@ void tcp_init_transfer(struct sock *sk, int bpf_op, struct sk_buff *skb) · 973 unmodified lines | ||
| 5922 | 5930 | tp->snd_cwnd = tcp_init_cwnd(tp, __sk_dst_get(sk)); |
| 5923 | 5931 | tp->snd_cwnd_stamp = tcp_jiffies32; |
| 5924 | 5932 | |
| 5925 | − icsk->icsk_ca_initialized = 0; | |
| 5926 | 5933 | bpf_skops_established(sk, bpf_op, skb); |
| 5934 | + /* Initialize congestion control unless BPF initialized it already: */ | |
| 5927 | 5935 | if (!icsk->icsk_ca_initialized) |
| 5928 | 5936 | tcp_init_congestion_control(sk); |
| 5929 | 5937 | tcp_init_buffer_space(sk); |
| @@ -6523,8 +6531,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) · 593 unmodified lines | ||
| 6523 | 6531 | case TCP_CLOSING: |
| 6524 | 6532 | case TCP_LAST_ACK: |
| 6525 | 6533 | if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { |
| 6526 | − if (sk_is_mptcp(sk)) | |
| 6527 | − mptcp_incoming_options(sk, skb); | |
| 6534 | + /* If a subflow has been reset, the packet should not | |
| 6535 | + * continue to be processed, drop the packet. | |
| 6536 | + */ | |
| 6537 | + if (sk_is_mptcp(sk) && !mptcp_incoming_options(sk, skb)) | |
| 6538 | + goto discard; | |
| 6528 | 6539 | break; |
| 6529 | 6540 | } |
| 6530 | 6541 | fallthrough; |
| @@ -342,7 +342,7 @@ void tcp_v4_mtu_reduced(struct sock *sk) · 341 unmodified lines | ||
| 342 | 342 | |
| 343 | 343 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) |
| 344 | 344 | return; |
| 345 | − mtu = tcp_sk(sk)->mtu_info; | |
| 345 | + mtu = READ_ONCE(tcp_sk(sk)->mtu_info); | |
| 346 | 346 | dst = inet_csk_update_pmtu(sk, mtu); |
| 347 | 347 | if (!dst) |
| 348 | 348 | return; |
| @@ -546,7 +546,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) · 197 unmodified lines | ||
| 546 | 546 | if (sk->sk_state == TCP_LISTEN) |
| 547 | 547 | goto out; |
| 548 | 548 | |
| 549 | − tp->mtu_info = info; | |
| 549 | + WRITE_ONCE(tp->mtu_info, info); | |
| 550 | 550 | if (!sock_owned_by_user(sk)) { |
| 551 | 551 | tcp_v4_mtu_reduced(sk); |
| 552 | 552 | } else { |
| @@ -1732,6 +1732,7 @@ int tcp_mtu_to_mss(struct sock *sk, int pmtu) · 1731 unmodified lines | ||
| 1732 | 1732 | return __tcp_mtu_to_mss(sk, pmtu) - |
| 1733 | 1733 | (tcp_sk(sk)->tcp_header_len - sizeof(struct tcphdr)); |
| 1734 | 1734 | } |
| 1735 | +EXPORT_SYMBOL(tcp_mtu_to_mss); | |
| 1735 | 1736 | |
| 1736 | 1737 | /* Inverse of above */ |
| 1737 | 1738 | int tcp_mss_to_mtu(struct sock *sk, int mss) |
| @@ -1102,7 +1102,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) · 1101 unmodified lines | ||
| 1102 | 1102 | } |
| 1103 | 1103 | |
| 1104 | 1104 | ipcm_init_sk(&ipc, inet); |
| 1105 | − ipc.gso_size = up->gso_size; | |
| 1105 | + ipc.gso_size = READ_ONCE(up->gso_size); | |
| 1106 | 1106 | |
| 1107 | 1107 | if (msg->msg_controllen) { |
| 1108 | 1108 | err = udp_cmsg_send(sk, msg, &ipc.gso_size); |
| @@ -2695,7 +2695,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, · 1586 unmodified lines | ||
| 2695 | 2695 | case UDP_SEGMENT: |
| 2696 | 2696 | if (val < 0 || val > USHRT_MAX) |
| 2697 | 2697 | return -EINVAL; |
| 2698 | − up->gso_size = val; | |
| 2698 | + WRITE_ONCE(up->gso_size, val); | |
| 2699 | 2699 | break; |
| 2700 | 2700 | |
| 2701 | 2701 | case UDP_GRO: |
| @@ -2790,7 +2790,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, · 88 unmodified lines | ||
| 2790 | 2790 | break; |
| 2791 | 2791 | |
| 2792 | 2792 | case UDP_SEGMENT: |
| 2793 | − val = up->gso_size; | |
| 2793 | + val = READ_ONCE(up->gso_size); | |
| 2794 | 2794 | break; |
| 2795 | 2795 | |
| 2796 | 2796 | case UDP_GRO: |
| @@ -77,10 +77,8 @@ static int udp_dump_one(struct udp_table *tbl, · 76 unmodified lines | ||
| 77 | 77 | kfree_skb(rep); |
| 78 | 78 | goto out; |
| 79 | 79 | } |
| 80 | − err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | |
| 81 | − MSG_DONTWAIT); | |
| 82 | − if (err > 0) | |
| 83 | − err = 0; | |
| 80 | + err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); | |
| 81 | + | |
| 84 | 82 | out: |
| 85 | 83 | if (sk) |
| 86 | 84 | sock_put(sk); |
| @@ -525,8 +525,10 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb, · 524 unmodified lines | ||
| 525 | 525 | |
| 526 | 526 | if ((!sk && (skb->dev->features & NETIF_F_GRO_UDP_FWD)) || |
| 527 | 527 | (sk && udp_sk(sk)->gro_enabled) || NAPI_GRO_CB(skb)->is_flist) |
| 528 | − pp = call_gro_receive(udp_gro_receive_segment, head, skb); | |
| 529 | − return pp; | |
| 528 | + return call_gro_receive(udp_gro_receive_segment, head, skb); | |
| 529 | + | |
| 530 | + /* no GRO, be sure flush the current packet */ | |
| 531 | + goto out; | |
| 530 | 532 | } |
| 531 | 533 | |
| 532 | 534 | if (NAPI_GRO_CB(skb)->encap_mark || |
| @@ -60,10 +60,38 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * · 59 unmodified lines | ||
| 60 | 60 | { |
| 61 | 61 | struct dst_entry *dst = skb_dst(skb); |
| 62 | 62 | struct net_device *dev = dst->dev; |
| 63 | + unsigned int hh_len = LL_RESERVED_SPACE(dev); | |
| 64 | + int delta = hh_len - skb_headroom(skb); | |
| 63 | 65 | const struct in6_addr *nexthop; |
| 64 | 66 | struct neighbour *neigh; |
| 65 | 67 | int ret; |
| 66 | 68 | |
| 69 | + /* Be paranoid, rather than too clever. */ | |
| 70 | + if (unlikely(delta > 0) && dev->header_ops) { | |
| 71 | + /* pskb_expand_head() might crash, if skb is shared */ | |
| 72 | + if (skb_shared(skb)) { | |
| 73 | + struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); | |
| 74 | + | |
| 75 | + if (likely(nskb)) { | |
| 76 | + if (skb->sk) | |
| 77 | + skb_set_owner_w(skb, skb->sk); | |
| 78 | + consume_skb(skb); | |
| 79 | + } else { | |
| 80 | + kfree_skb(skb); | |
| 81 | + } | |
| 82 | + skb = nskb; | |
| 83 | + } | |
| 84 | + if (skb && | |
| 85 | + pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { | |
| 86 | + kfree_skb(skb); | |
| 87 | + skb = NULL; | |
| 88 | + } | |
| 89 | + if (!skb) { | |
| 90 | + IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); | |
| 91 | + return -ENOMEM; | |
| 92 | + } | |
| 93 | + } | |
| 94 | + | |
| 67 | 95 | if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { |
| 68 | 96 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
| 69 | 97 | |
| @@ -479,7 +507,9 @@ int ip6_forward(struct sk_buff *skb) · 409 unmodified lines | ||
| 479 | 507 | if (skb_warn_if_lro(skb)) |
| 480 | 508 | goto drop; |
| 481 | 509 | |
| 482 | − if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | |
| 510 | + if (!net->ipv6.devconf_all->disable_policy && | |
| 511 | + !idev->cnf.disable_policy && | |
| 512 | + !xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | |
| 483 | 513 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); |
| 484 | 514 | goto drop; |
| 485 | 515 | } |
| @@ -348,11 +348,20 @@ failure: · 347 unmodified lines | ||
| 348 | 348 | static void tcp_v6_mtu_reduced(struct sock *sk) |
| 349 | 349 | { |
| 350 | 350 | struct dst_entry *dst; |
| 351 | + u32 mtu; | |
| 351 | 352 | |
| 352 | 353 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) |
| 353 | 354 | return; |
| 354 | 355 | |
| 355 | − dst = inet6_csk_update_pmtu(sk, tcp_sk(sk)->mtu_info); | |
| 356 | + mtu = READ_ONCE(tcp_sk(sk)->mtu_info); | |
| 357 | + | |
| 358 | + /* Drop requests trying to increase our current mss. | |
| 359 | + * Check done in __ip6_rt_update_pmtu() is too late. | |
| 360 | + */ | |
| 361 | + if (tcp_mtu_to_mss(sk, mtu) >= tcp_sk(sk)->mss_cache) | |
| 362 | + return; | |
| 363 | + | |
| 364 | + dst = inet6_csk_update_pmtu(sk, mtu); | |
| 356 | 365 | if (!dst) |
| 357 | 366 | return; |
| 358 | 367 | |
| @@ -433,6 +442,8 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, · 74 unmodified lines | ||
| 433 | 442 | } |
| 434 | 443 | |
| 435 | 444 | if (type == ICMPV6_PKT_TOOBIG) { |
| 445 | + u32 mtu = ntohl(info); | |
| 446 | + | |
| 436 | 447 | /* We are not interested in TCP_LISTEN and open_requests |
| 437 | 448 | * (SYN-ACKs send out by Linux are always <576bytes so |
| 438 | 449 | * they should go through unfragmented). |
| @@ -443,7 +454,11 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, · 4 unmodified lines | ||
| 443 | 454 | if (!ip6_sk_accept_pmtu(sk)) |
| 444 | 455 | goto out; |
| 445 | 456 | |
| 446 | − tp->mtu_info = ntohl(info); | |
| 457 | + if (mtu < IPV6_MIN_MTU) | |
| 458 | + goto out; | |
| 459 | + | |
| 460 | + WRITE_ONCE(tp->mtu_info, mtu); | |
| 461 | + | |
| 447 | 462 | if (!sock_owned_by_user(sk)) |
| 448 | 463 | tcp_v6_mtu_reduced(sk); |
| 449 | 464 | else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, |
| @@ -540,7 +555,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, · 90 unmodified lines | ||
| 540 | 555 | opt = ireq->ipv6_opt; |
| 541 | 556 | if (!opt) |
| 542 | 557 | opt = rcu_dereference(np->opt); |
| 543 | − err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, | |
| 558 | + err = ip6_xmit(sk, skb, fl6, skb->mark ? : sk->sk_mark, opt, | |
| 544 | 559 | tclass, sk->sk_priority); |
| 545 | 560 | rcu_read_unlock(); |
| 546 | 561 | err = net_xmit_eval(err); |
| @@ -1296,7 +1296,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) · 1295 unmodified lines | ||
| 1296 | 1296 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); |
| 1297 | 1297 | |
| 1298 | 1298 | ipcm6_init(&ipc6); |
| 1299 | − ipc6.gso_size = up->gso_size; | |
| 1299 | + ipc6.gso_size = READ_ONCE(up->gso_size); | |
| 1300 | 1300 | ipc6.sockc.tsflags = sk->sk_tsflags; |
| 1301 | 1301 | ipc6.sockc.mark = sk->sk_mark; |
| 1302 | 1302 | |
| @@ -49,7 +49,7 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) · 48 unmodified lines | ||
| 49 | 49 | { |
| 50 | 50 | struct dst_entry *dst = skb_dst(skb); |
| 51 | 51 | struct xfrm_state *x = dst->xfrm; |
| 52 | − int mtu; | |
| 52 | + unsigned int mtu; | |
| 53 | 53 | bool toobig; |
| 54 | 54 | |
| 55 | 55 | #ifdef CONFIG_NETFILTER |
| @@ -1635,14 +1635,16 @@ struct iucv_message_pending { · 1634 unmodified lines | ||
| 1635 | 1635 | u8 iptype; |
| 1636 | 1636 | u32 ipmsgid; |
| 1637 | 1637 | u32 iptrgcls; |
| 1638 | − union { | |
| 1639 | − u32 iprmmsg1_u32; | |
| 1640 | − u8 iprmmsg1[4]; | |
| 1641 | − } ln1msg1; | |
| 1642 | − union { | |
| 1643 | − u32 ipbfln1f; | |
| 1644 | − u8 iprmmsg2[4]; | |
| 1645 | − } ln1msg2; | |
| 1638 | + struct { | |
| 1639 | + union { | |
| 1640 | + u32 iprmmsg1_u32; | |
| 1641 | + u8 iprmmsg1[4]; | |
| 1642 | + } ln1msg1; | |
| 1643 | + union { | |
| 1644 | + u32 ipbfln1f; | |
| 1645 | + u8 iprmmsg2[4]; | |
| 1646 | + } ln1msg2; | |
| 1647 | + } rmmsg; | |
| 1646 | 1648 | u32 res1[3]; |
| 1647 | 1649 | u32 ipbfln2f; |
| 1648 | 1650 | u8 ippollfg; |
| @@ -1660,10 +1662,10 @@ static void iucv_message_pending(struct iucv_irq_data *data) · 11 unmodified lines | ||
| 1660 | 1662 | msg.id = imp->ipmsgid; |
| 1661 | 1663 | msg.class = imp->iptrgcls; |
| 1662 | 1664 | if (imp->ipflags1 & IUCV_IPRMDATA) { |
| 1663 | − memcpy(msg.rmmsg, imp->ln1msg1.iprmmsg1, 8); | |
| 1665 | + memcpy(msg.rmmsg, &imp->rmmsg, 8); | |
| 1664 | 1666 | msg.length = 8; |
| 1665 | 1667 | } else |
| 1666 | − msg.length = imp->ln1msg2.ipbfln1f; | |
| 1668 | + msg.length = imp->rmmsg.ln1msg2.ipbfln1f; | |
| 1667 | 1669 | msg.reply_size = imp->ipbfln2f; |
| 1668 | 1670 | path->handler->message_pending(path, &msg); |
| 1669 | 1671 | } |
| @@ -44,6 +44,7 @@ static const struct snmp_mib mptcp_snmp_list[] = { · 43 unmodified lines | ||
| 44 | 44 | SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW), |
| 45 | 45 | SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX), |
| 46 | 46 | SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX), |
| 47 | + SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED), | |
| 47 | 48 | SNMP_MIB_SENTINEL |
| 48 | 49 | }; |
| 49 | 50 | |
| @@ -37,6 +37,7 @@ enum linux_mptcp_mib_field { · 36 unmodified lines | ||
| 37 | 37 | MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */ |
| 38 | 38 | MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */ |
| 39 | 39 | MPTCP_MIB_MPPRIORX, /* Received a MP_PRIO */ |
| 40 | + MPTCP_MIB_RCVPRUNED, /* Incoming packet dropped due to memory limit */ | |
| 40 | 41 | __MPTCP_MIB_MAX |
| 41 | 42 | }; |
| 42 | 43 | |
| @@ -57,10 +57,8 @@ static int mptcp_diag_dump_one(struct netlink_callback *cb, · 56 unmodified lines | ||
| 57 | 57 | kfree_skb(rep); |
| 58 | 58 | goto out; |
| 59 | 59 | } |
| 60 | − err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | |
| 61 | − MSG_DONTWAIT); | |
| 62 | − if (err > 0) | |
| 63 | − err = 0; | |
| 60 | + err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); | |
| 61 | + | |
| 64 | 62 | out: |
| 65 | 63 | sock_put(sk); |
| 66 | 64 | |
| @@ -1035,7 +1035,8 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk, · 1034 unmodified lines | ||
| 1035 | 1035 | return hmac == mp_opt->ahmac; |
| 1036 | 1036 | } |
| 1037 | 1037 | |
| 1038 | −void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) | |
| 1038 | +/* Return false if a subflow has been reset, else return true */ | |
| 1039 | +bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) | |
| 1039 | 1040 | { |
| 1040 | 1041 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); |
| 1041 | 1042 | struct mptcp_sock *msk = mptcp_sk(subflow->conn); |
| @@ -1053,12 +1054,16 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) · 11 unmodified lines | ||
| 1053 | 1054 | __mptcp_check_push(subflow->conn, sk); |
| 1054 | 1055 | __mptcp_data_acked(subflow->conn); |
| 1055 | 1056 | mptcp_data_unlock(subflow->conn); |
| 1056 | − return; | |
| 1057 | + return true; | |
| 1057 | 1058 | } |
| 1058 | 1059 | |
| 1059 | 1060 | mptcp_get_options(sk, skb, &mp_opt); |
| 1061 | + | |
| 1062 | + /* The subflow can be in close state only if check_fully_established() | |
| 1063 | + * just sent a reset. If so, tell the caller to ignore the current packet. | |
| 1064 | + */ | |
| 1060 | 1065 | if (!check_fully_established(msk, sk, subflow, skb, &mp_opt)) |
| 1061 | − return; | |
| 1066 | + return sk->sk_state != TCP_CLOSE; | |
| 1062 | 1067 | |
| 1063 | 1068 | if (mp_opt.fastclose && |
| 1064 | 1069 | msk->local_key == mp_opt.rcvr_key) { |
| @@ -1100,7 +1105,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) · 35 unmodified lines | ||
| 1100 | 1105 | } |
| 1101 | 1106 | |
| 1102 | 1107 | if (!mp_opt.dss) |
| 1103 | − return; | |
| 1108 | + return true; | |
| 1104 | 1109 | |
| 1105 | 1110 | /* we can't wait for recvmsg() to update the ack_seq, otherwise |
| 1106 | 1111 | * monodirectional flows will stuck |
| @@ -1119,12 +1124,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) · 12 unmodified lines | ||
| 1119 | 1124 | schedule_work(&msk->work)) |
| 1120 | 1125 | sock_hold(subflow->conn); |
| 1121 | 1126 | |
| 1122 | − return; | |
| 1127 | + return true; | |
| 1123 | 1128 | } |
| 1124 | 1129 | |
| 1125 | 1130 | mpext = skb_ext_add(skb, SKB_EXT_MPTCP); |
| 1126 | 1131 | if (!mpext) |
| 1127 | − return; | |
| 1132 | + return true; | |
| 1128 | 1133 | |
| 1129 | 1134 | memset(mpext, 0, sizeof(*mpext)); |
| 1130 | 1135 | |
| @@ -1153,6 +1158,8 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) · 22 unmodified lines | ||
| 1153 | 1158 | if (mpext->csum_reqd) |
| 1154 | 1159 | mpext->csum = mp_opt.csum; |
| 1155 | 1160 | } |
| 1161 | + | |
| 1162 | + return true; | |
| 1156 | 1163 | } |
| 1157 | 1164 | |
| 1158 | 1165 | static void mptcp_set_rwin(const struct tcp_sock *tp) |
| @@ -474,7 +474,7 @@ static void mptcp_cleanup_rbuf(struct mptcp_sock *msk) · 473 unmodified lines | ||
| 474 | 474 | bool cleanup, rx_empty; |
| 475 | 475 | |
| 476 | 476 | cleanup = (space > 0) && (space >= (old_space << 1)); |
| 477 | − rx_empty = !atomic_read(&sk->sk_rmem_alloc); | |
| 477 | + rx_empty = !__mptcp_rmem(sk); | |
| 478 | 478 | |
| 479 | 479 | mptcp_for_each_subflow(msk, subflow) { |
| 480 | 480 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); |
| @@ -720,8 +720,10 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk) · 239 unmodified lines | ||
| 720 | 720 | sk_rbuf = ssk_rbuf; |
| 721 | 721 | |
| 722 | 722 | /* over limit? can't append more skbs to msk, Also, no need to wake-up*/ |
| 723 | − if (atomic_read(&sk->sk_rmem_alloc) > sk_rbuf) | |
| 723 | + if (__mptcp_rmem(sk) > sk_rbuf) { | |
| 724 | + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); | |
| 724 | 725 | return; |
| 726 | + } | |
| 725 | 727 | |
| 726 | 728 | /* Wake-up the reader only for in-sequence data */ |
| 727 | 729 | mptcp_data_lock(sk); |
| @@ -1754,7 +1756,7 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk, · 1026 unmodified lines | ||
| 1754 | 1756 | if (!(flags & MSG_PEEK)) { |
| 1755 | 1757 | /* we will bulk release the skb memory later */ |
| 1756 | 1758 | skb->destructor = NULL; |
| 1757 | − msk->rmem_released += skb->truesize; | |
| 1759 | + WRITE_ONCE(msk->rmem_released, msk->rmem_released + skb->truesize); | |
| 1758 | 1760 | __skb_unlink(skb, &msk->receive_queue); |
| 1759 | 1761 | __kfree_skb(skb); |
| 1760 | 1762 | } |
| @@ -1873,7 +1875,7 @@ static void __mptcp_update_rmem(struct sock *sk) · 112 unmodified lines | ||
| 1873 | 1875 | |
| 1874 | 1876 | atomic_sub(msk->rmem_released, &sk->sk_rmem_alloc); |
| 1875 | 1877 | sk_mem_uncharge(sk, msk->rmem_released); |
| 1876 | − msk->rmem_released = 0; | |
| 1878 | + WRITE_ONCE(msk->rmem_released, 0); | |
| 1877 | 1879 | } |
| 1878 | 1880 | |
| 1879 | 1881 | static void __mptcp_splice_receive_queue(struct sock *sk) |
| @@ -2380,7 +2382,7 @@ static int __mptcp_init_sock(struct sock *sk) · 500 unmodified lines | ||
| 2380 | 2382 | msk->out_of_order_queue = RB_ROOT; |
| 2381 | 2383 | msk->first_pending = NULL; |
| 2382 | 2384 | msk->wmem_reserved = 0; |
| 2383 | − msk->rmem_released = 0; | |
| 2385 | + WRITE_ONCE(msk->rmem_released, 0); | |
| 2384 | 2386 | msk->tx_pending_data = 0; |
| 2385 | 2387 | |
| 2386 | 2388 | msk->first = NULL; |
| @@ -296,9 +296,17 @@ static inline struct mptcp_sock *mptcp_sk(const struct sock *sk) · 295 unmodified lines | ||
| 296 | 296 | return (struct mptcp_sock *)sk; |
| 297 | 297 | } |
| 298 | 298 | |
| 299 | +/* the msk socket don't use the backlog, also account for the bulk | |
| 300 | + * free memory | |
| 301 | + */ | |
| 302 | +static inline int __mptcp_rmem(const struct sock *sk) | |
| 303 | +{ | |
| 304 | + return atomic_read(&sk->sk_rmem_alloc) - READ_ONCE(mptcp_sk(sk)->rmem_released); | |
| 305 | +} | |
| 306 | + | |
| 299 | 307 | static inline int __mptcp_space(const struct sock *sk) |
| 300 | 308 | { |
| 301 | − return tcp_space(sk) + READ_ONCE(mptcp_sk(sk)->rmem_released); | |
| 309 | + return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf) - __mptcp_rmem(sk)); | |
| 302 | 310 | } |
| 303 | 311 | |
| 304 | 312 | static inline struct mptcp_data_frag *mptcp_send_head(const struct sock *sk) |
| @@ -157,19 +157,7 @@ static int mptcp_setsockopt_sol_socket_tstamp(struct mptcp_sock *msk, int optnam · 156 unmodified lines | ||
| 157 | 157 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); |
| 158 | 158 | bool slow = lock_sock_fast(ssk); |
| 159 | 159 | |
| 160 | − switch (optname) { | |
| 161 | − case SO_TIMESTAMP_OLD: | |
| 162 | − case SO_TIMESTAMP_NEW: | |
| 163 | − case SO_TIMESTAMPNS_OLD: | |
| 164 | − case SO_TIMESTAMPNS_NEW: | |
| 165 | − sock_set_timestamp(sk, optname, !!val); | |
| 166 | − break; | |
| 167 | − case SO_TIMESTAMPING_NEW: | |
| 168 | − case SO_TIMESTAMPING_OLD: | |
| 169 | − sock_set_timestamping(sk, optname, val); | |
| 170 | − break; | |
| 171 | − } | |
| 172 | − | |
| 160 | + sock_set_timestamp(sk, optname, !!val); | |
| 173 | 161 | unlock_sock_fast(ssk, slow); |
| 174 | 162 | } |
| 175 | 163 | |
| @@ -178,7 +166,8 @@ static int mptcp_setsockopt_sol_socket_tstamp(struct mptcp_sock *msk, int optnam · 2 unmodified lines | ||
| 178 | 166 | } |
| 179 | 167 | |
| 180 | 168 | static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int optname, |
| 181 | − sockptr_t optval, unsigned int optlen) | |
| 169 | + sockptr_t optval, | |
| 170 | + unsigned int optlen) | |
| 182 | 171 | { |
| 183 | 172 | int val, ret; |
| 184 | 173 | |
| @@ -205,14 +194,56 @@ static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int optname, · 20 unmodified lines | ||
| 205 | 194 | case SO_TIMESTAMP_NEW: |
| 206 | 195 | case SO_TIMESTAMPNS_OLD: |
| 207 | 196 | case SO_TIMESTAMPNS_NEW: |
| 208 | − case SO_TIMESTAMPING_OLD: | |
| 209 | − case SO_TIMESTAMPING_NEW: | |
| 210 | 197 | return mptcp_setsockopt_sol_socket_tstamp(msk, optname, val); |
| 211 | 198 | } |
| 212 | 199 | |
| 213 | 200 | return -ENOPROTOOPT; |
| 214 | 201 | } |
| 215 | 202 | |
| 203 | +static int mptcp_setsockopt_sol_socket_timestamping(struct mptcp_sock *msk, | |
| 204 | + int optname, | |
| 205 | + sockptr_t optval, | |
| 206 | + unsigned int optlen) | |
| 207 | +{ | |
| 208 | + struct mptcp_subflow_context *subflow; | |
| 209 | + struct sock *sk = (struct sock *)msk; | |
| 210 | + struct so_timestamping timestamping; | |
| 211 | + int ret; | |
| 212 | + | |
| 213 | + if (optlen == sizeof(timestamping)) { | |
| 214 | + if (copy_from_sockptr(×tamping, optval, | |
| 215 | + sizeof(timestamping))) | |
| 216 | + return -EFAULT; | |
| 217 | + } else if (optlen == sizeof(int)) { | |
| 218 | + memset(×tamping, 0, sizeof(timestamping)); | |
| 219 | + | |
| 220 | + if (copy_from_sockptr(×tamping.flags, optval, sizeof(int))) | |
| 221 | + return -EFAULT; | |
| 222 | + } else { | |
| 223 | + return -EINVAL; | |
| 224 | + } | |
| 225 | + | |
| 226 | + ret = sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, | |
| 227 | + KERNEL_SOCKPTR(×tamping), | |
| 228 | + sizeof(timestamping)); | |
| 229 | + if (ret) | |
| 230 | + return ret; | |
| 231 | + | |
| 232 | + lock_sock(sk); | |
| 233 | + | |
| 234 | + mptcp_for_each_subflow(msk, subflow) { | |
| 235 | + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | |
| 236 | + bool slow = lock_sock_fast(ssk); | |
| 237 | + | |
| 238 | + sock_set_timestamping(sk, optname, timestamping); | |
| 239 | + unlock_sock_fast(ssk, slow); | |
| 240 | + } | |
| 241 | + | |
| 242 | + release_sock(sk); | |
| 243 | + | |
| 244 | + return 0; | |
| 245 | +} | |
| 246 | + | |
| 216 | 247 | static int mptcp_setsockopt_sol_socket_linger(struct mptcp_sock *msk, sockptr_t optval, |
| 217 | 248 | unsigned int optlen) |
| 218 | 249 | { |
| @@ -299,9 +330,12 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, · 80 unmodified lines | ||
| 299 | 330 | case SO_TIMESTAMP_NEW: |
| 300 | 331 | case SO_TIMESTAMPNS_OLD: |
| 301 | 332 | case SO_TIMESTAMPNS_NEW: |
| 333 | + return mptcp_setsockopt_sol_socket_int(msk, optname, optval, | |
| 334 | + optlen); | |
| 302 | 335 | case SO_TIMESTAMPING_OLD: |
| 303 | 336 | case SO_TIMESTAMPING_NEW: |
| 304 | − return mptcp_setsockopt_sol_socket_int(msk, optname, optval, optlen); | |
| 337 | + return mptcp_setsockopt_sol_socket_timestamping(msk, optname, | |
| 338 | + optval, optlen); | |
| 305 | 339 | case SO_LINGER: |
| 306 | 340 | return mptcp_setsockopt_sol_socket_linger(msk, optval, optlen); |
| 307 | 341 | case SO_RCVLOWAT: |
| @@ -214,11 +214,6 @@ again: · 213 unmodified lines | ||
| 214 | 214 | ntohs(inet_sk(sk_listener)->inet_sport), |
| 215 | 215 | ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport)); |
| 216 | 216 | if (!mptcp_pm_sport_in_anno_list(subflow_req->msk, sk_listener)) { |
| 217 | − sock_put((struct sock *)subflow_req->msk); | |
| 218 | − mptcp_token_destroy_request(req); | |
| 219 | − tcp_request_sock_ops.destructor(req); | |
| 220 | − subflow_req->msk = NULL; | |
| 221 | − subflow_req->mp_join = 0; | |
| 222 | 217 | SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX); |
| 223 | 218 | return -EPERM; |
| 224 | 219 | } |
| @@ -230,6 +225,8 @@ again: · 5 unmodified lines | ||
| 230 | 225 | if (unlikely(req->syncookie)) { |
| 231 | 226 | if (mptcp_can_accept_new_subflow(subflow_req->msk)) |
| 232 | 227 | subflow_init_req_cookie_join_save(subflow_req, skb); |
| 228 | + else | |
| 229 | + return -EPERM; | |
| 233 | 230 | } |
| 234 | 231 | |
| 235 | 232 | pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token, |
| @@ -269,9 +266,7 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req, · 33 unmodified lines | ||
| 269 | 266 | if (!mptcp_token_join_cookie_init_state(subflow_req, skb)) |
| 270 | 267 | return -EINVAL; |
| 271 | 268 | |
| 272 | − if (mptcp_can_accept_new_subflow(subflow_req->msk)) | |
| 273 | − subflow_req->mp_join = 1; | |
| 274 | − | |
| 269 | + subflow_req->mp_join = 1; | |
| 275 | 270 | subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq - 1; |
| 276 | 271 | } |
| 277 | 272 | |
| @@ -37,7 +37,21 @@ static spinlock_t join_entry_locks[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | static u32 mptcp_join_entry_hash(struct sk_buff *skb, struct net *net) |
| 39 | 39 | { |
| 40 | − u32 i = skb_get_hash(skb) ^ net_hash_mix(net); | |
| 40 | + static u32 mptcp_join_hash_secret __read_mostly; | |
| 41 | + struct tcphdr *th = tcp_hdr(skb); | |
| 42 | + u32 seq, i; | |
| 43 | + | |
| 44 | + net_get_random_once(&mptcp_join_hash_secret, | |
| 45 | + sizeof(mptcp_join_hash_secret)); | |
| 46 | + | |
| 47 | + if (th->syn) | |
| 48 | + seq = TCP_SKB_CB(skb)->seq; | |
| 49 | + else | |
| 50 | + seq = TCP_SKB_CB(skb)->seq - 1; | |
| 51 | + | |
| 52 | + i = jhash_3words(seq, net_hash_mix(net), | |
| 53 | + (__force __u32)th->source << 16 | (__force __u32)th->dest, | |
| 54 | + mptcp_join_hash_secret); | |
| 41 | 55 | |
| 42 | 56 | return i % ARRAY_SIZE(join_entries); |
| 43 | 57 | } |
| @@ -17,3 +17,9 @@ config NCSI_OEM_CMD_GET_MAC · 16 unmodified lines | ||
| 17 | 17 | help |
| 18 | 18 | This allows to get MAC address from NCSI firmware and set them back to |
| 19 | 19 | controller. |
| 20 | +config NCSI_OEM_CMD_KEEP_PHY | |
| 21 | + bool "Keep PHY Link up" | |
| 22 | + depends on NET_NCSI | |
| 23 | + help | |
| 24 | + This allows to keep PHY link up and prevents any channel resets during | |
| 25 | + the host load. | |
| @@ -78,6 +78,9 @@ enum { · 77 unmodified lines | ||
| 78 | 78 | /* OEM Vendor Manufacture ID */ |
| 79 | 79 | #define NCSI_OEM_MFR_MLX_ID 0x8119 |
| 80 | 80 | #define NCSI_OEM_MFR_BCM_ID 0x113d |
| 81 | +#define NCSI_OEM_MFR_INTEL_ID 0x157 | |
| 82 | +/* Intel specific OEM command */ | |
| 83 | +#define NCSI_OEM_INTEL_CMD_KEEP_PHY 0x20 /* CMD ID for Keep PHY up */ | |
| 81 | 84 | /* Broadcom specific OEM Command */ |
| 82 | 85 | #define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */ |
| 83 | 86 | /* Mellanox specific OEM Command */ |
| @@ -86,6 +89,7 @@ enum { · 2 unmodified lines | ||
| 86 | 89 | #define NCSI_OEM_MLX_CMD_SMAF 0x01 /* CMD ID for Set MC Affinity */ |
| 87 | 90 | #define NCSI_OEM_MLX_CMD_SMAF_PARAM 0x07 /* Parameter for SMAF */ |
| 88 | 91 | /* OEM Command payload lengths*/ |
| 92 | +#define NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN 7 | |
| 89 | 93 | #define NCSI_OEM_BCM_CMD_GMA_LEN 12 |
| 90 | 94 | #define NCSI_OEM_MLX_CMD_GMA_LEN 8 |
| 91 | 95 | #define NCSI_OEM_MLX_CMD_SMAF_LEN 60 |
| @@ -271,6 +275,7 @@ enum { · 179 unmodified lines | ||
| 271 | 275 | ncsi_dev_state_probe_mlx_gma, |
| 272 | 276 | ncsi_dev_state_probe_mlx_smaf, |
| 273 | 277 | ncsi_dev_state_probe_cis, |
| 278 | + ncsi_dev_state_probe_keep_phy, | |
| 274 | 279 | ncsi_dev_state_probe_gvi, |
| 275 | 280 | ncsi_dev_state_probe_gc, |
| 276 | 281 | ncsi_dev_state_probe_gls, |
| @@ -689,6 +689,35 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, · 688 unmodified lines | ||
| 689 | 689 | return 0; |
| 690 | 690 | } |
| 691 | 691 | |
| 692 | +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) | |
| 693 | + | |
| 694 | +static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) | |
| 695 | +{ | |
| 696 | + unsigned char data[NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN]; | |
| 697 | + int ret = 0; | |
| 698 | + | |
| 699 | + nca->payload = NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN; | |
| 700 | + | |
| 701 | + memset(data, 0, NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN); | |
| 702 | + *(unsigned int *)data = ntohl((__force __be32)NCSI_OEM_MFR_INTEL_ID); | |
| 703 | + | |
| 704 | + data[4] = NCSI_OEM_INTEL_CMD_KEEP_PHY; | |
| 705 | + | |
| 706 | + /* PHY Link up attribute */ | |
| 707 | + data[6] = 0x1; | |
| 708 | + | |
| 709 | + nca->data = data; | |
| 710 | + | |
| 711 | + ret = ncsi_xmit_cmd(nca); | |
| 712 | + if (ret) | |
| 713 | + netdev_err(nca->ndp->ndev.dev, | |
| 714 | + "NCSI: Failed to transmit cmd 0x%x during configure\n", | |
| 715 | + nca->type); | |
| 716 | + return ret; | |
| 717 | +} | |
| 718 | + | |
| 719 | +#endif | |
| 720 | + | |
| 692 | 721 | #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) |
| 693 | 722 | |
| 694 | 723 | /* NCSI OEM Command APIs */ |
| @@ -700,7 +729,7 @@ static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca) · 5 unmodified lines | ||
| 700 | 729 | nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN; |
| 701 | 730 | |
| 702 | 731 | memset(data, 0, NCSI_OEM_BCM_CMD_GMA_LEN); |
| 703 | − *(unsigned int *)data = ntohl(NCSI_OEM_MFR_BCM_ID); | |
| 732 | + *(unsigned int *)data = ntohl((__force __be32)NCSI_OEM_MFR_BCM_ID); | |
| 704 | 733 | data[5] = NCSI_OEM_BCM_CMD_GMA; |
| 705 | 734 | |
| 706 | 735 | nca->data = data; |
| @@ -724,7 +753,7 @@ static int ncsi_oem_gma_handler_mlx(struct ncsi_cmd_arg *nca) · 17 unmodified lines | ||
| 724 | 753 | nca->payload = NCSI_OEM_MLX_CMD_GMA_LEN; |
| 725 | 754 | |
| 726 | 755 | memset(&u, 0, sizeof(u)); |
| 727 | − u.data_u32[0] = ntohl(NCSI_OEM_MFR_MLX_ID); | |
| 756 | + u.data_u32[0] = ntohl((__force __be32)NCSI_OEM_MFR_MLX_ID); | |
| 728 | 757 | u.data_u8[5] = NCSI_OEM_MLX_CMD_GMA; |
| 729 | 758 | u.data_u8[6] = NCSI_OEM_MLX_CMD_GMA_PARAM; |
| 730 | 759 | |
| @@ -747,7 +776,7 @@ static int ncsi_oem_smaf_mlx(struct ncsi_cmd_arg *nca) · 16 unmodified lines | ||
| 747 | 776 | int ret = 0; |
| 748 | 777 | |
| 749 | 778 | memset(&u, 0, sizeof(u)); |
| 750 | − u.data_u32[0] = ntohl(NCSI_OEM_MFR_MLX_ID); | |
| 779 | + u.data_u32[0] = ntohl((__force __be32)NCSI_OEM_MFR_MLX_ID); | |
| 751 | 780 | u.data_u8[5] = NCSI_OEM_MLX_CMD_SMAF; |
| 752 | 781 | u.data_u8[6] = NCSI_OEM_MLX_CMD_SMAF_PARAM; |
| 753 | 782 | memcpy(&u.data_u8[MLX_SMAF_MAC_ADDR_OFFSET], |
| @@ -1391,8 +1420,24 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) · 637 unmodified lines | ||
| 1391 | 1420 | goto error; |
| 1392 | 1421 | } |
| 1393 | 1422 | |
| 1423 | + nd->state = ncsi_dev_state_probe_gvi; | |
| 1424 | + if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)) | |
| 1425 | + nd->state = ncsi_dev_state_probe_keep_phy; | |
| 1426 | + break; | |
| 1427 | +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) | |
| 1428 | + case ncsi_dev_state_probe_keep_phy: | |
| 1429 | + ndp->pending_req_num = 1; | |
| 1430 | + | |
| 1431 | + nca.type = NCSI_PKT_CMD_OEM; | |
| 1432 | + nca.package = ndp->active_package->id; | |
| 1433 | + nca.channel = 0; | |
| 1434 | + ret = ncsi_oem_keep_phy_intel(&nca); | |
| 1435 | + if (ret) | |
| 1436 | + goto error; | |
| 1437 | + | |
| 1394 | 1438 | nd->state = ncsi_dev_state_probe_gvi; |
| 1395 | 1439 | break; |
| 1440 | +#endif /* CONFIG_NCSI_OEM_CMD_KEEP_PHY */ | |
| 1396 | 1441 | case ncsi_dev_state_probe_gvi: |
| 1397 | 1442 | case ncsi_dev_state_probe_gc: |
| 1398 | 1443 | case ncsi_dev_state_probe_gls: |
| @@ -403,7 +403,7 @@ static int ncsi_rsp_handler_ev(struct ncsi_request *nr) · 402 unmodified lines | ||
| 403 | 403 | /* Update to VLAN mode */ |
| 404 | 404 | cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd); |
| 405 | 405 | ncm->enable = 1; |
| 406 | − ncm->data[0] = ntohl(cmd->mode); | |
| 406 | + ncm->data[0] = ntohl((__force __be32)cmd->mode); | |
| 407 | 407 | |
| 408 | 408 | return 0; |
| 409 | 409 | } |
| @@ -699,12 +699,19 @@ static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr) · 289 unmodified lines | ||
| 699 | 699 | return 0; |
| 700 | 700 | } |
| 701 | 701 | |
| 702 | +/* Response handler for Intel card */ | |
| 703 | +static int ncsi_rsp_handler_oem_intel(struct ncsi_request *nr) | |
| 704 | +{ | |
| 705 | + return 0; | |
| 706 | +} | |
| 707 | + | |
| 702 | 708 | static struct ncsi_rsp_oem_handler { |
| 703 | 709 | unsigned int mfr_id; |
| 704 | 710 | int (*handler)(struct ncsi_request *nr); |
| 705 | 711 | } ncsi_rsp_oem_handlers[] = { |
| 706 | 712 | { NCSI_OEM_MFR_MLX_ID, ncsi_rsp_handler_oem_mlx }, |
| 707 | − { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm } | |
| 713 | + { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm }, | |
| 714 | + { NCSI_OEM_MFR_INTEL_ID, ncsi_rsp_handler_oem_intel } | |
| 708 | 715 | }; |
| 709 | 716 | |
| 710 | 717 | /* Response handler for OEM command */ |
| @@ -149,7 +149,15 @@ static void nf_conntrack_all_lock(void) · 148 unmodified lines | ||
| 149 | 149 | |
| 150 | 150 | spin_lock(&nf_conntrack_locks_all_lock); |
| 151 | 151 | |
| 152 | − nf_conntrack_locks_all = true; | |
| 152 | + /* For nf_contrack_locks_all, only the latest time when another | |
| 153 | + * CPU will see an update is controlled, by the "release" of the | |
| 154 | + * spin_lock below. | |
| 155 | + * The earliest time is not controlled, an thus KCSAN could detect | |
| 156 | + * a race when nf_conntract_lock() reads the variable. | |
| 157 | + * WRITE_ONCE() is used to ensure the compiler will not | |
| 158 | + * optimize the write. | |
| 159 | + */ | |
| 160 | + WRITE_ONCE(nf_conntrack_locks_all, true); | |
| 153 | 161 | |
| 154 | 162 | for (i = 0; i < CONNTRACK_LOCKS; i++) { |
| 155 | 163 | spin_lock(&nf_conntrack_locks[i]); |
| @@ -2457,7 +2465,6 @@ i_see_dead_people: · 2301 unmodified lines | ||
| 2457 | 2465 | } |
| 2458 | 2466 | |
| 2459 | 2467 | list_for_each_entry(net, net_exit_list, exit_list) { |
| 2460 | − nf_conntrack_proto_pernet_fini(net); | |
| 2461 | 2468 | nf_conntrack_ecache_pernet_fini(net); |
| 2462 | 2469 | nf_conntrack_expect_pernet_fini(net); |
| 2463 | 2470 | free_percpu(net->ct.stat); |
| @@ -218,6 +218,7 @@ static int ctnetlink_dump_helpinfo(struct sk_buff *skb, · 217 unmodified lines | ||
| 218 | 218 | if (!help) |
| 219 | 219 | return 0; |
| 220 | 220 | |
| 221 | + rcu_read_lock(); | |
| 221 | 222 | helper = rcu_dereference(help->helper); |
| 222 | 223 | if (!helper) |
| 223 | 224 | goto out; |
| @@ -233,9 +234,11 @@ static int ctnetlink_dump_helpinfo(struct sk_buff *skb, · 9 unmodified lines | ||
| 233 | 234 | |
| 234 | 235 | nla_nest_end(skb, nest_helper); |
| 235 | 236 | out: |
| 237 | + rcu_read_unlock(); | |
| 236 | 238 | return 0; |
| 237 | 239 | |
| 238 | 240 | nla_put_failure: |
| 241 | + rcu_read_unlock(); | |
| 239 | 242 | return -1; |
| 240 | 243 | } |
| 241 | 244 | |
| @@ -697,13 +697,6 @@ void nf_conntrack_proto_pernet_init(struct net *net) · 696 unmodified lines | ||
| 697 | 697 | #endif |
| 698 | 698 | } |
| 699 | 699 | |
| 700 | −void nf_conntrack_proto_pernet_fini(struct net *net) | |
| 701 | −{ | |
| 702 | −#ifdef CONFIG_NF_CT_PROTO_GRE | |
| 703 | − nf_ct_gre_keymap_flush(net); | |
| 704 | −#endif | |
| 705 | −} | |
| 706 | − | |
| 707 | 700 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, |
| 708 | 701 | &nf_conntrack_htable_size, 0600); |
| 709 | 702 | |
| @@ -55,19 +55,6 @@ static inline struct nf_gre_net *gre_pernet(struct net *net) · 54 unmodified lines | ||
| 55 | 55 | return &net->ct.nf_ct_proto.gre; |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | −void nf_ct_gre_keymap_flush(struct net *net) | |
| 59 | −{ | |
| 60 | − struct nf_gre_net *net_gre = gre_pernet(net); | |
| 61 | − struct nf_ct_gre_keymap *km, *tmp; | |
| 62 | − | |
| 63 | − spin_lock_bh(&keymap_lock); | |
| 64 | − list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) { | |
| 65 | − list_del_rcu(&km->list); | |
| 66 | − kfree_rcu(km, rcu); | |
| 67 | − } | |
| 68 | − spin_unlock_bh(&keymap_lock); | |
| 69 | −} | |
| 70 | − | |
| 71 | 58 | static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, |
| 72 | 59 | const struct nf_conntrack_tuple *t) |
| 73 | 60 | { |
| @@ -823,6 +823,22 @@ static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, · 822 unmodified lines | ||
| 823 | 823 | return true; |
| 824 | 824 | } |
| 825 | 825 | |
| 826 | +static bool tcp_can_early_drop(const struct nf_conn *ct) | |
| 827 | +{ | |
| 828 | + switch (ct->proto.tcp.state) { | |
| 829 | + case TCP_CONNTRACK_FIN_WAIT: | |
| 830 | + case TCP_CONNTRACK_LAST_ACK: | |
| 831 | + case TCP_CONNTRACK_TIME_WAIT: | |
| 832 | + case TCP_CONNTRACK_CLOSE: | |
| 833 | + case TCP_CONNTRACK_CLOSE_WAIT: | |
| 834 | + return true; | |
| 835 | + default: | |
| 836 | + break; | |
| 837 | + } | |
| 838 | + | |
| 839 | + return false; | |
| 840 | +} | |
| 841 | + | |
| 826 | 842 | /* Returns verdict for packet, or -1 for invalid. */ |
| 827 | 843 | int nf_conntrack_tcp_packet(struct nf_conn *ct, |
| 828 | 844 | struct sk_buff *skb, |
| @@ -1030,10 +1046,30 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, · 201 unmodified lines | ||
| 1030 | 1046 | if (index != TCP_RST_SET) |
| 1031 | 1047 | break; |
| 1032 | 1048 | |
| 1033 | − if (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) { | |
| 1049 | + /* If we are closing, tuple might have been re-used already. | |
| 1050 | + * last_index, last_ack, and all other ct fields used for | |
| 1051 | + * sequence/window validation are outdated in that case. | |
| 1052 | + * | |
| 1053 | + * As the conntrack can already be expired by GC under pressure, | |
| 1054 | + * just skip validation checks. | |
| 1055 | + */ | |
| 1056 | + if (tcp_can_early_drop(ct)) | |
| 1057 | + goto in_window; | |
| 1058 | + | |
| 1059 | + /* td_maxack might be outdated if we let a SYN through earlier */ | |
| 1060 | + if ((ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) && | |
| 1061 | + ct->proto.tcp.last_index != TCP_SYN_SET) { | |
| 1034 | 1062 | u32 seq = ntohl(th->seq); |
| 1035 | 1063 | |
| 1036 | − if (before(seq, ct->proto.tcp.seen[!dir].td_maxack)) { | |
| 1064 | + /* If we are not in established state and SEQ=0 this is most | |
| 1065 | + * likely an answer to a SYN we let go through above (last_index | |
| 1066 | + * can be updated due to out-of-order ACKs). | |
| 1067 | + */ | |
| 1068 | + if (seq == 0 && !nf_conntrack_tcp_established(ct)) | |
| 1069 | + break; | |
| 1070 | + | |
| 1071 | + if (before(seq, ct->proto.tcp.seen[!dir].td_maxack) && | |
| 1072 | + !tn->tcp_ignore_invalid_rst) { | |
| 1037 | 1073 | /* Invalid RST */ |
| 1038 | 1074 | spin_unlock_bh(&ct->lock); |
| 1039 | 1075 | nf_ct_l4proto_log_invalid(skb, ct, state, "invalid rst"); |
| @@ -1134,6 +1170,16 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, · 94 unmodified lines | ||
| 1134 | 1170 | nf_ct_kill_acct(ct, ctinfo, skb); |
| 1135 | 1171 | return NF_ACCEPT; |
| 1136 | 1172 | } |
| 1173 | + | |
| 1174 | + if (index == TCP_SYN_SET && old_state == TCP_CONNTRACK_SYN_SENT) { | |
| 1175 | + /* do not renew timeout on SYN retransmit. | |
| 1176 | + * | |
| 1177 | + * Else port reuse by client or NAT middlebox can keep | |
| 1178 | + * entry alive indefinitely (including nat info). | |
| 1179 | + */ | |
| 1180 | + return NF_ACCEPT; | |
| 1181 | + } | |
| 1182 | + | |
| 1137 | 1183 | /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection |
| 1138 | 1184 | * pickup with loose=1. Avoid large ESTABLISHED timeout. |
| 1139 | 1185 | */ |
| @@ -1155,22 +1201,6 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, · 15 unmodified lines | ||
| 1155 | 1201 | return NF_ACCEPT; |
| 1156 | 1202 | } |
| 1157 | 1203 | |
| 1158 | −static bool tcp_can_early_drop(const struct nf_conn *ct) | |
| 1159 | −{ | |
| 1160 | − switch (ct->proto.tcp.state) { | |
| 1161 | − case TCP_CONNTRACK_FIN_WAIT: | |
| 1162 | − case TCP_CONNTRACK_LAST_ACK: | |
| 1163 | − case TCP_CONNTRACK_TIME_WAIT: | |
| 1164 | − case TCP_CONNTRACK_CLOSE: | |
| 1165 | − case TCP_CONNTRACK_CLOSE_WAIT: | |
| 1166 | − return true; | |
| 1167 | − default: | |
| 1168 | − break; | |
| 1169 | − } | |
| 1170 | − | |
| 1171 | − return false; | |
| 1172 | −} | |
| 1173 | − | |
| 1174 | 1204 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 1175 | 1205 | |
| 1176 | 1206 | #include <linux/netfilter/nfnetlink.h> |
| @@ -1437,6 +1467,9 @@ void nf_conntrack_tcp_init_net(struct net *net) · 260 unmodified lines | ||
| 1437 | 1467 | */ |
| 1438 | 1468 | tn->tcp_be_liberal = 0; |
| 1439 | 1469 | |
| 1470 | + /* If it's non-zero, we turn off RST sequence number check */ | |
| 1471 | + tn->tcp_ignore_invalid_rst = 0; | |
| 1472 | + | |
| 1440 | 1473 | /* Max number of the retransmitted packets without receiving an (acceptable) |
| 1441 | 1474 | * ACK from the destination. If this number is reached, a shorter timer |
| 1442 | 1475 | * will be started. |
| @@ -579,6 +579,7 @@ enum nf_ct_sysctl_index { · 578 unmodified lines | ||
| 579 | 579 | #endif |
| 580 | 580 | NF_SYSCTL_CT_PROTO_TCP_LOOSE, |
| 581 | 581 | NF_SYSCTL_CT_PROTO_TCP_LIBERAL, |
| 582 | + NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST, | |
| 582 | 583 | NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, |
| 583 | 584 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, |
| 584 | 585 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM, |
| @@ -798,6 +799,14 @@ static struct ctl_table nf_ct_sysctl_table[] = { · 213 unmodified lines | ||
| 798 | 799 | .extra1 = SYSCTL_ZERO, |
| 799 | 800 | .extra2 = SYSCTL_ONE, |
| 800 | 801 | }, |
| 802 | + [NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST] = { | |
| 803 | + .procname = "nf_conntrack_tcp_ignore_invalid_rst", | |
| 804 | + .maxlen = sizeof(u8), | |
| 805 | + .mode = 0644, | |
| 806 | + .proc_handler = proc_dou8vec_minmax, | |
| 807 | + .extra1 = SYSCTL_ZERO, | |
| 808 | + .extra2 = SYSCTL_ONE, | |
| 809 | + }, | |
| 801 | 810 | [NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS] = { |
| 802 | 811 | .procname = "nf_conntrack_tcp_max_retrans", |
| 803 | 812 | .maxlen = sizeof(u8), |
| @@ -1004,6 +1013,7 @@ static void nf_conntrack_standalone_init_tcp_sysctl(struct net *net, · 200 unmodified lines | ||
| 1004 | 1013 | XASSIGN(LOOSE, &tn->tcp_loose); |
| 1005 | 1014 | XASSIGN(LIBERAL, &tn->tcp_be_liberal); |
| 1006 | 1015 | XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans); |
| 1016 | + XASSIGN(IGNORE_INVALID_RST, &tn->tcp_ignore_invalid_rst); | |
| 1007 | 1017 | #undef XASSIGN |
| 1008 | 1018 | |
| 1009 | 1019 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
| @@ -3446,7 +3446,8 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info, · 3445 unmodified lines | ||
| 3446 | 3446 | return 0; |
| 3447 | 3447 | |
| 3448 | 3448 | err_destroy_flow_rule: |
| 3449 | − nft_flow_rule_destroy(flow); | |
| 3449 | + if (flow) | |
| 3450 | + nft_flow_rule_destroy(flow); | |
| 3450 | 3451 | err_release_rule: |
| 3451 | 3452 | nf_tables_rule_release(&ctx, rule); |
| 3452 | 3453 | err_release_expr: |
| @@ -23,15 +23,21 @@ static int nft_last_init(const struct nft_ctx *ctx, const struct nft_expr *expr, · 22 unmodified lines | ||
| 23 | 23 | { |
| 24 | 24 | struct nft_last_priv *priv = nft_expr_priv(expr); |
| 25 | 25 | u64 last_jiffies; |
| 26 | + u32 last_set = 0; | |
| 26 | 27 | int err; |
| 27 | 28 | |
| 28 | − if (tb[NFTA_LAST_MSECS]) { | |
| 29 | + if (tb[NFTA_LAST_SET]) { | |
| 30 | + last_set = ntohl(nla_get_be32(tb[NFTA_LAST_SET])); | |
| 31 | + if (last_set == 1) | |
| 32 | + priv->last_set = 1; | |
| 33 | + } | |
| 34 | + | |
| 35 | + if (last_set && tb[NFTA_LAST_MSECS]) { | |
| 29 | 36 | err = nf_msecs_to_jiffies64(tb[NFTA_LAST_MSECS], &last_jiffies); |
| 30 | 37 | if (err < 0) |
| 31 | 38 | return err; |
| 32 | 39 | |
| 33 | − priv->last_jiffies = jiffies + (unsigned long)last_jiffies; | |
| 34 | − priv->last_set = 1; | |
| 40 | + priv->last_jiffies = jiffies - (unsigned long)last_jiffies; | |
| 35 | 41 | } |
| 36 | 42 | |
| 37 | 43 | return 0; |
| @@ -2471,7 +2471,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err, · 2470 unmodified lines | ||
| 2471 | 2471 | |
| 2472 | 2472 | nlmsg_end(skb, rep); |
| 2473 | 2473 | |
| 2474 | − netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT); | |
| 2474 | + nlmsg_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid); | |
| 2475 | 2475 | } |
| 2476 | 2476 | EXPORT_SYMBOL(netlink_ack); |
| 2477 | 2477 | |
| @@ -670,13 +670,13 @@ static bool cmp_key(const struct sw_flow_key *key1, · 669 unmodified lines | ||
| 670 | 670 | { |
| 671 | 671 | const long *cp1 = (const long *)((const u8 *)key1 + key_start); |
| 672 | 672 | const long *cp2 = (const long *)((const u8 *)key2 + key_start); |
| 673 | − long diffs = 0; | |
| 674 | 673 | int i; |
| 675 | 674 | |
| 676 | 675 | for (i = key_start; i < key_end; i += sizeof(long)) |
| 677 | − diffs |= *cp1++ ^ *cp2++; | |
| 676 | + if (*cp1++ ^ *cp2++) | |
| 677 | + return false; | |
| 678 | 678 | |
| 679 | − return diffs == 0; | |
| 679 | + return true; | |
| 680 | 680 | } |
| 681 | 681 | |
| 682 | 682 | static bool flow_cmp_masked_key(const struct sw_flow *flow, |
| @@ -322,11 +322,22 @@ err_alloc: · 321 unmodified lines | ||
| 322 | 322 | |
| 323 | 323 | static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) |
| 324 | 324 | { |
| 325 | + struct flow_block_cb *block_cb, *tmp_cb; | |
| 325 | 326 | struct tcf_ct_flow_table *ct_ft; |
| 327 | + struct flow_block *block; | |
| 326 | 328 | |
| 327 | 329 | ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, |
| 328 | 330 | rwork); |
| 329 | 331 | nf_flow_table_free(&ct_ft->nf_ft); |
| 332 | + | |
| 333 | + /* Remove any remaining callbacks before cleanup */ | |
| 334 | + block = &ct_ft->nf_ft.flow_block; | |
| 335 | + down_write(&ct_ft->nf_ft.flow_block_lock); | |
| 336 | + list_for_each_entry_safe(block_cb, tmp_cb, &block->cb_list, list) { | |
| 337 | + list_del(&block_cb->list); | |
| 338 | + flow_block_cb_free(block_cb); | |
| 339 | + } | |
| 340 | + up_write(&ct_ft->nf_ft.flow_block_lock); | |
| 330 | 341 | kfree(ct_ft); |
| 331 | 342 | |
| 332 | 343 | module_put(THIS_MODULE); |
| @@ -1026,7 +1037,8 @@ do_nat: · 693 unmodified lines | ||
| 1026 | 1037 | /* This will take care of sending queued events |
| 1027 | 1038 | * even if the connection is already confirmed. |
| 1028 | 1039 | */ |
| 1029 | − nf_conntrack_confirm(skb); | |
| 1040 | + if (nf_conntrack_confirm(skb) != NF_ACCEPT) | |
| 1041 | + goto drop; | |
| 1030 | 1042 | } |
| 1031 | 1043 | |
| 1032 | 1044 | if (!skip_add) |
| @@ -564,7 +564,7 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) · 563 unmodified lines | ||
| 564 | 564 | /* if there's no entry, it means that the schedule didn't |
| 565 | 565 | * start yet, so force all gates to be open, this is in |
| 566 | 566 | * accordance to IEEE 802.1Qbv-2015 Section 8.6.9.4.5 |
| 567 | − * "AdminGateSates" | |
| 567 | + * "AdminGateStates" | |
| 568 | 568 | */ |
| 569 | 569 | gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN; |
| 570 | 570 | |
| @@ -284,10 +284,8 @@ static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p) · 283 unmodified lines | ||
| 284 | 284 | goto out; |
| 285 | 285 | } |
| 286 | 286 | |
| 287 | − err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | |
| 288 | − MSG_DONTWAIT); | |
| 289 | − if (err > 0) | |
| 290 | − err = 0; | |
| 287 | + err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); | |
| 288 | + | |
| 291 | 289 | out: |
| 292 | 290 | return err; |
| 293 | 291 | } |
| @@ -398,7 +398,8 @@ static enum sctp_scope sctp_v4_scope(union sctp_addr *addr) · 397 unmodified lines | ||
| 398 | 398 | retval = SCTP_SCOPE_LINK; |
| 399 | 399 | } else if (ipv4_is_private_10(addr->v4.sin_addr.s_addr) || |
| 400 | 400 | ipv4_is_private_172(addr->v4.sin_addr.s_addr) || |
| 401 | − ipv4_is_private_192(addr->v4.sin_addr.s_addr)) { | |
| 401 | + ipv4_is_private_192(addr->v4.sin_addr.s_addr) || | |
| 402 | + ipv4_is_test_198(addr->v4.sin_addr.s_addr)) { | |
| 402 | 403 | retval = SCTP_SCOPE_PRIVATE; |
| 403 | 404 | } else { |
| 404 | 405 | retval = SCTP_SCOPE_GLOBAL; |
| @@ -1163,7 +1163,7 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, · 1162 unmodified lines | ||
| 1163 | 1163 | const struct sctp_transport *transport, |
| 1164 | 1164 | __u32 probe_size) |
| 1165 | 1165 | { |
| 1166 | − struct sctp_sender_hb_info hbinfo; | |
| 1166 | + struct sctp_sender_hb_info hbinfo = {}; | |
| 1167 | 1167 | struct sctp_chunk *retval; |
| 1168 | 1168 | |
| 1169 | 1169 | retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, |
| @@ -335,10 +335,13 @@ void sctp_transport_pl_recv(struct sctp_transport *t) · 334 unmodified lines | ||
| 335 | 335 | t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t); |
| 336 | 336 | sctp_assoc_sync_pmtu(t->asoc); |
| 337 | 337 | } |
| 338 | − } else if (t->pl.state == SCTP_PL_COMPLETE && ++t->pl.raise_count == 30) { | |
| 339 | − /* Raise probe_size again after 30 * interval in Search Complete */ | |
| 340 | − t->pl.state = SCTP_PL_SEARCH; /* Search Complete -> Search */ | |
| 341 | − t->pl.probe_size += SCTP_PL_MIN_STEP; | |
| 338 | + } else if (t->pl.state == SCTP_PL_COMPLETE) { | |
| 339 | + t->pl.raise_count++; | |
| 340 | + if (t->pl.raise_count == 30) { | |
| 341 | + /* Raise probe_size again after 30 * interval in Search Complete */ | |
| 342 | + t->pl.state = SCTP_PL_SEARCH; /* Search Complete -> Search */ | |
| 343 | + t->pl.probe_size += SCTP_PL_MIN_STEP; | |
| 344 | + } | |
| 342 | 345 | } |
| 343 | 346 | } |
| 344 | 347 | |
| @@ -104,6 +104,7 @@ · 103 unmodified lines | ||
| 104 | 104 | #include <linux/sockios.h> |
| 105 | 105 | #include <net/busy_poll.h> |
| 106 | 106 | #include <linux/errqueue.h> |
| 107 | +#include <linux/ptp_clock_kernel.h> | |
| 107 | 108 | |
| 108 | 109 | #ifdef CONFIG_NET_RX_BUSY_POLL |
| 109 | 110 | unsigned int sysctl_net_busy_read __read_mostly; |
| @@ -873,12 +874,18 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, · 763 unmodified lines | ||
| 873 | 874 | empty = 0; |
| 874 | 875 | if (shhwtstamps && |
| 875 | 876 | (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && |
| 876 | − !skb_is_swtx_tstamp(skb, false_tstamp) && | |
| 877 | − ktime_to_timespec64_cond(shhwtstamps->hwtstamp, tss.ts + 2)) { | |
| 878 | − empty = 0; | |
| 879 | − if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) && | |
| 880 | − !skb_is_err_queue(skb)) | |
| 881 | − put_ts_pktinfo(msg, skb); | |
| 877 | + !skb_is_swtx_tstamp(skb, false_tstamp)) { | |
| 878 | + if (sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC) | |
| 879 | + ptp_convert_timestamp(shhwtstamps, sk->sk_bind_phc); | |
| 880 | + | |
| 881 | + if (ktime_to_timespec64_cond(shhwtstamps->hwtstamp, | |
| 882 | + tss.ts + 2)) { | |
| 883 | + empty = 0; | |
| 884 | + | |
| 885 | + if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) && | |
| 886 | + !skb_is_err_queue(skb)) | |
| 887 | + put_ts_pktinfo(msg, skb); | |
| 888 | + } | |
| 882 | 889 | } |
| 883 | 890 | if (!empty) { |
| 884 | 891 | if (sock_flag(sk, SOCK_TSTAMP_NEW)) |
| @@ -295,10 +295,8 @@ again: · 294 unmodified lines | ||
| 295 | 295 | |
| 296 | 296 | goto again; |
| 297 | 297 | } |
| 298 | − err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | |
| 299 | − MSG_DONTWAIT); | |
| 300 | − if (err > 0) | |
| 301 | − err = 0; | |
| 298 | + err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); | |
| 299 | + | |
| 302 | 300 | out: |
| 303 | 301 | if (sk) |
| 304 | 302 | sock_put(sk); |
| @@ -331,6 +331,7 @@ $(obj)/%.o: $(src)/%.c · 330 unmodified lines | ||
| 331 | 331 | -Wno-gnu-variable-sized-type-not-at-end \ |
| 332 | 332 | -Wno-address-of-packed-member -Wno-tautological-compare \ |
| 333 | 333 | -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \ |
| 334 | + -fno-asynchronous-unwind-tables \ | |
| 334 | 335 | -I$(srctree)/samples/bpf/ -include asm_goto_workaround.h \ |
| 335 | 336 | -O2 -emit-llvm -Xclang -disable-llvm-passes -c $< -o - | \ |
| 336 | 337 | $(OPT) -O2 -mtriple=bpf-pc-linux | $(LLVM_DIS) | \ |
| @@ -96,6 +96,7 @@ static int opt_xsk_frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; · 95 unmodified lines | ||
| 96 | 96 | static int opt_timeout = 1000; |
| 97 | 97 | static bool opt_need_wakeup = true; |
| 98 | 98 | static u32 opt_num_xsks = 1; |
| 99 | +static u32 prog_id; | |
| 99 | 100 | static bool opt_busy_poll; |
| 100 | 101 | static bool opt_reduced_cap; |
| 101 | 102 | |
| @@ -461,6 +462,23 @@ static void *poller(void *arg) · 359 unmodified lines | ||
| 461 | 462 | return NULL; |
| 462 | 463 | } |
| 463 | 464 | |
| 465 | +static void remove_xdp_program(void) | |
| 466 | +{ | |
| 467 | + u32 curr_prog_id = 0; | |
| 468 | + | |
| 469 | + if (bpf_get_link_xdp_id(opt_ifindex, &curr_prog_id, opt_xdp_flags)) { | |
| 470 | + printf("bpf_get_link_xdp_id failed\n"); | |
| 471 | + exit(EXIT_FAILURE); | |
| 472 | + } | |
| 473 | + | |
| 474 | + if (prog_id == curr_prog_id) | |
| 475 | + bpf_set_link_xdp_fd(opt_ifindex, -1, opt_xdp_flags); | |
| 476 | + else if (!curr_prog_id) | |
| 477 | + printf("couldn't find a prog id on a given interface\n"); | |
| 478 | + else | |
| 479 | + printf("program on interface changed, not removing\n"); | |
| 480 | +} | |
| 481 | + | |
| 464 | 482 | static void int_exit(int sig) |
| 465 | 483 | { |
| 466 | 484 | benchmark_done = true; |
| @@ -471,6 +489,9 @@ static void __exit_with_error(int error, const char *file, const char *func, · 4 unmodified lines | ||
| 471 | 489 | { |
| 472 | 490 | fprintf(stderr, "%s:%s:%i: errno: %d/\"%s\"\n", file, func, |
| 473 | 491 | line, error, strerror(error)); |
| 492 | + | |
| 493 | + if (opt_num_xsks > 1) | |
| 494 | + remove_xdp_program(); | |
| 474 | 495 | exit(EXIT_FAILURE); |
| 475 | 496 | } |
| 476 | 497 | |
| @@ -490,6 +511,9 @@ static void xdpsock_cleanup(void) · 13 unmodified lines | ||
| 490 | 511 | if (write(sock, &cmd, sizeof(int)) < 0) |
| 491 | 512 | exit_with_error(errno); |
| 492 | 513 | } |
| 514 | + | |
| 515 | + if (opt_num_xsks > 1) | |
| 516 | + remove_xdp_program(); | |
| 493 | 517 | } |
| 494 | 518 | |
| 495 | 519 | static void swap_mac_addresses(void *data) |
| @@ -857,6 +881,10 @@ static struct xsk_socket_info *xsk_configure_socket(struct xsk_umem_info *umem, · 361 unmodified lines | ||
| 857 | 881 | if (ret) |
| 858 | 882 | exit_with_error(-ret); |
| 859 | 883 | |
| 884 | + ret = bpf_get_link_xdp_id(opt_ifindex, &prog_id, opt_xdp_flags); | |
| 885 | + if (ret) | |
| 886 | + exit_with_error(-ret); | |
| 887 | + | |
| 860 | 888 | xsk->app_stats.rx_empty_polls = 0; |
| 861 | 889 | xsk->app_stats.fill_fail_polls = 0; |
| 862 | 890 | xsk->app_stats.copy_tx_sendtos = 0; |
| @@ -97,7 +97,7 @@ clean: bpftool_clean runqslower_clean resolve_btfids_clean · 96 unmodified lines | ||
| 97 | 97 | $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpf |
| 98 | 98 | $(Q)$(RM) -r -- $(OUTPUT)feature |
| 99 | 99 | |
| 100 | −install: $(PROGS) bpftool_install runqslower_install | |
| 100 | +install: $(PROGS) bpftool_install | |
| 101 | 101 | $(call QUIET_INSTALL, bpf_jit_disasm) |
| 102 | 102 | $(Q)$(INSTALL) -m 0755 -d $(DESTDIR)$(prefix)/bin |
| 103 | 103 | $(Q)$(INSTALL) $(OUTPUT)bpf_jit_disasm $(DESTDIR)$(prefix)/bin/bpf_jit_disasm |
| @@ -118,9 +118,6 @@ bpftool_clean: · 14 unmodified lines | ||
| 118 | 118 | runqslower: |
| 119 | 119 | $(call descend,runqslower) |
| 120 | 120 | |
| 121 | −runqslower_install: | |
| 122 | − $(call descend,runqslower,install) | |
| 123 | − | |
| 124 | 121 | runqslower_clean: |
| 125 | 122 | $(call descend,runqslower,clean) |
| 126 | 123 | |
| @@ -131,5 +128,5 @@ resolve_btfids_clean: · 4 unmodified lines | ||
| 131 | 128 | $(call descend,resolve_btfids,clean) |
| 132 | 129 | |
| 133 | 130 | .PHONY: all install clean bpftool bpftool_install bpftool_clean \ |
| 134 | − runqslower runqslower_install runqslower_clean \ | |
| 131 | + runqslower runqslower_clean \ | |
| 135 | 132 | resolve_btfids resolve_btfids_clean |
| @@ -43,11 +43,13 @@ static int fprintf_json(void *out, const char *fmt, ...) · 42 unmodified lines | ||
| 43 | 43 | { |
| 44 | 44 | va_list ap; |
| 45 | 45 | char *s; |
| 46 | + int err; | |
| 46 | 47 | |
| 47 | 48 | va_start(ap, fmt); |
| 48 | − if (vasprintf(&s, fmt, ap) < 0) | |
| 49 | − return -1; | |
| 49 | + err = vasprintf(&s, fmt, ap); | |
| 50 | 50 | va_end(ap); |
| 51 | + if (err < 0) | |
| 52 | + return -1; | |
| 51 | 53 | |
| 52 | 54 | if (!oper_count) { |
| 53 | 55 | int i; |
| @@ -74,7 +74,7 @@ int handle__sched_switch(u64 *ctx) · 73 unmodified lines | ||
| 74 | 74 | u32 pid; |
| 75 | 75 | |
| 76 | 76 | /* ivcsw: treat like an enqueue event and store timestamp */ |
| 77 | − if (prev->state == TASK_RUNNING) | |
| 77 | + if (prev->__state == TASK_RUNNING) | |
| 78 | 78 | trace_enqueue(prev); |
| 79 | 79 | |
| 80 | 80 | pid = next->pid; |
| @@ -10136,7 +10136,7 @@ int bpf_link__unpin(struct bpf_link *link) · 10135 unmodified lines | ||
| 10136 | 10136 | |
| 10137 | 10137 | err = unlink(link->pin_path); |
| 10138 | 10138 | if (err != 0) |
| 10139 | − return libbpf_err_errno(err); | |
| 10139 | + return -errno; | |
| 10140 | 10140 | |
| 10141 | 10141 | pr_debug("link fd=%d: unpinned from %s\n", link->fd, link->pin_path); |
| 10142 | 10142 | zfree(&link->pin_path); |
| @@ -11197,7 +11197,7 @@ int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms) · 1054 unmodified lines | ||
| 11197 | 11197 | |
| 11198 | 11198 | cnt = epoll_wait(pb->epoll_fd, pb->events, pb->cpu_cnt, timeout_ms); |
| 11199 | 11199 | if (cnt < 0) |
| 11200 | − return libbpf_err_errno(cnt); | |
| 11200 | + return -errno; | |
| 11201 | 11201 | |
| 11202 | 11202 | for (i = 0; i < cnt; i++) { |
| 11203 | 11203 | struct perf_cpu_buf *cpu_buf = pb->events[i].data.ptr; |
| @@ -715,6 +715,8 @@ out: · 714 unmodified lines | ||
| 715 | 715 | bpf_object__close(obj); |
| 716 | 716 | } |
| 717 | 717 | |
| 718 | +#include "tailcall_bpf2bpf4.skel.h" | |
| 719 | + | |
| 718 | 720 | /* test_tailcall_bpf2bpf_4 checks that tailcall counter is correctly preserved |
| 719 | 721 | * across tailcalls combined with bpf2bpf calls. for making sure that tailcall |
| 720 | 722 | * counter behaves correctly, bpf program will go through following flow: |
| @@ -727,10 +729,15 @@ out: · 6 unmodified lines | ||
| 727 | 729 | * the loop begins. At the end of the test make sure that the global counter is |
| 728 | 730 | * equal to 31, because tailcall counter includes the first two tailcalls |
| 729 | 731 | * whereas global counter is incremented only on loop presented on flow above. |
| 732 | + * | |
| 733 | + * The noise parameter is used to insert bpf_map_update calls into the logic | |
| 734 | + * to force verifier to patch instructions. This allows us to ensure jump | |
| 735 | + * logic remains correct with instruction movement. | |
| 730 | 736 | */ |
| 731 | −static void test_tailcall_bpf2bpf_4(void) | |
| 737 | +static void test_tailcall_bpf2bpf_4(bool noise) | |
| 732 | 738 | { |
| 733 | − int err, map_fd, prog_fd, main_fd, data_fd, i, val; | |
| 739 | + int err, map_fd, prog_fd, main_fd, data_fd, i; | |
| 740 | + struct tailcall_bpf2bpf4__bss val; | |
| 734 | 741 | struct bpf_map *prog_array, *data_map; |
| 735 | 742 | struct bpf_program *prog; |
| 736 | 743 | struct bpf_object *obj; |
| @@ -774,11 +781,6 @@ static void test_tailcall_bpf2bpf_4(void) · 37 unmodified lines | ||
| 774 | 781 | goto out; |
| 775 | 782 | } |
| 776 | 783 | |
| 777 | − err = bpf_prog_test_run(main_fd, 1, &pkt_v4, sizeof(pkt_v4), 0, | |
| 778 | − &duration, &retval, NULL); | |
| 779 | − CHECK(err || retval != sizeof(pkt_v4) * 3, "tailcall", "err %d errno %d retval %d\n", | |
| 780 | − err, errno, retval); | |
| 781 | − | |
| 782 | 784 | data_map = bpf_object__find_map_by_name(obj, "tailcall.bss"); |
| 783 | 785 | if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map))) |
| 784 | 786 | return; |
| @@ -787,10 +789,22 @@ static void test_tailcall_bpf2bpf_4(void) · 2 unmodified lines | ||
| 787 | 789 | if (CHECK_FAIL(map_fd < 0)) |
| 788 | 790 | return; |
| 789 | 791 | |
| 792 | + i = 0; | |
| 793 | + val.noise = noise; | |
| 794 | + val.count = 0; | |
| 795 | + err = bpf_map_update_elem(data_fd, &i, &val, BPF_ANY); | |
| 796 | + if (CHECK_FAIL(err)) | |
| 797 | + goto out; | |
| 798 | + | |
| 799 | + err = bpf_prog_test_run(main_fd, 1, &pkt_v4, sizeof(pkt_v4), 0, | |
| 800 | + &duration, &retval, NULL); | |
| 801 | + CHECK(err || retval != sizeof(pkt_v4) * 3, "tailcall", "err %d errno %d retval %d\n", | |
| 802 | + err, errno, retval); | |
| 803 | + | |
| 790 | 804 | i = 0; |
| 791 | 805 | err = bpf_map_lookup_elem(data_fd, &i, &val); |
| 792 | − CHECK(err || val != 31, "tailcall count", "err %d errno %d count %d\n", | |
| 793 | − err, errno, val); | |
| 806 | + CHECK(err || val.count != 31, "tailcall count", "err %d errno %d count %d\n", | |
| 807 | + err, errno, val.count); | |
| 794 | 808 | |
| 795 | 809 | out: |
| 796 | 810 | bpf_object__close(obj); |
| @@ -815,5 +829,7 @@ void test_tailcalls(void) · 18 unmodified lines | ||
| 815 | 829 | if (test__start_subtest("tailcall_bpf2bpf_3")) |
| 816 | 830 | test_tailcall_bpf2bpf_3(); |
| 817 | 831 | if (test__start_subtest("tailcall_bpf2bpf_4")) |
| 818 | − test_tailcall_bpf2bpf_4(); | |
| 832 | + test_tailcall_bpf2bpf_4(false); | |
| 833 | + if (test__start_subtest("tailcall_bpf2bpf_5")) | |
| 834 | + test_tailcall_bpf2bpf_4(true); | |
| 819 | 835 | } |
| @@ -2,6 +2,13 @@ · 1 unmodified line | ||
| 2 | 2 | #include <linux/bpf.h> |
| 3 | 3 | #include <bpf/bpf_helpers.h> |
| 4 | 4 | |
| 5 | +struct { | |
| 6 | + __uint(type, BPF_MAP_TYPE_ARRAY); | |
| 7 | + __uint(max_entries, 1); | |
| 8 | + __uint(key_size, sizeof(__u32)); | |
| 9 | + __uint(value_size, sizeof(__u32)); | |
| 10 | +} nop_table SEC(".maps"); | |
| 11 | + | |
| 5 | 12 | struct { |
| 6 | 13 | __uint(type, BPF_MAP_TYPE_PROG_ARRAY); |
| 7 | 14 | __uint(max_entries, 3); |
| @@ -10,10 +17,21 @@ struct { · 2 unmodified lines | ||
| 10 | 17 | } jmp_table SEC(".maps"); |
| 11 | 18 | |
| 12 | 19 | int count = 0; |
| 20 | +int noise = 0; | |
| 21 | + | |
| 22 | +__always_inline int subprog_noise(void) | |
| 23 | +{ | |
| 24 | + __u32 key = 0; | |
| 25 | + | |
| 26 | + bpf_map_lookup_elem(&nop_table, &key); | |
| 27 | + return 0; | |
| 28 | +} | |
| 13 | 29 | |
| 14 | 30 | __noinline |
| 15 | 31 | int subprog_tail_2(struct __sk_buff *skb) |
| 16 | 32 | { |
| 33 | + if (noise) | |
| 34 | + subprog_noise(); | |
| 17 | 35 | bpf_tail_call_static(skb, &jmp_table, 2); |
| 18 | 36 | return skb->len * 3; |
| 19 | 37 | } |
| @@ -313,9 +313,10 @@ check_exception() · 312 unmodified lines | ||
| 313 | 313 | fi |
| 314 | 314 | log_test $? 0 "IPv4: ${desc}" |
| 315 | 315 | |
| 316 | − if [ "$with_redirect" = "yes" ]; then | |
| 316 | + # No PMTU info for test "redirect" and "mtu exception plus redirect" | |
| 317 | + if [ "$with_redirect" = "yes" ] && [ "$desc" != "redirect exception plus mtu" ]; then | |
| 317 | 318 | ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ |
| 318 | − grep -q "${H2_N2_IP6} from :: via ${R2_LLADDR} dev br0.*${mtu}" | |
| 319 | + grep -v "mtu" | grep -q "${H2_N2_IP6} .*via ${R2_LLADDR} dev br0" | |
| 319 | 320 | elif [ -n "${mtu}" ]; then |
| 320 | 321 | ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ |
| 321 | 322 | grep -q "${mtu}" |
| @@ -1409,7 +1409,7 @@ syncookies_tests() · 1408 unmodified lines | ||
| 1409 | 1409 | ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow |
| 1410 | 1410 | ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow |
| 1411 | 1411 | run_tests $ns1 $ns2 10.0.1.1 |
| 1412 | − chk_join_nr "subflows limited by server w cookies" 2 2 1 | |
| 1412 | + chk_join_nr "subflows limited by server w cookies" 2 1 1 | |
| 1413 | 1413 | |
| 1414 | 1414 | # test signal address with cookies |
| 1415 | 1415 | reset_with_cookies |
| @@ -47,7 +47,7 @@ static void usage(const char *error) · 46 unmodified lines | ||
| 47 | 47 | { |
| 48 | 48 | if (error) |
| 49 | 49 | printf("invalid option: %s\n", error); |
| 50 | − printf("timestamping interface option*\n\n" | |
| 50 | + printf("timestamping <interface> [bind_phc_index] [option]*\n\n" | |
| 51 | 51 | "Options:\n" |
| 52 | 52 | " IP_MULTICAST_LOOP - looping outgoing multicasts\n" |
| 53 | 53 | " SO_TIMESTAMP - normal software time stamping, ms resolution\n" |
| @@ -58,6 +58,7 @@ static void usage(const char *error) · 4 unmodified lines | ||
| 58 | 58 | " SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n" |
| 59 | 59 | " SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n" |
| 60 | 60 | " SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n" |
| 61 | + " SOF_TIMESTAMPING_BIND_PHC - request to bind a PHC of PTP vclock\n" | |
| 61 | 62 | " SIOCGSTAMP - check last socket time stamp\n" |
| 62 | 63 | " SIOCGSTAMPNS - more accurate socket time stamp\n" |
| 63 | 64 | " PTPV2 - use PTPv2 messages\n"); |
| @@ -311,7 +312,6 @@ static void recvpacket(int sock, int recvmsg_flags, · 247 unmodified lines | ||
| 311 | 312 | |
| 312 | 313 | int main(int argc, char **argv) |
| 313 | 314 | { |
| 314 | − int so_timestamping_flags = 0; | |
| 315 | 315 | int so_timestamp = 0; |
| 316 | 316 | int so_timestampns = 0; |
| 317 | 317 | int siocgstamp = 0; |
| @@ -325,6 +325,8 @@ int main(int argc, char **argv) · 7 unmodified lines | ||
| 325 | 325 | struct ifreq device; |
| 326 | 326 | struct ifreq hwtstamp; |
| 327 | 327 | struct hwtstamp_config hwconfig, hwconfig_requested; |
| 328 | + struct so_timestamping so_timestamping_get = { 0, -1 }; | |
| 329 | + struct so_timestamping so_timestamping = { 0, -1 }; | |
| 328 | 330 | struct sockaddr_in addr; |
| 329 | 331 | struct ip_mreq imr; |
| 330 | 332 | struct in_addr iaddr; |
| @@ -342,7 +344,12 @@ int main(int argc, char **argv) · 11 unmodified lines | ||
| 342 | 344 | exit(1); |
| 343 | 345 | } |
| 344 | 346 | |
| 345 | − for (i = 2; i < argc; i++) { | |
| 347 | + if (argc >= 3 && sscanf(argv[2], "%d", &so_timestamping.bind_phc) == 1) | |
| 348 | + val = 3; | |
| 349 | + else | |
| 350 | + val = 2; | |
| 351 | + | |
| 352 | + for (i = val; i < argc; i++) { | |
| 346 | 353 | if (!strcasecmp(argv[i], "SO_TIMESTAMP")) |
| 347 | 354 | so_timestamp = 1; |
| 348 | 355 | else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS")) |
| @@ -356,17 +363,19 @@ int main(int argc, char **argv) · 7 unmodified lines | ||
| 356 | 363 | else if (!strcasecmp(argv[i], "PTPV2")) |
| 357 | 364 | ptpv2 = 1; |
| 358 | 365 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE")) |
| 359 | − so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE; | |
| 366 | + so_timestamping.flags |= SOF_TIMESTAMPING_TX_HARDWARE; | |
| 360 | 367 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE")) |
| 361 | − so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE; | |
| 368 | + so_timestamping.flags |= SOF_TIMESTAMPING_TX_SOFTWARE; | |
| 362 | 369 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE")) |
| 363 | − so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE; | |
| 370 | + so_timestamping.flags |= SOF_TIMESTAMPING_RX_HARDWARE; | |
| 364 | 371 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE")) |
| 365 | − so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE; | |
| 372 | + so_timestamping.flags |= SOF_TIMESTAMPING_RX_SOFTWARE; | |
| 366 | 373 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE")) |
| 367 | − so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE; | |
| 374 | + so_timestamping.flags |= SOF_TIMESTAMPING_SOFTWARE; | |
| 368 | 375 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE")) |
| 369 | − so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; | |
| 376 | + so_timestamping.flags |= SOF_TIMESTAMPING_RAW_HARDWARE; | |
| 377 | + else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_BIND_PHC")) | |
| 378 | + so_timestamping.flags |= SOF_TIMESTAMPING_BIND_PHC; | |
| 370 | 379 | else |
| 371 | 380 | usage(argv[i]); |
| 372 | 381 | } |
| @@ -385,10 +394,10 @@ int main(int argc, char **argv) · 12 unmodified lines | ||
| 385 | 394 | hwtstamp.ifr_data = (void *)&hwconfig; |
| 386 | 395 | memset(&hwconfig, 0, sizeof(hwconfig)); |
| 387 | 396 | hwconfig.tx_type = |
| 388 | − (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ? | |
| 397 | + (so_timestamping.flags & SOF_TIMESTAMPING_TX_HARDWARE) ? | |
| 389 | 398 | HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; |
| 390 | 399 | hwconfig.rx_filter = |
| 391 | − (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ? | |
| 400 | + (so_timestamping.flags & SOF_TIMESTAMPING_RX_HARDWARE) ? | |
| 392 | 401 | ptpv2 ? HWTSTAMP_FILTER_PTP_V2_L4_SYNC : |
| 393 | 402 | HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE; |
| 394 | 403 | hwconfig_requested = hwconfig; |
| @@ -413,6 +422,9 @@ int main(int argc, char **argv) · 18 unmodified lines | ||
| 413 | 422 | sizeof(struct sockaddr_in)) < 0) |
| 414 | 423 | bail("bind"); |
| 415 | 424 | |
| 425 | + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, if_len)) | |
| 426 | + bail("bind device"); | |
| 427 | + | |
| 416 | 428 | /* set multicast group for outgoing packets */ |
| 417 | 429 | inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */ |
| 418 | 430 | addr.sin_addr = iaddr; |
| @@ -444,10 +456,9 @@ int main(int argc, char **argv) · 25 unmodified lines | ||
| 444 | 456 | &enabled, sizeof(enabled)) < 0) |
| 445 | 457 | bail("setsockopt SO_TIMESTAMPNS"); |
| 446 | 458 | |
| 447 | − if (so_timestamping_flags && | |
| 448 | − setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, | |
| 449 | − &so_timestamping_flags, | |
| 450 | − sizeof(so_timestamping_flags)) < 0) | |
| 459 | + if (so_timestamping.flags && | |
| 460 | + setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping, | |
| 461 | + sizeof(so_timestamping)) < 0) | |
| 451 | 462 | bail("setsockopt SO_TIMESTAMPING"); |
| 452 | 463 | |
| 453 | 464 | /* request IP_PKTINFO for debugging purposes */ |
| @@ -468,14 +479,18 @@ int main(int argc, char **argv) · 14 unmodified lines | ||
| 468 | 479 | else |
| 469 | 480 | printf("SO_TIMESTAMPNS %d\n", val); |
| 470 | 481 | |
| 471 | − if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) { | |
| 482 | + len = sizeof(so_timestamping_get); | |
| 483 | + if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping_get, | |
| 484 | + &len) < 0) { | |
| 472 | 485 | printf("%s: %s\n", "getsockopt SO_TIMESTAMPING", |
| 473 | 486 | strerror(errno)); |
| 474 | 487 | } else { |
| 475 | − printf("SO_TIMESTAMPING %d\n", val); | |
| 476 | − if (val != so_timestamping_flags) | |
| 477 | − printf(" not the expected value %d\n", | |
| 478 | − so_timestamping_flags); | |
| 488 | + printf("SO_TIMESTAMPING flags %d, bind phc %d\n", | |
| 489 | + so_timestamping_get.flags, so_timestamping_get.bind_phc); | |
| 490 | + if (so_timestamping_get.flags != so_timestamping.flags || | |
| 491 | + so_timestamping_get.bind_phc != so_timestamping.bind_phc) | |
| 492 | + printf(" not expected, flags %d, bind phc %d\n", | |
| 493 | + so_timestamping.flags, so_timestamping.bind_phc); | |
| 479 | 494 | } |
| 480 | 495 | |
| 481 | 496 | /* send packets forever every five seconds */ |
| @@ -5,7 +5,7 @@ TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \ · 4 unmodified lines | ||
| 5 | 5 | conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \ |
| 6 | 6 | nft_concat_range.sh nft_conntrack_helper.sh \ |
| 7 | 7 | nft_queue.sh nft_meta.sh nf_nat_edemux.sh \ |
| 8 | − ipip-conntrack-mtu.sh | |
| 8 | + ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh | |
| 9 | 9 | |
| 10 | 10 | LDLIBS = -lmnl |
| 11 | 11 | TEST_GEN_FILES = nf-queue |
| @@ -0,0 +1,167 @@ | ||
| 1 | +#!/bin/bash | |
| 2 | +# SPDX-License-Identifier: GPL-2.0 | |
| 3 | +# | |
| 4 | +# Check that UNREPLIED tcp conntrack will eventually timeout. | |
| 5 | +# | |
| 6 | + | |
| 7 | +# Kselftest framework requirement - SKIP code is 4. | |
| 8 | +ksft_skip=4 | |
| 9 | +ret=0 | |
| 10 | + | |
| 11 | +waittime=20 | |
| 12 | +sfx=$(mktemp -u "XXXXXXXX") | |
| 13 | +ns1="ns1-$sfx" | |
| 14 | +ns2="ns2-$sfx" | |
| 15 | + | |
| 16 | +nft --version > /dev/null 2>&1 | |
| 17 | +if [ $? -ne 0 ];then | |
| 18 | + echo "SKIP: Could not run test without nft tool" | |
| 19 | + exit $ksft_skip | |
| 20 | +fi | |
| 21 | + | |
| 22 | +ip -Version > /dev/null 2>&1 | |
| 23 | +if [ $? -ne 0 ];then | |
| 24 | + echo "SKIP: Could not run test without ip tool" | |
| 25 | + exit $ksft_skip | |
| 26 | +fi | |
| 27 | + | |
| 28 | +cleanup() { | |
| 29 | + ip netns pids $ns1 | xargs kill 2>/dev/null | |
| 30 | + ip netns pids $ns2 | xargs kill 2>/dev/null | |
| 31 | + | |
| 32 | + ip netns del $ns1 | |
| 33 | + ip netns del $ns2 | |
| 34 | +} | |
| 35 | + | |
| 36 | +ipv4() { | |
| 37 | + echo -n 192.168.$1.2 | |
| 38 | +} | |
| 39 | + | |
| 40 | +check_counter() | |
| 41 | +{ | |
| 42 | + ns=$1 | |
| 43 | + name=$2 | |
| 44 | + expect=$3 | |
| 45 | + local lret=0 | |
| 46 | + | |
| 47 | + cnt=$(ip netns exec $ns2 nft list counter inet filter "$name" | grep -q "$expect") | |
| 48 | + if [ $? -ne 0 ]; then | |
| 49 | + echo "ERROR: counter $name in $ns2 has unexpected value (expected $expect)" 1>&2 | |
| 50 | + ip netns exec $ns2 nft list counter inet filter "$name" 1>&2 | |
| 51 | + lret=1 | |
| 52 | + fi | |
| 53 | + | |
| 54 | + return $lret | |
| 55 | +} | |
| 56 | + | |
| 57 | +# Create test namespaces | |
| 58 | +ip netns add $ns1 || exit 1 | |
| 59 | + | |
| 60 | +trap cleanup EXIT | |
| 61 | + | |
| 62 | +ip netns add $ns2 || exit 1 | |
| 63 | + | |
| 64 | +# Connect the namespace to the host using a veth pair | |
| 65 | +ip -net $ns1 link add name veth1 type veth peer name veth2 | |
| 66 | +ip -net $ns1 link set netns $ns2 dev veth2 | |
| 67 | + | |
| 68 | +ip -net $ns1 link set up dev lo | |
| 69 | +ip -net $ns2 link set up dev lo | |
| 70 | +ip -net $ns1 link set up dev veth1 | |
| 71 | +ip -net $ns2 link set up dev veth2 | |
| 72 | + | |
| 73 | +ip -net $ns2 addr add 10.11.11.2/24 dev veth2 | |
| 74 | +ip -net $ns2 route add default via 10.11.11.1 | |
| 75 | + | |
| 76 | +ip netns exec $ns2 sysctl -q net.ipv4.conf.veth2.forwarding=1 | |
| 77 | + | |
| 78 | +# add a rule inside NS so we enable conntrack | |
| 79 | +ip netns exec $ns1 iptables -A INPUT -m state --state established,related -j ACCEPT | |
| 80 | + | |
| 81 | +ip -net $ns1 addr add 10.11.11.1/24 dev veth1 | |
| 82 | +ip -net $ns1 route add 10.99.99.99 via 10.11.11.2 | |
| 83 | + | |
| 84 | +# Check connectivity works | |
| 85 | +ip netns exec $ns1 ping -q -c 2 10.11.11.2 >/dev/null || exit 1 | |
| 86 | + | |
| 87 | +ip netns exec $ns2 nc -l -p 8080 < /dev/null & | |
| 88 | + | |
| 89 | +# however, conntrack entries are there | |
| 90 | + | |
| 91 | +ip netns exec $ns2 nft -f - <<EOF | |
| 92 | +table inet filter { | |
| 93 | + counter connreq { } | |
| 94 | + counter redir { } | |
| 95 | + chain input { | |
| 96 | + type filter hook input priority 0; policy accept; | |
| 97 | + ct state new tcp flags syn ip daddr 10.99.99.99 tcp dport 80 counter name "connreq" accept | |
| 98 | + ct state new ct status dnat tcp dport 8080 counter name "redir" accept | |
| 99 | + } | |
| 100 | +} | |
| 101 | +EOF | |
| 102 | +if [ $? -ne 0 ]; then | |
| 103 | + echo "ERROR: Could not load nft rules" | |
| 104 | + exit 1 | |
| 105 | +fi | |
| 106 | + | |
| 107 | +ip netns exec $ns2 sysctl -q net.netfilter.nf_conntrack_tcp_timeout_syn_sent=10 | |
| 108 | + | |
| 109 | +echo "INFO: connect $ns1 -> $ns2 to the virtual ip" | |
| 110 | +ip netns exec $ns1 bash -c 'while true ; do | |
| 111 | + nc -p 60000 10.99.99.99 80 | |
| 112 | + sleep 1 | |
| 113 | + done' & | |
| 114 | + | |
| 115 | +sleep 1 | |
| 116 | + | |
| 117 | +ip netns exec $ns2 nft -f - <<EOF | |
| 118 | +table inet nat { | |
| 119 | + chain prerouting { | |
| 120 | + type nat hook prerouting priority 0; policy accept; | |
| 121 | + ip daddr 10.99.99.99 tcp dport 80 redirect to :8080 | |
| 122 | + } | |
| 123 | +} | |
| 124 | +EOF | |
| 125 | +if [ $? -ne 0 ]; then | |
| 126 | + echo "ERROR: Could not load nat redirect" | |
| 127 | + exit 1 | |
| 128 | +fi | |
| 129 | + | |
| 130 | +count=$(ip netns exec $ns2 conntrack -L -p tcp --dport 80 2>/dev/null | wc -l) | |
| 131 | +if [ $count -eq 0 ]; then | |
| 132 | + echo "ERROR: $ns2 did not pick up tcp connection from peer" | |
| 133 | + exit 1 | |
| 134 | +fi | |
| 135 | + | |
| 136 | +echo "INFO: NAT redirect added in ns $ns2, waiting for $waittime seconds for nat to take effect" | |
| 137 | +for i in $(seq 1 $waittime); do | |
| 138 | + echo -n "." | |
| 139 | + | |
| 140 | + sleep 1 | |
| 141 | + | |
| 142 | + count=$(ip netns exec $ns2 conntrack -L -p tcp --reply-port-src 8080 2>/dev/null | wc -l) | |
| 143 | + if [ $count -gt 0 ]; then | |
| 144 | + echo | |
| 145 | + echo "PASS: redirection took effect after $i seconds" | |
| 146 | + break | |
| 147 | + fi | |
| 148 | + | |
| 149 | + m=$((i%20)) | |
| 150 | + if [ $m -eq 0 ]; then | |
| 151 | + echo " waited for $i seconds" | |
| 152 | + fi | |
| 153 | +done | |
| 154 | + | |
| 155 | +expect="packets 1 bytes 60" | |
| 156 | +check_counter "$ns2" "redir" "$expect" | |
| 157 | +if [ $? -ne 0 ]; then | |
| 158 | + ret=1 | |
| 159 | +fi | |
| 160 | + | |
| 161 | +if [ $ret -eq 0 ];then | |
| 162 | + echo "PASS: redirection counter has expected values" | |
| 163 | +else | |
| 164 | + echo "ERROR: no tcp connection was redirected" | |
| 165 | +fi | |
| 166 | + | |
| 167 | +exit $ret | |