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 | frequency adjustment value (a positive integer) in | 33 | frequency adjustment value (a positive integer) in |
| 34 | parts per billion. | 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 | What: /sys/class/ptp/ptpN/n_alarms | 43 | What: /sys/class/ptp/ptpN/n_alarms |
| 37 | Date: September 2010 | 44 | Date: September 2010 |
| 38 | Contact: Richard Cochran <richardcochran@gmail.com> | 45 | Contact: Richard Cochran <richardcochran@gmail.com> |
| @@ -61,6 +68,19 @@ Description: · 22 unmodified lines | |||
| 61 | This file contains the number of programmable pins | 68 | This file contains the number of programmable pins |
| 62 | offered by the PTP hardware clock. | 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 | What: /sys/class/ptp/ptpN/pins | 84 | What: /sys/class/ptp/ptpN/pins |
| 65 | Date: March 2014 | 85 | Date: March 2014 |
| 66 | Contact: Richard Cochran <richardcochran@gmail.com> | 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 | For the properties relevant to the ethernet controller connected to the GPMC | 14 | For the properties relevant to the ethernet controller connected to the GPMC |
| 15 | refer to the binding documentation of the device. For example, the documentation | 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 | Child nodes need to specify the GPMC bus address width using the "bank-width" | 18 | Child nodes need to specify the GPMC bus address width using the "bank-width" |
| 19 | property but is possible that an ethernet controller also has a property to | 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 | ``ETHTOOL_MSG_FEC_SET`` set FEC settings | 212 | ``ETHTOOL_MSG_FEC_SET`` set FEC settings |
| 213 | ``ETHTOOL_MSG_MODULE_EEPROM_GET`` read SFP module EEPROM | 213 | ``ETHTOOL_MSG_MODULE_EEPROM_GET`` read SFP module EEPROM |
| 214 | ``ETHTOOL_MSG_STATS_GET`` get standard statistics | 214 | ``ETHTOOL_MSG_STATS_GET`` get standard statistics |
| 215 | ``ETHTOOL_MSG_PHC_VCLOCKS_GET`` get PHC virtual clocks info | ||
| 215 | ===================================== ================================ | 216 | ===================================== ================================ |
| 216 | 217 | ||
| 217 | Kernel to userspace: | 218 | Kernel to userspace: |
| @@ -250,6 +251,7 @@ Kernel to userspace: · 32 unmodified lines | |||
| 250 | ``ETHTOOL_MSG_FEC_NTF`` FEC settings | 251 | ``ETHTOOL_MSG_FEC_NTF`` FEC settings |
| 251 | ``ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY`` read SFP module EEPROM | 252 | ``ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY`` read SFP module EEPROM |
| 252 | ``ETHTOOL_MSG_STATS_GET_REPLY`` standard statistics | 253 | ``ETHTOOL_MSG_STATS_GET_REPLY`` standard statistics |
| 254 | ``ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY`` PHC virtual clocks info | ||
| 253 | ======================================== ================================= | 255 | ======================================== ================================= |
| 254 | 256 | ||
| 255 | ``GET`` requests are sent by userspace applications to retrieve device | 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 | etherStatsPkts512to1023Octets 512 1023 | 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 | Request translation | 1501 | Request translation |
| 1481 | =================== | 1502 | =================== |
| 1482 | 1503 | ||
| @@ -1575,4 +1596,5 @@ are netlink only. · 92 unmodified lines | |||
| 1575 | n/a ``ETHTOOL_MSG_CABLE_TEST_ACT`` | 1596 | n/a ``ETHTOOL_MSG_CABLE_TEST_ACT`` |
| 1576 | n/a ``ETHTOOL_MSG_CABLE_TEST_TDR_ACT`` | 1597 | n/a ``ETHTOOL_MSG_CABLE_TEST_TDR_ACT`` |
| 1577 | n/a ``ETHTOOL_MSG_TUNNEL_INFO_GET`` | 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 | Be conservative in what you do, be liberal in what you accept from others. | 110 | Be conservative in what you do, be liberal in what you accept from others. |
| 111 | If it's non-zero, we mark only out of window RST segments as INVALID. | 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 | nf_conntrack_tcp_loose - BOOLEAN | 119 | nf_conntrack_tcp_loose - BOOLEAN |
| 114 | - 0 - disabled | 120 | - 0 - disabled |
| 115 | - not 0 - enabled (default) | 121 | - not 0 - enabled (default) |
| @@ -4,10 +4,125 @@ · 3 unmodified lines | |||
| 4 | Linux Kernel TIPC | 4 | Linux Kernel TIPC |
| 5 | ================= | 5 | ================= |
| 6 | 6 | ||
| 7 | TIPC (Transparent Inter Process Communication) is a protocol that is | 7 | Introduction |
| 8 | specially designed for intra-cluster communication. | 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 | TIPC Base Types | 127 | TIPC Base Types |
| 13 | --------------- | 128 | --------------- |
| @@ -15009,6 +15009,13 @@ F: drivers/net/phy/dp83640* · 15008 unmodified lines | |||
| 15009 | F: drivers/ptp/* | 15009 | F: drivers/ptp/* |
| 15010 | F: include/linux/ptp_cl* | 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 | PTRACE SUPPORT | 15019 | PTRACE SUPPORT |
| 15013 | M: Oleg Nesterov <oleg@redhat.com> | 15020 | M: Oleg Nesterov <oleg@redhat.com> |
| 15014 | S: Maintained | 15021 | S: Maintained |
| @@ -581,7 +581,7 @@ · 580 unmodified lines | |||
| 581 | * EBI2. This has a 25MHz chrystal next to it, so no | 581 | * EBI2. This has a 25MHz chrystal next to it, so no |
| 582 | * clocking is needed. | 582 | * clocking is needed. |
| 583 | */ | 583 | */ |
| 584 | ethernet-ebi2@2,0 { | 584 | ethernet@2,0 { |
| 585 | compatible = "smsc,lan9221", "smsc,lan9115"; | 585 | compatible = "smsc,lan9221", "smsc,lan9115"; |
| 586 | reg = <2 0x0 0x100>; | 586 | reg = <2 0x0 0x100>; |
| 587 | /* | 587 | /* |
| @@ -598,8 +598,6 @@ · 10 unmodified lines | |||
| 598 | phy-mode = "mii"; | 598 | phy-mode = "mii"; |
| 599 | reg-io-width = <2>; | 599 | reg-io-width = <2>; |
| 600 | smsc,force-external-phy; | 600 | smsc,force-external-phy; |
| 601 | /* IRQ on edge falling = active low */ | ||
| 602 | smsc,irq-active-low; | ||
| 603 | smsc,irq-push-pull; | 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 | for (i = 0; i < prog->aux->size_poke_tab; i++) { | 571 | for (i = 0; i < prog->aux->size_poke_tab; i++) { |
| 572 | poke = &prog->aux->poke_tab[i]; | 572 | poke = &prog->aux->poke_tab[i]; |
| 573 | if (poke->aux && poke->aux != prog->aux) | ||
| 574 | continue; | ||
| 575 | |||
| 573 | WARN_ON_ONCE(READ_ONCE(poke->tailcall_target_stable)); | 576 | WARN_ON_ONCE(READ_ONCE(poke->tailcall_target_stable)); |
| 574 | 577 | ||
| 575 | if (poke->reason != BPF_POKE_REASON_TAIL_CALL) | 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 | static int bond_ipsec_add_sa(struct xfrm_state *xs) | 401 | static int bond_ipsec_add_sa(struct xfrm_state *xs) |
| 402 | { | 402 | { |
| 403 | struct net_device *bond_dev = xs->xso.dev; | 403 | struct net_device *bond_dev = xs->xso.dev; |
| 404 | struct bond_ipsec *ipsec; | ||
| 404 | struct bonding *bond; | 405 | struct bonding *bond; |
| 405 | struct slave *slave; | 406 | struct slave *slave; |
| 407 | int err; | ||
| 406 | 408 | ||
| 407 | if (!bond_dev) | 409 | if (!bond_dev) |
| 408 | return -EINVAL; | 410 | return -EINVAL; |
| 409 | 411 | ||
| 412 | rcu_read_lock(); | ||
| 410 | bond = netdev_priv(bond_dev); | 413 | bond = netdev_priv(bond_dev); |
| 411 | slave = rcu_dereference(bond->curr_active_slave); | 414 | slave = rcu_dereference(bond->curr_active_slave); |
| 412 | xs->xso.real_dev = slave->dev; | 415 | if (!slave) { |
| 413 | bond->xs = xs; | 416 | rcu_read_unlock(); |
| 417 | return -ENODEV; | ||
| 418 | } | ||
| 414 | 419 | ||
| 415 | if (!(slave->dev->xfrmdev_ops | 420 | if (!slave->dev->xfrmdev_ops || |
| 416 | && slave->dev->xfrmdev_ops->xdo_dev_state_add)) { | 421 | !slave->dev->xfrmdev_ops->xdo_dev_state_add || |
| 422 | netif_is_bond_master(slave->dev)) { | ||
| 417 | slave_warn(bond_dev, slave->dev, "Slave does not support ipsec offload\n"); | 423 | slave_warn(bond_dev, slave->dev, "Slave does not support ipsec offload\n"); |
| 424 | rcu_read_unlock(); | ||
| 418 | return -EINVAL; | 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 | static void bond_ipsec_del_sa(struct xfrm_state *xs) | 489 | static void bond_ipsec_del_sa(struct xfrm_state *xs) |
| 429 | { | 490 | { |
| 430 | struct net_device *bond_dev = xs->xso.dev; | 491 | struct net_device *bond_dev = xs->xso.dev; |
| 492 | struct bond_ipsec *ipsec; | ||
| 431 | struct bonding *bond; | 493 | struct bonding *bond; |
| 432 | struct slave *slave; | 494 | struct slave *slave; |
| 433 | 495 | ||
| 434 | if (!bond_dev) | 496 | if (!bond_dev) |
| 435 | return; | 497 | return; |
| 436 | 498 | ||
| 499 | rcu_read_lock(); | ||
| 437 | bond = netdev_priv(bond_dev); | 500 | bond = netdev_priv(bond_dev); |
| 438 | slave = rcu_dereference(bond->curr_active_slave); | 501 | slave = rcu_dereference(bond->curr_active_slave); |
| 439 | 502 | ||
| 440 | if (!slave) | 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 | 511 | if (!slave->dev->xfrmdev_ops || |
| 446 | && slave->dev->xfrmdev_ops->xdo_dev_state_delete)) { | 512 | !slave->dev->xfrmdev_ops->xdo_dev_state_delete || |
| 513 | netif_is_bond_master(slave->dev)) { | ||
| 447 | slave_warn(bond_dev, slave->dev, "%s: no slave xdo_dev_state_delete\n", __func__); | 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 | slave->dev->xfrmdev_ops->xdo_dev_state_delete(xs); | 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 | static bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) | 570 | static bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) |
| 460 | { | 571 | { |
| 461 | struct net_device *bond_dev = xs->xso.dev; | 572 | struct net_device *bond_dev = xs->xso.dev; |
| 462 | struct bonding *bond = netdev_priv(bond_dev); | 573 | struct net_device *real_dev; |
| 463 | struct slave *curr_active = rcu_dereference(bond->curr_active_slave); | 574 | struct slave *curr_active; |
| 464 | struct net_device *slave_dev = curr_active->dev; | 575 | struct bonding *bond; |
| 576 | int err; | ||
| 465 | 577 | ||
| 466 | if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) | 578 | bond = netdev_priv(bond_dev); |
| 467 | return true; | 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 | 583 | if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { |
| 470 | && slave_dev->xfrmdev_ops->xdo_dev_offload_ok)) { | 584 | err = false; |
| 471 | slave_warn(bond_dev, slave_dev, "%s: no slave xdo_dev_offload_ok\n", __func__); | 585 | goto out; |
| 472 | return false; | ||
| 473 | } | 586 | } |
| 474 | 587 | ||
| 475 | xs->xso.real_dev = slave_dev; | 588 | if (!xs->xso.real_dev) { |
| 476 | return slave_dev->xfrmdev_ops->xdo_dev_offload_ok(skb, xs); | 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 | static const struct xfrmdev_ops bond_xfrmdev_ops = { | 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 | return; | 1117 | return; |
| 991 | 1118 | ||
| 992 | #ifdef CONFIG_XFRM_OFFLOAD | 1119 | #ifdef CONFIG_XFRM_OFFLOAD |
| 993 | if (old_active && bond->xs) | 1120 | bond_ipsec_del_sa_all(bond); |
| 994 | bond_ipsec_del_sa(bond->xs); | ||
| 995 | #endif /* CONFIG_XFRM_OFFLOAD */ | 1121 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 996 | 1122 | ||
| 997 | if (new_active) { | 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 | #ifdef CONFIG_XFRM_OFFLOAD | 1194 | #ifdef CONFIG_XFRM_OFFLOAD |
| 1069 | if (new_active && bond->xs) { | 1195 | bond_ipsec_add_sa_all(bond); |
| 1070 | xfrm_dev_state_flush(dev_net(bond->dev), bond->dev, true); | ||
| 1071 | bond_ipsec_add_sa(bond->xs); | ||
| 1072 | } | ||
| 1073 | #endif /* CONFIG_XFRM_OFFLOAD */ | 1196 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 1074 | 1197 | ||
| 1075 | /* resend IGMP joins since active slave has changed or | 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 | return bond_event_changename(event_bond); | 3450 | return bond_event_changename(event_bond); |
| 3328 | case NETDEV_UNREGISTER: | 3451 | case NETDEV_UNREGISTER: |
| 3329 | bond_remove_proc_entry(event_bond); | 3452 | bond_remove_proc_entry(event_bond); |
| 3453 | xfrm_dev_state_flush(dev_net(bond_dev), bond_dev, true); | ||
| 3330 | break; | 3454 | break; |
| 3331 | case NETDEV_REGISTER: | 3455 | case NETDEV_REGISTER: |
| 3332 | bond_create_proc_entry(event_bond); | 3456 | bond_create_proc_entry(event_bond); |
| @@ -4894,7 +5018,8 @@ void bond_setup(struct net_device *bond_dev) · 1561 unmodified lines | |||
| 4894 | #ifdef CONFIG_XFRM_OFFLOAD | 5018 | #ifdef CONFIG_XFRM_OFFLOAD |
| 4895 | /* set up xfrm device ops (only supported in active-backup right now) */ | 5019 | /* set up xfrm device ops (only supported in active-backup right now) */ |
| 4896 | bond_dev->xfrmdev_ops = &bond_xfrmdev_ops; | 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 | #endif /* CONFIG_XFRM_OFFLOAD */ | 5023 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 4899 | 5024 | ||
| 4900 | /* don't acquire bond device's netif_tx_lock when transmitting */ | 5025 | /* don't acquire bond device's netif_tx_lock when transmitting */ |
| @@ -20,15 +20,6 @@ config CAIF_TTY · 19 unmodified lines | |||
| 20 | identified as N_CAIF. When this ldisc is opened from user space | 20 | identified as N_CAIF. When this ldisc is opened from user space |
| 21 | it will redirect the TTY's traffic into the CAIF stack. | 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 | config CAIF_VIRTIO | 23 | config CAIF_VIRTIO |
| 33 | tristate "CAIF virtio transport driver" | 24 | tristate "CAIF virtio transport driver" |
| 34 | depends on CAIF && HAS_DMA | 25 | depends on CAIF && HAS_DMA |
| @@ -4,8 +4,5 @@ ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG · 3 unmodified lines | |||
| 4 | # Serial interface | 4 | # Serial interface |
| 5 | obj-$(CONFIG_CAIF_TTY) += caif_serial.o | 5 | obj-$(CONFIG_CAIF_TTY) += caif_serial.o |
| 6 | 6 | ||
| 7 | # HSI interface | ||
| 8 | obj-$(CONFIG_CAIF_HSI) += caif_hsi.o | ||
| 9 | |||
| 10 | # Virtio interface | 7 | # Virtio interface |
| 11 | obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o | 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 | if (of_property_read_u32(port, "reg", | 419 | if (of_property_read_u32(port, "reg", |
| 420 | &port_num)) | 420 | &port_num)) |
| 421 | continue; | 421 | continue; |
| 422 | if (!(dev->port_mask & BIT(port_num))) | 422 | if (!(dev->port_mask & BIT(port_num))) { |
| 423 | of_node_put(port); | ||
| 423 | return -EINVAL; | 424 | return -EINVAL; |
| 425 | } | ||
| 424 | of_get_phy_mode(port, | 426 | of_get_phy_mode(port, |
| 425 | &dev->ports[port_num].interface); | 427 | &dev->ports[port_num].interface); |
| 426 | } | 428 | } |
| @@ -3583,6 +3583,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { · 3582 unmodified lines | |||
| 3583 | .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, | 3583 | .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, |
| 3584 | .port_max_speed_mode = mv88e6341_port_max_speed_mode, | 3584 | .port_max_speed_mode = mv88e6341_port_max_speed_mode, |
| 3585 | .port_tag_remap = mv88e6095_port_tag_remap, | 3585 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 3586 | .port_set_policy = mv88e6352_port_set_policy, | ||
| 3586 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, | 3587 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 3587 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, | 3588 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 3588 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, | 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 | .port_set_cmode = mv88e6341_port_set_cmode, | 3597 | .port_set_cmode = mv88e6341_port_set_cmode, |
| 3597 | .port_setup_message_port = mv88e6xxx_setup_message_port, | 3598 | .port_setup_message_port = mv88e6xxx_setup_message_port, |
| 3598 | .stats_snapshot = mv88e6390_g1_stats_snapshot, | 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 | .stats_get_sset_count = mv88e6320_stats_get_sset_count, | 3601 | .stats_get_sset_count = mv88e6320_stats_get_sset_count, |
| 3601 | .stats_get_strings = mv88e6320_stats_get_strings, | 3602 | .stats_get_strings = mv88e6320_stats_get_strings, |
| 3602 | .stats_get_stats = mv88e6390_stats_get_stats, | 3603 | .stats_get_stats = mv88e6390_stats_get_stats, |
| @@ -3606,6 +3607,9 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { · 3 unmodified lines | |||
| 3606 | .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, | 3607 | .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, |
| 3607 | .pot_clear = mv88e6xxx_g2_pot_clear, | 3608 | .pot_clear = mv88e6xxx_g2_pot_clear, |
| 3608 | .reset = mv88e6352_g1_reset, | 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 | .vtu_getnext = mv88e6352_g1_vtu_getnext, | 3613 | .vtu_getnext = mv88e6352_g1_vtu_getnext, |
| 3610 | .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, | 3614 | .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, |
| 3611 | .serdes_power = mv88e6390_serdes_power, | 3615 | .serdes_power = mv88e6390_serdes_power, |
| @@ -3619,6 +3623,11 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { · 7 unmodified lines | |||
| 3619 | .serdes_irq_enable = mv88e6390_serdes_irq_enable, | 3623 | .serdes_irq_enable = mv88e6390_serdes_irq_enable, |
| 3620 | .serdes_irq_status = mv88e6390_serdes_irq_status, | 3624 | .serdes_irq_status = mv88e6390_serdes_irq_status, |
| 3621 | .gpio_ops = &mv88e6352_gpio_ops, | 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 | .phylink_validate = mv88e6341_phylink_validate, | 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 | .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, | 4392 | .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, |
| 4384 | .port_max_speed_mode = mv88e6341_port_max_speed_mode, | 4393 | .port_max_speed_mode = mv88e6341_port_max_speed_mode, |
| 4385 | .port_tag_remap = mv88e6095_port_tag_remap, | 4394 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 4395 | .port_set_policy = mv88e6352_port_set_policy, | ||
| 4386 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, | 4396 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 4387 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, | 4397 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 4388 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, | 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 | .port_set_cmode = mv88e6341_port_set_cmode, | 4406 | .port_set_cmode = mv88e6341_port_set_cmode, |
| 4397 | .port_setup_message_port = mv88e6xxx_setup_message_port, | 4407 | .port_setup_message_port = mv88e6xxx_setup_message_port, |
| 4398 | .stats_snapshot = mv88e6390_g1_stats_snapshot, | 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 | .stats_get_sset_count = mv88e6320_stats_get_sset_count, | 4410 | .stats_get_sset_count = mv88e6320_stats_get_sset_count, |
| 4401 | .stats_get_strings = mv88e6320_stats_get_strings, | 4411 | .stats_get_strings = mv88e6320_stats_get_strings, |
| 4402 | .stats_get_stats = mv88e6390_stats_get_stats, | 4412 | .stats_get_stats = mv88e6390_stats_get_stats, |
| @@ -4406,6 +4416,9 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { · 3 unmodified lines | |||
| 4406 | .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, | 4416 | .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, |
| 4407 | .pot_clear = mv88e6xxx_g2_pot_clear, | 4417 | .pot_clear = mv88e6xxx_g2_pot_clear, |
| 4408 | .reset = mv88e6352_g1_reset, | 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 | .vtu_getnext = mv88e6352_g1_vtu_getnext, | 4422 | .vtu_getnext = mv88e6352_g1_vtu_getnext, |
| 4410 | .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, | 4423 | .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, |
| 4411 | .serdes_power = mv88e6390_serdes_power, | 4424 | .serdes_power = mv88e6390_serdes_power, |
| @@ -4421,6 +4434,11 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { · 9 unmodified lines | |||
| 4421 | .gpio_ops = &mv88e6352_gpio_ops, | 4434 | .gpio_ops = &mv88e6352_gpio_ops, |
| 4422 | .avb_ops = &mv88e6390_avb_ops, | 4435 | .avb_ops = &mv88e6390_avb_ops, |
| 4423 | .ptp_ops = &mv88e6352_ptp_ops, | 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 | .phylink_validate = mv88e6341_phylink_validate, | 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 | int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) | 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 | return 0; | 726 | return 0; |
| 727 | 727 | ||
| 728 | return ARRAY_SIZE(mv88e6390_serdes_hw_stats); | 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 | struct mv88e6390_serdes_hw_stat *stat; | 734 | struct mv88e6390_serdes_hw_stat *stat; |
| 735 | int i; | 735 | int i; |
| 736 | 736 | ||
| 737 | if (mv88e6390_serdes_get_lane(chip, port) < 0) | 737 | if (mv88e6xxx_serdes_get_lane(chip, port) < 0) |
| 738 | return 0; | 738 | return 0; |
| 739 | 739 | ||
| 740 | for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { | 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 | int lane; | 770 | int lane; |
| 771 | int i; | 771 | int i; |
| 772 | 772 | ||
| 773 | lane = mv88e6390_serdes_get_lane(chip, port); | 773 | lane = mv88e6xxx_serdes_get_lane(chip, port); |
| 774 | if (lane < 0) | 774 | if (lane < 0) |
| 775 | return 0; | 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 | for (i = 0; i < ds->num_ports; i++) { | 123 | for (i = 0; i < ds->num_ports; i++) { |
| 124 | mac[i] = default_mac; | 124 | mac[i] = default_mac; |
| 125 | if (i == dsa_upstream_port(priv->ds, i)) { | 125 | |
| 126 | /* STP doesn't get called for CPU port, so we need to | 126 | /* Let sja1105_bridge_stp_state_set() keep address learning |
| 127 | * set the I/O parameters statically. | 127 | * enabled for the CPU port. |
| 128 | */ | 128 | */ |
| 129 | mac[i].dyn_learn = true; | 129 | if (dsa_is_cpu_port(ds, i)) |
| 130 | mac[i].ingress = true; | 130 | priv->learn_ena |= BIT(i); |
| 131 | mac[i].egress = true; | ||
| 132 | } | ||
| 133 | } | 131 | } |
| 134 | 132 | ||
| 135 | return 0; | 133 | return 0; |
| @@ -594,6 +594,11 @@ int atl1c_phy_init(struct atl1c_hw *hw) · 593 unmodified lines | |||
| 594 | int ret_val; | 594 | int ret_val; |
| 595 | u16 mii_bmcr_data = BMCR_RESET; | 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 | if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) || | 602 | if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) || |
| 598 | (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) { | 603 | (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) { |
| 599 | dev_err(&pdev->dev, "Error get phy ID\n"); | 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 | switch (mode) { | 1641 | switch (mode) { |
| 1642 | case GENET_POWER_PASSIVE: | 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 | if (GENET_IS_V5(priv)) { | 1645 | if (GENET_IS_V5(priv)) { |
| 1645 | reg &= ~(EXT_PWR_DOWN_PHY_EN | | 1646 | reg &= ~(EXT_PWR_DOWN_PHY_EN | |
| 1646 | EXT_PWR_DOWN_PHY_RD | | 1647 | EXT_PWR_DOWN_PHY_RD | |
| @@ -3237,15 +3238,21 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, · 1590 unmodified lines | |||
| 3237 | /* Returns a reusable dma control register value */ | 3238 | /* Returns a reusable dma control register value */ |
| 3238 | static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) | 3239 | static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) |
| 3239 | { | 3240 | { |
| 3241 | unsigned int i; | ||
| 3240 | u32 reg; | 3242 | u32 reg; |
| 3241 | u32 dma_ctrl; | 3243 | u32 dma_ctrl; |
| 3242 | 3244 | ||
| 3243 | /* disable DMA */ | 3245 | /* disable DMA */ |
| 3244 | dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; | 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 | reg = bcmgenet_tdma_readl(priv, DMA_CTRL); | 3249 | reg = bcmgenet_tdma_readl(priv, DMA_CTRL); |
| 3246 | reg &= ~dma_ctrl; | 3250 | reg &= ~dma_ctrl; |
| 3247 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); | 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 | reg = bcmgenet_rdma_readl(priv, DMA_CTRL); | 3256 | reg = bcmgenet_rdma_readl(priv, DMA_CTRL); |
| 3250 | reg &= ~dma_ctrl; | 3257 | reg &= ~dma_ctrl; |
| 3251 | bcmgenet_rdma_writel(priv, reg, DMA_CTRL); | 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 | struct bcmgenet_priv *priv = netdev_priv(dev); | 3300 | struct bcmgenet_priv *priv = netdev_priv(dev); |
| 3294 | unsigned long dma_ctrl; | 3301 | unsigned long dma_ctrl; |
| 3295 | u32 reg; | ||
| 3296 | int ret; | 3302 | int ret; |
| 3297 | 3303 | ||
| 3298 | netif_dbg(priv, ifup, dev, "bcmgenet_open\n"); | 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 | bcmgenet_set_hw_addr(priv, dev->dev_addr); | 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 | /* Disable RX/TX DMA and flush TX queues */ | 3327 | /* Disable RX/TX DMA and flush TX queues */ |
| 3328 | dma_ctrl = bcmgenet_dma_disable(priv); | 3328 | dma_ctrl = bcmgenet_dma_disable(priv); |
| 3329 | 3329 | ||
| @@ -4139,7 +4139,6 @@ static int bcmgenet_resume(struct device *d) · 809 unmodified lines | |||
| 4139 | struct bcmgenet_priv *priv = netdev_priv(dev); | 4139 | struct bcmgenet_priv *priv = netdev_priv(dev); |
| 4140 | struct bcmgenet_rxnfc_rule *rule; | 4140 | struct bcmgenet_rxnfc_rule *rule; |
| 4141 | unsigned long dma_ctrl; | 4141 | unsigned long dma_ctrl; |
| 4142 | u32 reg; | ||
| 4143 | int ret; | 4142 | int ret; |
| 4144 | 4143 | ||
| 4145 | if (!netif_running(dev)) | 4144 | if (!netif_running(dev)) |
| @@ -4176,12 +4175,6 @@ static int bcmgenet_resume(struct device *d) · 30 unmodified lines | |||
| 4176 | if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) | 4175 | if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) |
| 4177 | bcmgenet_hfb_create_rxnfc_filter(priv, rule); | 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 | /* Disable RX/TX DMA and flush TX queues */ | 4178 | /* Disable RX/TX DMA and flush TX queues */ |
| 4186 | dma_ctrl = bcmgenet_dma_disable(priv); | 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 | reg |= CMD_RX_EN; | 186 | reg |= CMD_RX_EN; |
| 187 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | 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 | reg = UMAC_IRQ_MPD_R; | 189 | reg = UMAC_IRQ_MPD_R; |
| 196 | if (hfb_enable) | 190 | if (hfb_enable) |
| 197 | reg |= UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM; | 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 | unsigned int i; | 2644 | unsigned int i; |
| 2645 | 2645 | ||
| 2646 | if (!is_uld(adap)) | ||
| 2647 | return; | ||
| 2648 | |||
| 2646 | mutex_lock(&uld_mutex); | 2649 | mutex_lock(&uld_mutex); |
| 2647 | list_del(&adap->list_node); | 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 | destroy_workqueue(adapter->workq); | 7145 | destroy_workqueue(adapter->workq); |
| 7143 | 7146 | ||
| 7144 | if (is_uld(adapter)) { | 7147 | detach_ulds(adapter); |
| 7145 | detach_ulds(adapter); | 7148 | |
| 7146 | t4_uld_clean_up(adapter); | 7149 | for_each_port(adapter, i) |
| 7147 | } | 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 | adap_free_hma_mem(adapter); | 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 | cxgb4_free_mps_ref_entries(adapter); | 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 | debugfs_remove_recursive(adapter->debugfs_root); | 7161 | debugfs_remove_recursive(adapter->debugfs_root); |
| 7160 | 7162 | ||
| 7161 | if (!is_t4(adapter->params.chip)) | 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 | unsigned int i; | 582 | unsigned int i; |
| 583 | 583 | ||
| 584 | if (!is_uld(adap)) | ||
| 585 | return; | ||
| 586 | |||
| 584 | mutex_lock(&uld_mutex); | 587 | mutex_lock(&uld_mutex); |
| 585 | for (i = 0; i < CXGB4_ULD_MAX; i++) { | 588 | for (i = 0; i < CXGB4_ULD_MAX; i++) { |
| 586 | if (!adap->uld[i].handle) | 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 | err = pci_enable_device(pdev); | 1470 | err = pci_enable_device(pdev); |
| 1471 | if (err) | 1471 | if (err) |
| 1472 | return -ENXIO; | 1472 | return err; |
| 1473 | 1473 | ||
| 1474 | err = pci_request_regions(pdev, "gvnic-cfg"); | 1474 | err = pci_request_regions(pdev, "gvnic-cfg"); |
| 1475 | if (err) | 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 | pci_set_master(pdev); | 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 | if (err) { | 1481 | if (err) { |
| 1482 | dev_err(&pdev->dev, "Failed to set dma mask: err=%d\n", err); | 1482 | dev_err(&pdev->dev, "Failed to set dma mask: err=%d\n", err); |
| 1483 | goto abort_with_pci_region; | 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 | reg_bar = pci_iomap(pdev, GVE_REGISTER_BAR, 0); | 1486 | reg_bar = pci_iomap(pdev, GVE_REGISTER_BAR, 0); |
| 1494 | if (!reg_bar) { | 1487 | if (!reg_bar) { |
| 1495 | dev_err(&pdev->dev, "Failed to map pci bar!\n"); | 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 | dev = alloc_etherdev_mqs(sizeof(*priv), max_tx_queues, max_rx_queues); | 1505 | dev = alloc_etherdev_mqs(sizeof(*priv), max_tx_queues, max_rx_queues); |
| 1513 | if (!dev) { | 1506 | if (!dev) { |
| 1514 | dev_err(&pdev->dev, "could not allocate netdev\n"); | 1507 | dev_err(&pdev->dev, "could not allocate netdev\n"); |
| 1508 | err = -ENOMEM; | ||
| 1515 | goto abort_with_db_bar; | 1509 | goto abort_with_db_bar; |
| 1516 | } | 1510 | } |
| 1517 | SET_NETDEV_DEV(dev, &pdev->dev); | 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 | err = register_netdev(dev); | 1560 | err = register_netdev(dev); |
| 1567 | if (err) | 1561 | if (err) |
| 1568 | goto abort_with_wq; | 1562 | goto abort_with_gve_init; |
| 1569 | 1563 | ||
| 1570 | dev_info(&pdev->dev, "GVE version %s\n", gve_version_str); | 1564 | dev_info(&pdev->dev, "GVE version %s\n", gve_version_str); |
| 1571 | dev_info(&pdev->dev, "GVE queue format %d\n", (int)priv->queue_format); | 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 | queue_work(priv->gve_wq, &priv->service_task); | 1567 | queue_work(priv->gve_wq, &priv->service_task); |
| 1574 | return 0; | 1568 | return 0; |
| 1575 | 1569 | ||
| 1570 | abort_with_gve_init: | ||
| 1571 | gve_teardown_priv_resources(priv); | ||
| 1572 | |||
| 1576 | abort_with_wq: | 1573 | abort_with_wq: |
| 1577 | destroy_workqueue(priv->gve_wq); | 1574 | destroy_workqueue(priv->gve_wq); |
| 1578 | 1575 | ||
| @@ -1590,7 +1587,7 @@ abort_with_pci_region: · 11 unmodified lines | |||
| 1590 | 1587 | ||
| 1591 | abort_with_enabled: | 1588 | abort_with_enabled: |
| 1592 | pci_disable_device(pdev); | 1589 | pci_disable_device(pdev); |
| 1593 | return -ENXIO; | 1590 | return err; |
| 1594 | } | 1591 | } |
| 1595 | 1592 | ||
| 1596 | static void gve_remove(struct pci_dev *pdev) | 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 | return 0; | 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 | if (eop && buf_len <= priv->rx_copybreak) { | 569 | if (eop && buf_len <= priv->rx_copybreak) { |
| 577 | rx->skb_head = gve_rx_copy(priv->dev, napi, | 570 | rx->skb_head = gve_rx_copy(priv->dev, napi, |
| 578 | &buf_state->page_info, buf_len, 0); | 571 | &buf_state->page_info, buf_len, 0); |
| @@ -2420,9 +2420,10 @@ out: · 2419 unmodified lines | |||
| 2420 | 2420 | ||
| 2421 | static void __ibmvnic_reset(struct work_struct *work) | 2421 | static void __ibmvnic_reset(struct work_struct *work) |
| 2422 | { | 2422 | { |
| 2423 | struct ibmvnic_rwi *rwi; | ||
| 2424 | struct ibmvnic_adapter *adapter; | 2423 | struct ibmvnic_adapter *adapter; |
| 2425 | bool saved_state = false; | 2424 | bool saved_state = false; |
| 2425 | struct ibmvnic_rwi *tmprwi; | ||
| 2426 | struct ibmvnic_rwi *rwi; | ||
| 2426 | unsigned long flags; | 2427 | unsigned long flags; |
| 2427 | u32 reset_state; | 2428 | u32 reset_state; |
| 2428 | int rc = 0; | 2429 | int rc = 0; |
| @@ -2489,7 +2490,7 @@ static void __ibmvnic_reset(struct work_struct *work) · 60 unmodified lines | |||
| 2489 | } else { | 2490 | } else { |
| 2490 | rc = do_reset(adapter, rwi, reset_state); | 2491 | rc = do_reset(adapter, rwi, reset_state); |
| 2491 | } | 2492 | } |
| 2492 | kfree(rwi); | 2493 | tmprwi = rwi; |
| 2493 | adapter->last_reset_time = jiffies; | 2494 | adapter->last_reset_time = jiffies; |
| 2494 | 2495 | ||
| 2495 | if (rc) | 2496 | if (rc) |
| @@ -2497,8 +2498,23 @@ static void __ibmvnic_reset(struct work_struct *work) · 1 unmodified line | |||
| 2497 | 2498 | ||
| 2498 | rwi = get_next_rwi(adapter); | 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 | if (rwi && (rwi->reset_reason == VNIC_RESET_FAILOVER || | 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 | adapter->force_reset_recovery = true; | 2518 | adapter->force_reset_recovery = true; |
| 2503 | } | 2519 | } |
| 2504 | 2520 | ||
| @@ -7664,6 +7664,7 @@ err_flashmap: · 7663 unmodified lines | |||
| 7664 | err_ioremap: | 7664 | err_ioremap: |
| 7665 | free_netdev(netdev); | 7665 | free_netdev(netdev); |
| 7666 | err_alloc_etherdev: | 7666 | err_alloc_etherdev: |
| 7667 | pci_disable_pcie_error_reporting(pdev); | ||
| 7667 | pci_release_mem_regions(pdev); | 7668 | pci_release_mem_regions(pdev); |
| 7668 | err_pci_reg: | 7669 | err_pci_reg: |
| 7669 | err_dma: | 7670 | err_dma: |
| @@ -2227,6 +2227,7 @@ err_sw_init: · 2226 unmodified lines | |||
| 2227 | err_ioremap: | 2227 | err_ioremap: |
| 2228 | free_netdev(netdev); | 2228 | free_netdev(netdev); |
| 2229 | err_alloc_netdev: | 2229 | err_alloc_netdev: |
| 2230 | pci_disable_pcie_error_reporting(pdev); | ||
| 2230 | pci_release_mem_regions(pdev); | 2231 | pci_release_mem_regions(pdev); |
| 2231 | err_pci_reg: | 2232 | err_pci_reg: |
| 2232 | err_dma: | 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 | err_ioremap: | 3798 | err_ioremap: |
| 3799 | free_netdev(netdev); | 3799 | free_netdev(netdev); |
| 3800 | err_alloc_etherdev: | 3800 | err_alloc_etherdev: |
| 3801 | pci_disable_pcie_error_reporting(pdev); | ||
| 3801 | pci_release_regions(pdev); | 3802 | pci_release_regions(pdev); |
| 3802 | err_pci_reg: | 3803 | err_pci_reg: |
| 3803 | err_dma: | 3804 | err_dma: |
| @@ -931,6 +931,7 @@ static void igb_configure_msix(struct igb_adapter *adapter) · 930 unmodified lines | |||
| 931 | **/ | 931 | **/ |
| 932 | static int igb_request_msix(struct igb_adapter *adapter) | 932 | static int igb_request_msix(struct igb_adapter *adapter) |
| 933 | { | 933 | { |
| 934 | unsigned int num_q_vectors = adapter->num_q_vectors; | ||
| 934 | struct net_device *netdev = adapter->netdev; | 935 | struct net_device *netdev = adapter->netdev; |
| 935 | int i, err = 0, vector = 0, free_vector = 0; | 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 | if (err) | 940 | if (err) |
| 940 | goto err_out; | 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 | struct igb_q_vector *q_vector = adapter->q_vector[i]; | 950 | struct igb_q_vector *q_vector = adapter->q_vector[i]; |
| 944 | 951 | ||
| 945 | vector++; | 952 | vector++; |
| @@ -1678,14 +1685,15 @@ static bool is_any_txtime_enabled(struct igb_adapter *adapter) · 732 unmodified lines | |||
| 1678 | **/ | 1685 | **/ |
| 1679 | static void igb_config_tx_modes(struct igb_adapter *adapter, int queue) | 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 | struct net_device *netdev = adapter->netdev; | 1688 | struct net_device *netdev = adapter->netdev; |
| 1683 | struct e1000_hw *hw = &adapter->hw; | 1689 | struct e1000_hw *hw = &adapter->hw; |
| 1690 | struct igb_ring *ring; | ||
| 1684 | u32 tqavcc, tqavctrl; | 1691 | u32 tqavcc, tqavctrl; |
| 1685 | u16 value; | 1692 | u16 value; |
| 1686 | 1693 | ||
| 1687 | WARN_ON(hw->mac.type != e1000_i210); | 1694 | WARN_ON(hw->mac.type != e1000_i210); |
| 1688 | WARN_ON(queue < 0 || queue > 1); | 1695 | WARN_ON(queue < 0 || queue > 1); |
| 1696 | ring = adapter->tx_ring[queue]; | ||
| 1689 | 1697 | ||
| 1690 | /* If any of the Qav features is enabled, configure queues as SR and | 1698 | /* If any of the Qav features is enabled, configure queues as SR and |
| 1691 | * with HIGH PRIO. If none is, then configure them with LOW PRIO and | 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 | err_ioremap: | 3623 | err_ioremap: |
| 3616 | free_netdev(netdev); | 3624 | free_netdev(netdev); |
| 3617 | err_alloc_etherdev: | 3625 | err_alloc_etherdev: |
| 3626 | pci_disable_pcie_error_reporting(pdev); | ||
| 3618 | pci_release_mem_regions(pdev); | 3627 | pci_release_mem_regions(pdev); |
| 3619 | err_pci_reg: | 3628 | err_pci_reg: |
| 3620 | err_dma: | 3629 | err_dma: |
| @@ -4835,6 +4844,8 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring) · 1214 unmodified lines | |||
| 4835 | DMA_TO_DEVICE); | 4844 | DMA_TO_DEVICE); |
| 4836 | } | 4845 | } |
| 4837 | 4846 | ||
| 4847 | tx_buffer->next_to_watch = NULL; | ||
| 4848 | |||
| 4838 | /* move us one more past the eop_desc for start of next pkt */ | 4849 | /* move us one more past the eop_desc for start of next pkt */ |
| 4839 | tx_buffer++; | 4850 | tx_buffer++; |
| 4840 | i++; | 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 | if (hw->phy.ops.read_reg) | 578 | if (hw->phy.ops.read_reg) |
| 579 | return hw->phy.ops.read_reg(hw, offset, data); | 579 | return hw->phy.ops.read_reg(hw, offset, data); |
| 580 | 580 | ||
| 581 | return 0; | 581 | return -EOPNOTSUPP; |
| 582 | } | 582 | } |
| 583 | 583 | ||
| 584 | void igc_reinit_locked(struct igc_adapter *); | 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 | igc_unmap_tx_buffer(tx_ring->dev, tx_buffer); | 232 | igc_unmap_tx_buffer(tx_ring->dev, tx_buffer); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | tx_buffer->next_to_watch = NULL; | ||
| 236 | |||
| 235 | /* move us one more past the eop_desc for start of next pkt */ | 237 | /* move us one more past the eop_desc for start of next pkt */ |
| 236 | tx_buffer++; | 238 | tx_buffer++; |
| 237 | i++; | 239 | i++; |
| @@ -6054,6 +6056,7 @@ err_sw_init: · 5816 unmodified lines | |||
| 6054 | err_ioremap: | 6056 | err_ioremap: |
| 6055 | free_netdev(netdev); | 6057 | free_netdev(netdev); |
| 6056 | err_alloc_etherdev: | 6058 | err_alloc_etherdev: |
| 6059 | pci_disable_pcie_error_reporting(pdev); | ||
| 6057 | pci_release_mem_regions(pdev); | 6060 | pci_release_mem_regions(pdev); |
| 6058 | err_pci_reg: | 6061 | err_pci_reg: |
| 6059 | err_dma: | 6062 | err_dma: |
| @@ -11067,6 +11067,7 @@ err_ioremap: · 11066 unmodified lines | |||
| 11067 | disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); | 11067 | disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); |
| 11068 | free_netdev(netdev); | 11068 | free_netdev(netdev); |
| 11069 | err_alloc_etherdev: | 11069 | err_alloc_etherdev: |
| 11070 | pci_disable_pcie_error_reporting(pdev); | ||
| 11070 | pci_release_mem_regions(pdev); | 11071 | pci_release_mem_regions(pdev); |
| 11071 | err_pci_reg: | 11072 | err_pci_reg: |
| 11072 | err_dma: | 11073 | err_dma: |
| @@ -211,7 +211,7 @@ struct xfrm_state *ixgbevf_ipsec_find_rx_state(struct ixgbevf_ipsec *ipsec, · 210 unmodified lines | |||
| 211 | static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs, | 211 | static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs, |
| 212 | u32 *mykey, u32 *mysalt) | 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 | unsigned char *key_data; | 215 | unsigned char *key_data; |
| 216 | char *alg_name = NULL; | 216 | char *alg_name = NULL; |
| 217 | int key_len; | 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 | static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs) | 261 | static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs) |
| 262 | { | 262 | { |
| 263 | struct net_device *dev = xs->xso.dev; | 263 | struct net_device *dev = xs->xso.real_dev; |
| 264 | struct ixgbevf_adapter *adapter = netdev_priv(dev); | 264 | struct ixgbevf_adapter *adapter; |
| 265 | struct ixgbevf_ipsec *ipsec = adapter->ipsec; | 265 | struct ixgbevf_ipsec *ipsec; |
| 266 | u16 sa_idx; | 266 | u16 sa_idx; |
| 267 | int ret; | 267 | int ret; |
| 268 | 268 | ||
| 269 | adapter = netdev_priv(dev); | ||
| 270 | ipsec = adapter->ipsec; | ||
| 271 | |||
| 269 | if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) { | 272 | if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) { |
| 270 | netdev_err(dev, "Unsupported protocol 0x%04x for IPsec offload\n", | 273 | netdev_err(dev, "Unsupported protocol 0x%04x for IPsec offload\n", |
| 271 | xs->id.proto); | 274 | xs->id.proto); |
| @@ -383,11 +386,14 @@ static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs) · 111 unmodified lines | |||
| 383 | **/ | 386 | **/ |
| 384 | static void ixgbevf_ipsec_del_sa(struct xfrm_state *xs) | 387 | static void ixgbevf_ipsec_del_sa(struct xfrm_state *xs) |
| 385 | { | 388 | { |
| 386 | struct net_device *dev = xs->xso.dev; | 389 | struct net_device *dev = xs->xso.real_dev; |
| 387 | struct ixgbevf_adapter *adapter = netdev_priv(dev); | 390 | struct ixgbevf_adapter *adapter; |
| 388 | struct ixgbevf_ipsec *ipsec = adapter->ipsec; | 391 | struct ixgbevf_ipsec *ipsec; |
| 389 | u16 sa_idx; | 392 | u16 sa_idx; |
| 390 | 393 | ||
| 394 | adapter = netdev_priv(dev); | ||
| 395 | ipsec = adapter->ipsec; | ||
| 396 | |||
| 391 | if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) { | 397 | if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) { |
| 392 | sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX; | 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 | skb_frag_off_set(frag, pp->rx_offset_correction); | 2299 | skb_frag_off_set(frag, pp->rx_offset_correction); |
| 2300 | skb_frag_size_set(frag, data_len); | 2300 | skb_frag_size_set(frag, data_len); |
| 2301 | __skb_frag_set_page(frag, page); | 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 | } else { | 2302 | } else { |
| 2313 | page_pool_put_full_page(rxq->page_pool, page, true); | 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 | *size -= len; | 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 | return test_bit(lmac_id, &cgx->lmac_bmap); | 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 | struct mac_ops *get_mac_ops(void *cgxd) | 105 | struct mac_ops *get_mac_ops(void *cgxd) |
| 90 | { | 106 | { |
| 91 | if (!cgxd) | 107 | if (!cgxd) |
| @@ -211,37 +227,257 @@ static u64 mac2u64 (u8 *mac_addr) · 119 unmodified lines | |||
| 211 | return mac; | 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 | int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr) | 238 | int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr) |
| 215 | { | 239 | { |
| 216 | struct cgx *cgx_dev = cgx_get_pdata(cgx_id); | 240 | struct cgx *cgx_dev = cgx_get_pdata(cgx_id); |
| 241 | struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | ||
| 217 | struct mac_ops *mac_ops; | 242 | struct mac_ops *mac_ops; |
| 243 | int index, id; | ||
| 218 | u64 cfg; | 244 | u64 cfg; |
| 219 | 245 | ||
| 246 | /* access mac_ops to know csr_offset */ | ||
| 220 | mac_ops = cgx_dev->mac_ops; | 247 | mac_ops = cgx_dev->mac_ops; |
| 248 | |||
| 221 | /* copy 6bytes from macaddr */ | 249 | /* copy 6bytes from macaddr */ |
| 222 | /* memcpy(&cfg, mac_addr, 6); */ | 250 | /* memcpy(&cfg, mac_addr, 6); */ |
| 223 | 251 | ||
| 224 | cfg = mac2u64 (mac_addr); | 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 | cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64)lmac_id << 49)); | 259 | cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64)lmac_id << 49)); |
| 228 | 260 | ||
| 229 | cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); | 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 | cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); | 264 | cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); |
| 232 | 265 | ||
| 233 | return 0; | 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 | u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) | 465 | u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) |
| 237 | { | 466 | { |
| 238 | struct cgx *cgx_dev = cgx_get_pdata(cgx_id); | 467 | struct cgx *cgx_dev = cgx_get_pdata(cgx_id); |
| 468 | struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev); | ||
| 239 | struct mac_ops *mac_ops; | 469 | struct mac_ops *mac_ops; |
| 470 | int index; | ||
| 240 | u64 cfg; | 471 | u64 cfg; |
| 472 | int id; | ||
| 241 | 473 | ||
| 242 | mac_ops = cgx_dev->mac_ops; | 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 | return cfg & CGX_RX_DMAC_ADR_MASK; | 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 | void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) | 533 | void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) |
| 298 | { | 534 | { |
| 299 | struct cgx *cgx = cgx_get_pdata(cgx_id); | 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 | struct mac_ops *mac_ops; | 538 | struct mac_ops *mac_ops; |
| 539 | int index, i; | ||
| 301 | u64 cfg = 0; | 540 | u64 cfg = 0; |
| 541 | int id; | ||
| 302 | 542 | ||
| 303 | if (!cgx) | 543 | if (!cgx) |
| 304 | return; | 544 | return; |
| 305 | 545 | ||
| 546 | id = get_sequence_id_of_lmac(cgx, lmac_id); | ||
| 547 | |||
| 306 | mac_ops = cgx->mac_ops; | 548 | mac_ops = cgx->mac_ops; |
| 307 | if (enable) { | 549 | if (enable) { |
| 308 | /* Enable promiscuous mode on LMAC */ | 550 | /* Enable promiscuous mode on LMAC */ |
| 309 | cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); | 551 | cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); |
| 310 | cfg &= ~(CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE); | 552 | cfg &= ~CGX_DMAC_CAM_ACCEPT; |
| 311 | cfg |= CGX_DMAC_BCAST_MODE; | 553 | cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_MCAST_MODE); |
| 312 | cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); | 554 | cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); |
| 313 | 555 | ||
| 314 | cfg = cgx_read(cgx, 0, | 556 | for (i = 0; i < max_dmac; i++) { |
| 315 | (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); | 557 | index = id * max_dmac + i; |
| 316 | cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE; | 558 | cfg = cgx_read(cgx, 0, |
| 317 | cgx_write(cgx, 0, | 559 | (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8)); |
| 318 | (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); | 560 | cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE; |
| 561 | cgx_write(cgx, 0, | ||
| 562 | (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8), cfg); | ||
| 563 | } | ||
| 319 | } else { | 564 | } else { |
| 320 | /* Disable promiscuous mode */ | 565 | /* Disable promiscuous mode */ |
| 321 | cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); | 566 | cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); |
| 322 | cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE; | 567 | cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE; |
| 323 | cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); | 568 | cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); |
| 324 | cfg = cgx_read(cgx, 0, | 569 | for (i = 0; i < max_dmac; i++) { |
| 325 | (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); | 570 | index = id * max_dmac + i; |
| 326 | cfg |= CGX_DMAC_CAM_ADDR_ENABLE; | 571 | cfg = cgx_read(cgx, 0, |
| 327 | cgx_write(cgx, 0, | 572 | (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8)); |
| 328 | (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); | 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 | lmac->cgx = cgx; | 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 | init_waitqueue_head(&lmac->wq_cmd_cmplt); | 1498 | init_waitqueue_head(&lmac->wq_cmd_cmplt); |
| 1238 | mutex_init(&lmac->cmd_lock); | 1499 | mutex_init(&lmac->cmd_lock); |
| 1239 | spin_lock_init(&lmac->event_cb_lock); | 1500 | spin_lock_init(&lmac->event_cb_lock); |
| @@ -1274,6 +1535,7 @@ static int cgx_lmac_exit(struct cgx *cgx) · 34 unmodified lines | |||
| 1274 | continue; | 1535 | continue; |
| 1275 | cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, false); | 1536 | cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, false); |
| 1276 | cgx_configure_interrupt(cgx, lmac, lmac->lmac_id, true); | 1537 | cgx_configure_interrupt(cgx, lmac, lmac->lmac_id, true); |
| 1538 | kfree(lmac->mac_to_index_bmap.bmap); | ||
| 1277 | kfree(lmac->name); | 1539 | kfree(lmac->name); |
| 1278 | kfree(lmac); | 1540 | kfree(lmac); |
| 1279 | } | 1541 | } |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | |||
| 23 | 23 | ||
| 24 | #define CGX_ID_MASK 0x7 | 24 | #define CGX_ID_MASK 0x7 |
| 25 | #define MAX_LMAC_PER_CGX 4 | 25 | #define MAX_LMAC_PER_CGX 4 |
| 26 | #define MAX_DMAC_ENTRIES_PER_CGX 32 | ||
| 26 | #define CGX_FIFO_LEN 65536 /* 64K for both Rx & Tx */ | 27 | #define CGX_FIFO_LEN 65536 /* 64K for both Rx & Tx */ |
| 27 | #define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX) | 28 | #define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX) |
| 28 | 29 | ||
| @@ -46,10 +47,12 @@ · 17 unmodified lines | |||
| 46 | #define CGXX_CMRX_RX_DMAC_CTL0 (0x1F8 + mac_ops->csr_offset) | 47 | #define CGXX_CMRX_RX_DMAC_CTL0 (0x1F8 + mac_ops->csr_offset) |
| 47 | #define CGX_DMAC_CTL0_CAM_ENABLE BIT_ULL(3) | 48 | #define CGX_DMAC_CTL0_CAM_ENABLE BIT_ULL(3) |
| 48 | #define CGX_DMAC_CAM_ACCEPT BIT_ULL(3) | 49 | #define CGX_DMAC_CAM_ACCEPT BIT_ULL(3) |
| 50 | #define CGX_DMAC_MCAST_MODE_CAM BIT_ULL(2) | ||
| 49 | #define CGX_DMAC_MCAST_MODE BIT_ULL(1) | 51 | #define CGX_DMAC_MCAST_MODE BIT_ULL(1) |
| 50 | #define CGX_DMAC_BCAST_MODE BIT_ULL(0) | 52 | #define CGX_DMAC_BCAST_MODE BIT_ULL(0) |
| 51 | #define CGXX_CMRX_RX_DMAC_CAM0 (0x200 + mac_ops->csr_offset) | 53 | #define CGXX_CMRX_RX_DMAC_CAM0 (0x200 + mac_ops->csr_offset) |
| 52 | #define CGX_DMAC_CAM_ADDR_ENABLE BIT_ULL(48) | 54 | #define CGX_DMAC_CAM_ADDR_ENABLE BIT_ULL(48) |
| 55 | #define CGX_DMAC_CAM_ENTRY_LMACID GENMASK_ULL(50, 49) | ||
| 53 | #define CGXX_CMRX_RX_DMAC_CAM1 0x400 | 56 | #define CGXX_CMRX_RX_DMAC_CAM1 0x400 |
| 54 | #define CGX_RX_DMAC_ADR_MASK GENMASK_ULL(47, 0) | 57 | #define CGX_RX_DMAC_ADR_MASK GENMASK_ULL(47, 0) |
| 55 | #define CGXX_CMRX_TX_STAT0 0x700 | 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 | int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); | 142 | int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); |
| 140 | int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable); | 143 | int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable); |
| 141 | int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr); | 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 | u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id); | 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 | void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable); | 150 | void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable); |
| 144 | void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable); | 151 | void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable); |
| 145 | int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable); | 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 | unsigned long cgx_get_lmac_bmap(void *cgxd); | 172 | unsigned long cgx_get_lmac_bmap(void *cgxd); |
| 166 | void cgx_lmac_write(int cgx_id, int lmac_id, u64 offset, u64 val); | 173 | void cgx_lmac_write(int cgx_id, int lmac_id, u64 offset, u64 val); |
| 167 | u64 cgx_lmac_read(int cgx_id, int lmac_id, u64 offset); | 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 | #endif /* CGX_H */ | 178 | #endif /* CGX_H */ |
| @@ -10,17 +10,19 @@ · 9 unmodified lines | |||
| 10 | #include "rvu.h" | 10 | #include "rvu.h" |
| 11 | #include "cgx.h" | 11 | #include "cgx.h" |
| 12 | /** | 12 | /** |
| 13 | * struct lmac | 13 | * struct lmac - per lmac locks and properties |
| 14 | * @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion | 14 | * @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion |
| 15 | * @cmd_lock: Lock to serialize the command interface | 15 | * @cmd_lock: Lock to serialize the command interface |
| 16 | * @resp: command response | 16 | * @resp: command response |
| 17 | * @link_info: link related information | 17 | * @link_info: link related information |
| 18 | * @mac_to_index_bmap: Mac address to CGX table index mapping | ||
| 18 | * @event_cb: callback for linkchange events | 19 | * @event_cb: callback for linkchange events |
| 19 | * @event_cb_lock: lock for serializing callback with unregister | 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 | * @cgx: parent cgx port | 21 | * @cgx: parent cgx port |
| 22 | * @mcast_filters_count: Number of multicast filters installed | ||
| 23 | * @lmac_id: lmac port id | 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 | * @name: lmac port name | 26 | * @name: lmac port name |
| 25 | */ | 27 | */ |
| 26 | struct lmac { | 28 | struct lmac { |
| @@ -29,12 +31,14 @@ struct lmac { · 2 unmodified lines | |||
| 29 | struct mutex cmd_lock; | 31 | struct mutex cmd_lock; |
| 30 | u64 resp; | 32 | u64 resp; |
| 31 | struct cgx_link_user_info link_info; | 33 | struct cgx_link_user_info link_info; |
| 34 | struct rsrc_bmap mac_to_index_bmap; | ||
| 32 | struct cgx_event_cb event_cb; | 35 | struct cgx_event_cb event_cb; |
| 33 | /* lock for serializing callback with unregister */ | 36 | /* lock for serializing callback with unregister */ |
| 34 | spinlock_t event_cb_lock; | 37 | spinlock_t event_cb_lock; |
| 35 | bool cmd_pend; | ||
| 36 | struct cgx *cgx; | 38 | struct cgx *cgx; |
| 39 | u8 mcast_filters_count; | ||
| 37 | u8 lmac_id; | 40 | u8 lmac_id; |
| 41 | bool cmd_pend; | ||
| 38 | char *name; | 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 | M(VF_FLR, 0x006, vf_flr, msg_req, msg_rsp) \ | 134 | M(VF_FLR, 0x006, vf_flr, msg_req, msg_rsp) \ |
| 135 | M(PTP_OP, 0x007, ptp_op, ptp_req, ptp_rsp) \ | 135 | M(PTP_OP, 0x007, ptp_op, ptp_req, ptp_rsp) \ |
| 136 | M(GET_HW_CAP, 0x008, get_hw_cap, msg_req, get_hw_cap_rsp) \ | 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 | M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \ | 139 | M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \ |
| 138 | /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ | 140 | /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ |
| 139 | M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \ | 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 | M(CGX_FEATURES_GET, 0x215, cgx_features_get, msg_req, \ | 165 | M(CGX_FEATURES_GET, 0x215, cgx_features_get, msg_req, \ |
| 164 | cgx_features_info_msg) \ | 166 | cgx_features_info_msg) \ |
| 165 | M(RPM_STATS, 0x216, rpm_stats, msg_req, rpm_stats_rsp) \ | 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 | /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ | 177 | /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ |
| 168 | M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \ | 178 | M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \ |
| 169 | npa_lf_alloc_req, npa_lf_alloc_rsp) \ | 179 | npa_lf_alloc_req, npa_lf_alloc_rsp) \ |
| @@ -401,6 +411,38 @@ struct cgx_mac_addr_set_or_get { · 231 unmodified lines | |||
| 401 | u8 mac_addr[ETH_ALEN]; | 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 | struct cgx_link_user_info { | 446 | struct cgx_link_user_info { |
| 405 | uint64_t link_up:1; | 447 | uint64_t link_up:1; |
| 406 | uint64_t full_duplex:1; | 448 | uint64_t full_duplex:1; |
| @@ -499,6 +541,12 @@ struct cgx_set_link_mode_rsp { · 92 unmodified lines | |||
| 499 | int status; | 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 | #define RVU_LMAC_FEAT_FC BIT_ULL(0) /* pause frames */ | 550 | #define RVU_LMAC_FEAT_FC BIT_ULL(0) /* pause frames */ |
| 503 | #define RVU_LMAC_FEAT_PTP BIT_ULL(1) /* precision time protocol */ | 551 | #define RVU_LMAC_FEAT_PTP BIT_ULL(1) /* precision time protocol */ |
| 504 | #define RVU_MAC_VERSION BIT_ULL(2) | 552 | #define RVU_MAC_VERSION BIT_ULL(2) |
| @@ -1278,6 +1326,14 @@ struct set_vf_perm { · 773 unmodified lines | |||
| 1278 | u64 flags; | 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 | /* CPT mailbox error codes | 1337 | /* CPT mailbox error codes |
| 1282 | * Range 901 - 1000. | 1338 | * Range 901 - 1000. |
| 1283 | */ | 1339 | */ |
| @@ -2333,6 +2333,7 @@ static void __rvu_flr_handler(struct rvu *rvu, u16 pcifunc) · 2332 unmodified lines | |||
| 2333 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSOW); | 2333 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSOW); |
| 2334 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSO); | 2334 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSO); |
| 2335 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NPA); | 2335 | rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NPA); |
| 2336 | rvu_reset_lmt_map_tbl(rvu, pcifunc); | ||
| 2336 | rvu_detach_rsrcs(rvu, NULL, pcifunc); | 2337 | rvu_detach_rsrcs(rvu, NULL, pcifunc); |
| 2337 | mutex_unlock(&rvu->flr_lock); | 2338 | mutex_unlock(&rvu->flr_lock); |
| 2338 | } | 2339 | } |
| @@ -243,6 +243,7 @@ struct rvu_pfvf { · 242 unmodified lines | |||
| 243 | u8 nix_blkaddr; /* BLKADDR_NIX0/1 assigned to this PF */ | 243 | u8 nix_blkaddr; /* BLKADDR_NIX0/1 assigned to this PF */ |
| 244 | u8 nix_rx_intf; /* NIX0_RX/NIX1_RX interface to NPC */ | 244 | u8 nix_rx_intf; /* NIX0_RX/NIX1_RX interface to NPC */ |
| 245 | u8 nix_tx_intf; /* NIX0_TX/NIX1_TX interface to NPC */ | 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 | unsigned long flags; | 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 | int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start); | 657 | int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start); |
| 657 | int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index, | 658 | int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index, |
| 658 | int rxtxflag, u64 *stat); | 659 | int rxtxflag, u64 *stat); |
| 660 | void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc); | ||
| 661 | |||
| 659 | /* NPA APIs */ | 662 | /* NPA APIs */ |
| 660 | int rvu_npa_init(struct rvu *rvu); | 663 | int rvu_npa_init(struct rvu *rvu); |
| 661 | void rvu_npa_freemem(struct rvu *rvu); | 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 | bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature); | 744 | bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature); |
| 742 | u32 rvu_cgx_get_fifolen(struct rvu *rvu); | 745 | u32 rvu_cgx_get_fifolen(struct rvu *rvu); |
| 743 | void *rvu_first_cgx_pdata(struct rvu *rvu); | 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 | int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf, | 749 | int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf, |
| 746 | int type); | 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 | int rvu_set_channels_base(struct rvu *rvu); | 758 | int rvu_set_channels_base(struct rvu *rvu); |
| 755 | void rvu_program_channels(struct rvu *rvu); | 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 | #ifdef CONFIG_DEBUG_FS | 764 | #ifdef CONFIG_DEBUG_FS |
| 758 | void rvu_dbg_init(struct rvu *rvu); | 765 | void rvu_dbg_init(struct rvu *rvu); |
| 759 | void rvu_dbg_exit(struct rvu *rvu); | 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 | return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id]; | 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 | unsigned long pfmap; | 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 | return 0; | 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 | int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req, | 482 | int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req, |
| 458 | struct msg_rsp *rsp) | 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 | return 0; | 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 | int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu, | 642 | int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu, |
| 561 | struct cgx_mac_addr_set_or_get *req, | 643 | struct cgx_mac_addr_set_or_get *req, |
| 562 | struct cgx_mac_addr_set_or_get *rsp) | 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 | rsp->status = cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac); | 1035 | rsp->status = cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac); |
| 954 | return 0; | 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 | #include "cgx.h" | 10 | #include "cgx.h" |
| 11 | #include "rvu_reg.h" | 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 | int rvu_set_channels_base(struct rvu *rvu) | 213 | int rvu_set_channels_base(struct rvu *rvu) |
| 14 | { | 214 | { |
| 15 | struct rvu_hwinfo *hw = rvu->hw; | 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 | return err; | 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 | struct dentry *current_dir; | 1976 | struct dentry *current_dir; |
| 1977 | int err, lmac_id; | ||
| 1978 | char *buf; | 1977 | char *buf; |
| 1979 | 1978 | ||
| 1980 | current_dir = filp->file->f_path.dentry->d_parent; | 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 | if (!buf) | 1981 | if (!buf) |
| 1983 | return -EINVAL; | 1982 | return -EINVAL; |
| 1984 | 1983 | ||
| 1985 | err = kstrtoint(buf + 1, 10, &lmac_id); | 1984 | return kstrtoint(buf + 1, 10, lmac_id); |
| 1986 | if (!err) { | 1985 | } |
| 1987 | err = cgx_print_stats(filp, lmac_id); | 1986 | |
| 1988 | if (err) | 1987 | static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused) |
| 1989 | return err; | 1988 | { |
| 1990 | } | 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 | return err; | 1995 | return err; |
| 1992 | } | 1996 | } |
| 1993 | 1997 | ||
| 1994 | RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL); | 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 | static void rvu_dbg_cgx_init(struct rvu *rvu) | 2065 | static void rvu_dbg_cgx_init(struct rvu *rvu) |
| 1997 | { | 2066 | { |
| 1998 | struct mac_ops *mac_ops; | 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 | debugfs_create_file("stats", 0600, rvu->rvu_dbg.lmac, | 2099 | debugfs_create_file("stats", 0600, rvu->rvu_dbg.lmac, |
| 2031 | cgx, &rvu_dbg_cgx_stat_fops); | 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 | /* Free and disable any MCAM entries used by this NIX LF */ | 347 | /* Free and disable any MCAM entries used by this NIX LF */ |
| 348 | rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf); | 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 | int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, | 354 | int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, |
| @@ -49,6 +49,11 @@ · 48 unmodified lines | |||
| 49 | #define RVU_AF_PFX_VF_BAR4_ADDR (0x5400 | (a) << 4) | 49 | #define RVU_AF_PFX_VF_BAR4_ADDR (0x5400 | (a) << 4) |
| 50 | #define RVU_AF_PFX_VF_BAR4_CFG (0x5600 | (a) << 4) | 50 | #define RVU_AF_PFX_VF_BAR4_CFG (0x5600 | (a) << 4) |
| 51 | #define RVU_AF_PFX_LMTLINE_ADDR (0x5800 | (a) << 4) | 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 | /* Admin function's privileged PF/VF registers */ | 58 | /* Admin function's privileged PF/VF registers */ |
| 54 | #define RVU_PRIV_CONST (0x8000000) | 59 | #define RVU_PRIV_CONST (0x8000000) |
| @@ -692,4 +697,9 @@ · 637 unmodified lines | |||
| 692 | #define LBK_LINK_CFG_ID_MASK GENMASK_ULL(11, 6) | 697 | #define LBK_LINK_CFG_ID_MASK GENMASK_ULL(11, 6) |
| 693 | #define LBK_LINK_CFG_BASE_MASK GENMASK_ULL(5, 0) | 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 | #endif /* RVU_REG_H */ | 705 | #endif /* RVU_REG_H */ |
| @@ -35,7 +35,8 @@ enum rvu_block_addr_e { · 34 unmodified lines | |||
| 35 | BLKADDR_NDC_NPA0 = 0xeULL, | 35 | BLKADDR_NDC_NPA0 = 0xeULL, |
| 36 | BLKADDR_NDC_NIX1_RX = 0x10ULL, | 36 | BLKADDR_NDC_NIX1_RX = 0x10ULL, |
| 37 | BLKADDR_NDC_NIX1_TX = 0x11ULL, | 37 | BLKADDR_NDC_NIX1_TX = 0x11ULL, |
| 38 | BLK_COUNT = 0x12ULL, | 38 | BLKADDR_APR = 0x16ULL, |
| 39 | BLK_COUNT = 0x17ULL, | ||
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| 41 | /* RVU Block Type Enumeration */ | 42 | /* RVU Block Type Enumeration */ |
| @@ -7,7 +7,7 @@ obj-$(CONFIG_OCTEONTX2_PF) += rvu_nicpf.o · 6 unmodified lines | |||
| 7 | obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o | 7 | obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o |
| 8 | 8 | ||
| 9 | rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \ | 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 | rvu_nicvf-y := otx2_vf.o | 11 | rvu_nicvf-y := otx2_vf.o |
| 12 | 12 | ||
| 13 | ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af | 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 | .refill_pool_ptrs = cn10k_refill_pool_ptrs, | 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)) { | 28 | struct lmtst_tbl_setup_req *req; |
| 31 | pf->hw_ops = &otx2_hw_ops; | 29 | int qcount, err; |
| 30 | |||
| 31 | if (!test_bit(CN10K_LMTST, &pfvf->hw.cap_flag)) { | ||
| 32 | pfvf->hw_ops = &otx2_hw_ops; | ||
| 32 | return 0; | 33 | return 0; |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | pf->hw_ops = &cn10k_hw_ops; | 36 | pfvf->hw_ops = &cn10k_hw_ops; |
| 36 | base = pci_resource_start(pf->pdev, PCI_MBOX_BAR_NUM) + | 37 | qcount = pfvf->hw.max_queues; |
| 37 | (MBOX_SIZE * (pf->total_vfs + 1)); | 38 | /* LMTST lines allocation |
| 38 | 39 | * qcount = num_online_cpus(); | |
| 39 | size = pci_resource_len(pf->pdev, PCI_MBOX_BAR_NUM) - | 40 | * NPA = TX + RX + XDP. |
| 40 | (MBOX_SIZE * (pf->total_vfs + 1)); | 41 | * NIX = TX * 32 (For Burst SQE flush). |
| 41 | 42 | */ | |
| 42 | pf->hw.lmt_base = ioremap(base, size); | 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) { | 47 | mutex_lock(&pfvf->mbox.lock); |
| 45 | dev_err(pf->dev, "Unable to map PF LMTST region\n"); | 48 | req = otx2_mbox_alloc_msg_lmtst_tbl_setup(&pfvf->mbox); |
| 49 | if (!req) { | ||
| 50 | mutex_unlock(&pfvf->mbox.lock); | ||
| 46 | return -ENOMEM; | 51 | return -ENOMEM; |
| 47 | } | 52 | } |
| 48 | 53 | ||
| 49 | /* FIXME: Get the num of LMTST lines from LMT table */ | 54 | req->use_local_lmt_region = true; |
| 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 | } | ||
| 59 | 55 | ||
| 60 | int cn10k_vf_lmtst_init(struct otx2_nic *vf) | 56 | err = qmem_alloc(pfvf->dev, &pfvf->dync_lmt, pfvf->tot_lmt_lines, |
| 61 | { | 57 | LMT_LINE_SIZE); |
| 62 | int size, num_lines; | 58 | if (err) { |
| 63 | 59 | mutex_unlock(&pfvf->mbox.lock); | |
| 64 | if (!test_bit(CN10K_LMTST, &vf->hw.cap_flag)) { | 60 | return err; |
| 65 | vf->hw_ops = &otx2_hw_ops; | ||
| 66 | return 0; | ||
| 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; | 65 | err = otx2_sync_mbox_msg(&pfvf->mbox); |
| 70 | size = pci_resource_len(vf->pdev, PCI_MBOX_BAR_NUM); | 66 | mutex_unlock(&pfvf->mbox.lock); |
| 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 | } | ||
| 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 | return 0; | 68 | return 0; |
| 86 | } | 69 | } |
| 87 | EXPORT_SYMBOL(cn10k_vf_lmtst_init); | 70 | EXPORT_SYMBOL(cn10k_lmtst_init); |
| 88 | 71 | ||
| 89 | int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) | 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 | struct otx2_snd_queue *sq; | 76 | struct otx2_snd_queue *sq; |
| 94 | 77 | ||
| 95 | sq = &pfvf->qset.sq[qidx]; | 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 | (qidx * pfvf->nix_lmt_size)); | 80 | (qidx * pfvf->nix_lmt_size)); |
| 98 | 81 | ||
| 82 | sq->lmt_id = pfvf->npa_lmt_lines + (qidx * LMT_BURST_SIZE); | ||
| 83 | |||
| 99 | /* Get memory to put this msg */ | 84 | /* Get memory to put this msg */ |
| 100 | aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox); | 85 | aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox); |
| 101 | if (!aq) | 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 | void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx) | 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 | u64 val = 0, tar_addr = 0; | 146 | u64 val = 0, tar_addr = 0; |
| 164 | 147 | ||
| 165 | /* FIXME: val[0:10] LMT_ID. | 148 | /* FIXME: val[0:10] LMT_ID. |
| 166 | * [12:15] no of LMTST - 1 in the burst. | 149 | * [12:15] no of LMTST - 1 in the burst. |
| 167 | * [19:63] data size of each LMTST in the burst except first. | 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 | /* Target address for LMTST flush tells HW how many 128bit | 153 | /* Target address for LMTST flush tells HW how many 128bit |
| 171 | * words are present. | 154 | * words are present. |
| 172 | * tar_addr[6:4] size of first LMTST - 1 in units of 128b. | 155 | * tar_addr[6:4] size of first LMTST - 1 in units of 128b. |
| @@ -12,8 +12,7 @@ · 11 unmodified lines | |||
| 12 | void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); | 12 | void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); |
| 13 | void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); | 13 | void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); |
| 14 | int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); | 14 | int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); |
| 15 | int cn10k_pf_lmtst_init(struct otx2_nic *pf); | 15 | int cn10k_lmtst_init(struct otx2_nic *pfvf); |
| 16 | int cn10k_vf_lmtst_init(struct otx2_nic *vf); | ||
| 17 | int cn10k_free_all_ipolicers(struct otx2_nic *pfvf); | 16 | int cn10k_free_all_ipolicers(struct otx2_nic *pfvf); |
| 18 | int cn10k_alloc_matchall_ipolicer(struct otx2_nic *pfvf); | 17 | int cn10k_alloc_matchall_ipolicer(struct otx2_nic *pfvf); |
| 19 | int cn10k_free_matchall_ipolicer(struct otx2_nic *pfvf); | 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 | /* update dmac field in vlan offload rule */ | 210 | /* update dmac field in vlan offload rule */ |
| 211 | if (pfvf->flags & OTX2_FLAG_RX_VLAN_SUPPORT) | 211 | if (pfvf->flags & OTX2_FLAG_RX_VLAN_SUPPORT) |
| 212 | otx2_install_rxvlan_offload_flow(pfvf); | 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 | } else { | 216 | } else { |
| 214 | return -EPERM; | 217 | return -EPERM; |
| 215 | } | 218 | } |
| @@ -218,8 +218,8 @@ struct otx2_hw { · 217 unmodified lines | |||
| 218 | unsigned long cap_flag; | 218 | unsigned long cap_flag; |
| 219 | 219 | ||
| 220 | #define LMT_LINE_SIZE 128 | 220 | #define LMT_LINE_SIZE 128 |
| 221 | #define NIX_LMTID_BASE 72 /* RX + TX + XDP */ | 221 | #define LMT_BURST_SIZE 32 /* 32 LMTST lines for burst SQE flush */ |
| 222 | void __iomem *lmt_base; | 222 | u64 *lmt_base; |
| 223 | u64 *npa_lmt_base; | 223 | u64 *npa_lmt_base; |
| 224 | u64 *nix_lmt_base; | 224 | u64 *nix_lmt_base; |
| 225 | }; | 225 | }; |
| @@ -288,6 +288,9 @@ struct otx2_flow_config { · 62 unmodified lines | |||
| 288 | u16 tc_flower_offset; | 288 | u16 tc_flower_offset; |
| 289 | u16 ntuple_max_flows; | 289 | u16 ntuple_max_flows; |
| 290 | u16 tc_max_flows; | 290 | u16 tc_max_flows; |
| 291 | u8 dmacflt_max_flows; | ||
| 292 | u8 *bmap_to_dmacindex; | ||
| 293 | unsigned long dmacflt_bmap; | ||
| 291 | struct list_head flow_list; | 294 | struct list_head flow_list; |
| 292 | }; | 295 | }; |
| 293 | 296 | ||
| @@ -329,6 +332,7 @@ struct otx2_nic { · 35 unmodified lines | |||
| 329 | #define OTX2_FLAG_TC_FLOWER_SUPPORT BIT_ULL(11) | 332 | #define OTX2_FLAG_TC_FLOWER_SUPPORT BIT_ULL(11) |
| 330 | #define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED BIT_ULL(12) | 333 | #define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED BIT_ULL(12) |
| 331 | #define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED BIT_ULL(13) | 334 | #define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED BIT_ULL(13) |
| 335 | #define OTX2_FLAG_DMACFLTR_SUPPORT BIT_ULL(14) | ||
| 332 | u64 flags; | 336 | u64 flags; |
| 333 | 337 | ||
| 334 | struct otx2_qset qset; | 338 | struct otx2_qset qset; |
| @@ -363,8 +367,9 @@ struct otx2_nic { · 28 unmodified lines | |||
| 363 | /* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */ | 367 | /* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */ |
| 364 | int nix_blkaddr; | 368 | int nix_blkaddr; |
| 365 | /* LMTST Lines info */ | 369 | /* LMTST Lines info */ |
| 370 | struct qmem *dync_lmt; | ||
| 366 | u16 tot_lmt_lines; | 371 | u16 tot_lmt_lines; |
| 367 | u16 nix_lmt_lines; | 372 | u16 npa_lmt_lines; |
| 368 | u32 nix_lmt_size; | 373 | u32 nix_lmt_size; |
| 369 | 374 | ||
| 370 | struct otx2_ptp *ptp; | 375 | struct otx2_ptp *ptp; |
| @@ -833,4 +838,11 @@ int otx2_init_tc(struct otx2_nic *nic); · 462 unmodified lines | |||
| 833 | void otx2_shutdown_tc(struct otx2_nic *nic); | 838 | void otx2_shutdown_tc(struct otx2_nic *nic); |
| 834 | int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type, | 839 | int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type, |
| 835 | void *type_data); | 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 | #endif /* OTX2_COMMON_H */ | 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 | bool is_vf; | 18 | bool is_vf; |
| 19 | u8 rss_ctx_id; | 19 | u8 rss_ctx_id; |
| 20 | int vf; | 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 | static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_config *flow_cfg) | 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 | if (!pf->mac_table) | 225 | if (!pf->mac_table) |
| 220 | return -ENOMEM; | 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 | return 0; | 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 | struct otx2_nic *pf = netdev_priv(netdev); | 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 | return otx2_do_add_macfilter(pf, mac); | 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 | list_add(&flow->list, head); | 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 | int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc, | 392 | int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc, |
| 355 | u32 location) | 393 | u32 location) |
| 356 | { | 394 | { |
| 357 | struct otx2_flow *iter; | 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 | return -EINVAL; | 398 | return -EINVAL; |
| 361 | 399 | ||
| 362 | list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) { | 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 | int idx = 0; | 416 | int idx = 0; |
| 379 | int err = 0; | 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 | while ((!err || err == -ENOENT) && idx < rule_cnt) { | 420 | while ((!err || err == -ENOENT) && idx < rule_cnt) { |
| 383 | err = otx2_get_flow(pfvf, nfc, location); | 421 | err = otx2_get_flow(pfvf, nfc, location); |
| 384 | if (!err) | 422 | if (!err) |
| @@ -760,6 +798,32 @@ int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp, · 375 unmodified lines | |||
| 760 | return 0; | 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 | static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow) | 827 | static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow) |
| 764 | { | 828 | { |
| 765 | u64 ring_cookie = flow->flow_spec.ring_cookie; | 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 | return err; | 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 | int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) | 916 | int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) |
| 822 | { | 917 | { |
| 823 | struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; | 918 | struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; |
| 824 | struct ethtool_rx_flow_spec *fsp = &nfc->fs; | 919 | struct ethtool_rx_flow_spec *fsp = &nfc->fs; |
| 825 | struct otx2_flow *flow; | 920 | struct otx2_flow *flow; |
| 921 | struct ethhdr *eth_hdr; | ||
| 826 | bool new = false; | 922 | bool new = false; |
| 923 | int err = 0; | ||
| 827 | u32 ring; | 924 | u32 ring; |
| 828 | int err; | ||
| 829 | 925 | ||
| 830 | ring = ethtool_get_flow_spec_ring(fsp->ring_cookie); | 926 | ring = ethtool_get_flow_spec_ring(fsp->ring_cookie); |
| 831 | if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT)) | 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 | if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC) | 930 | if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC) |
| 835 | return -EINVAL; | 931 | return -EINVAL; |
| 836 | 932 | ||
| 837 | if (fsp->location >= flow_cfg->ntuple_max_flows) | 933 | if (fsp->location >= otx2_get_maxflows(flow_cfg)) |
| 838 | return -EINVAL; | 934 | return -EINVAL; |
| 839 | 935 | ||
| 840 | flow = otx2_find_flow(pfvf, fsp->location); | 936 | flow = otx2_find_flow(pfvf, fsp->location); |
| 841 | if (!flow) { | 937 | if (!flow) { |
| 842 | flow = kzalloc(sizeof(*flow), GFP_ATOMIC); | 938 | flow = kzalloc(sizeof(*flow), GFP_KERNEL); |
| 843 | if (!flow) | 939 | if (!flow) |
| 844 | return -ENOMEM; | 940 | return -ENOMEM; |
| 845 | flow->location = fsp->location; | 941 | flow->location = fsp->location; |
| 846 | flow->entry = flow_cfg->flow_ent[flow->location]; | ||
| 847 | new = true; | 942 | new = true; |
| 848 | } | 943 | } |
| 849 | /* struct copy */ | 944 | /* struct copy */ |
| @@ -852,7 +947,54 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc) · 2 unmodified lines | |||
| 852 | if (fsp->flow_type & FLOW_RSS) | 947 | if (fsp->flow_type & FLOW_RSS) |
| 853 | flow->rss_ctx_id = nfc->rss_context; | 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 | if (err) { | 998 | if (err) { |
| 857 | if (new) | 999 | if (new) |
| 858 | kfree(flow); | 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 | return err; | 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 | int otx2_remove_flow(struct otx2_nic *pfvf, u32 location) | 1065 | int otx2_remove_flow(struct otx2_nic *pfvf, u32 location) |
| 894 | { | 1066 | { |
| 895 | struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; | 1067 | struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; |
| 896 | struct otx2_flow *flow; | 1068 | struct otx2_flow *flow; |
| 897 | int err; | 1069 | int err; |
| 898 | 1070 | ||
| 899 | if (location >= flow_cfg->ntuple_max_flows) | 1071 | if (location >= otx2_get_maxflows(flow_cfg)) |
| 900 | return -EINVAL; | 1072 | return -EINVAL; |
| 901 | 1073 | ||
| 902 | flow = otx2_find_flow(pfvf, location); | 1074 | flow = otx2_find_flow(pfvf, location); |
| 903 | if (!flow) | 1075 | if (!flow) |
| 904 | return -ENOENT; | 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 | if (err) | 1099 | if (err) |
| 908 | return err; | 1100 | return err; |
| 909 | 1101 | ||
| @@ -1100,3 +1292,22 @@ int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable) · 190 unmodified lines | |||
| 1100 | mutex_unlock(&pf->mbox.lock); | 1292 | mutex_unlock(&pf->mbox.lock); |
| 1101 | return rsp_hdr->rc; | 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 | struct msg_req *msg; | 1110 | struct msg_req *msg; |
| 1111 | int err; | 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 | mutex_lock(&pf->mbox.lock); | 1118 | mutex_lock(&pf->mbox.lock); |
| 1114 | if (enable) | 1119 | if (enable) |
| 1115 | msg = otx2_mbox_alloc_msg_cgx_intlbk_enable(&pf->mbox); | 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 | if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) { | 1539 | if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) { |
| 1535 | /* Reserve LMT lines for NPA AURA batch free */ | 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 | /* Reserve LMT lines for NIX TX */ | 1542 | /* Reserve LMT lines for NIX TX */ |
| 1538 | pf->hw.nix_lmt_base = (__force u64 *)((u64)pf->hw.npa_lmt_base + | 1543 | pf->hw.nix_lmt_base = (u64 *)((u64)pf->hw.npa_lmt_base + |
| 1539 | (NIX_LMTID_BASE * LMT_LINE_SIZE)); | 1544 | (pf->npa_lmt_lines * LMT_LINE_SIZE)); |
| 1540 | } | 1545 | } |
| 1541 | 1546 | ||
| 1542 | err = otx2_init_hw_resources(pf); | 1547 | err = otx2_init_hw_resources(pf); |
| @@ -1644,6 +1649,10 @@ int otx2_open(struct net_device *netdev) · 101 unmodified lines | |||
| 1644 | /* Restore pause frame settings */ | 1649 | /* Restore pause frame settings */ |
| 1645 | otx2_config_pause_frm(pf); | 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 | err = otx2_rxtx_enable(pf, true); | 1656 | err = otx2_rxtx_enable(pf, true); |
| 1648 | if (err) | 1657 | if (err) |
| 1649 | goto err_tx_stop_queues; | 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 | if (err) | 2535 | if (err) |
| 2527 | goto err_detach_rsrc; | 2536 | goto err_detach_rsrc; |
| 2528 | 2537 | ||
| 2529 | err = cn10k_pf_lmtst_init(pf); | 2538 | err = cn10k_lmtst_init(pf); |
| 2530 | if (err) | 2539 | if (err) |
| 2531 | goto err_detach_rsrc; | 2540 | goto err_detach_rsrc; |
| 2532 | 2541 | ||
| @@ -2630,8 +2639,8 @@ err_del_mcam_entries: · 97 unmodified lines | |||
| 2630 | err_ptp_destroy: | 2639 | err_ptp_destroy: |
| 2631 | otx2_ptp_destroy(pf); | 2640 | otx2_ptp_destroy(pf); |
| 2632 | err_detach_rsrc: | 2641 | err_detach_rsrc: |
| 2633 | if (hw->lmt_base) | 2642 | if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) |
| 2634 | iounmap(hw->lmt_base); | 2643 | qmem_free(pf->dev, pf->dync_lmt); |
| 2635 | otx2_detach_resources(&pf->mbox); | 2644 | otx2_detach_resources(&pf->mbox); |
| 2636 | err_disable_mbox_intr: | 2645 | err_disable_mbox_intr: |
| 2637 | otx2_disable_mbox_intr(pf); | 2646 | otx2_disable_mbox_intr(pf); |
| @@ -2772,9 +2781,8 @@ static void otx2_remove(struct pci_dev *pdev) · 134 unmodified lines | |||
| 2772 | otx2_mcam_flow_del(pf); | 2781 | otx2_mcam_flow_del(pf); |
| 2773 | otx2_shutdown_tc(pf); | 2782 | otx2_shutdown_tc(pf); |
| 2774 | otx2_detach_resources(&pf->mbox); | 2783 | otx2_detach_resources(&pf->mbox); |
| 2775 | if (pf->hw.lmt_base) | 2784 | if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) |
| 2776 | iounmap(pf->hw.lmt_base); | 2785 | qmem_free(pf->dev, pf->dync_lmt); |
| 2777 | |||
| 2778 | otx2_disable_mbox_intr(pf); | 2786 | otx2_disable_mbox_intr(pf); |
| 2779 | otx2_pfaf_mbox_destroy(pf); | 2787 | otx2_pfaf_mbox_destroy(pf); |
| 2780 | pci_free_irq_vectors(pf->pdev); | 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 | struct otx2_nic *priv; | 288 | struct otx2_nic *priv; |
| 289 | u32 burst, mark = 0; | 289 | u32 burst, mark = 0; |
| 290 | u8 nr_police = 0; | 290 | u8 nr_police = 0; |
| 291 | bool pps; | 291 | bool pps = false; |
| 292 | u64 rate; | 292 | u64 rate; |
| 293 | int i; | 293 | int i; |
| 294 | 294 | ||
| @@ -83,6 +83,7 @@ struct otx2_snd_queue { · 82 unmodified lines | |||
| 83 | u16 num_sqbs; | 83 | u16 num_sqbs; |
| 84 | u16 sqe_thresh; | 84 | u16 sqe_thresh; |
| 85 | u8 sqe_per_sqb; | 85 | u8 sqe_per_sqb; |
| 86 | u32 lmt_id; | ||
| 86 | u64 io_addr; | 87 | u64 io_addr; |
| 87 | u64 *aura_fc_addr; | 88 | u64 *aura_fc_addr; |
| 88 | u64 *lmt_addr; | 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 | if (err) | 609 | if (err) |
| 610 | goto err_detach_rsrc; | 610 | goto err_detach_rsrc; |
| 611 | 611 | ||
| 612 | err = cn10k_vf_lmtst_init(vf); | 612 | err = cn10k_lmtst_init(vf); |
| 613 | if (err) | 613 | if (err) |
| 614 | goto err_detach_rsrc; | 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 | err_unreg_netdev: | 667 | err_unreg_netdev: |
| 668 | unregister_netdev(netdev); | 668 | unregister_netdev(netdev); |
| 669 | err_detach_rsrc: | 669 | err_detach_rsrc: |
| 670 | if (hw->lmt_base) | 670 | if (test_bit(CN10K_LMTST, &vf->hw.cap_flag)) |
| 671 | iounmap(hw->lmt_base); | 671 | qmem_free(vf->dev, vf->dync_lmt); |
| 672 | otx2_detach_resources(&vf->mbox); | 672 | otx2_detach_resources(&vf->mbox); |
| 673 | err_disable_mbox_intr: | 673 | err_disable_mbox_intr: |
| 674 | otx2vf_disable_mbox_intr(vf); | 674 | otx2vf_disable_mbox_intr(vf); |
| @@ -700,10 +700,8 @@ static void otx2vf_remove(struct pci_dev *pdev) · 25 unmodified lines | |||
| 700 | destroy_workqueue(vf->otx2_wq); | 700 | destroy_workqueue(vf->otx2_wq); |
| 701 | otx2vf_disable_mbox_intr(vf); | 701 | otx2vf_disable_mbox_intr(vf); |
| 702 | otx2_detach_resources(&vf->mbox); | 702 | otx2_detach_resources(&vf->mbox); |
| 703 | 703 | if (test_bit(CN10K_LMTST, &vf->hw.cap_flag)) | |
| 704 | if (vf->hw.lmt_base) | 704 | qmem_free(vf->dev, vf->dync_lmt); |
| 705 | iounmap(vf->hw.lmt_base); | ||
| 706 | |||
| 707 | otx2vf_vfaf_mbox_destroy(vf); | 705 | otx2vf_vfaf_mbox_destroy(vf); |
| 708 | pci_free_irq_vectors(vf->pdev); | 706 | pci_free_irq_vectors(vf->pdev); |
| 709 | pci_set_drvdata(pdev, NULL); | 707 | pci_set_drvdata(pdev, NULL); |
| @@ -2,6 +2,7 @@ config SPARX5_SWITCH · 1 unmodified line | |||
| 2 | tristate "Sparx5 switch driver" | 2 | tristate "Sparx5 switch driver" |
| 3 | depends on NET_SWITCHDEV | 3 | depends on NET_SWITCHDEV |
| 4 | depends on HAS_IOMEM | 4 | depends on HAS_IOMEM |
| 5 | depends on OF | ||
| 5 | select PHYLINK | 6 | select PHYLINK |
| 6 | select PHY_SPARX5_SERDES | 7 | select PHY_SPARX5_SERDES |
| 7 | select RESET_CONTROLLER | 8 | select RESET_CONTROLLER |
| @@ -540,10 +540,8 @@ static int moxart_mac_probe(struct platform_device *pdev) · 539 unmodified lines | |||
| 540 | SET_NETDEV_DEV(ndev, &pdev->dev); | 540 | SET_NETDEV_DEV(ndev, &pdev->dev); |
| 541 | 541 | ||
| 542 | ret = register_netdev(ndev); | 542 | ret = register_netdev(ndev); |
| 543 | if (ret) { | 543 | if (ret) |
| 544 | free_netdev(ndev); | ||
| 545 | goto init_fail; | 544 | goto init_fail; |
| 546 | } | ||
| 547 | 545 | ||
| 548 | netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n", | 546 | netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n", |
| 549 | __func__, ndev->irq, ndev->dev_addr); | 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 | static int ocelot_netdevice_changeupper(struct net_device *dev, | 1300 | static int ocelot_netdevice_changeupper(struct net_device *dev, |
| 1301 | struct net_device *brport_dev, | ||
| 1301 | struct netdev_notifier_changeupper_info *info) | 1302 | struct netdev_notifier_changeupper_info *info) |
| 1302 | { | 1303 | { |
| 1303 | struct netlink_ext_ack *extack; | 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 | if (netif_is_bridge_master(info->upper_dev)) { | 1309 | if (netif_is_bridge_master(info->upper_dev)) { |
| 1309 | if (info->linking) | 1310 | if (info->linking) |
| 1310 | err = ocelot_netdevice_bridge_join(dev, dev, | 1311 | err = ocelot_netdevice_bridge_join(dev, brport_dev, |
| 1311 | info->upper_dev, | 1312 | info->upper_dev, |
| 1312 | extack); | 1313 | extack); |
| 1313 | else | 1314 | else |
| 1314 | err = ocelot_netdevice_bridge_leave(dev, dev, | 1315 | err = ocelot_netdevice_bridge_leave(dev, brport_dev, |
| 1315 | info->upper_dev); | 1316 | info->upper_dev); |
| 1316 | } | 1317 | } |
| 1317 | if (netif_is_lag_master(info->upper_dev)) { | 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 | if (ocelot_port->bond != dev) | 1347 | if (ocelot_port->bond != dev) |
| 1347 | return NOTIFY_OK; | 1348 | return NOTIFY_OK; |
| 1348 | 1349 | ||
| 1349 | err = ocelot_netdevice_changeupper(lower, info); | 1350 | err = ocelot_netdevice_changeupper(lower, dev, info); |
| 1350 | if (err) | 1351 | if (err) |
| 1351 | return notifier_from_errno(err); | 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 | struct netdev_notifier_changeupper_info *info = ptr; | 1386 | struct netdev_notifier_changeupper_info *info = ptr; |
| 1386 | 1387 | ||
| 1387 | if (ocelot_netdevice_dev_check(dev)) | 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 | if (netif_is_lag_master(dev)) | 1391 | if (netif_is_lag_master(dev)) |
| 1391 | return ocelot_netdevice_lag_changeupper(dev, info); | 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 | nfp_fl_ct_clean_flow_entry(ct_entry); | 1141 | nfp_fl_ct_clean_flow_entry(ct_entry); |
| 1142 | kfree(ct_map_ent); | 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 | if (!zt->pre_ct_count) { | 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 | zt->nft = NULL; | 1145 | zt->nft = NULL; |
| 1159 | nfp_fl_ct_clean_nft_entries(zt); | 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 | put_device(&adpt->phydev->mdio.dev); | 736 | put_device(&adpt->phydev->mdio.dev); |
| 737 | mdiobus_unregister(adpt->mii_bus); | 737 | mdiobus_unregister(adpt->mii_bus); |
| 738 | free_netdev(netdev); | ||
| 739 | 738 | ||
| 740 | if (adpt->phy.digital) | 739 | if (adpt->phy.digital) |
| 741 | iounmap(adpt->phy.digital); | 740 | iounmap(adpt->phy.digital); |
| 742 | iounmap(adpt->phy.base); | 741 | iounmap(adpt->phy.base); |
| 743 | 742 | ||
| 743 | free_netdev(netdev); | ||
| 744 | |||
| 744 | return 0; | 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 | * maximum size. | 152 | * maximum size. |
| 153 | */ | 153 | */ |
| 154 | tx_per_ev = EFX_MAX_EVQ_SIZE / EFX_TXQ_MAX_ENT(efx); | 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 | n_xdp_tx = num_possible_cpus(); | 156 | n_xdp_tx = num_possible_cpus(); |
| 156 | n_xdp_ev = DIV_ROUND_UP(n_xdp_tx, tx_per_ev); | 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 | netif_err(efx, drv, efx->net_dev, | 170 | netif_err(efx, drv, efx->net_dev, |
| 170 | "Insufficient resources for %d XDP event queues (%d other channels, max %d)\n", | 171 | "Insufficient resources for %d XDP event queues (%d other channels, max %d)\n", |
| 171 | n_xdp_ev, n_channels, max_channels); | 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 | efx->n_xdp_channels = 0; | 175 | efx->n_xdp_channels = 0; |
| 173 | efx->xdp_tx_per_channel = 0; | 176 | efx->xdp_tx_per_channel = 0; |
| 174 | efx->xdp_tx_queue_count = 0; | 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 | netif_err(efx, drv, efx->net_dev, | 179 | netif_err(efx, drv, efx->net_dev, |
| 177 | "Insufficient resources for %d XDP TX queues (%d other channels, max VIs %d)\n", | 180 | "Insufficient resources for %d XDP TX queues (%d other channels, max VIs %d)\n", |
| 178 | n_xdp_tx, n_channels, efx->max_vis); | 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 | efx->n_xdp_channels = 0; | 184 | efx->n_xdp_channels = 0; |
| 180 | efx->xdp_tx_per_channel = 0; | 185 | efx->xdp_tx_per_channel = 0; |
| 181 | efx->xdp_tx_queue_count = 0; | 186 | efx->xdp_tx_queue_count = 0; |
| 182 | } else { | 187 | } else { |
| 183 | efx->n_xdp_channels = n_xdp_ev; | 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 | efx->xdp_tx_queue_count = n_xdp_tx; | 190 | efx->xdp_tx_queue_count = n_xdp_tx; |
| 186 | n_channels += n_xdp_ev; | 191 | n_channels += n_xdp_ev; |
| 187 | netif_dbg(efx, drv, efx->net_dev, | 192 | netif_dbg(efx, drv, efx->net_dev, |
| @@ -891,18 +896,20 @@ int efx_set_channels(struct efx_nic *efx) · 703 unmodified lines | |||
| 891 | if (efx_channel_is_xdp_tx(channel)) { | 896 | if (efx_channel_is_xdp_tx(channel)) { |
| 892 | efx_for_each_channel_tx_queue(tx_queue, channel) { | 897 | efx_for_each_channel_tx_queue(tx_queue, channel) { |
| 893 | tx_queue->queue = next_queue++; | 898 | tx_queue->queue = next_queue++; |
| 894 | netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n", | 899 | |
| 895 | channel->channel, tx_queue->label, | ||
| 896 | xdp_queue_number, tx_queue->queue); | ||
| 897 | /* We may have a few left-over XDP TX | 900 | /* We may have a few left-over XDP TX |
| 898 | * queues owing to xdp_tx_queue_count | 901 | * queues owing to xdp_tx_queue_count |
| 899 | * not dividing evenly by EFX_MAX_TXQ_PER_CHANNEL. | 902 | * not dividing evenly by EFX_MAX_TXQ_PER_CHANNEL. |
| 900 | * We still allocate and probe those | 903 | * We still allocate and probe those |
| 901 | * TXQs, but never use them. | 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 | efx->xdp_tx_queues[xdp_queue_number] = tx_queue; | 910 | efx->xdp_tx_queues[xdp_queue_number] = tx_queue; |
| 905 | xdp_queue_number++; | 911 | xdp_queue_number++; |
| 912 | } | ||
| 906 | } | 913 | } |
| 907 | } else { | 914 | } else { |
| 908 | efx_for_each_channel_tx_queue(tx_queue, channel) { | 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) | 924 | WARN_ON(xdp_queue_number != efx->xdp_tx_queue_count); |
| 918 | efx->xdp_tx_queue_count = xdp_queue_number; | ||
| 919 | 925 | ||
| 920 | rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); | 926 | rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); |
| 921 | if (rc) | 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 | struct plat_stmmacenet_data *plat; | 50 | struct plat_stmmacenet_data *plat; |
| 51 | struct stmmac_resources res; | 51 | struct stmmac_resources res; |
| 52 | bool mdio = false; | ||
| 53 | int ret, i; | ||
| 54 | struct device_node *np; | 52 | struct device_node *np; |
| 53 | int ret, i, phy_mode; | ||
| 54 | bool mdio = false; | ||
| 55 | 55 | ||
| 56 | np = dev_of_node(&pdev->dev); | 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 | if (plat->bus_id < 0) | 108 | if (plat->bus_id < 0) |
| 109 | plat->bus_id = pci_dev_id(pdev); | 109 | plat->bus_id = pci_dev_id(pdev); |
| 110 | 110 | ||
| 111 | plat->phy_interface = device_get_phy_mode(&pdev->dev); | 111 | phy_mode = device_get_phy_mode(&pdev->dev); |
| 112 | if (plat->phy_interface < 0) | 112 | if (phy_mode < 0) |
| 113 | dev_err(&pdev->dev, "phy_mode not found\n"); | 113 | dev_err(&pdev->dev, "phy_mode not found\n"); |
| 114 | 114 | ||
| 115 | plat->phy_interface = phy_mode; | ||
| 115 | plat->interface = PHY_INTERFACE_MODE_GMII; | 116 | plat->interface = PHY_INTERFACE_MODE_GMII; |
| 116 | 117 | ||
| 117 | pci_set_master(pdev); | 118 | pci_set_master(pdev); |
| @@ -349,6 +349,9 @@ void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue); · 348 unmodified lines | |||
| 349 | void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue); | 349 | void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue); |
| 350 | void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue); | 350 | void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue); |
| 351 | int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags); | 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 | #if IS_ENABLED(CONFIG_STMMAC_SELFTESTS) | 356 | #if IS_ENABLED(CONFIG_STMMAC_SELFTESTS) |
| 354 | void stmmac_selftest_run(struct net_device *dev, | 357 | void stmmac_selftest_run(struct net_device *dev, |
| @@ -7171,6 +7171,7 @@ int stmmac_suspend(struct device *dev) · 7170 unmodified lines | |||
| 7171 | priv->plat->rx_queues_to_use, false); | 7171 | priv->plat->rx_queues_to_use, false); |
| 7172 | 7172 | ||
| 7173 | stmmac_fpe_handshake(priv, false); | 7173 | stmmac_fpe_handshake(priv, false); |
| 7174 | stmmac_fpe_stop_wq(priv); | ||
| 7174 | } | 7175 | } |
| 7175 | 7176 | ||
| 7176 | priv->speed = SPEED_UNKNOWN; | 7177 | priv->speed = SPEED_UNKNOWN; |
| @@ -397,6 +397,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) · 396 unmodified lines | |||
| 397 | struct device_node *np = pdev->dev.of_node; | 397 | struct device_node *np = pdev->dev.of_node; |
| 398 | struct plat_stmmacenet_data *plat; | 398 | struct plat_stmmacenet_data *plat; |
| 399 | struct stmmac_dma_cfg *dma_cfg; | 399 | struct stmmac_dma_cfg *dma_cfg; |
| 400 | int phy_mode; | ||
| 400 | void *ret; | 401 | void *ret; |
| 401 | int rc; | 402 | int rc; |
| 402 | 403 | ||
| @@ -412,10 +413,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) · 9 unmodified lines | |||
| 412 | eth_zero_addr(mac); | 413 | eth_zero_addr(mac); |
| 413 | } | 414 | } |
| 414 | 415 | ||
| 415 | plat->phy_interface = device_get_phy_mode(&pdev->dev); | 416 | phy_mode = device_get_phy_mode(&pdev->dev); |
| 416 | if (plat->phy_interface < 0) | 417 | if (phy_mode < 0) |
| 417 | return ERR_PTR(plat->phy_interface); | 418 | return ERR_PTR(phy_mode); |
| 418 | 419 | ||
| 420 | plat->phy_interface = phy_mode; | ||
| 419 | plat->interface = stmmac_of_get_mac_mode(np); | 421 | plat->interface = stmmac_of_get_mac_mode(np); |
| 420 | if (plat->interface < 0) | 422 | if (plat->interface < 0) |
| 421 | plat->interface = plat->phy_interface; | 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 | u32 sec, nsec; | 62 | u32 sec, nsec; |
| 63 | u32 quotient, reminder; | 63 | u32 quotient, reminder; |
| 64 | int neg_adj = 0; | 64 | int neg_adj = 0; |
| 65 | bool xmac; | 65 | bool xmac, est_rst = false; |
| 66 | int ret; | ||
| 66 | 67 | ||
| 67 | xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; | 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 | sec = quotient; | 76 | sec = quotient; |
| 76 | nsec = reminder; | 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 | spin_lock_irqsave(&priv->ptp_lock, flags); | 89 | spin_lock_irqsave(&priv->ptp_lock, flags); |
| 79 | stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac); | 90 | stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac); |
| 80 | spin_unlock_irqrestore(&priv->ptp_lock, flags); | 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 | return 0; | 121 | return 0; |
| 83 | } | 122 | } |
| 84 | 123 | ||
| @@ -711,12 +711,35 @@ static int tc_setup_cls(struct stmmac_priv *priv, · 710 unmodified lines | |||
| 711 | return ret; | 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 | static int tc_setup_taprio(struct stmmac_priv *priv, | 737 | static int tc_setup_taprio(struct stmmac_priv *priv, |
| 715 | struct tc_taprio_qopt_offload *qopt) | 738 | struct tc_taprio_qopt_offload *qopt) |
| 716 | { | 739 | { |
| 717 | u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep; | 740 | u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep; |
| 718 | struct plat_stmmacenet_data *plat = priv->plat; | 741 | struct plat_stmmacenet_data *plat = priv->plat; |
| 719 | struct timespec64 time, current_time; | 742 | struct timespec64 time, current_time, qopt_time; |
| 720 | ktime_t current_time_ns; | 743 | ktime_t current_time_ns; |
| 721 | bool fpe = false; | 744 | bool fpe = false; |
| 722 | int i, ret = 0; | 745 | int i, ret = 0; |
| @@ -773,14 +796,18 @@ static int tc_setup_taprio(struct stmmac_priv *priv, · 50 unmodified lines | |||
| 773 | GFP_KERNEL); | 796 | GFP_KERNEL); |
| 774 | if (!plat->est) | 797 | if (!plat->est) |
| 775 | return -ENOMEM; | 798 | return -ENOMEM; |
| 799 | |||
| 800 | mutex_init(&priv->plat->est->lock); | ||
| 776 | } else { | 801 | } else { |
| 777 | memset(plat->est, 0, sizeof(*plat->est)); | 802 | memset(plat->est, 0, sizeof(*plat->est)); |
| 778 | } | 803 | } |
| 779 | 804 | ||
| 780 | size = qopt->num_entries; | 805 | size = qopt->num_entries; |
| 781 | 806 | ||
| 807 | mutex_lock(&priv->plat->est->lock); | ||
| 782 | priv->plat->est->gcl_size = size; | 808 | priv->plat->est->gcl_size = size; |
| 783 | priv->plat->est->enable = qopt->enable; | 809 | priv->plat->est->enable = qopt->enable; |
| 810 | mutex_unlock(&priv->plat->est->lock); | ||
| 784 | 811 | ||
| 785 | for (i = 0; i < size; i++) { | 812 | for (i = 0; i < size; i++) { |
| 786 | s64 delta_ns = qopt->entries[i].interval; | 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 | priv->plat->est->gcl[i] = delta_ns | (gates << wid); | 838 | priv->plat->est->gcl[i] = delta_ns | (gates << wid); |
| 812 | } | 839 | } |
| 813 | 840 | ||
| 841 | mutex_lock(&priv->plat->est->lock); | ||
| 814 | /* Adjust for real system time */ | 842 | /* Adjust for real system time */ |
| 815 | priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, ¤t_time); | 843 | priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, ¤t_time); |
| 816 | current_time_ns = timespec64_to_ktime(current_time); | 844 | current_time_ns = timespec64_to_ktime(current_time); |
| 817 | if (ktime_after(qopt->base_time, current_time_ns)) { | 845 | time = stmmac_calc_tas_basetime(qopt->base_time, current_time_ns, |
| 818 | time = ktime_to_timespec64(qopt->base_time); | 846 | qopt->cycle_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 | } | ||
| 830 | 847 | ||
| 831 | priv->plat->est->btr[0] = (u32)time.tv_nsec; | 848 | priv->plat->est->btr[0] = (u32)time.tv_nsec; |
| 832 | priv->plat->est->btr[1] = (u32)time.tv_sec; | 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 | ctr = qopt->cycle_time; | 855 | ctr = qopt->cycle_time; |
| 835 | priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC); | 856 | priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC); |
| 836 | priv->plat->est->ctr[1] = (u32)ctr; | 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 | return -EOPNOTSUPP; | 861 | return -EOPNOTSUPP; |
| 862 | } | ||
| 840 | 863 | ||
| 841 | /* Actual FPE register configuration will be done after FPE handshake | 864 | /* Actual FPE register configuration will be done after FPE handshake |
| 842 | * is success. | 865 | * is success. |
| @@ -845,6 +868,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv, · 2 unmodified lines | |||
| 845 | 868 | ||
| 846 | ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, | 869 | ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, |
| 847 | priv->plat->clk_ptp_rate); | 870 | priv->plat->clk_ptp_rate); |
| 871 | mutex_unlock(&priv->plat->est->lock); | ||
| 848 | if (ret) { | 872 | if (ret) { |
| 849 | netdev_err(priv->dev, "failed to configure EST\n"); | 873 | netdev_err(priv->dev, "failed to configure EST\n"); |
| 850 | goto disable; | 874 | goto disable; |
| @@ -860,9 +884,11 @@ static int tc_setup_taprio(struct stmmac_priv *priv, · 9 unmodified lines | |||
| 860 | return 0; | 884 | return 0; |
| 861 | 885 | ||
| 862 | disable: | 886 | disable: |
| 887 | mutex_lock(&priv->plat->est->lock); | ||
| 863 | priv->plat->est->enable = false; | 888 | priv->plat->est->enable = false; |
| 864 | stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, | 889 | stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, |
| 865 | priv->plat->clk_ptp_rate); | 890 | priv->plat->clk_ptp_rate); |
| 891 | mutex_unlock(&priv->plat->est->lock); | ||
| 866 | 892 | ||
| 867 | priv->plat->fpe_cfg->enable = false; | 893 | priv->plat->fpe_cfg->enable = false; |
| 868 | stmmac_fpe_configure(priv, priv->ioaddr, | 894 | stmmac_fpe_configure(priv, priv->ioaddr, |
| @@ -313,9 +313,8 @@ static void tlan_remove_one(struct pci_dev *pdev) · 312 unmodified lines | |||
| 313 | pci_release_regions(pdev); | 313 | pci_release_regions(pdev); |
| 314 | #endif | 314 | #endif |
| 315 | 315 | ||
| 316 | free_netdev(dev); | ||
| 317 | |||
| 318 | cancel_work_sync(&priv->tlan_tqueue); | 316 | cancel_work_sync(&priv->tlan_tqueue); |
| 317 | free_netdev(dev); | ||
| 319 | } | 318 | } |
| 320 | 319 | ||
| 321 | static void tlan_start(struct net_device *dev) | 320 | static void tlan_start(struct net_device *dev) |
| @@ -1504,9 +1504,8 @@ err_out_resource: · 1503 unmodified lines | |||
| 1504 | release_mem_region(start, len); | 1504 | release_mem_region(start, len); |
| 1505 | 1505 | ||
| 1506 | err_out_kfree: | 1506 | err_out_kfree: |
| 1507 | free_netdev(dev); | ||
| 1508 | |||
| 1509 | pr_err("%s: initialization failure, aborting!\n", fp->name); | 1507 | pr_err("%s: initialization failure, aborting!\n", fp->name); |
| 1508 | free_netdev(dev); | ||
| 1510 | return ret; | 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 | u32 *mykey, u32 *mysalt) | 85 | u32 *mykey, u32 *mysalt) |
| 86 | { | 86 | { |
| 87 | const char aes_gcm_name[] = "rfc4106(gcm(aes))"; | 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 | unsigned char *key_data; | 89 | unsigned char *key_data; |
| 90 | char *alg_name = NULL; | 90 | char *alg_name = NULL; |
| 91 | int key_len; | 91 | int key_len; |
| @@ -134,7 +134,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs) · 42 unmodified lines | |||
| 134 | u16 sa_idx; | 134 | u16 sa_idx; |
| 135 | int ret; | 135 | int ret; |
| 136 | 136 | ||
| 137 | dev = xs->xso.dev; | 137 | dev = xs->xso.real_dev; |
| 138 | ns = netdev_priv(dev); | 138 | ns = netdev_priv(dev); |
| 139 | ipsec = &ns->ipsec; | 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 | static void nsim_ipsec_del_sa(struct xfrm_state *xs) | 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 | struct nsim_ipsec *ipsec = &ns->ipsec; | 198 | struct nsim_ipsec *ipsec = &ns->ipsec; |
| 199 | u16 sa_idx; | 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 | static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) | 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 | struct nsim_ipsec *ipsec = &ns->ipsec; | 215 | struct nsim_ipsec *ipsec = &ns->ipsec; |
| 216 | 216 | ||
| 217 | ipsec->ok++; | 217 | ipsec->ok++; |
| @@ -78,6 +78,11 @@ enum { · 77 unmodified lines | |||
| 78 | /* Temperature read register (88E2110 only) */ | 78 | /* Temperature read register (88E2110 only) */ |
| 79 | MV_PCS_TEMP = 0x8042, | 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 | /* These registers appear at 0x800X and 0xa00X - the 0xa00X control | 86 | /* These registers appear at 0x800X and 0xa00X - the 0xa00X control |
| 82 | * registers appear to set themselves to the 0x800X when AN is | 87 | * registers appear to set themselves to the 0x800X when AN is |
| 83 | * restarted, but status registers appear readable from either. | 88 | * restarted, but status registers appear readable from either. |
| @@ -966,6 +971,30 @@ static const struct mv3310_chip mv2111_type = { · 882 unmodified lines | |||
| 966 | #endif | 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 | static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) | 998 | static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) |
| 970 | { | 999 | { |
| 971 | int val; | 1000 | int val; |
| @@ -994,7 +1023,8 @@ static int mv2111_match_phy_device(struct phy_device *phydev) · 22 unmodified lines | |||
| 994 | static struct phy_driver mv3310_drivers[] = { | 1023 | static struct phy_driver mv3310_drivers[] = { |
| 995 | { | 1024 | { |
| 996 | .phy_id = MARVELL_PHY_ID_88X3310, | 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 | .name = "mv88x3310", | 1028 | .name = "mv88x3310", |
| 999 | .driver_data = &mv3310_type, | 1029 | .driver_data = &mv3310_type, |
| 1000 | .get_features = mv3310_get_features, | 1030 | .get_features = mv3310_get_features, |
| @@ -1011,8 +1041,9 @@ static struct phy_driver mv3310_drivers[] = { · 10 unmodified lines | |||
| 1011 | .set_loopback = genphy_c45_loopback, | 1041 | .set_loopback = genphy_c45_loopback, |
| 1012 | }, | 1042 | }, |
| 1013 | { | 1043 | { |
| 1014 | .phy_id = MARVELL_PHY_ID_88X3340, | 1044 | .phy_id = MARVELL_PHY_ID_88X3310, |
| 1015 | .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK, | 1045 | .phy_id_mask = MARVELL_PHY_ID_MASK, |
| 1046 | .match_phy_device = mv3340_match_phy_device, | ||
| 1016 | .name = "mv88x3340", | 1047 | .name = "mv88x3340", |
| 1017 | .driver_data = &mv3340_type, | 1048 | .driver_data = &mv3340_type, |
| 1018 | .get_features = mv3310_get_features, | 1049 | .get_features = mv3310_get_features, |
| @@ -1069,8 +1100,7 @@ static struct phy_driver mv3310_drivers[] = { · 50 unmodified lines | |||
| 1069 | module_phy_driver(mv3310_drivers); | 1100 | module_phy_driver(mv3310_drivers); |
| 1070 | 1101 | ||
| 1071 | static struct mdio_device_id __maybe_unused mv3310_tbl[] = { | 1102 | static struct mdio_device_id __maybe_unused mv3310_tbl[] = { |
| 1072 | { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_88X33X0_MASK }, | 1103 | { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK }, |
| 1073 | { MARVELL_PHY_ID_88X3340, MARVELL_PHY_ID_88X33X0_MASK }, | ||
| 1074 | { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK }, | 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 | return ret; | 701 | return ret; |
| 702 | } | 702 | } |
| 703 | 703 | ||
| 704 | phy_suspend(priv->phydev); | ||
| 704 | priv->phydev->mac_managed_pm = 1; | 705 | priv->phydev->mac_managed_pm = 1; |
| 705 | 706 | ||
| 706 | phy_attached_info(priv->phydev); | 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 | struct scatterlist *sgs[4], hdr, stat; | 1772 | struct scatterlist *sgs[4], hdr, stat; |
| 1773 | unsigned out_num = 0, tmp; | 1773 | unsigned out_num = 0, tmp; |
| 1774 | int ret; | ||
| 1774 | 1775 | ||
| 1775 | /* Caller should know better */ | 1776 | /* Caller should know better */ |
| 1776 | BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)); | 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 | sgs[out_num] = &stat; | 1791 | sgs[out_num] = &stat; |
| 1791 | 1792 | ||
| 1792 | BUG_ON(out_num + 1 > ARRAY_SIZE(sgs)); | 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 | if (unlikely(!virtqueue_kick(vi->cvq))) | 1801 | if (unlikely(!virtqueue_kick(vi->cvq))) |
| 1796 | return vi->ctrl->status == VIRTIO_NET_OK; | 1802 | return vi->ctrl->status == VIRTIO_NET_OK; |
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Linux driver for VMware's vmxnet3 ethernet NIC. | 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 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the | 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 | #include "vmxnet3_int.h" | 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 | struct vmxnet3_stat_desc { | 34 | struct vmxnet3_stat_desc { |
| 31 | char desc[ETH_GSTRING_LEN]; | 35 | char desc[ETH_GSTRING_LEN]; |
| @@ -262,6 +266,8 @@ netdev_features_t vmxnet3_features_check(struct sk_buff *skb, · 230 unmodified lines | |||
| 262 | if (VMXNET3_VERSION_GE_4(adapter) && | 266 | if (VMXNET3_VERSION_GE_4(adapter) && |
| 263 | skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) { | 267 | skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) { |
| 264 | u8 l4_proto = 0; | 268 | u8 l4_proto = 0; |
| 269 | u16 port; | ||
| 270 | struct udphdr *udph; | ||
| 265 | 271 | ||
| 266 | switch (vlan_get_protocol(skb)) { | 272 | switch (vlan_get_protocol(skb)) { |
| 267 | case htons(ETH_P_IP): | 273 | case htons(ETH_P_IP): |
| @@ -274,8 +280,20 @@ netdev_features_t vmxnet3_features_check(struct sk_buff *skb, · 6 unmodified lines | |||
| 274 | return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); | 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 | return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); | 295 | return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); |
| 296 | } | ||
| 279 | } | 297 | } |
| 280 | return features; | 298 | return features; |
| 281 | } | 299 | } |
| @@ -364,19 +364,19 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) · 363 unmodified lines | |||
| 364 | return -EINVAL; | 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 | register_hdlc_protocol(&proto); | 369 | register_hdlc_protocol(&proto); |
| 370 | return 0; | 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 | unregister_hdlc_protocol(&proto); | 375 | unregister_hdlc_protocol(&proto); |
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | module_init(mod_init); | 378 | module_init(hdlc_cisco_init); |
| 379 | module_exit(mod_exit); | 379 | module_exit(hdlc_cisco_exit); |
| 380 | 380 | ||
| 381 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 381 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 382 | MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC"); | 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 | return -EINVAL; | 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 | register_hdlc_protocol(&proto); | 1284 | register_hdlc_protocol(&proto); |
| 1285 | return 0; | 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 | unregister_hdlc_protocol(&proto); | 1290 | unregister_hdlc_protocol(&proto); |
| 1291 | } | 1291 | } |
| 1292 | 1292 | ||
| 1293 | module_init(mod_init); | 1293 | module_init(hdlc_fr_init); |
| 1294 | module_exit(mod_exit); | 1294 | module_exit(hdlc_fr_exit); |
| 1295 | 1295 | ||
| 1296 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 1296 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 1297 | MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC"); | 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 | return -EINVAL; | 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 | skb_queue_head_init(&tx_queue); | 710 | skb_queue_head_init(&tx_queue); |
| 711 | register_hdlc_protocol(&proto); | 711 | register_hdlc_protocol(&proto); |
| 712 | return 0; | 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 | unregister_hdlc_protocol(&proto); | 717 | unregister_hdlc_protocol(&proto); |
| 718 | } | 718 | } |
| 719 | 719 | ||
| 720 | module_init(mod_init); | 720 | module_init(hdlc_ppp_init); |
| 721 | module_exit(mod_exit); | 721 | module_exit(hdlc_ppp_exit); |
| 722 | 722 | ||
| 723 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 723 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 724 | MODULE_DESCRIPTION("PPP protocol support for generic HDLC"); | 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 | register_hdlc_protocol(&proto); | 95 | register_hdlc_protocol(&proto); |
| 96 | return 0; | 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 | unregister_hdlc_protocol(&proto); | 103 | unregister_hdlc_protocol(&proto); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | 106 | ||
| 107 | module_init(mod_init); | 107 | module_init(hdlc_raw_init); |
| 108 | module_exit(mod_exit); | 108 | module_exit(hdlc_raw_exit); |
| 109 | 109 | ||
| 110 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 110 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 111 | MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC"); | 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 | register_hdlc_protocol(&proto); | 115 | register_hdlc_protocol(&proto); |
| 116 | return 0; | 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 | unregister_hdlc_protocol(&proto); | 123 | unregister_hdlc_protocol(&proto); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | 126 | ||
| 127 | module_init(mod_init); | 127 | module_init(hdlc_eth_init); |
| 128 | module_exit(mod_exit); | 128 | module_exit(hdlc_eth_exit); |
| 129 | 129 | ||
| 130 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 130 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 131 | MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC"); | 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 | return -EINVAL; | 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 | register_hdlc_protocol(&proto); | 370 | register_hdlc_protocol(&proto); |
| 371 | return 0; | 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 | unregister_hdlc_protocol(&proto); | 376 | unregister_hdlc_protocol(&proto); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | module_init(mod_init); | 379 | module_init(hdlc_x25_init); |
| 380 | module_exit(mod_exit); | 380 | module_exit(hdlc_x25_exit); |
| 381 | 381 | ||
| 382 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | 382 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); |
| 383 | MODULE_DESCRIPTION("X.25 protocol support for generic HDLC"); | 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 | ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); | 931 | ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); |
| 932 | if (ret) { | 932 | if (ret) { |
| 933 | dev_dbg(dev->mt76.dev, "Firmware is already download\n"); | 933 | dev_dbg(dev->mt76.dev, "Firmware is already download\n"); |
| 934 | return -EIO; | 934 | goto fw_loaded; |
| 935 | } | 935 | } |
| 936 | 936 | ||
| 937 | ret = mt7921_load_patch(dev); | 937 | ret = mt7921_load_patch(dev); |
| @@ -949,6 +949,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) · 11 unmodified lines | |||
| 949 | return -EIO; | 949 | return -EIO; |
| 950 | } | 950 | } |
| 951 | 951 | ||
| 952 | fw_loaded: | ||
| 952 | mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); | 953 | mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); |
| 953 | 954 | ||
| 954 | #ifdef CONFIG_PM | 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 | return -EIO; | 24 | return -EIO; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | /* check for the interafce id | 27 | return ipc_mux_open_session(ipc_imem->mux, if_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; | ||
| 36 | } | 28 | } |
| 37 | 29 | ||
| 38 | /* Release a net link to CP. */ | 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 | if (ipc_imem->mux && if_id >= IP_MUX_SESSION_START && | 34 | if (ipc_imem->mux && if_id >= IP_MUX_SESSION_START && |
| 43 | if_id <= IP_MUX_SESSION_END) | 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 | /* Tasklet call to do uplink transfer. */ | 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 | goto out; | 75 | goto out; |
| 84 | } | 76 | } |
| 85 | 77 | ||
| 86 | if (if_id >= IP_MUX_SESSION_START && if_id <= IP_MUX_SESSION_END) | 78 | /* Route the UL packet through IP MUX Layer */ |
| 87 | /* Route the UL packet through IP MUX Layer */ | 79 | ret = ipc_mux_ul_trigger_encode(ipc_imem->mux, if_id, skb); |
| 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); | ||
| 93 | out: | 80 | out: |
| 94 | return ret; | 81 | return ret; |
| 95 | } | 82 | } |
| @@ -27,11 +27,11 @@ · 26 unmodified lines | |||
| 27 | #define BOOT_CHECK_DEFAULT_TIMEOUT 400 | 27 | #define BOOT_CHECK_DEFAULT_TIMEOUT 400 |
| 28 | 28 | ||
| 29 | /* IP MUX channel range */ | 29 | /* IP MUX channel range */ |
| 30 | #define IP_MUX_SESSION_START 1 | 30 | #define IP_MUX_SESSION_START 0 |
| 31 | #define IP_MUX_SESSION_END 8 | 31 | #define IP_MUX_SESSION_END 7 |
| 32 | 32 | ||
| 33 | /* Default IP MUX channel */ | 33 | /* Default IP MUX channel */ |
| 34 | #define IP_MUX_SESSION_DEFAULT 1 | 34 | #define IP_MUX_SESSION_DEFAULT 0 |
| 35 | 35 | ||
| 36 | /** | 36 | /** |
| 37 | * ipc_imem_sys_port_open - Open a port link to CP. | 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 | /* Pass the packet to the netif layer. */ | 288 | /* Pass the packet to the netif layer. */ |
| 289 | dest_skb->priority = service_class; | 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 | /* Decode Flow Credit Table in the block */ | 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 | /* Store the device and event information */ | 38 | /* Store the device and event information */ |
| 39 | info->dev = dev; | 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 | /* Schedule uevent in process context using work queue */ | 42 | /* Schedule uevent in process context using work queue */ |
| 43 | schedule_work(&info->work); | 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 | struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev); | 108 | struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev); |
| 109 | struct iosm_wwan *ipc_wwan = priv->ipc_wwan; | 109 | struct iosm_wwan *ipc_wwan = priv->ipc_wwan; |
| 110 | unsigned int len = skb->len; | ||
| 110 | int if_id = priv->if_id; | 111 | int if_id = priv->if_id; |
| 111 | int ret; | 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 | /* Return code of zero is success */ | 125 | /* Return code of zero is success */ |
| 125 | if (ret == 0) { | 126 | if (ret == 0) { |
| 127 | netdev->stats.tx_packets++; | ||
| 128 | netdev->stats.tx_bytes += len; | ||
| 126 | ret = NETDEV_TX_OK; | 129 | ret = NETDEV_TX_OK; |
| 127 | } else if (ret == -EBUSY) { | 130 | } else if (ret == -EBUSY) { |
| 128 | ret = NETDEV_TX_BUSY; | 131 | ret = NETDEV_TX_BUSY; |
| @@ -140,7 +143,8 @@ exit: · 11 unmodified lines | |||
| 140 | ret); | 143 | ret); |
| 141 | 144 | ||
| 142 | dev_kfree_skb_any(skb); | 145 | dev_kfree_skb_any(skb); |
| 143 | return ret; | 146 | netdev->stats.tx_dropped++; |
| 147 | return NETDEV_TX_OK; | ||
| 144 | } | 148 | } |
| 145 | 149 | ||
| 146 | /* Ops structure for wwan net link */ | 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 | iosm_dev->priv_flags |= IFF_NO_QUEUE; | 162 | iosm_dev->priv_flags |= IFF_NO_QUEUE; |
| 159 | 163 | ||
| 160 | iosm_dev->type = ARPHRD_NONE; | 164 | iosm_dev->type = ARPHRD_NONE; |
| 165 | iosm_dev->mtu = ETH_DATA_LEN; | ||
| 161 | iosm_dev->min_mtu = ETH_MIN_MTU; | 166 | iosm_dev->min_mtu = ETH_MIN_MTU; |
| 162 | iosm_dev->max_mtu = ETH_MAX_MTU; | 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 | skb->pkt_type = PACKET_HOST; | 258 | skb->pkt_type = PACKET_HOST; |
| 254 | 259 | ||
| 255 | if (if_id < (IP_MUX_SESSION_START - 1) || | 260 | if (if_id < IP_MUX_SESSION_START || |
| 256 | if_id > (IP_MUX_SESSION_END - 1)) { | 261 | if_id > IP_MUX_SESSION_END) { |
| 257 | ret = -EINVAL; | 262 | ret = -EINVAL; |
| 258 | goto free; | 263 | goto free; |
| 259 | } | 264 | } |
| @@ -3,7 +3,7 @@ · 2 unmodified lines | |||
| 3 | # Makefile for PTP 1588 clock support. | 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 | ptp_kvm-$(CONFIG_X86) := ptp_kvm_x86.o ptp_kvm_common.o | 7 | ptp_kvm-$(CONFIG_X86) := ptp_kvm_x86.o ptp_kvm_common.o |
| 8 | ptp_kvm-$(CONFIG_HAVE_ARM_SMCCC) := ptp_kvm_arm.o ptp_kvm_common.o | 8 | ptp_kvm-$(CONFIG_HAVE_ARM_SMCCC) := ptp_kvm_arm.o ptp_kvm_common.o |
| 9 | obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o | 9 | obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o |
| @@ -24,10 +24,11 @@ · 23 unmodified lines | |||
| 24 | #define PTP_PPS_EVENT PPS_CAPTUREASSERT | 24 | #define PTP_PPS_EVENT PPS_CAPTUREASSERT |
| 25 | #define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC) | 25 | #define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC) |
| 26 | 26 | ||
| 27 | struct class *ptp_class; | ||
| 28 | |||
| 27 | /* private globals */ | 29 | /* private globals */ |
| 28 | 30 | ||
| 29 | static dev_t ptp_devt; | 31 | static dev_t ptp_devt; |
| 30 | static struct class *ptp_class; | ||
| 31 | 32 | ||
| 32 | static DEFINE_IDA(ptp_clocks_map); | 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 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); | 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 | return ptp->info->settime64(ptp->info, tp); | 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 | struct ptp_clock_info *ops; | 103 | struct ptp_clock_info *ops; |
| 98 | int err = -EOPNOTSUPP; | 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 | ops = ptp->info; | 111 | ops = ptp->info; |
| 101 | 112 | ||
| 102 | if (tx->modes & ADJ_SETOFFSET) { | 113 | if (tx->modes & ADJ_SETOFFSET) { |
| @@ -161,6 +172,7 @@ static void ptp_clock_release(struct device *dev) · 58 unmodified lines | |||
| 161 | ptp_cleanup_pin_groups(ptp); | 172 | ptp_cleanup_pin_groups(ptp); |
| 162 | mutex_destroy(&ptp->tsevq_mux); | 173 | mutex_destroy(&ptp->tsevq_mux); |
| 163 | mutex_destroy(&ptp->pincfg_mux); | 174 | mutex_destroy(&ptp->pincfg_mux); |
| 175 | mutex_destroy(&ptp->n_vclocks_mux); | ||
| 164 | ida_simple_remove(&ptp_clocks_map, ptp->index); | 176 | ida_simple_remove(&ptp_clocks_map, ptp->index); |
| 165 | kfree(ptp); | 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 | struct ptp_clock *ptp; | 198 | struct ptp_clock *ptp; |
| 187 | int err = 0, index, major = MAJOR(ptp_devt); | 199 | int err = 0, index, major = MAJOR(ptp_devt); |
| 200 | size_t size; | ||
| 188 | 201 | ||
| 189 | if (info->n_alarm > PTP_MAX_ALARMS) | 202 | if (info->n_alarm > PTP_MAX_ALARMS) |
| 190 | return ERR_PTR(-EINVAL); | 203 | return ERR_PTR(-EINVAL); |
| @@ -208,6 +221,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, · 17 unmodified lines | |||
| 208 | spin_lock_init(&ptp->tsevq.lock); | 221 | spin_lock_init(&ptp->tsevq.lock); |
| 209 | mutex_init(&ptp->tsevq_mux); | 222 | mutex_init(&ptp->tsevq_mux); |
| 210 | mutex_init(&ptp->pincfg_mux); | 223 | mutex_init(&ptp->pincfg_mux); |
| 224 | mutex_init(&ptp->n_vclocks_mux); | ||
| 211 | init_waitqueue_head(&ptp->tsev_wq); | 225 | init_waitqueue_head(&ptp->tsev_wq); |
| 212 | 226 | ||
| 213 | if (ptp->info->do_aux_work) { | 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 | pr_err("failed to create ptp aux_worker %d\n", err); | 232 | pr_err("failed to create ptp aux_worker %d\n", err); |
| 219 | goto kworker_err; | 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 | err = ptp_populate_pin_groups(ptp); | 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 | pr_err("failed to register pps source\n"); | 267 | pr_err("failed to register pps source\n"); |
| 239 | goto no_pps; | 268 | goto no_pps; |
| 240 | } | 269 | } |
| 270 | ptp->pps_source->lookup_cookie = ptp; | ||
| 241 | } | 271 | } |
| 242 | 272 | ||
| 243 | /* Initialize a new device of our class in our clock structure. */ | 273 | /* Initialize a new device of our class in our clock structure. */ |
| @@ -265,11 +295,14 @@ no_clock: · 21 unmodified lines | |||
| 265 | no_pps: | 295 | no_pps: |
| 266 | ptp_cleanup_pin_groups(ptp); | 296 | ptp_cleanup_pin_groups(ptp); |
| 267 | no_pin_groups: | 297 | no_pin_groups: |
| 298 | kfree(ptp->vclock_index); | ||
| 299 | no_mem_for_vclocks: | ||
| 268 | if (ptp->kworker) | 300 | if (ptp->kworker) |
| 269 | kthread_destroy_worker(ptp->kworker); | 301 | kthread_destroy_worker(ptp->kworker); |
| 270 | kworker_err: | 302 | kworker_err: |
| 271 | mutex_destroy(&ptp->tsevq_mux); | 303 | mutex_destroy(&ptp->tsevq_mux); |
| 272 | mutex_destroy(&ptp->pincfg_mux); | 304 | mutex_destroy(&ptp->pincfg_mux); |
| 305 | mutex_destroy(&ptp->n_vclocks_mux); | ||
| 273 | ida_simple_remove(&ptp_clocks_map, index); | 306 | ida_simple_remove(&ptp_clocks_map, index); |
| 274 | no_slot: | 307 | no_slot: |
| 275 | kfree(ptp); | 308 | kfree(ptp); |
| @@ -280,9 +313,16 @@ EXPORT_SYMBOL(ptp_clock_register); · 4 unmodified lines | |||
| 280 | 313 | ||
| 281 | int ptp_clock_unregister(struct ptp_clock *ptp) | 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 | ptp->defunct = 1; | 321 | ptp->defunct = 1; |
| 284 | wake_up_interruptible(&ptp->tsev_wq); | 322 | wake_up_interruptible(&ptp->tsev_wq); |
| 285 | 323 | ||
| 324 | kfree(ptp->vclock_index); | ||
| 325 | |||
| 286 | if (ptp->kworker) { | 326 | if (ptp->kworker) { |
| 287 | kthread_cancel_delayed_work_sync(&ptp->aux_work); | 327 | kthread_cancel_delayed_work_sync(&ptp->aux_work); |
| 288 | kthread_destroy_worker(ptp->kworker); | 328 | kthread_destroy_worker(ptp->kworker); |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | #define PTP_MAX_TIMESTAMPS 128 | 19 | #define PTP_MAX_TIMESTAMPS 128 |
| 20 | #define PTP_BUF_TIMESTAMPS 30 | 20 | #define PTP_BUF_TIMESTAMPS 30 |
| 21 | #define PTP_DEFAULT_MAX_VCLOCKS 20 | ||
| 21 | 22 | ||
| 22 | struct timestamp_event_queue { | 23 | struct timestamp_event_queue { |
| 23 | struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS]; | 24 | struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS]; |
| @@ -46,6 +47,24 @@ struct ptp_clock { · 22 unmodified lines | |||
| 46 | const struct attribute_group *pin_attr_groups[2]; | 47 | const struct attribute_group *pin_attr_groups[2]; |
| 47 | struct kthread_worker *kworker; | 48 | struct kthread_worker *kworker; |
| 48 | struct kthread_delayed_work aux_work; | 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 | return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt; | 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 | * see ptp_chardev.c | 102 | * see ptp_chardev.c |
| 66 | */ | 103 | */ |
| @@ -89,4 +126,6 @@ extern const struct attribute_group *ptp_groups[]; · 22 unmodified lines | |||
| 89 | int ptp_populate_pin_groups(struct ptp_clock *ptp); | 126 | int ptp_populate_pin_groups(struct ptp_clock *ptp); |
| 90 | void ptp_cleanup_pin_groups(struct ptp_clock *ptp); | 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 | #endif | 131 | #endif |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | |||
| 3 | * PTP 1588 clock support - sysfs interface. | 3 | * PTP 1588 clock support - sysfs interface. |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2010 OMICRON electronics GmbH | 5 | * Copyright (C) 2010 OMICRON electronics GmbH |
| 6 | * Copyright 2021 NXP | ||
| 6 | */ | 7 | */ |
| 7 | #include <linux/capability.h> | 8 | #include <linux/capability.h> |
| 8 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
| @@ -148,6 +149,159 @@ out: · 139 unmodified lines | |||
| 148 | } | 149 | } |
| 149 | static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store); | 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 | static struct attribute *ptp_attrs[] = { | 305 | static struct attribute *ptp_attrs[] = { |
| 152 | &dev_attr_clock_name.attr, | 306 | &dev_attr_clock_name.attr, |
| 153 | 307 | ||
| @@ -162,6 +316,8 @@ static struct attribute *ptp_attrs[] = { · 8 unmodified lines | |||
| 162 | &dev_attr_fifo.attr, | 316 | &dev_attr_fifo.attr, |
| 163 | &dev_attr_period.attr, | 317 | &dev_attr_period.attr, |
| 164 | &dev_attr_pps_enable.attr, | 318 | &dev_attr_pps_enable.attr, |
| 319 | &dev_attr_n_vclocks.attr, | ||
| 320 | &dev_attr_max_vclocks.attr, | ||
| 165 | NULL | 321 | NULL |
| 166 | }; | 322 | }; |
| 167 | 323 | ||
| @@ -183,6 +339,10 @@ static umode_t ptp_is_attribute_visible(struct kobject *kobj, · 15 unmodified lines | |||
| 183 | } else if (attr == &dev_attr_pps_enable.attr) { | 339 | } else if (attr == &dev_attr_pps_enable.attr) { |
| 184 | if (!info->pps) | 340 | if (!info->pps) |
| 185 | mode = 0; | 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 | return mode; | 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 | void *tailcall_target; | 780 | void *tailcall_target; |
| 781 | void *tailcall_bypass; | 781 | void *tailcall_bypass; |
| 782 | void *bypass_addr; | 782 | void *bypass_addr; |
| 783 | void *aux; | ||
| 783 | union { | 784 | union { |
| 784 | struct { | 785 | struct { |
| 785 | struct bpf_map *map; | 786 | struct bpf_map *map; |
| @@ -757,6 +757,16 @@ void · 756 unmodified lines | |||
| 757 | ethtool_params_from_link_mode(struct ethtool_link_ksettings *link_ksettings, | 757 | ethtool_params_from_link_mode(struct ethtool_link_ksettings *link_ksettings, |
| 758 | enum ethtool_link_mode_bit_indices link_mode); | 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 | * ethtool_sprintf - Write formatted string to ethtool string data | 771 | * ethtool_sprintf - Write formatted string to ethtool string data |
| 762 | * @data: Pointer to start of string to update | 772 | * @data: Pointer to start of string to update |
| @@ -22,14 +22,10 @@ · 21 unmodified lines | |||
| 22 | #define MARVELL_PHY_ID_88E1545 0x01410ea0 | 22 | #define MARVELL_PHY_ID_88E1545 0x01410ea0 |
| 23 | #define MARVELL_PHY_ID_88E1548P 0x01410ec0 | 23 | #define MARVELL_PHY_ID_88E1548P 0x01410ec0 |
| 24 | #define MARVELL_PHY_ID_88E3016 0x01410e60 | 24 | #define MARVELL_PHY_ID_88E3016 0x01410e60 |
| 25 | #define MARVELL_PHY_ID_88X3310 0x002b09a0 | ||
| 25 | #define MARVELL_PHY_ID_88E2110 0x002b09b0 | 26 | #define MARVELL_PHY_ID_88E2110 0x002b09b0 |
| 26 | #define MARVELL_PHY_ID_88X2222 0x01410f10 | 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 | /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ | 29 | /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ |
| 34 | #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 | 30 | #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 |
| 35 | 31 | ||
| @@ -11,7 +11,10 @@ · 10 unmodified lines | |||
| 11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 12 | #include <linux/pps_kernel.h> | 12 | #include <linux/pps_kernel.h> |
| 13 | #include <linux/ptp_clock.h> | 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 | * struct ptp_clock_request - request PTP clock event | 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 | struct ptp_clock_info { | 138 | struct ptp_clock_info { |
| 136 | struct module *owner; | 139 | struct module *owner; |
| 137 | char name[16]; | 140 | char name[PTP_CLOCK_NAME_LEN]; |
| 138 | s32 max_adj; | 141 | s32 max_adj; |
| 139 | int n_alarm; | 142 | int n_alarm; |
| 140 | int n_ext_ts; | 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 | void ptp_cancel_worker_sync(struct ptp_clock *ptp); | 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 | #else | 331 | #else |
| 308 | static inline struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, | 332 | static inline struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, |
| 309 | struct device *parent) | 333 | struct device *parent) |
| @@ -323,6 +347,11 @@ static inline int ptp_schedule_worker(struct ptp_clock *ptp, · 13 unmodified lines | |||
| 323 | { return -EOPNOTSUPP; } | 347 | { return -EOPNOTSUPP; } |
| 324 | static inline void ptp_cancel_worker_sync(struct ptp_clock *ptp) | 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 | #endif | 356 | #endif |
| 328 | 357 | ||
| @@ -115,7 +115,9 @@ struct stmmac_axi { · 114 unmodified lines | |||
| 115 | 115 | ||
| 116 | #define EST_GCL 1024 | 116 | #define EST_GCL 1024 |
| 117 | struct stmmac_est { | 117 | struct stmmac_est { |
| 118 | struct mutex lock; | ||
| 118 | int enable; | 119 | int enable; |
| 120 | u32 btr_reserve[2]; | ||
| 119 | u32 btr_offset[2]; | 121 | u32 btr_offset[2]; |
| 120 | u32 btr[2]; | 122 | u32 btr[2]; |
| 121 | u32 ctr[2]; | 123 | u32 ctr[2]; |
| @@ -201,6 +201,11 @@ struct bond_up_slave { · 200 unmodified lines | |||
| 201 | */ | 201 | */ |
| 202 | #define BOND_LINK_NOCHANGE -1 | 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 | * Here are the locking policies for the two bonding locks: | 210 | * Here are the locking policies for the two bonding locks: |
| 206 | * Get rcu_read_lock when reading or RTNL when writing slave list. | 211 | * Get rcu_read_lock when reading or RTNL when writing slave list. |
| @@ -249,7 +254,9 @@ struct bonding { · 42 unmodified lines | |||
| 249 | #endif /* CONFIG_DEBUG_FS */ | 254 | #endif /* CONFIG_DEBUG_FS */ |
| 250 | struct rtnl_link_stats64 bond_stats; | 255 | struct rtnl_link_stats64 bond_stats; |
| 251 | #ifdef CONFIG_XFRM_OFFLOAD | 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 | #endif /* CONFIG_XFRM_OFFLOAD */ | 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 | static inline bool sk_can_busy_loop(const struct sock *sk) | 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 | bool sk_busy_loop_end(void *p, unsigned long start_time); | 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 | return &md_dst->u.tun_info; | 45 | return &md_dst->u.tun_info; |
| 46 | 46 | ||
| 47 | dst = skb_dst(skb); | 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 | return lwt_tun_info(dst->lwtstate); | 51 | return lwt_tun_info(dst->lwtstate); |
| 50 | 52 | ||
| 51 | return NULL; | 53 | return NULL; |
| @@ -263,7 +263,7 @@ static inline bool ipv6_anycast_destination(const struct dst_entry *dst, · 262 unmodified lines | |||
| 263 | int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | 263 | int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, |
| 264 | int (*output)(struct net *, struct sock *, struct sk_buff *)); | 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 | int mtu; | 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 | bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, | 105 | bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, |
| 106 | unsigned int *size, unsigned int remaining, | 106 | unsigned int *size, unsigned int remaining, |
| 107 | struct mptcp_out_options *opts); | 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 | void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, | 110 | void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, |
| 111 | struct mptcp_out_options *opts); | 111 | struct mptcp_out_options *opts); |
| @@ -227,9 +227,10 @@ static inline bool mptcp_established_options(struct sock *sk, · 115 unmodified lines | |||
| 227 | return false; | 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 | struct sk_buff *skb) | 231 | struct sk_buff *skb) |
| 232 | { | 232 | { |
| 233 | return true; | ||
| 233 | } | 234 | } |
| 234 | 235 | ||
| 235 | static inline void mptcp_skb_ext_move(struct sk_buff *to, | 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 | void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list); | 30 | void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list); |
| 31 | 31 | ||
| 32 | void nf_conntrack_proto_pernet_init(struct net *net); | 32 | void nf_conntrack_proto_pernet_init(struct net *net); |
| 33 | void nf_conntrack_proto_pernet_fini(struct net *net); | ||
| 34 | 33 | ||
| 35 | int nf_conntrack_proto_init(void); | 34 | int nf_conntrack_proto_init(void); |
| 36 | void nf_conntrack_proto_fini(void); | 35 | void nf_conntrack_proto_fini(void); |
| @@ -27,6 +27,7 @@ struct nf_tcp_net { · 26 unmodified lines | |||
| 27 | u8 tcp_loose; | 27 | u8 tcp_loose; |
| 28 | u8 tcp_be_liberal; | 28 | u8 tcp_be_liberal; |
| 29 | u8 tcp_max_retrans; | 29 | u8 tcp_max_retrans; |
| 30 | u8 tcp_ignore_invalid_rst; | ||
| 30 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | 31 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
| 31 | unsigned int offload_timeout; | 32 | unsigned int offload_timeout; |
| 32 | unsigned int offload_pickup; | 33 | unsigned int offload_pickup; |
| @@ -360,8 +360,7 @@ enum { · 359 unmodified lines | |||
| 360 | #define SCTP_SCOPE_POLICY_MAX SCTP_SCOPE_POLICY_LINK | 360 | #define SCTP_SCOPE_POLICY_MAX SCTP_SCOPE_POLICY_LINK |
| 361 | 361 | ||
| 362 | /* Based on IPv4 scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>, | 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, | 363 | * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 192.88.99.0/24. |
| 364 | * 192.88.99.0/24. | ||
| 365 | * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP | 364 | * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP |
| 366 | * addresses. | 365 | * addresses. |
| 367 | */ | 366 | */ |
| @@ -369,7 +368,6 @@ enum { · 1 unmodified line | |||
| 369 | ((htonl(INADDR_BROADCAST) == a) || \ | 368 | ((htonl(INADDR_BROADCAST) == a) || \ |
| 370 | ipv4_is_multicast(a) || \ | 369 | ipv4_is_multicast(a) || \ |
| 371 | ipv4_is_zeronet(a) || \ | 370 | ipv4_is_zeronet(a) || \ |
| 372 | ipv4_is_test_198(a) || \ | ||
| 373 | ipv4_is_anycast_6to4(a)) | 371 | ipv4_is_anycast_6to4(a)) |
| 374 | 372 | ||
| 375 | /* Flags used for the bind address copy functions. */ | 373 | /* Flags used for the bind address copy functions. */ |
| @@ -316,7 +316,9 @@ struct bpf_local_storage; · 315 unmodified lines | |||
| 316 | * @sk_timer: sock cleanup timer | 316 | * @sk_timer: sock cleanup timer |
| 317 | * @sk_stamp: time stamp of last packet received | 317 | * @sk_stamp: time stamp of last packet received |
| 318 | * @sk_stamp_seq: lock for accessing sk_stamp on 32 bit architectures only | 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 | * @sk_tskey: counter to disambiguate concurrent tstamp requests | 322 | * @sk_tskey: counter to disambiguate concurrent tstamp requests |
| 321 | * @sk_zckey: counter to order MSG_ZEROCOPY notifications | 323 | * @sk_zckey: counter to order MSG_ZEROCOPY notifications |
| 322 | * @sk_socket: Identd and reporting IO signals | 324 | * @sk_socket: Identd and reporting IO signals |
| @@ -493,6 +495,7 @@ struct sock { · 170 unmodified lines | |||
| 493 | seqlock_t sk_stamp_seq; | 495 | seqlock_t sk_stamp_seq; |
| 494 | #endif | 496 | #endif |
| 495 | u16 sk_tsflags; | 497 | u16 sk_tsflags; |
| 498 | int sk_bind_phc; | ||
| 496 | u8 sk_shutdown; | 499 | u8 sk_shutdown; |
| 497 | u32 sk_tskey; | 500 | u32 sk_tskey; |
| 498 | atomic_t sk_zckey; | 501 | atomic_t sk_zckey; |
| @@ -2755,7 +2758,8 @@ void sock_def_readable(struct sock *sk); · 2256 unmodified lines | |||
| 2755 | 2758 | ||
| 2756 | int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk); | 2759 | int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk); |
| 2757 | void sock_set_timestamp(struct sock *sk, int optname, bool valbool); | 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 | void sock_enable_timestamps(struct sock *sk); | 2764 | void sock_enable_timestamps(struct sock *sk); |
| 2761 | void sock_no_linger(struct sock *sk); | 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 | static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd) | 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 | tp->pred_flags = htonl((tp->tcp_header_len << 26) | | 693 | tp->pred_flags = htonl((tp->tcp_header_len << 26) | |
| 690 | ntohl(TCP_FLAG_ACK) | | 694 | ntohl(TCP_FLAG_ACK) | |
| 691 | snd_wnd); | 695 | snd_wnd); |
| @@ -46,6 +46,7 @@ enum { · 45 unmodified lines | |||
| 46 | ETHTOOL_MSG_FEC_SET, | 46 | ETHTOOL_MSG_FEC_SET, |
| 47 | ETHTOOL_MSG_MODULE_EEPROM_GET, | 47 | ETHTOOL_MSG_MODULE_EEPROM_GET, |
| 48 | ETHTOOL_MSG_STATS_GET, | 48 | ETHTOOL_MSG_STATS_GET, |
| 49 | ETHTOOL_MSG_PHC_VCLOCKS_GET, | ||
| 49 | 50 | ||
| 50 | /* add new constants above here */ | 51 | /* add new constants above here */ |
| 51 | __ETHTOOL_MSG_USER_CNT, | 52 | __ETHTOOL_MSG_USER_CNT, |
| @@ -88,6 +89,7 @@ enum { · 36 unmodified lines | |||
| 88 | ETHTOOL_MSG_FEC_NTF, | 89 | ETHTOOL_MSG_FEC_NTF, |
| 89 | ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY, | 90 | ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY, |
| 90 | ETHTOOL_MSG_STATS_GET_REPLY, | 91 | ETHTOOL_MSG_STATS_GET_REPLY, |
| 92 | ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY, | ||
| 91 | 93 | ||
| 92 | /* add new constants above here */ | 94 | /* add new constants above here */ |
| 93 | __ETHTOOL_MSG_KERNEL_CNT, | 95 | __ETHTOOL_MSG_KERNEL_CNT, |
| @@ -440,6 +442,19 @@ enum { · 346 unmodified lines | |||
| 440 | ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1) | 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 | /* CABLE TEST */ | 458 | /* CABLE TEST */ |
| 444 | 459 | ||
| 445 | enum { | 460 | enum { |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 14 | #include <linux/socket.h> /* for SO_TIMESTAMPING */ | 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 | enum { | 17 | enum { |
| 18 | SOF_TIMESTAMPING_TX_HARDWARE = (1<<0), | 18 | SOF_TIMESTAMPING_TX_HARDWARE = (1<<0), |
| 19 | SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1), | 19 | SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1), |
| @@ -30,8 +30,9 @@ enum { · 10 unmodified lines | |||
| 30 | SOF_TIMESTAMPING_OPT_STATS = (1<<12), | 30 | SOF_TIMESTAMPING_OPT_STATS = (1<<12), |
| 31 | SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13), | 31 | SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13), |
| 32 | SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14), | 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 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | | 36 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | |
| 36 | SOF_TIMESTAMPING_LAST | 37 | SOF_TIMESTAMPING_LAST |
| 37 | }; | 38 | }; |
| @@ -46,6 +47,18 @@ enum { · 8 unmodified lines | |||
| 46 | SOF_TIMESTAMPING_TX_SCHED | \ | 47 | SOF_TIMESTAMPING_TX_SCHED | \ |
| 47 | SOF_TIMESTAMPING_TX_ACK) | 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 | * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter | 63 | * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter |
| 51 | * | 64 | * |
| @@ -61,7 +61,7 @@ enum nfulnl_attr_type { · 60 unmodified lines | |||
| 61 | NFULA_HWTYPE, /* hardware type */ | 61 | NFULA_HWTYPE, /* hardware type */ |
| 62 | NFULA_HWHEADER, /* hardware header */ | 62 | NFULA_HWHEADER, /* hardware header */ |
| 63 | NFULA_HWLEN, /* hardware header length */ | 63 | NFULA_HWLEN, /* hardware header length */ |
| 64 | NFULA_CT, /* nf_conntrack_netlink.h */ | 64 | NFULA_CT, /* nfnetlink_conntrack.h */ |
| 65 | NFULA_CT_INFO, /* enum ip_conntrack_info */ | 65 | NFULA_CT_INFO, /* enum ip_conntrack_info */ |
| 66 | NFULA_VLAN, /* nested attribute: packet vlan info */ | 66 | NFULA_VLAN, /* nested attribute: packet vlan info */ |
| 67 | NFULA_L2HDR, /* full L2 header */ | 67 | NFULA_L2HDR, /* full L2 header */ |
| @@ -51,11 +51,11 @@ enum nfqnl_attr_type { · 50 unmodified lines | |||
| 51 | NFQA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */ | 51 | NFQA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */ |
| 52 | NFQA_HWADDR, /* nfqnl_msg_packet_hw */ | 52 | NFQA_HWADDR, /* nfqnl_msg_packet_hw */ |
| 53 | NFQA_PAYLOAD, /* opaque data payload */ | 53 | NFQA_PAYLOAD, /* opaque data payload */ |
| 54 | NFQA_CT, /* nf_conntrack_netlink.h */ | 54 | NFQA_CT, /* nfnetlink_conntrack.h */ |
| 55 | NFQA_CT_INFO, /* enum ip_conntrack_info */ | 55 | NFQA_CT_INFO, /* enum ip_conntrack_info */ |
| 56 | NFQA_CAP_LEN, /* __u32 length of captured packet */ | 56 | NFQA_CAP_LEN, /* __u32 length of captured packet */ |
| 57 | NFQA_SKB_INFO, /* __u32 skb meta information */ | 57 | NFQA_SKB_INFO, /* __u32 skb meta information */ |
| 58 | NFQA_EXP, /* nf_conntrack_netlink.h */ | 58 | NFQA_EXP, /* nfnetlink_conntrack.h */ |
| 59 | NFQA_UID, /* __u32 sk uid */ | 59 | NFQA_UID, /* __u32 sk uid */ |
| 60 | NFQA_GID, /* __u32 sk gid */ | 60 | NFQA_GID, /* __u32 sk gid */ |
| 61 | NFQA_SECCTX, /* security context string */ | 61 | NFQA_SECCTX, /* security context string */ |
| @@ -2236,8 +2236,14 @@ static void bpf_prog_free_deferred(struct work_struct *work) · 2235 unmodified lines | |||
| 2236 | #endif | 2236 | #endif |
| 2237 | if (aux->dst_trampoline) | 2237 | if (aux->dst_trampoline) |
| 2238 | bpf_trampoline_put(aux->dst_trampoline); | 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 | bpf_jit_free(aux->func[i]); | 2245 | bpf_jit_free(aux->func[i]); |
| 2246 | } | ||
| 2241 | if (aux->func_cnt) { | 2247 | if (aux->func_cnt) { |
| 2242 | kfree(aux->func); | 2248 | kfree(aux->func); |
| 2243 | bpf_prog_unlock_free(aux->prog); | 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 | if (map->map_type == BPF_MAP_TYPE_DEVMAP) { | 559 | if (map->map_type == BPF_MAP_TYPE_DEVMAP) { |
| 560 | for (i = 0; i < map->max_entries; i++) { | 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 | if (!is_valid_dst(dst, xdp, exclude_ifindex)) | 563 | if (!is_valid_dst(dst, xdp, exclude_ifindex)) |
| 563 | continue; | 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 | if (map->map_type == BPF_MAP_TYPE_DEVMAP) { | 656 | if (map->map_type == BPF_MAP_TYPE_DEVMAP) { |
| 656 | for (i = 0; i < map->max_entries; i++) { | 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 | if (!dst || dst->dev->ifindex == exclude_ifindex) | 660 | if (!dst || dst->dev->ifindex == exclude_ifindex) |
| 659 | continue; | 661 | continue; |
| 660 | 662 | ||
| @@ -12121,33 +12121,19 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 12120 unmodified lines | |||
| 12121 | goto out_free; | 12121 | goto out_free; |
| 12122 | func[i]->is_func = 1; | 12122 | func[i]->is_func = 1; |
| 12123 | func[i]->aux->func_idx = i; | 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 | func[i]->aux->btf = prog->aux->btf; | 12125 | func[i]->aux->btf = prog->aux->btf; |
| 12126 | func[i]->aux->func_info = prog->aux->func_info; | 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 | for (j = 0; j < prog->aux->size_poke_tab; j++) { | 12130 | for (j = 0; j < prog->aux->size_poke_tab; j++) { |
| 12129 | u32 insn_idx = prog->aux->poke_tab[j].insn_idx; | 12131 | struct bpf_jit_poke_descriptor *poke; |
| 12130 | int ret; | ||
| 12131 | 12132 | ||
| 12132 | if (!(insn_idx >= subprog_start && | 12133 | poke = &prog->aux->poke_tab[j]; |
| 12133 | insn_idx <= subprog_end)) | 12134 | if (poke->insn_idx < subprog_end && |
| 12134 | continue; | 12135 | poke->insn_idx >= subprog_start) |
| 12135 | 12136 | poke->aux = func[i]->aux; | |
| 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 | } | ||
| 12151 | } | 12137 | } |
| 12152 | 12138 | ||
| 12153 | /* Use bpf_prog_F_tag to indicate functions in stack traces. | 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 | cond_resched(); | 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 | /* at this point all bpf functions were successfully JITed | 12167 | /* at this point all bpf functions were successfully JITed |
| 12194 | * now populate all bpf_calls with correct addresses and | 12168 | * now populate all bpf_calls with correct addresses and |
| 12195 | * run last pass of JIT | 12169 | * run last pass of JIT |
| @@ -12267,14 +12241,22 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 71 unmodified lines | |||
| 12267 | bpf_prog_jit_attempt_done(prog); | 12241 | bpf_prog_jit_attempt_done(prog); |
| 12268 | return 0; | 12242 | return 0; |
| 12269 | out_free: | 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 | for (i = 0; i < env->subprog_cnt; i++) { | 12256 | for (i = 0; i < env->subprog_cnt; i++) { |
| 12271 | if (!func[i]) | 12257 | if (!func[i]) |
| 12272 | continue; | 12258 | continue; |
| 12273 | 12259 | func[i]->aux->poke_tab = NULL; | |
| 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 | } | ||
| 12278 | bpf_jit_free(func[i]); | 12260 | bpf_jit_free(func[i]); |
| 12279 | } | 12261 | } |
| 12280 | kfree(func); | 12262 | kfree(func); |
| @@ -203,6 +203,19 @@ static void garp_attr_destroy(struct garp_applicant *app, struct garp_attr *attr · 202 unmodified lines | |||
| 203 | kfree(attr); | 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 | static int garp_pdu_init(struct garp_applicant *app) | 219 | static int garp_pdu_init(struct garp_applicant *app) |
| 207 | { | 220 | { |
| 208 | struct sk_buff *skb; | 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 | spin_lock_bh(&app->lock); | 623 | spin_lock_bh(&app->lock); |
| 611 | garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); | 624 | garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU); |
| 625 | garp_attr_destroy_all(app); | ||
| 612 | garp_pdu_queue(app); | 626 | garp_pdu_queue(app); |
| 613 | spin_unlock_bh(&app->lock); | 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 | kfree(attr); | 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 | static int mrp_pdu_init(struct mrp_applicant *app) | 308 | static int mrp_pdu_init(struct mrp_applicant *app) |
| 296 | { | 309 | { |
| 297 | struct sk_buff *skb; | 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 | spin_lock_bh(&app->lock); | 909 | spin_lock_bh(&app->lock); |
| 897 | mrp_mad_event(app, MRP_EVENT_TX); | 910 | mrp_mad_event(app, MRP_EVENT_TX); |
| 911 | mrp_attr_destroy_all(app); | ||
| 898 | mrp_pdu_queue(app); | 912 | mrp_pdu_queue(app); |
| 899 | spin_unlock_bh(&app->lock); | 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 | struct net_bridge_port *p; | 562 | struct net_bridge_port *p; |
| 563 | int err = 0; | 563 | int err = 0; |
| 564 | unsigned br_hr, dev_hr; | 564 | unsigned br_hr, dev_hr; |
| 565 | bool changed_addr; | 565 | bool changed_addr, fdb_synced = false; |
| 566 | 566 | ||
| 567 | /* Don't allow bridging non-ethernet like devices. */ | 567 | /* Don't allow bridging non-ethernet like devices. */ |
| 568 | if ((dev->flags & IFF_LOOPBACK) || | 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 | list_add_rcu(&p->list, &br->port_list); | 652 | list_add_rcu(&p->list, &br->port_list); |
| 653 | 653 | ||
| 654 | nbp_update_port_count(br); | 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 | netdev_update_features(br->dev); | 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 | return 0; | 714 | return 0; |
| 702 | 715 | ||
| 703 | err7: | 716 | err7: |
| 717 | if (fdb_synced) | ||
| 718 | br_fdb_unsync_static(br, p); | ||
| 704 | list_del_rcu(&p->list); | 719 | list_del_rcu(&p->list); |
| 705 | br_fdb_delete_by_port(br, p, 0, 1); | 720 | br_fdb_delete_by_port(br, p, 0, 1); |
| 706 | nbp_update_port_count(br); | 721 | nbp_update_port_count(br); |
| @@ -3264,7 +3264,9 @@ static void br_multicast_pim(struct net_bridge *br, · 3263 unmodified lines | |||
| 3264 | pim_hdr_type(pimhdr) != PIM_TYPE_HELLO) | 3264 | pim_hdr_type(pimhdr) != PIM_TYPE_HELLO) |
| 3265 | return; | 3265 | return; |
| 3266 | 3266 | ||
| 3267 | spin_lock(&br->multicast_lock); | ||
| 3267 | br_ip4_multicast_mark_router(br, port); | 3268 | br_ip4_multicast_mark_router(br, port); |
| 3269 | spin_unlock(&br->multicast_lock); | ||
| 3268 | } | 3270 | } |
| 3269 | 3271 | ||
| 3270 | static int br_ip4_multicast_mrd_rcv(struct net_bridge *br, | 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 | igmp_hdr(skb)->type != IGMP_MRDISC_ADV) | 3277 | igmp_hdr(skb)->type != IGMP_MRDISC_ADV) |
| 3276 | return -ENOMSG; | 3278 | return -ENOMSG; |
| 3277 | 3279 | ||
| 3280 | spin_lock(&br->multicast_lock); | ||
| 3278 | br_ip4_multicast_mark_router(br, port); | 3281 | br_ip4_multicast_mark_router(br, port); |
| 3282 | spin_unlock(&br->multicast_lock); | ||
| 3279 | 3283 | ||
| 3280 | return 0; | 3284 | return 0; |
| 3281 | } | 3285 | } |
| @@ -3343,7 +3347,9 @@ static void br_ip6_multicast_mrd_rcv(struct net_bridge *br, · 61 unmodified lines | |||
| 3343 | if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV) | 3347 | if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV) |
| 3344 | return; | 3348 | return; |
| 3345 | 3349 | ||
| 3350 | spin_lock(&br->multicast_lock); | ||
| 3346 | br_ip6_multicast_mark_router(br, port); | 3351 | br_ip6_multicast_mark_router(br, port); |
| 3352 | spin_unlock(&br->multicast_lock); | ||
| 3347 | } | 3353 | } |
| 3348 | 3354 | ||
| 3349 | static int br_multicast_ipv6_rcv(struct net_bridge *br, | 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 | diffs = memcmp(skb_mac_header(p), | 6008 | diffs = memcmp(skb_mac_header(p), |
| 6009 | skb_mac_header(skb), | 6009 | skb_mac_header(skb), |
| 6010 | maclen); | 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 | NAPI_GRO_CB(p)->same_flow = !diffs; | 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 | case GRO_MERGED_FREE: | 6234 | case GRO_MERGED_FREE: |
| 6222 | if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) | 6235 | if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) |
| 6223 | napi_skb_free_stolen_head(skb); | 6236 | napi_skb_free_stolen_head(skb); |
| 6237 | else if (skb->fclone != SKB_FCLONE_UNAVAILABLE) | ||
| 6238 | __kfree_skb(skb); | ||
| 6224 | else | 6239 | else |
| 6225 | __kfree_skb_defer(skb); | 6240 | __kfree_skb_defer(skb); |
| 6226 | break; | 6241 | break; |
| @@ -6270,6 +6285,7 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) · 43 unmodified lines | |||
| 6270 | skb_shinfo(skb)->gso_type = 0; | 6285 | skb_shinfo(skb)->gso_type = 0; |
| 6271 | skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); | 6286 | skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); |
| 6272 | skb_ext_reset(skb); | 6287 | skb_ext_reset(skb); |
| 6288 | nf_reset_ct(skb); | ||
| 6273 | 6289 | ||
| 6274 | napi->skb = skb; | 6290 | napi->skb = skb; |
| 6275 | } | 6291 | } |
| @@ -943,6 +943,7 @@ void __kfree_skb_defer(struct sk_buff *skb) · 942 unmodified lines | |||
| 943 | 943 | ||
| 944 | void napi_skb_free_stolen_head(struct sk_buff *skb) | 944 | void napi_skb_free_stolen_head(struct sk_buff *skb) |
| 945 | { | 945 | { |
| 946 | nf_reset_ct(skb); | ||
| 946 | skb_dst_drop(skb); | 947 | skb_dst_drop(skb); |
| 947 | skb_ext_put(skb); | 948 | skb_ext_put(skb); |
| 948 | napi_skb_cache_put(skb); | 949 | napi_skb_cache_put(skb); |
| @@ -139,6 +139,8 @@ · 138 unmodified lines | |||
| 139 | #include <net/tcp.h> | 139 | #include <net/tcp.h> |
| 140 | #include <net/busy_poll.h> | 140 | #include <net/busy_poll.h> |
| 141 | 141 | ||
| 142 | #include <linux/ethtool.h> | ||
| 143 | |||
| 142 | static DEFINE_MUTEX(proto_list_mutex); | 144 | static DEFINE_MUTEX(proto_list_mutex); |
| 143 | static LIST_HEAD(proto_list); | 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 | if (val & ~SOF_TIMESTAMPING_MASK) | 856 | if (val & ~SOF_TIMESTAMPING_MASK) |
| 816 | return -EINVAL; | 857 | return -EINVAL; |
| 817 | 858 | ||
| @@ -832,6 +873,12 @@ int sock_set_timestamping(struct sock *sk, int optname, int val) · 14 unmodified lines | |||
| 832 | !(val & SOF_TIMESTAMPING_OPT_TSONLY)) | 873 | !(val & SOF_TIMESTAMPING_OPT_TSONLY)) |
| 833 | return -EINVAL; | 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 | sk->sk_tsflags = val; | 882 | sk->sk_tsflags = val; |
| 836 | sock_valbool_flag(sk, SOCK_TSTAMP_NEW, optname == SO_TIMESTAMPING_NEW); | 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 | int sock_setsockopt(struct socket *sock, int level, int optname, | 954 | int sock_setsockopt(struct socket *sock, int level, int optname, |
| 908 | sockptr_t optval, unsigned int optlen) | 955 | sockptr_t optval, unsigned int optlen) |
| 909 | { | 956 | { |
| 957 | struct so_timestamping timestamping; | ||
| 910 | struct sock_txtime sk_txtime; | 958 | struct sock_txtime sk_txtime; |
| 911 | struct sock *sk = sock->sk; | 959 | struct sock *sk = sock->sk; |
| 912 | int val; | 960 | int val; |
| @@ -1068,12 +1116,22 @@ set_sndbuf: · 155 unmodified lines | |||
| 1068 | case SO_TIMESTAMP_NEW: | 1116 | case SO_TIMESTAMP_NEW: |
| 1069 | case SO_TIMESTAMPNS_OLD: | 1117 | case SO_TIMESTAMPNS_OLD: |
| 1070 | case SO_TIMESTAMPNS_NEW: | 1118 | case SO_TIMESTAMPNS_NEW: |
| 1071 | sock_set_timestamp(sk, valbool, optname); | 1119 | sock_set_timestamp(sk, optname, valbool); |
| 1072 | break; | 1120 | break; |
| 1073 | 1121 | ||
| 1074 | case SO_TIMESTAMPING_NEW: | 1122 | case SO_TIMESTAMPING_NEW: |
| 1075 | case SO_TIMESTAMPING_OLD: | 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 | break; | 1135 | break; |
| 1078 | 1136 | ||
| 1079 | case SO_RCVLOWAT: | 1137 | case SO_RCVLOWAT: |
| @@ -1201,7 +1259,7 @@ set_sndbuf: · 121 unmodified lines | |||
| 1201 | if (val < 0) | 1259 | if (val < 0) |
| 1202 | ret = -EINVAL; | 1260 | ret = -EINVAL; |
| 1203 | else | 1261 | else |
| 1204 | sk->sk_ll_usec = val; | 1262 | WRITE_ONCE(sk->sk_ll_usec, val); |
| 1205 | } | 1263 | } |
| 1206 | break; | 1264 | break; |
| 1207 | case SO_PREFER_BUSY_POLL: | 1265 | case SO_PREFER_BUSY_POLL: |
| @@ -1348,6 +1406,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 140 unmodified lines | |||
| 1348 | struct __kernel_old_timeval tm; | 1406 | struct __kernel_old_timeval tm; |
| 1349 | struct __kernel_sock_timeval stm; | 1407 | struct __kernel_sock_timeval stm; |
| 1350 | struct sock_txtime txtime; | 1408 | struct sock_txtime txtime; |
| 1409 | struct so_timestamping timestamping; | ||
| 1351 | } v; | 1410 | } v; |
| 1352 | 1411 | ||
| 1353 | int lv = sizeof(int); | 1412 | int lv = sizeof(int); |
| @@ -1451,7 +1510,9 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 97 unmodified lines | |||
| 1451 | break; | 1510 | break; |
| 1452 | 1511 | ||
| 1453 | case SO_TIMESTAMPING_OLD: | 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 | break; | 1516 | break; |
| 1456 | 1517 | ||
| 1457 | case SO_RCVTIMEO_OLD: | 1518 | case SO_RCVTIMEO_OLD: |
| @@ -113,11 +113,11 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, · 112 unmodified lines | |||
| 113 | int err, port; | 113 | int err, port; |
| 114 | 114 | ||
| 115 | if (dst->index == info->tree_index && ds->index == info->sw_index && | 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 | ds->ops->port_bridge_leave(ds, info->port, info->br); | 117 | ds->ops->port_bridge_leave(ds, info->port, info->br); |
| 118 | 118 | ||
| 119 | if ((dst->index != info->tree_index || ds->index != info->sw_index) && | 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 | ds->ops->crosschip_bridge_leave(ds, info->tree_index, | 121 | ds->ops->crosschip_bridge_leave(ds, info->tree_index, |
| 122 | info->sw_index, info->port, | 122 | info->sw_index, info->port, |
| 123 | info->br); | 123 | info->br); |
| @@ -427,7 +427,7 @@ static int dsa_switch_lag_join(struct dsa_switch *ds, · 303 unmodified lines | |||
| 427 | info->port, info->lag, | 427 | info->port, info->lag, |
| 428 | info->info); | 428 | info->info); |
| 429 | 429 | ||
| 430 | return 0; | 430 | return -EOPNOTSUPP; |
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | static int dsa_switch_lag_leave(struct dsa_switch *ds, | 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 | return ds->ops->crosschip_lag_leave(ds, info->sw_index, | 440 | return ds->ops->crosschip_lag_leave(ds, info->sw_index, |
| 441 | info->port, info->lag); | 441 | info->port, info->lag); |
| 442 | 442 | ||
| 443 | return 0; | 443 | return -EOPNOTSUPP; |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | static int dsa_switch_mdb_add(struct dsa_switch *ds, | 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 | ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ | 7 | ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ |
| 8 | linkstate.o debug.o wol.o features.o privflags.o rings.o \ | 8 | linkstate.o debug.o wol.o features.o privflags.o rings.o \ |
| 9 | channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ | 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 | #include <linux/net_tstamp.h> | 4 | #include <linux/net_tstamp.h> |
| 5 | #include <linux/phy.h> | 5 | #include <linux/phy.h> |
| 6 | #include <linux/rtnetlink.h> | 6 | #include <linux/rtnetlink.h> |
| 7 | #include <linux/ptp_clock_kernel.h> | ||
| 7 | 8 | ||
| 8 | #include "common.h" | 9 | #include "common.h" |
| 9 | 10 | ||
| @@ -397,6 +398,7 @@ const char sof_timestamping_names[][ETH_GSTRING_LEN] = { · 387 unmodified lines | |||
| 397 | [const_ilog2(SOF_TIMESTAMPING_OPT_STATS)] = "option-stats", | 398 | [const_ilog2(SOF_TIMESTAMPING_OPT_STATS)] = "option-stats", |
| 398 | [const_ilog2(SOF_TIMESTAMPING_OPT_PKTINFO)] = "option-pktinfo", | 399 | [const_ilog2(SOF_TIMESTAMPING_OPT_PKTINFO)] = "option-pktinfo", |
| 399 | [const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw", | 400 | [const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw", |
| 401 | [const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc", | ||
| 400 | }; | 402 | }; |
| 401 | static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT); | 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 | return 0; | 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 | const struct ethtool_phy_ops *ethtool_phy_ops; | 571 | const struct ethtool_phy_ops *ethtool_phy_ops; |
| 558 | 572 | ||
| 559 | void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops) | 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 | [ETHTOOL_MSG_TSINFO_GET] = ðnl_tsinfo_request_ops, | 248 | [ETHTOOL_MSG_TSINFO_GET] = ðnl_tsinfo_request_ops, |
| 249 | [ETHTOOL_MSG_MODULE_EEPROM_GET] = ðnl_module_eeprom_request_ops, | 249 | [ETHTOOL_MSG_MODULE_EEPROM_GET] = ðnl_module_eeprom_request_ops, |
| 250 | [ETHTOOL_MSG_STATS_GET] = ðnl_stats_request_ops, | 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 | static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) | 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 | .policy = ethnl_stats_get_policy, | 959 | .policy = ethnl_stats_get_policy, |
| 959 | .maxattr = ARRAY_SIZE(ethnl_stats_get_policy) - 1, | 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 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { | 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 | extern const struct ethnl_request_ops ethnl_fec_request_ops; | 347 | extern const struct ethnl_request_ops ethnl_fec_request_ops; |
| 348 | extern const struct ethnl_request_ops ethnl_module_eeprom_request_ops; | 348 | extern const struct ethnl_request_ops ethnl_module_eeprom_request_ops; |
| 349 | extern const struct ethnl_request_ops ethnl_stats_request_ops; | 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 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; | 352 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; |
| 352 | extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; | 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 | extern const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1]; | 383 | extern const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1]; |
| 383 | extern const struct nla_policy ethnl_module_eeprom_get_policy[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS + 1]; | 384 | extern const struct nla_policy ethnl_module_eeprom_get_policy[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS + 1]; |
| 384 | extern const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1]; | 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 | int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); | 388 | int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); |
| 387 | int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); | 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 | portid = NETLINK_CB(skb).portid; /* netlink portid */ | 1376 | portid = NETLINK_CB(skb).portid; /* netlink portid */ |
| 1377 | NETLINK_CB(skb).portid = 0; /* from kernel */ | 1377 | NETLINK_CB(skb).portid = 0; /* from kernel */ |
| 1378 | NETLINK_CB(skb).dst_group = 0; /* unicast */ | 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 | static int __net_init nl_fib_lookup_init(struct net *net) | 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 | nlmsg_free(rep); | 580 | nlmsg_free(rep); |
| 581 | goto out; | 581 | goto out; |
| 582 | } | 582 | } |
| 583 | err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | 583 | err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); |
| 584 | MSG_DONTWAIT); | ||
| 585 | if (err > 0) | ||
| 586 | err = 0; | ||
| 587 | 584 | ||
| 588 | out: | 585 | out: |
| 589 | if (sk) | 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 | dev->needed_headroom = t_hlen + hlen; | 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 | if (mtu < IPV4_MIN_MTU) | 322 | if (mtu < IPV4_MIN_MTU) |
| 323 | mtu = IPV4_MIN_MTU; | 323 | mtu = IPV4_MIN_MTU; |
| @@ -348,6 +348,9 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net, · 24 unmodified lines | |||
| 348 | t_hlen = nt->hlen + sizeof(struct iphdr); | 348 | t_hlen = nt->hlen + sizeof(struct iphdr); |
| 349 | dev->min_mtu = ETH_MIN_MTU; | 349 | dev->min_mtu = ETH_MIN_MTU; |
| 350 | dev->max_mtu = IP_MAX_MTU - t_hlen; | 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 | ip_tunnel_add(itn, nt); | 354 | ip_tunnel_add(itn, nt); |
| 352 | return nt; | 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 | tunnel_hlen = md ? tunnel_hlen : tunnel->hlen; | 493 | tunnel_hlen = md ? tunnel_hlen : tunnel->hlen; |
| 491 | pkt_size = skb->len - tunnel_hlen; | 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 | mtu = dst_mtu(&rt->dst) - (sizeof(struct iphdr) + tunnel_hlen); | 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 | mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; | 501 | mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; |
| 502 | } | ||
| 497 | 503 | ||
| 498 | if (skb_valid_dst(skb)) | 504 | if (skb_valid_dst(skb)) |
| 499 | skb_dst_update_pmtu_no_confirm(skb, mtu); | 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 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | 978 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); |
| 973 | int max_mtu = IP_MAX_MTU - t_hlen; | 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 | if (new_mtu < ETH_MIN_MTU) | 984 | if (new_mtu < ETH_MIN_MTU) |
| 976 | return -EINVAL; | 985 | return -EINVAL; |
| 977 | 986 | ||
| @@ -1149,6 +1158,9 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], · 171 unmodified lines | |||
| 1149 | if (tb[IFLA_MTU]) { | 1158 | if (tb[IFLA_MTU]) { |
| 1150 | unsigned int max = IP_MAX_MTU - (nt->hlen + sizeof(struct iphdr)); | 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 | mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, max); | 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 | raw_rcv(mroute_sk, skb); | 2119 | raw_rcv(mroute_sk, skb); |
| 2120 | return 0; | 2120 | return 0; |
| 2121 | } | 2121 | } |
| 2122 | } | 2122 | } |
| 2123 | } | 2123 | } |
| 2124 | 2124 | ||
| 2125 | /* already under rcu_read_lock() */ | 2125 | /* already under rcu_read_lock() */ |
| @@ -119,11 +119,8 @@ static int raw_diag_dump_one(struct netlink_callback *cb, · 118 unmodified lines | |||
| 119 | return err; | 119 | return err; |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | err = netlink_unicast(net->diag_nlsk, rep, | 122 | err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); |
| 123 | NETLINK_CB(in_skb).portid, | 123 | |
| 124 | MSG_DONTWAIT); | ||
| 125 | if (err > 0) | ||
| 126 | err = 0; | ||
| 127 | return err; | 124 | return err; |
| 128 | } | 125 | } |
| 129 | 126 | ||
| @@ -1375,6 +1375,9 @@ new_segment: · 1374 unmodified lines | |||
| 1375 | } | 1375 | } |
| 1376 | pfrag->offset += copy; | 1376 | pfrag->offset += copy; |
| 1377 | } else { | 1377 | } else { |
| 1378 | if (!sk_wmem_schedule(sk, copy)) | ||
| 1379 | goto wait_for_space; | ||
| 1380 | |||
| 1378 | err = skb_zerocopy_iter_stream(sk, skb, msg, copy, uarg); | 1381 | err = skb_zerocopy_iter_stream(sk, skb, msg, copy, uarg); |
| 1379 | if (err == -EMSGSIZE || err == -EEXIST) { | 1382 | if (err == -EMSGSIZE || err == -EEXIST) { |
| 1380 | tcp_mark_push(tp, skb); | 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 | trace_tcp_receive_reset(sk); | 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 | if (sk_is_mptcp(sk)) | 4253 | if (sk_is_mptcp(sk)) |
| 4251 | mptcp_incoming_options(sk, skb); | 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 | bool fragstolen; | 4944 | bool fragstolen; |
| 4942 | int eaten; | 4945 | int eaten; |
| 4943 | 4946 | ||
| 4944 | if (sk_is_mptcp(sk)) | 4947 | /* If a subflow has been reset, the packet should not continue |
| 4945 | mptcp_incoming_options(sk, skb); | 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 | if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { | 4955 | if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { |
| 4948 | __kfree_skb(skb); | 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 | tp->snd_cwnd = tcp_init_cwnd(tp, __sk_dst_get(sk)); | 5930 | tp->snd_cwnd = tcp_init_cwnd(tp, __sk_dst_get(sk)); |
| 5923 | tp->snd_cwnd_stamp = tcp_jiffies32; | 5931 | tp->snd_cwnd_stamp = tcp_jiffies32; |
| 5924 | 5932 | ||
| 5925 | icsk->icsk_ca_initialized = 0; | ||
| 5926 | bpf_skops_established(sk, bpf_op, skb); | 5933 | bpf_skops_established(sk, bpf_op, skb); |
| 5934 | /* Initialize congestion control unless BPF initialized it already: */ | ||
| 5927 | if (!icsk->icsk_ca_initialized) | 5935 | if (!icsk->icsk_ca_initialized) |
| 5928 | tcp_init_congestion_control(sk); | 5936 | tcp_init_congestion_control(sk); |
| 5929 | tcp_init_buffer_space(sk); | 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 | case TCP_CLOSING: | 6531 | case TCP_CLOSING: |
| 6524 | case TCP_LAST_ACK: | 6532 | case TCP_LAST_ACK: |
| 6525 | if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { | 6533 | if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { |
| 6526 | if (sk_is_mptcp(sk)) | 6534 | /* If a subflow has been reset, the packet should not |
| 6527 | mptcp_incoming_options(sk, skb); | 6535 | * continue to be processed, drop the packet. |
| 6536 | */ | ||
| 6537 | if (sk_is_mptcp(sk) && !mptcp_incoming_options(sk, skb)) | ||
| 6538 | goto discard; | ||
| 6528 | break; | 6539 | break; |
| 6529 | } | 6540 | } |
| 6530 | fallthrough; | 6541 | fallthrough; |
| @@ -342,7 +342,7 @@ void tcp_v4_mtu_reduced(struct sock *sk) · 341 unmodified lines | |||
| 342 | 342 | ||
| 343 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) | 343 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) |
| 344 | return; | 344 | return; |
| 345 | mtu = tcp_sk(sk)->mtu_info; | 345 | mtu = READ_ONCE(tcp_sk(sk)->mtu_info); |
| 346 | dst = inet_csk_update_pmtu(sk, mtu); | 346 | dst = inet_csk_update_pmtu(sk, mtu); |
| 347 | if (!dst) | 347 | if (!dst) |
| 348 | return; | 348 | return; |
| @@ -546,7 +546,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) · 197 unmodified lines | |||
| 546 | if (sk->sk_state == TCP_LISTEN) | 546 | if (sk->sk_state == TCP_LISTEN) |
| 547 | goto out; | 547 | goto out; |
| 548 | 548 | ||
| 549 | tp->mtu_info = info; | 549 | WRITE_ONCE(tp->mtu_info, info); |
| 550 | if (!sock_owned_by_user(sk)) { | 550 | if (!sock_owned_by_user(sk)) { |
| 551 | tcp_v4_mtu_reduced(sk); | 551 | tcp_v4_mtu_reduced(sk); |
| 552 | } else { | 552 | } else { |
| @@ -1732,6 +1732,7 @@ int tcp_mtu_to_mss(struct sock *sk, int pmtu) · 1731 unmodified lines | |||
| 1732 | return __tcp_mtu_to_mss(sk, pmtu) - | 1732 | return __tcp_mtu_to_mss(sk, pmtu) - |
| 1733 | (tcp_sk(sk)->tcp_header_len - sizeof(struct tcphdr)); | 1733 | (tcp_sk(sk)->tcp_header_len - sizeof(struct tcphdr)); |
| 1734 | } | 1734 | } |
| 1735 | EXPORT_SYMBOL(tcp_mtu_to_mss); | ||
| 1735 | 1736 | ||
| 1736 | /* Inverse of above */ | 1737 | /* Inverse of above */ |
| 1737 | int tcp_mss_to_mtu(struct sock *sk, int mss) | 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 | ipcm_init_sk(&ipc, inet); | 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 | if (msg->msg_controllen) { | 1107 | if (msg->msg_controllen) { |
| 1108 | err = udp_cmsg_send(sk, msg, &ipc.gso_size); | 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 | case UDP_SEGMENT: | 2695 | case UDP_SEGMENT: |
| 2696 | if (val < 0 || val > USHRT_MAX) | 2696 | if (val < 0 || val > USHRT_MAX) |
| 2697 | return -EINVAL; | 2697 | return -EINVAL; |
| 2698 | up->gso_size = val; | 2698 | WRITE_ONCE(up->gso_size, val); |
| 2699 | break; | 2699 | break; |
| 2700 | 2700 | ||
| 2701 | case UDP_GRO: | 2701 | case UDP_GRO: |
| @@ -2790,7 +2790,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, · 88 unmodified lines | |||
| 2790 | break; | 2790 | break; |
| 2791 | 2791 | ||
| 2792 | case UDP_SEGMENT: | 2792 | case UDP_SEGMENT: |
| 2793 | val = up->gso_size; | 2793 | val = READ_ONCE(up->gso_size); |
| 2794 | break; | 2794 | break; |
| 2795 | 2795 | ||
| 2796 | case UDP_GRO: | 2796 | case UDP_GRO: |
| @@ -77,10 +77,8 @@ static int udp_dump_one(struct udp_table *tbl, · 76 unmodified lines | |||
| 77 | kfree_skb(rep); | 77 | kfree_skb(rep); |
| 78 | goto out; | 78 | goto out; |
| 79 | } | 79 | } |
| 80 | err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | 80 | err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); |
| 81 | MSG_DONTWAIT); | 81 | |
| 82 | if (err > 0) | ||
| 83 | err = 0; | ||
| 84 | out: | 82 | out: |
| 85 | if (sk) | 83 | if (sk) |
| 86 | sock_put(sk); | 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 | if ((!sk && (skb->dev->features & NETIF_F_GRO_UDP_FWD)) || | 526 | if ((!sk && (skb->dev->features & NETIF_F_GRO_UDP_FWD)) || |
| 527 | (sk && udp_sk(sk)->gro_enabled) || NAPI_GRO_CB(skb)->is_flist) | 527 | (sk && udp_sk(sk)->gro_enabled) || NAPI_GRO_CB(skb)->is_flist) |
| 528 | pp = call_gro_receive(udp_gro_receive_segment, head, skb); | 528 | return call_gro_receive(udp_gro_receive_segment, head, skb); |
| 529 | return pp; | 529 | |
| 530 | /* no GRO, be sure flush the current packet */ | ||
| 531 | goto out; | ||
| 530 | } | 532 | } |
| 531 | 533 | ||
| 532 | if (NAPI_GRO_CB(skb)->encap_mark || | 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 | struct dst_entry *dst = skb_dst(skb); | 61 | struct dst_entry *dst = skb_dst(skb); |
| 62 | struct net_device *dev = dst->dev; | 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 | const struct in6_addr *nexthop; | 65 | const struct in6_addr *nexthop; |
| 64 | struct neighbour *neigh; | 66 | struct neighbour *neigh; |
| 65 | int ret; | 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 | if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { | 95 | if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { |
| 68 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); | 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 | if (skb_warn_if_lro(skb)) | 507 | if (skb_warn_if_lro(skb)) |
| 480 | goto drop; | 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 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); | 513 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); |
| 484 | goto drop; | 514 | goto drop; |
| 485 | } | 515 | } |
| @@ -348,11 +348,20 @@ failure: · 347 unmodified lines | |||
| 348 | static void tcp_v6_mtu_reduced(struct sock *sk) | 348 | static void tcp_v6_mtu_reduced(struct sock *sk) |
| 349 | { | 349 | { |
| 350 | struct dst_entry *dst; | 350 | struct dst_entry *dst; |
| 351 | u32 mtu; | ||
| 351 | 352 | ||
| 352 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) | 353 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) |
| 353 | return; | 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 | if (!dst) | 365 | if (!dst) |
| 357 | return; | 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 | if (type == ICMPV6_PKT_TOOBIG) { | 444 | if (type == ICMPV6_PKT_TOOBIG) { |
| 445 | u32 mtu = ntohl(info); | ||
| 446 | |||
| 436 | /* We are not interested in TCP_LISTEN and open_requests | 447 | /* We are not interested in TCP_LISTEN and open_requests |
| 437 | * (SYN-ACKs send out by Linux are always <576bytes so | 448 | * (SYN-ACKs send out by Linux are always <576bytes so |
| 438 | * they should go through unfragmented). | 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 | if (!ip6_sk_accept_pmtu(sk)) | 454 | if (!ip6_sk_accept_pmtu(sk)) |
| 444 | goto out; | 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 | if (!sock_owned_by_user(sk)) | 462 | if (!sock_owned_by_user(sk)) |
| 448 | tcp_v6_mtu_reduced(sk); | 463 | tcp_v6_mtu_reduced(sk); |
| 449 | else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, | 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 | opt = ireq->ipv6_opt; | 555 | opt = ireq->ipv6_opt; |
| 541 | if (!opt) | 556 | if (!opt) |
| 542 | opt = rcu_dereference(np->opt); | 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 | tclass, sk->sk_priority); | 559 | tclass, sk->sk_priority); |
| 545 | rcu_read_unlock(); | 560 | rcu_read_unlock(); |
| 546 | err = net_xmit_eval(err); | 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 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); | 1296 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); |
| 1297 | 1297 | ||
| 1298 | ipcm6_init(&ipc6); | 1298 | ipcm6_init(&ipc6); |
| 1299 | ipc6.gso_size = up->gso_size; | 1299 | ipc6.gso_size = READ_ONCE(up->gso_size); |
| 1300 | ipc6.sockc.tsflags = sk->sk_tsflags; | 1300 | ipc6.sockc.tsflags = sk->sk_tsflags; |
| 1301 | ipc6.sockc.mark = sk->sk_mark; | 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 | struct dst_entry *dst = skb_dst(skb); | 50 | struct dst_entry *dst = skb_dst(skb); |
| 51 | struct xfrm_state *x = dst->xfrm; | 51 | struct xfrm_state *x = dst->xfrm; |
| 52 | int mtu; | 52 | unsigned int mtu; |
| 53 | bool toobig; | 53 | bool toobig; |
| 54 | 54 | ||
| 55 | #ifdef CONFIG_NETFILTER | 55 | #ifdef CONFIG_NETFILTER |
| @@ -1635,14 +1635,16 @@ struct iucv_message_pending { · 1634 unmodified lines | |||
| 1635 | u8 iptype; | 1635 | u8 iptype; |
| 1636 | u32 ipmsgid; | 1636 | u32 ipmsgid; |
| 1637 | u32 iptrgcls; | 1637 | u32 iptrgcls; |
| 1638 | union { | 1638 | struct { |
| 1639 | u32 iprmmsg1_u32; | 1639 | union { |
| 1640 | u8 iprmmsg1[4]; | 1640 | u32 iprmmsg1_u32; |
| 1641 | } ln1msg1; | 1641 | u8 iprmmsg1[4]; |
| 1642 | union { | 1642 | } ln1msg1; |
| 1643 | u32 ipbfln1f; | 1643 | union { |
| 1644 | u8 iprmmsg2[4]; | 1644 | u32 ipbfln1f; |
| 1645 | } ln1msg2; | 1645 | u8 iprmmsg2[4]; |
| 1646 | } ln1msg2; | ||
| 1647 | } rmmsg; | ||
| 1646 | u32 res1[3]; | 1648 | u32 res1[3]; |
| 1647 | u32 ipbfln2f; | 1649 | u32 ipbfln2f; |
| 1648 | u8 ippollfg; | 1650 | u8 ippollfg; |
| @@ -1660,10 +1662,10 @@ static void iucv_message_pending(struct iucv_irq_data *data) · 11 unmodified lines | |||
| 1660 | msg.id = imp->ipmsgid; | 1662 | msg.id = imp->ipmsgid; |
| 1661 | msg.class = imp->iptrgcls; | 1663 | msg.class = imp->iptrgcls; |
| 1662 | if (imp->ipflags1 & IUCV_IPRMDATA) { | 1664 | if (imp->ipflags1 & IUCV_IPRMDATA) { |
| 1663 | memcpy(msg.rmmsg, imp->ln1msg1.iprmmsg1, 8); | 1665 | memcpy(msg.rmmsg, &imp->rmmsg, 8); |
| 1664 | msg.length = 8; | 1666 | msg.length = 8; |
| 1665 | } else | 1667 | } else |
| 1666 | msg.length = imp->ln1msg2.ipbfln1f; | 1668 | msg.length = imp->rmmsg.ln1msg2.ipbfln1f; |
| 1667 | msg.reply_size = imp->ipbfln2f; | 1669 | msg.reply_size = imp->ipbfln2f; |
| 1668 | path->handler->message_pending(path, &msg); | 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 | SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW), | 44 | SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW), |
| 45 | SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX), | 45 | SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX), |
| 46 | SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX), | 46 | SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX), |
| 47 | SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED), | ||
| 47 | SNMP_MIB_SENTINEL | 48 | SNMP_MIB_SENTINEL |
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| @@ -37,6 +37,7 @@ enum linux_mptcp_mib_field { · 36 unmodified lines | |||
| 37 | MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */ | 37 | MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */ |
| 38 | MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */ | 38 | MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */ |
| 39 | MPTCP_MIB_MPPRIORX, /* Received a MP_PRIO */ | 39 | MPTCP_MIB_MPPRIORX, /* Received a MP_PRIO */ |
| 40 | MPTCP_MIB_RCVPRUNED, /* Incoming packet dropped due to memory limit */ | ||
| 40 | __MPTCP_MIB_MAX | 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 | kfree_skb(rep); | 57 | kfree_skb(rep); |
| 58 | goto out; | 58 | goto out; |
| 59 | } | 59 | } |
| 60 | err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | 60 | err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); |
| 61 | MSG_DONTWAIT); | 61 | |
| 62 | if (err > 0) | ||
| 63 | err = 0; | ||
| 64 | out: | 62 | out: |
| 65 | sock_put(sk); | 63 | sock_put(sk); |
| 66 | 64 | ||
| @@ -1035,7 +1035,8 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk, · 1034 unmodified lines | |||
| 1035 | return hmac == mp_opt->ahmac; | 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 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); | 1041 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); |
| 1041 | struct mptcp_sock *msk = mptcp_sk(subflow->conn); | 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 | __mptcp_check_push(subflow->conn, sk); | 1054 | __mptcp_check_push(subflow->conn, sk); |
| 1054 | __mptcp_data_acked(subflow->conn); | 1055 | __mptcp_data_acked(subflow->conn); |
| 1055 | mptcp_data_unlock(subflow->conn); | 1056 | mptcp_data_unlock(subflow->conn); |
| 1056 | return; | 1057 | return true; |
| 1057 | } | 1058 | } |
| 1058 | 1059 | ||
| 1059 | mptcp_get_options(sk, skb, &mp_opt); | 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 | if (!check_fully_established(msk, sk, subflow, skb, &mp_opt)) | 1065 | if (!check_fully_established(msk, sk, subflow, skb, &mp_opt)) |
| 1061 | return; | 1066 | return sk->sk_state != TCP_CLOSE; |
| 1062 | 1067 | ||
| 1063 | if (mp_opt.fastclose && | 1068 | if (mp_opt.fastclose && |
| 1064 | msk->local_key == mp_opt.rcvr_key) { | 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 | if (!mp_opt.dss) | 1107 | if (!mp_opt.dss) |
| 1103 | return; | 1108 | return true; |
| 1104 | 1109 | ||
| 1105 | /* we can't wait for recvmsg() to update the ack_seq, otherwise | 1110 | /* we can't wait for recvmsg() to update the ack_seq, otherwise |
| 1106 | * monodirectional flows will stuck | 1111 | * monodirectional flows will stuck |
| @@ -1119,12 +1124,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) · 12 unmodified lines | |||
| 1119 | schedule_work(&msk->work)) | 1124 | schedule_work(&msk->work)) |
| 1120 | sock_hold(subflow->conn); | 1125 | sock_hold(subflow->conn); |
| 1121 | 1126 | ||
| 1122 | return; | 1127 | return true; |
| 1123 | } | 1128 | } |
| 1124 | 1129 | ||
| 1125 | mpext = skb_ext_add(skb, SKB_EXT_MPTCP); | 1130 | mpext = skb_ext_add(skb, SKB_EXT_MPTCP); |
| 1126 | if (!mpext) | 1131 | if (!mpext) |
| 1127 | return; | 1132 | return true; |
| 1128 | 1133 | ||
| 1129 | memset(mpext, 0, sizeof(*mpext)); | 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 | if (mpext->csum_reqd) | 1158 | if (mpext->csum_reqd) |
| 1154 | mpext->csum = mp_opt.csum; | 1159 | mpext->csum = mp_opt.csum; |
| 1155 | } | 1160 | } |
| 1161 | |||
| 1162 | return true; | ||
| 1156 | } | 1163 | } |
| 1157 | 1164 | ||
| 1158 | static void mptcp_set_rwin(const struct tcp_sock *tp) | 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 | bool cleanup, rx_empty; | 474 | bool cleanup, rx_empty; |
| 475 | 475 | ||
| 476 | cleanup = (space > 0) && (space >= (old_space << 1)); | 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 | mptcp_for_each_subflow(msk, subflow) { | 479 | mptcp_for_each_subflow(msk, subflow) { |
| 480 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | 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 | sk_rbuf = ssk_rbuf; | 720 | sk_rbuf = ssk_rbuf; |
| 721 | 721 | ||
| 722 | /* over limit? can't append more skbs to msk, Also, no need to wake-up*/ | 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 | return; | 725 | return; |
| 726 | } | ||
| 725 | 727 | ||
| 726 | /* Wake-up the reader only for in-sequence data */ | 728 | /* Wake-up the reader only for in-sequence data */ |
| 727 | mptcp_data_lock(sk); | 729 | mptcp_data_lock(sk); |
| @@ -1754,7 +1756,7 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk, · 1026 unmodified lines | |||
| 1754 | if (!(flags & MSG_PEEK)) { | 1756 | if (!(flags & MSG_PEEK)) { |
| 1755 | /* we will bulk release the skb memory later */ | 1757 | /* we will bulk release the skb memory later */ |
| 1756 | skb->destructor = NULL; | 1758 | skb->destructor = NULL; |
| 1757 | msk->rmem_released += skb->truesize; | 1759 | WRITE_ONCE(msk->rmem_released, msk->rmem_released + skb->truesize); |
| 1758 | __skb_unlink(skb, &msk->receive_queue); | 1760 | __skb_unlink(skb, &msk->receive_queue); |
| 1759 | __kfree_skb(skb); | 1761 | __kfree_skb(skb); |
| 1760 | } | 1762 | } |
| @@ -1873,7 +1875,7 @@ static void __mptcp_update_rmem(struct sock *sk) · 112 unmodified lines | |||
| 1873 | 1875 | ||
| 1874 | atomic_sub(msk->rmem_released, &sk->sk_rmem_alloc); | 1876 | atomic_sub(msk->rmem_released, &sk->sk_rmem_alloc); |
| 1875 | sk_mem_uncharge(sk, msk->rmem_released); | 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 | static void __mptcp_splice_receive_queue(struct sock *sk) | 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 | msk->out_of_order_queue = RB_ROOT; | 2382 | msk->out_of_order_queue = RB_ROOT; |
| 2381 | msk->first_pending = NULL; | 2383 | msk->first_pending = NULL; |
| 2382 | msk->wmem_reserved = 0; | 2384 | msk->wmem_reserved = 0; |
| 2383 | msk->rmem_released = 0; | 2385 | WRITE_ONCE(msk->rmem_released, 0); |
| 2384 | msk->tx_pending_data = 0; | 2386 | msk->tx_pending_data = 0; |
| 2385 | 2387 | ||
| 2386 | msk->first = NULL; | 2388 | msk->first = NULL; |
| @@ -296,9 +296,17 @@ static inline struct mptcp_sock *mptcp_sk(const struct sock *sk) · 295 unmodified lines | |||
| 296 | return (struct mptcp_sock *)sk; | 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 | static inline int __mptcp_space(const struct sock *sk) | 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 | static inline struct mptcp_data_frag *mptcp_send_head(const struct sock *sk) | 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 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | 157 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); |
| 158 | bool slow = lock_sock_fast(ssk); | 158 | bool slow = lock_sock_fast(ssk); |
| 159 | 159 | ||
| 160 | switch (optname) { | 160 | sock_set_timestamp(sk, optname, !!val); |
| 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 | |||
| 173 | unlock_sock_fast(ssk, slow); | 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 | static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int optname, | 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 | int val, ret; | 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 | case SO_TIMESTAMP_NEW: | 194 | case SO_TIMESTAMP_NEW: |
| 206 | case SO_TIMESTAMPNS_OLD: | 195 | case SO_TIMESTAMPNS_OLD: |
| 207 | case SO_TIMESTAMPNS_NEW: | 196 | case SO_TIMESTAMPNS_NEW: |
| 208 | case SO_TIMESTAMPING_OLD: | ||
| 209 | case SO_TIMESTAMPING_NEW: | ||
| 210 | return mptcp_setsockopt_sol_socket_tstamp(msk, optname, val); | 197 | return mptcp_setsockopt_sol_socket_tstamp(msk, optname, val); |
| 211 | } | 198 | } |
| 212 | 199 | ||
| 213 | return -ENOPROTOOPT; | 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 | static int mptcp_setsockopt_sol_socket_linger(struct mptcp_sock *msk, sockptr_t optval, | 247 | static int mptcp_setsockopt_sol_socket_linger(struct mptcp_sock *msk, sockptr_t optval, |
| 217 | unsigned int optlen) | 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 | case SO_TIMESTAMP_NEW: | 330 | case SO_TIMESTAMP_NEW: |
| 300 | case SO_TIMESTAMPNS_OLD: | 331 | case SO_TIMESTAMPNS_OLD: |
| 301 | case SO_TIMESTAMPNS_NEW: | 332 | case SO_TIMESTAMPNS_NEW: |
| 333 | return mptcp_setsockopt_sol_socket_int(msk, optname, optval, | ||
| 334 | optlen); | ||
| 302 | case SO_TIMESTAMPING_OLD: | 335 | case SO_TIMESTAMPING_OLD: |
| 303 | case SO_TIMESTAMPING_NEW: | 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 | case SO_LINGER: | 339 | case SO_LINGER: |
| 306 | return mptcp_setsockopt_sol_socket_linger(msk, optval, optlen); | 340 | return mptcp_setsockopt_sol_socket_linger(msk, optval, optlen); |
| 307 | case SO_RCVLOWAT: | 341 | case SO_RCVLOWAT: |
| @@ -214,11 +214,6 @@ again: · 213 unmodified lines | |||
| 214 | ntohs(inet_sk(sk_listener)->inet_sport), | 214 | ntohs(inet_sk(sk_listener)->inet_sport), |
| 215 | ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport)); | 215 | ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport)); |
| 216 | if (!mptcp_pm_sport_in_anno_list(subflow_req->msk, sk_listener)) { | 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 | SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX); | 217 | SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX); |
| 223 | return -EPERM; | 218 | return -EPERM; |
| 224 | } | 219 | } |
| @@ -230,6 +225,8 @@ again: · 5 unmodified lines | |||
| 230 | if (unlikely(req->syncookie)) { | 225 | if (unlikely(req->syncookie)) { |
| 231 | if (mptcp_can_accept_new_subflow(subflow_req->msk)) | 226 | if (mptcp_can_accept_new_subflow(subflow_req->msk)) |
| 232 | subflow_init_req_cookie_join_save(subflow_req, skb); | 227 | subflow_init_req_cookie_join_save(subflow_req, skb); |
| 228 | else | ||
| 229 | return -EPERM; | ||
| 233 | } | 230 | } |
| 234 | 231 | ||
| 235 | pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token, | 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 | if (!mptcp_token_join_cookie_init_state(subflow_req, skb)) | 266 | if (!mptcp_token_join_cookie_init_state(subflow_req, skb)) |
| 270 | return -EINVAL; | 267 | return -EINVAL; |
| 271 | 268 | ||
| 272 | if (mptcp_can_accept_new_subflow(subflow_req->msk)) | 269 | subflow_req->mp_join = 1; |
| 273 | subflow_req->mp_join = 1; | ||
| 274 | |||
| 275 | subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq - 1; | 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 | static u32 mptcp_join_entry_hash(struct sk_buff *skb, struct net *net) | 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 | return i % ARRAY_SIZE(join_entries); | 56 | return i % ARRAY_SIZE(join_entries); |
| 43 | } | 57 | } |
| @@ -17,3 +17,9 @@ config NCSI_OEM_CMD_GET_MAC · 16 unmodified lines | |||
| 17 | help | 17 | help |
| 18 | This allows to get MAC address from NCSI firmware and set them back to | 18 | This allows to get MAC address from NCSI firmware and set them back to |
| 19 | controller. | 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 | /* OEM Vendor Manufacture ID */ | 78 | /* OEM Vendor Manufacture ID */ |
| 79 | #define NCSI_OEM_MFR_MLX_ID 0x8119 | 79 | #define NCSI_OEM_MFR_MLX_ID 0x8119 |
| 80 | #define NCSI_OEM_MFR_BCM_ID 0x113d | 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 | /* Broadcom specific OEM Command */ | 84 | /* Broadcom specific OEM Command */ |
| 82 | #define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */ | 85 | #define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */ |
| 83 | /* Mellanox specific OEM Command */ | 86 | /* Mellanox specific OEM Command */ |
| @@ -86,6 +89,7 @@ enum { · 2 unmodified lines | |||
| 86 | #define NCSI_OEM_MLX_CMD_SMAF 0x01 /* CMD ID for Set MC Affinity */ | 89 | #define NCSI_OEM_MLX_CMD_SMAF 0x01 /* CMD ID for Set MC Affinity */ |
| 87 | #define NCSI_OEM_MLX_CMD_SMAF_PARAM 0x07 /* Parameter for SMAF */ | 90 | #define NCSI_OEM_MLX_CMD_SMAF_PARAM 0x07 /* Parameter for SMAF */ |
| 88 | /* OEM Command payload lengths*/ | 91 | /* OEM Command payload lengths*/ |
| 92 | #define NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN 7 | ||
| 89 | #define NCSI_OEM_BCM_CMD_GMA_LEN 12 | 93 | #define NCSI_OEM_BCM_CMD_GMA_LEN 12 |
| 90 | #define NCSI_OEM_MLX_CMD_GMA_LEN 8 | 94 | #define NCSI_OEM_MLX_CMD_GMA_LEN 8 |
| 91 | #define NCSI_OEM_MLX_CMD_SMAF_LEN 60 | 95 | #define NCSI_OEM_MLX_CMD_SMAF_LEN 60 |
| @@ -271,6 +275,7 @@ enum { · 179 unmodified lines | |||
| 271 | ncsi_dev_state_probe_mlx_gma, | 275 | ncsi_dev_state_probe_mlx_gma, |
| 272 | ncsi_dev_state_probe_mlx_smaf, | 276 | ncsi_dev_state_probe_mlx_smaf, |
| 273 | ncsi_dev_state_probe_cis, | 277 | ncsi_dev_state_probe_cis, |
| 278 | ncsi_dev_state_probe_keep_phy, | ||
| 274 | ncsi_dev_state_probe_gvi, | 279 | ncsi_dev_state_probe_gvi, |
| 275 | ncsi_dev_state_probe_gc, | 280 | ncsi_dev_state_probe_gc, |
| 276 | ncsi_dev_state_probe_gls, | 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 | return 0; | 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 | #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) | 721 | #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) |
| 693 | 722 | ||
| 694 | /* NCSI OEM Command APIs */ | 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 | nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN; | 729 | nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN; |
| 701 | 730 | ||
| 702 | memset(data, 0, NCSI_OEM_BCM_CMD_GMA_LEN); | 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 | data[5] = NCSI_OEM_BCM_CMD_GMA; | 733 | data[5] = NCSI_OEM_BCM_CMD_GMA; |
| 705 | 734 | ||
| 706 | nca->data = data; | 735 | nca->data = data; |
| @@ -724,7 +753,7 @@ static int ncsi_oem_gma_handler_mlx(struct ncsi_cmd_arg *nca) · 17 unmodified lines | |||
| 724 | nca->payload = NCSI_OEM_MLX_CMD_GMA_LEN; | 753 | nca->payload = NCSI_OEM_MLX_CMD_GMA_LEN; |
| 725 | 754 | ||
| 726 | memset(&u, 0, sizeof(u)); | 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 | u.data_u8[5] = NCSI_OEM_MLX_CMD_GMA; | 757 | u.data_u8[5] = NCSI_OEM_MLX_CMD_GMA; |
| 729 | u.data_u8[6] = NCSI_OEM_MLX_CMD_GMA_PARAM; | 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 | int ret = 0; | 776 | int ret = 0; |
| 748 | 777 | ||
| 749 | memset(&u, 0, sizeof(u)); | 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 | u.data_u8[5] = NCSI_OEM_MLX_CMD_SMAF; | 780 | u.data_u8[5] = NCSI_OEM_MLX_CMD_SMAF; |
| 752 | u.data_u8[6] = NCSI_OEM_MLX_CMD_SMAF_PARAM; | 781 | u.data_u8[6] = NCSI_OEM_MLX_CMD_SMAF_PARAM; |
| 753 | memcpy(&u.data_u8[MLX_SMAF_MAC_ADDR_OFFSET], | 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 | goto error; | 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 | nd->state = ncsi_dev_state_probe_gvi; | 1438 | nd->state = ncsi_dev_state_probe_gvi; |
| 1395 | break; | 1439 | break; |
| 1440 | #endif /* CONFIG_NCSI_OEM_CMD_KEEP_PHY */ | ||
| 1396 | case ncsi_dev_state_probe_gvi: | 1441 | case ncsi_dev_state_probe_gvi: |
| 1397 | case ncsi_dev_state_probe_gc: | 1442 | case ncsi_dev_state_probe_gc: |
| 1398 | case ncsi_dev_state_probe_gls: | 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 | /* Update to VLAN mode */ | 403 | /* Update to VLAN mode */ |
| 404 | cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd); | 404 | cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd); |
| 405 | ncm->enable = 1; | 405 | ncm->enable = 1; |
| 406 | ncm->data[0] = ntohl(cmd->mode); | 406 | ncm->data[0] = ntohl((__force __be32)cmd->mode); |
| 407 | 407 | ||
| 408 | return 0; | 408 | return 0; |
| 409 | } | 409 | } |
| @@ -699,12 +699,19 @@ static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr) · 289 unmodified lines | |||
| 699 | return 0; | 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 | static struct ncsi_rsp_oem_handler { | 708 | static struct ncsi_rsp_oem_handler { |
| 703 | unsigned int mfr_id; | 709 | unsigned int mfr_id; |
| 704 | int (*handler)(struct ncsi_request *nr); | 710 | int (*handler)(struct ncsi_request *nr); |
| 705 | } ncsi_rsp_oem_handlers[] = { | 711 | } ncsi_rsp_oem_handlers[] = { |
| 706 | { NCSI_OEM_MFR_MLX_ID, ncsi_rsp_handler_oem_mlx }, | 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 | /* Response handler for OEM command */ | 717 | /* Response handler for OEM command */ |
| @@ -149,7 +149,15 @@ static void nf_conntrack_all_lock(void) · 148 unmodified lines | |||
| 149 | 149 | ||
| 150 | spin_lock(&nf_conntrack_locks_all_lock); | 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 | for (i = 0; i < CONNTRACK_LOCKS; i++) { | 162 | for (i = 0; i < CONNTRACK_LOCKS; i++) { |
| 155 | spin_lock(&nf_conntrack_locks[i]); | 163 | spin_lock(&nf_conntrack_locks[i]); |
| @@ -2457,7 +2465,6 @@ i_see_dead_people: · 2301 unmodified lines | |||
| 2457 | } | 2465 | } |
| 2458 | 2466 | ||
| 2459 | list_for_each_entry(net, net_exit_list, exit_list) { | 2467 | list_for_each_entry(net, net_exit_list, exit_list) { |
| 2460 | nf_conntrack_proto_pernet_fini(net); | ||
| 2461 | nf_conntrack_ecache_pernet_fini(net); | 2468 | nf_conntrack_ecache_pernet_fini(net); |
| 2462 | nf_conntrack_expect_pernet_fini(net); | 2469 | nf_conntrack_expect_pernet_fini(net); |
| 2463 | free_percpu(net->ct.stat); | 2470 | free_percpu(net->ct.stat); |
| @@ -218,6 +218,7 @@ static int ctnetlink_dump_helpinfo(struct sk_buff *skb, · 217 unmodified lines | |||
| 218 | if (!help) | 218 | if (!help) |
| 219 | return 0; | 219 | return 0; |
| 220 | 220 | ||
| 221 | rcu_read_lock(); | ||
| 221 | helper = rcu_dereference(help->helper); | 222 | helper = rcu_dereference(help->helper); |
| 222 | if (!helper) | 223 | if (!helper) |
| 223 | goto out; | 224 | goto out; |
| @@ -233,9 +234,11 @@ static int ctnetlink_dump_helpinfo(struct sk_buff *skb, · 9 unmodified lines | |||
| 233 | 234 | ||
| 234 | nla_nest_end(skb, nest_helper); | 235 | nla_nest_end(skb, nest_helper); |
| 235 | out: | 236 | out: |
| 237 | rcu_read_unlock(); | ||
| 236 | return 0; | 238 | return 0; |
| 237 | 239 | ||
| 238 | nla_put_failure: | 240 | nla_put_failure: |
| 241 | rcu_read_unlock(); | ||
| 239 | return -1; | 242 | return -1; |
| 240 | } | 243 | } |
| 241 | 244 | ||
| @@ -697,13 +697,6 @@ void nf_conntrack_proto_pernet_init(struct net *net) · 696 unmodified lines | |||
| 697 | #endif | 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 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, | 700 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, |
| 708 | &nf_conntrack_htable_size, 0600); | 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 | return &net->ct.nf_ct_proto.gre; | 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 | static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, | 58 | static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, |
| 72 | const struct nf_conntrack_tuple *t) | 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 | return true; | 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 | /* Returns verdict for packet, or -1 for invalid. */ | 842 | /* Returns verdict for packet, or -1 for invalid. */ |
| 827 | int nf_conntrack_tcp_packet(struct nf_conn *ct, | 843 | int nf_conntrack_tcp_packet(struct nf_conn *ct, |
| 828 | struct sk_buff *skb, | 844 | struct sk_buff *skb, |
| @@ -1030,10 +1046,30 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, · 201 unmodified lines | |||
| 1030 | if (index != TCP_RST_SET) | 1046 | if (index != TCP_RST_SET) |
| 1031 | break; | 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 | u32 seq = ntohl(th->seq); | 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 | /* Invalid RST */ | 1073 | /* Invalid RST */ |
| 1038 | spin_unlock_bh(&ct->lock); | 1074 | spin_unlock_bh(&ct->lock); |
| 1039 | nf_ct_l4proto_log_invalid(skb, ct, state, "invalid rst"); | 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 | nf_ct_kill_acct(ct, ctinfo, skb); | 1170 | nf_ct_kill_acct(ct, ctinfo, skb); |
| 1135 | return NF_ACCEPT; | 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 | /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection | 1183 | /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection |
| 1138 | * pickup with loose=1. Avoid large ESTABLISHED timeout. | 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 | return NF_ACCEPT; | 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 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 1204 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 1175 | 1205 | ||
| 1176 | #include <linux/netfilter/nfnetlink.h> | 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 | tn->tcp_be_liberal = 0; | 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 | /* Max number of the retransmitted packets without receiving an (acceptable) | 1473 | /* Max number of the retransmitted packets without receiving an (acceptable) |
| 1441 | * ACK from the destination. If this number is reached, a shorter timer | 1474 | * ACK from the destination. If this number is reached, a shorter timer |
| 1442 | * will be started. | 1475 | * will be started. |
| @@ -579,6 +579,7 @@ enum nf_ct_sysctl_index { · 578 unmodified lines | |||
| 579 | #endif | 579 | #endif |
| 580 | NF_SYSCTL_CT_PROTO_TCP_LOOSE, | 580 | NF_SYSCTL_CT_PROTO_TCP_LOOSE, |
| 581 | NF_SYSCTL_CT_PROTO_TCP_LIBERAL, | 581 | NF_SYSCTL_CT_PROTO_TCP_LIBERAL, |
| 582 | NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST, | ||
| 582 | NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, | 583 | NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, |
| 583 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, | 584 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, |
| 584 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM, | 585 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM, |
| @@ -798,6 +799,14 @@ static struct ctl_table nf_ct_sysctl_table[] = { · 213 unmodified lines | |||
| 798 | .extra1 = SYSCTL_ZERO, | 799 | .extra1 = SYSCTL_ZERO, |
| 799 | .extra2 = SYSCTL_ONE, | 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 | [NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS] = { | 810 | [NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS] = { |
| 802 | .procname = "nf_conntrack_tcp_max_retrans", | 811 | .procname = "nf_conntrack_tcp_max_retrans", |
| 803 | .maxlen = sizeof(u8), | 812 | .maxlen = sizeof(u8), |
| @@ -1004,6 +1013,7 @@ static void nf_conntrack_standalone_init_tcp_sysctl(struct net *net, · 200 unmodified lines | |||
| 1004 | XASSIGN(LOOSE, &tn->tcp_loose); | 1013 | XASSIGN(LOOSE, &tn->tcp_loose); |
| 1005 | XASSIGN(LIBERAL, &tn->tcp_be_liberal); | 1014 | XASSIGN(LIBERAL, &tn->tcp_be_liberal); |
| 1006 | XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans); | 1015 | XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans); |
| 1016 | XASSIGN(IGNORE_INVALID_RST, &tn->tcp_ignore_invalid_rst); | ||
| 1007 | #undef XASSIGN | 1017 | #undef XASSIGN |
| 1008 | 1018 | ||
| 1009 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | 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 | return 0; | 3446 | return 0; |
| 3447 | 3447 | ||
| 3448 | err_destroy_flow_rule: | 3448 | err_destroy_flow_rule: |
| 3449 | nft_flow_rule_destroy(flow); | 3449 | if (flow) |
| 3450 | nft_flow_rule_destroy(flow); | ||
| 3450 | err_release_rule: | 3451 | err_release_rule: |
| 3451 | nf_tables_rule_release(&ctx, rule); | 3452 | nf_tables_rule_release(&ctx, rule); |
| 3452 | err_release_expr: | 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 | struct nft_last_priv *priv = nft_expr_priv(expr); | 24 | struct nft_last_priv *priv = nft_expr_priv(expr); |
| 25 | u64 last_jiffies; | 25 | u64 last_jiffies; |
| 26 | u32 last_set = 0; | ||
| 26 | int err; | 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 | err = nf_msecs_to_jiffies64(tb[NFTA_LAST_MSECS], &last_jiffies); | 36 | err = nf_msecs_to_jiffies64(tb[NFTA_LAST_MSECS], &last_jiffies); |
| 30 | if (err < 0) | 37 | if (err < 0) |
| 31 | return err; | 38 | return err; |
| 32 | 39 | ||
| 33 | priv->last_jiffies = jiffies + (unsigned long)last_jiffies; | 40 | priv->last_jiffies = jiffies - (unsigned long)last_jiffies; |
| 34 | priv->last_set = 1; | ||
| 35 | } | 41 | } |
| 36 | 42 | ||
| 37 | return 0; | 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 | nlmsg_end(skb, rep); | 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 | EXPORT_SYMBOL(netlink_ack); | 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 | const long *cp1 = (const long *)((const u8 *)key1 + key_start); | 671 | const long *cp1 = (const long *)((const u8 *)key1 + key_start); |
| 672 | const long *cp2 = (const long *)((const u8 *)key2 + key_start); | 672 | const long *cp2 = (const long *)((const u8 *)key2 + key_start); |
| 673 | long diffs = 0; | ||
| 674 | int i; | 673 | int i; |
| 675 | 674 | ||
| 676 | for (i = key_start; i < key_end; i += sizeof(long)) | 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 | static bool flow_cmp_masked_key(const struct sw_flow *flow, | 682 | static bool flow_cmp_masked_key(const struct sw_flow *flow, |
| @@ -322,11 +322,22 @@ err_alloc: · 321 unmodified lines | |||
| 322 | 322 | ||
| 323 | static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) | 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 | struct tcf_ct_flow_table *ct_ft; | 326 | struct tcf_ct_flow_table *ct_ft; |
| 327 | struct flow_block *block; | ||
| 326 | 328 | ||
| 327 | ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, | 329 | ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, |
| 328 | rwork); | 330 | rwork); |
| 329 | nf_flow_table_free(&ct_ft->nf_ft); | 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 | kfree(ct_ft); | 341 | kfree(ct_ft); |
| 331 | 342 | ||
| 332 | module_put(THIS_MODULE); | 343 | module_put(THIS_MODULE); |
| @@ -1026,7 +1037,8 @@ do_nat: · 693 unmodified lines | |||
| 1026 | /* This will take care of sending queued events | 1037 | /* This will take care of sending queued events |
| 1027 | * even if the connection is already confirmed. | 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 | if (!skip_add) | 1044 | if (!skip_add) |
| @@ -564,7 +564,7 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) · 563 unmodified lines | |||
| 564 | /* if there's no entry, it means that the schedule didn't | 564 | /* if there's no entry, it means that the schedule didn't |
| 565 | * start yet, so force all gates to be open, this is in | 565 | * start yet, so force all gates to be open, this is in |
| 566 | * accordance to IEEE 802.1Qbv-2015 Section 8.6.9.4.5 | 566 | * accordance to IEEE 802.1Qbv-2015 Section 8.6.9.4.5 |
| 567 | * "AdminGateSates" | 567 | * "AdminGateStates" |
| 568 | */ | 568 | */ |
| 569 | gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN; | 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 | goto out; | 284 | goto out; |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | 287 | err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); |
| 288 | MSG_DONTWAIT); | 288 | |
| 289 | if (err > 0) | ||
| 290 | err = 0; | ||
| 291 | out: | 289 | out: |
| 292 | return err; | 290 | return err; |
| 293 | } | 291 | } |
| @@ -398,7 +398,8 @@ static enum sctp_scope sctp_v4_scope(union sctp_addr *addr) · 397 unmodified lines | |||
| 398 | retval = SCTP_SCOPE_LINK; | 398 | retval = SCTP_SCOPE_LINK; |
| 399 | } else if (ipv4_is_private_10(addr->v4.sin_addr.s_addr) || | 399 | } else if (ipv4_is_private_10(addr->v4.sin_addr.s_addr) || |
| 400 | ipv4_is_private_172(addr->v4.sin_addr.s_addr) || | 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 | retval = SCTP_SCOPE_PRIVATE; | 403 | retval = SCTP_SCOPE_PRIVATE; |
| 403 | } else { | 404 | } else { |
| 404 | retval = SCTP_SCOPE_GLOBAL; | 405 | retval = SCTP_SCOPE_GLOBAL; |
| @@ -1163,7 +1163,7 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, · 1162 unmodified lines | |||
| 1163 | const struct sctp_transport *transport, | 1163 | const struct sctp_transport *transport, |
| 1164 | __u32 probe_size) | 1164 | __u32 probe_size) |
| 1165 | { | 1165 | { |
| 1166 | struct sctp_sender_hb_info hbinfo; | 1166 | struct sctp_sender_hb_info hbinfo = {}; |
| 1167 | struct sctp_chunk *retval; | 1167 | struct sctp_chunk *retval; |
| 1168 | 1168 | ||
| 1169 | retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, | 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 | t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t); | 335 | t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t); |
| 336 | sctp_assoc_sync_pmtu(t->asoc); | 336 | sctp_assoc_sync_pmtu(t->asoc); |
| 337 | } | 337 | } |
| 338 | } else if (t->pl.state == SCTP_PL_COMPLETE && ++t->pl.raise_count == 30) { | 338 | } else if (t->pl.state == SCTP_PL_COMPLETE) { |
| 339 | /* Raise probe_size again after 30 * interval in Search Complete */ | 339 | t->pl.raise_count++; |
| 340 | t->pl.state = SCTP_PL_SEARCH; /* Search Complete -> Search */ | 340 | if (t->pl.raise_count == 30) { |
| 341 | t->pl.probe_size += SCTP_PL_MIN_STEP; | 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 | #include <linux/sockios.h> | 104 | #include <linux/sockios.h> |
| 105 | #include <net/busy_poll.h> | 105 | #include <net/busy_poll.h> |
| 106 | #include <linux/errqueue.h> | 106 | #include <linux/errqueue.h> |
| 107 | #include <linux/ptp_clock_kernel.h> | ||
| 107 | 108 | ||
| 108 | #ifdef CONFIG_NET_RX_BUSY_POLL | 109 | #ifdef CONFIG_NET_RX_BUSY_POLL |
| 109 | unsigned int sysctl_net_busy_read __read_mostly; | 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 | empty = 0; | 874 | empty = 0; |
| 874 | if (shhwtstamps && | 875 | if (shhwtstamps && |
| 875 | (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && | 876 | (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && |
| 876 | !skb_is_swtx_tstamp(skb, false_tstamp) && | 877 | !skb_is_swtx_tstamp(skb, false_tstamp)) { |
| 877 | ktime_to_timespec64_cond(shhwtstamps->hwtstamp, tss.ts + 2)) { | 878 | if (sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC) |
| 878 | empty = 0; | 879 | ptp_convert_timestamp(shhwtstamps, sk->sk_bind_phc); |
| 879 | if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) && | 880 | |
| 880 | !skb_is_err_queue(skb)) | 881 | if (ktime_to_timespec64_cond(shhwtstamps->hwtstamp, |
| 881 | put_ts_pktinfo(msg, skb); | 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 | if (!empty) { | 890 | if (!empty) { |
| 884 | if (sock_flag(sk, SOCK_TSTAMP_NEW)) | 891 | if (sock_flag(sk, SOCK_TSTAMP_NEW)) |
| @@ -295,10 +295,8 @@ again: · 294 unmodified lines | |||
| 295 | 295 | ||
| 296 | goto again; | 296 | goto again; |
| 297 | } | 297 | } |
| 298 | err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, | 298 | err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid); |
| 299 | MSG_DONTWAIT); | 299 | |
| 300 | if (err > 0) | ||
| 301 | err = 0; | ||
| 302 | out: | 300 | out: |
| 303 | if (sk) | 301 | if (sk) |
| 304 | sock_put(sk); | 302 | sock_put(sk); |
| @@ -331,6 +331,7 @@ $(obj)/%.o: $(src)/%.c · 330 unmodified lines | |||
| 331 | -Wno-gnu-variable-sized-type-not-at-end \ | 331 | -Wno-gnu-variable-sized-type-not-at-end \ |
| 332 | -Wno-address-of-packed-member -Wno-tautological-compare \ | 332 | -Wno-address-of-packed-member -Wno-tautological-compare \ |
| 333 | -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \ | 333 | -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \ |
| 334 | -fno-asynchronous-unwind-tables \ | ||
| 334 | -I$(srctree)/samples/bpf/ -include asm_goto_workaround.h \ | 335 | -I$(srctree)/samples/bpf/ -include asm_goto_workaround.h \ |
| 335 | -O2 -emit-llvm -Xclang -disable-llvm-passes -c $< -o - | \ | 336 | -O2 -emit-llvm -Xclang -disable-llvm-passes -c $< -o - | \ |
| 336 | $(OPT) -O2 -mtriple=bpf-pc-linux | $(LLVM_DIS) | \ | 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 | static int opt_timeout = 1000; | 96 | static int opt_timeout = 1000; |
| 97 | static bool opt_need_wakeup = true; | 97 | static bool opt_need_wakeup = true; |
| 98 | static u32 opt_num_xsks = 1; | 98 | static u32 opt_num_xsks = 1; |
| 99 | static u32 prog_id; | ||
| 99 | static bool opt_busy_poll; | 100 | static bool opt_busy_poll; |
| 100 | static bool opt_reduced_cap; | 101 | static bool opt_reduced_cap; |
| 101 | 102 | ||
| @@ -461,6 +462,23 @@ static void *poller(void *arg) · 359 unmodified lines | |||
| 461 | return NULL; | 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 | static void int_exit(int sig) | 482 | static void int_exit(int sig) |
| 465 | { | 483 | { |
| 466 | benchmark_done = true; | 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 | fprintf(stderr, "%s:%s:%i: errno: %d/\"%s\"\n", file, func, | 490 | fprintf(stderr, "%s:%s:%i: errno: %d/\"%s\"\n", file, func, |
| 473 | line, error, strerror(error)); | 491 | line, error, strerror(error)); |
| 492 | |||
| 493 | if (opt_num_xsks > 1) | ||
| 494 | remove_xdp_program(); | ||
| 474 | exit(EXIT_FAILURE); | 495 | exit(EXIT_FAILURE); |
| 475 | } | 496 | } |
| 476 | 497 | ||
| @@ -490,6 +511,9 @@ static void xdpsock_cleanup(void) · 13 unmodified lines | |||
| 490 | if (write(sock, &cmd, sizeof(int)) < 0) | 511 | if (write(sock, &cmd, sizeof(int)) < 0) |
| 491 | exit_with_error(errno); | 512 | exit_with_error(errno); |
| 492 | } | 513 | } |
| 514 | |||
| 515 | if (opt_num_xsks > 1) | ||
| 516 | remove_xdp_program(); | ||
| 493 | } | 517 | } |
| 494 | 518 | ||
| 495 | static void swap_mac_addresses(void *data) | 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 | if (ret) | 881 | if (ret) |
| 858 | exit_with_error(-ret); | 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 | xsk->app_stats.rx_empty_polls = 0; | 888 | xsk->app_stats.rx_empty_polls = 0; |
| 861 | xsk->app_stats.fill_fail_polls = 0; | 889 | xsk->app_stats.fill_fail_polls = 0; |
| 862 | xsk->app_stats.copy_tx_sendtos = 0; | 890 | xsk->app_stats.copy_tx_sendtos = 0; |
| @@ -97,7 +97,7 @@ clean: bpftool_clean runqslower_clean resolve_btfids_clean · 96 unmodified lines | |||
| 97 | $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpf | 97 | $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpf |
| 98 | $(Q)$(RM) -r -- $(OUTPUT)feature | 98 | $(Q)$(RM) -r -- $(OUTPUT)feature |
| 99 | 99 | ||
| 100 | install: $(PROGS) bpftool_install runqslower_install | 100 | install: $(PROGS) bpftool_install |
| 101 | $(call QUIET_INSTALL, bpf_jit_disasm) | 101 | $(call QUIET_INSTALL, bpf_jit_disasm) |
| 102 | $(Q)$(INSTALL) -m 0755 -d $(DESTDIR)$(prefix)/bin | 102 | $(Q)$(INSTALL) -m 0755 -d $(DESTDIR)$(prefix)/bin |
| 103 | $(Q)$(INSTALL) $(OUTPUT)bpf_jit_disasm $(DESTDIR)$(prefix)/bin/bpf_jit_disasm | 103 | $(Q)$(INSTALL) $(OUTPUT)bpf_jit_disasm $(DESTDIR)$(prefix)/bin/bpf_jit_disasm |
| @@ -118,9 +118,6 @@ bpftool_clean: · 14 unmodified lines | |||
| 118 | runqslower: | 118 | runqslower: |
| 119 | $(call descend,runqslower) | 119 | $(call descend,runqslower) |
| 120 | 120 | ||
| 121 | runqslower_install: | ||
| 122 | $(call descend,runqslower,install) | ||
| 123 | |||
| 124 | runqslower_clean: | 121 | runqslower_clean: |
| 125 | $(call descend,runqslower,clean) | 122 | $(call descend,runqslower,clean) |
| 126 | 123 | ||
| @@ -131,5 +128,5 @@ resolve_btfids_clean: · 4 unmodified lines | |||
| 131 | $(call descend,resolve_btfids,clean) | 128 | $(call descend,resolve_btfids,clean) |
| 132 | 129 | ||
| 133 | .PHONY: all install clean bpftool bpftool_install bpftool_clean \ | 130 | .PHONY: all install clean bpftool bpftool_install bpftool_clean \ |
| 134 | runqslower runqslower_install runqslower_clean \ | 131 | runqslower runqslower_clean \ |
| 135 | resolve_btfids resolve_btfids_clean | 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 | va_list ap; | 44 | va_list ap; |
| 45 | char *s; | 45 | char *s; |
| 46 | int err; | ||
| 46 | 47 | ||
| 47 | va_start(ap, fmt); | 48 | va_start(ap, fmt); |
| 48 | if (vasprintf(&s, fmt, ap) < 0) | 49 | err = vasprintf(&s, fmt, ap); |
| 49 | return -1; | ||
| 50 | va_end(ap); | 50 | va_end(ap); |
| 51 | if (err < 0) | ||
| 52 | return -1; | ||
| 51 | 53 | ||
| 52 | if (!oper_count) { | 54 | if (!oper_count) { |
| 53 | int i; | 55 | int i; |
| @@ -74,7 +74,7 @@ int handle__sched_switch(u64 *ctx) · 73 unmodified lines | |||
| 74 | u32 pid; | 74 | u32 pid; |
| 75 | 75 | ||
| 76 | /* ivcsw: treat like an enqueue event and store timestamp */ | 76 | /* ivcsw: treat like an enqueue event and store timestamp */ |
| 77 | if (prev->state == TASK_RUNNING) | 77 | if (prev->__state == TASK_RUNNING) |
| 78 | trace_enqueue(prev); | 78 | trace_enqueue(prev); |
| 79 | 79 | ||
| 80 | pid = next->pid; | 80 | pid = next->pid; |
| @@ -10136,7 +10136,7 @@ int bpf_link__unpin(struct bpf_link *link) · 10135 unmodified lines | |||
| 10136 | 10136 | ||
| 10137 | err = unlink(link->pin_path); | 10137 | err = unlink(link->pin_path); |
| 10138 | if (err != 0) | 10138 | if (err != 0) |
| 10139 | return libbpf_err_errno(err); | 10139 | return -errno; |
| 10140 | 10140 | ||
| 10141 | pr_debug("link fd=%d: unpinned from %s\n", link->fd, link->pin_path); | 10141 | pr_debug("link fd=%d: unpinned from %s\n", link->fd, link->pin_path); |
| 10142 | zfree(&link->pin_path); | 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 | cnt = epoll_wait(pb->epoll_fd, pb->events, pb->cpu_cnt, timeout_ms); | 11198 | cnt = epoll_wait(pb->epoll_fd, pb->events, pb->cpu_cnt, timeout_ms); |
| 11199 | if (cnt < 0) | 11199 | if (cnt < 0) |
| 11200 | return libbpf_err_errno(cnt); | 11200 | return -errno; |
| 11201 | 11201 | ||
| 11202 | for (i = 0; i < cnt; i++) { | 11202 | for (i = 0; i < cnt; i++) { |
| 11203 | struct perf_cpu_buf *cpu_buf = pb->events[i].data.ptr; | 11203 | struct perf_cpu_buf *cpu_buf = pb->events[i].data.ptr; |
| @@ -715,6 +715,8 @@ out: · 714 unmodified lines | |||
| 715 | bpf_object__close(obj); | 715 | bpf_object__close(obj); |
| 716 | } | 716 | } |
| 717 | 717 | ||
| 718 | #include "tailcall_bpf2bpf4.skel.h" | ||
| 719 | |||
| 718 | /* test_tailcall_bpf2bpf_4 checks that tailcall counter is correctly preserved | 720 | /* test_tailcall_bpf2bpf_4 checks that tailcall counter is correctly preserved |
| 719 | * across tailcalls combined with bpf2bpf calls. for making sure that tailcall | 721 | * across tailcalls combined with bpf2bpf calls. for making sure that tailcall |
| 720 | * counter behaves correctly, bpf program will go through following flow: | 722 | * counter behaves correctly, bpf program will go through following flow: |
| @@ -727,10 +729,15 @@ out: · 6 unmodified lines | |||
| 727 | * the loop begins. At the end of the test make sure that the global counter is | 729 | * the loop begins. At the end of the test make sure that the global counter is |
| 728 | * equal to 31, because tailcall counter includes the first two tailcalls | 730 | * equal to 31, because tailcall counter includes the first two tailcalls |
| 729 | * whereas global counter is incremented only on loop presented on flow above. | 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 | struct bpf_map *prog_array, *data_map; | 741 | struct bpf_map *prog_array, *data_map; |
| 735 | struct bpf_program *prog; | 742 | struct bpf_program *prog; |
| 736 | struct bpf_object *obj; | 743 | struct bpf_object *obj; |
| @@ -774,11 +781,6 @@ static void test_tailcall_bpf2bpf_4(void) · 37 unmodified lines | |||
| 774 | goto out; | 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 | data_map = bpf_object__find_map_by_name(obj, "tailcall.bss"); | 784 | data_map = bpf_object__find_map_by_name(obj, "tailcall.bss"); |
| 783 | if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map))) | 785 | if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map))) |
| 784 | return; | 786 | return; |
| @@ -787,10 +789,22 @@ static void test_tailcall_bpf2bpf_4(void) · 2 unmodified lines | |||
| 787 | if (CHECK_FAIL(map_fd < 0)) | 789 | if (CHECK_FAIL(map_fd < 0)) |
| 788 | return; | 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 | i = 0; | 804 | i = 0; |
| 791 | err = bpf_map_lookup_elem(data_fd, &i, &val); | 805 | err = bpf_map_lookup_elem(data_fd, &i, &val); |
| 792 | CHECK(err || val != 31, "tailcall count", "err %d errno %d count %d\n", | 806 | CHECK(err || val.count != 31, "tailcall count", "err %d errno %d count %d\n", |
| 793 | err, errno, val); | 807 | err, errno, val.count); |
| 794 | 808 | ||
| 795 | out: | 809 | out: |
| 796 | bpf_object__close(obj); | 810 | bpf_object__close(obj); |
| @@ -815,5 +829,7 @@ void test_tailcalls(void) · 18 unmodified lines | |||
| 815 | if (test__start_subtest("tailcall_bpf2bpf_3")) | 829 | if (test__start_subtest("tailcall_bpf2bpf_3")) |
| 816 | test_tailcall_bpf2bpf_3(); | 830 | test_tailcall_bpf2bpf_3(); |
| 817 | if (test__start_subtest("tailcall_bpf2bpf_4")) | 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 | #include <linux/bpf.h> | 2 | #include <linux/bpf.h> |
| 3 | #include <bpf/bpf_helpers.h> | 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 | struct { | 12 | struct { |
| 6 | __uint(type, BPF_MAP_TYPE_PROG_ARRAY); | 13 | __uint(type, BPF_MAP_TYPE_PROG_ARRAY); |
| 7 | __uint(max_entries, 3); | 14 | __uint(max_entries, 3); |
| @@ -10,10 +17,21 @@ struct { · 2 unmodified lines | |||
| 10 | } jmp_table SEC(".maps"); | 17 | } jmp_table SEC(".maps"); |
| 11 | 18 | ||
| 12 | int count = 0; | 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 | __noinline | 30 | __noinline |
| 15 | int subprog_tail_2(struct __sk_buff *skb) | 31 | int subprog_tail_2(struct __sk_buff *skb) |
| 16 | { | 32 | { |
| 33 | if (noise) | ||
| 34 | subprog_noise(); | ||
| 17 | bpf_tail_call_static(skb, &jmp_table, 2); | 35 | bpf_tail_call_static(skb, &jmp_table, 2); |
| 18 | return skb->len * 3; | 36 | return skb->len * 3; |
| 19 | } | 37 | } |
| @@ -313,9 +313,10 @@ check_exception() · 312 unmodified lines | |||
| 313 | fi | 313 | fi |
| 314 | log_test $? 0 "IPv4: ${desc}" | 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 | ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ | 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 | elif [ -n "${mtu}" ]; then | 320 | elif [ -n "${mtu}" ]; then |
| 320 | ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ | 321 | ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \ |
| 321 | grep -q "${mtu}" | 322 | grep -q "${mtu}" |
| @@ -1409,7 +1409,7 @@ syncookies_tests() · 1408 unmodified lines | |||
| 1409 | ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow | 1409 | ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow |
| 1410 | ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow | 1410 | ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow |
| 1411 | run_tests $ns1 $ns2 10.0.1.1 | 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 | # test signal address with cookies | 1414 | # test signal address with cookies |
| 1415 | reset_with_cookies | 1415 | reset_with_cookies |
| @@ -47,7 +47,7 @@ static void usage(const char *error) · 46 unmodified lines | |||
| 47 | { | 47 | { |
| 48 | if (error) | 48 | if (error) |
| 49 | printf("invalid option: %s\n", error); | 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 | "Options:\n" | 51 | "Options:\n" |
| 52 | " IP_MULTICAST_LOOP - looping outgoing multicasts\n" | 52 | " IP_MULTICAST_LOOP - looping outgoing multicasts\n" |
| 53 | " SO_TIMESTAMP - normal software time stamping, ms resolution\n" | 53 | " SO_TIMESTAMP - normal software time stamping, ms resolution\n" |
| @@ -58,6 +58,7 @@ static void usage(const char *error) · 4 unmodified lines | |||
| 58 | " SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n" | 58 | " SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n" |
| 59 | " SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n" | 59 | " SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n" |
| 60 | " SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n" | 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 | " SIOCGSTAMP - check last socket time stamp\n" | 62 | " SIOCGSTAMP - check last socket time stamp\n" |
| 62 | " SIOCGSTAMPNS - more accurate socket time stamp\n" | 63 | " SIOCGSTAMPNS - more accurate socket time stamp\n" |
| 63 | " PTPV2 - use PTPv2 messages\n"); | 64 | " PTPV2 - use PTPv2 messages\n"); |
| @@ -311,7 +312,6 @@ static void recvpacket(int sock, int recvmsg_flags, · 247 unmodified lines | |||
| 311 | 312 | ||
| 312 | int main(int argc, char **argv) | 313 | int main(int argc, char **argv) |
| 313 | { | 314 | { |
| 314 | int so_timestamping_flags = 0; | ||
| 315 | int so_timestamp = 0; | 315 | int so_timestamp = 0; |
| 316 | int so_timestampns = 0; | 316 | int so_timestampns = 0; |
| 317 | int siocgstamp = 0; | 317 | int siocgstamp = 0; |
| @@ -325,6 +325,8 @@ int main(int argc, char **argv) · 7 unmodified lines | |||
| 325 | struct ifreq device; | 325 | struct ifreq device; |
| 326 | struct ifreq hwtstamp; | 326 | struct ifreq hwtstamp; |
| 327 | struct hwtstamp_config hwconfig, hwconfig_requested; | 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 | struct sockaddr_in addr; | 330 | struct sockaddr_in addr; |
| 329 | struct ip_mreq imr; | 331 | struct ip_mreq imr; |
| 330 | struct in_addr iaddr; | 332 | struct in_addr iaddr; |
| @@ -342,7 +344,12 @@ int main(int argc, char **argv) · 11 unmodified lines | |||
| 342 | exit(1); | 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 | if (!strcasecmp(argv[i], "SO_TIMESTAMP")) | 353 | if (!strcasecmp(argv[i], "SO_TIMESTAMP")) |
| 347 | so_timestamp = 1; | 354 | so_timestamp = 1; |
| 348 | else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS")) | 355 | else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS")) |
| @@ -356,17 +363,19 @@ int main(int argc, char **argv) · 7 unmodified lines | |||
| 356 | else if (!strcasecmp(argv[i], "PTPV2")) | 363 | else if (!strcasecmp(argv[i], "PTPV2")) |
| 357 | ptpv2 = 1; | 364 | ptpv2 = 1; |
| 358 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE")) | 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 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE")) | 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 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE")) | 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 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE")) | 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 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE")) | 373 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE")) |
| 367 | so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE; | 374 | so_timestamping.flags |= SOF_TIMESTAMPING_SOFTWARE; |
| 368 | else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE")) | 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 | else | 379 | else |
| 371 | usage(argv[i]); | 380 | usage(argv[i]); |
| 372 | } | 381 | } |
| @@ -385,10 +394,10 @@ int main(int argc, char **argv) · 12 unmodified lines | |||
| 385 | hwtstamp.ifr_data = (void *)&hwconfig; | 394 | hwtstamp.ifr_data = (void *)&hwconfig; |
| 386 | memset(&hwconfig, 0, sizeof(hwconfig)); | 395 | memset(&hwconfig, 0, sizeof(hwconfig)); |
| 387 | hwconfig.tx_type = | 396 | hwconfig.tx_type = |
| 388 | (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ? | 397 | (so_timestamping.flags & SOF_TIMESTAMPING_TX_HARDWARE) ? |
| 389 | HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; | 398 | HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; |
| 390 | hwconfig.rx_filter = | 399 | hwconfig.rx_filter = |
| 391 | (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ? | 400 | (so_timestamping.flags & SOF_TIMESTAMPING_RX_HARDWARE) ? |
| 392 | ptpv2 ? HWTSTAMP_FILTER_PTP_V2_L4_SYNC : | 401 | ptpv2 ? HWTSTAMP_FILTER_PTP_V2_L4_SYNC : |
| 393 | HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE; | 402 | HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE; |
| 394 | hwconfig_requested = hwconfig; | 403 | hwconfig_requested = hwconfig; |
| @@ -413,6 +422,9 @@ int main(int argc, char **argv) · 18 unmodified lines | |||
| 413 | sizeof(struct sockaddr_in)) < 0) | 422 | sizeof(struct sockaddr_in)) < 0) |
| 414 | bail("bind"); | 423 | bail("bind"); |
| 415 | 424 | ||
| 425 | if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, if_len)) | ||
| 426 | bail("bind device"); | ||
| 427 | |||
| 416 | /* set multicast group for outgoing packets */ | 428 | /* set multicast group for outgoing packets */ |
| 417 | inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */ | 429 | inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */ |
| 418 | addr.sin_addr = iaddr; | 430 | addr.sin_addr = iaddr; |
| @@ -444,10 +456,9 @@ int main(int argc, char **argv) · 25 unmodified lines | |||
| 444 | &enabled, sizeof(enabled)) < 0) | 456 | &enabled, sizeof(enabled)) < 0) |
| 445 | bail("setsockopt SO_TIMESTAMPNS"); | 457 | bail("setsockopt SO_TIMESTAMPNS"); |
| 446 | 458 | ||
| 447 | if (so_timestamping_flags && | 459 | if (so_timestamping.flags && |
| 448 | setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, | 460 | setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping, |
| 449 | &so_timestamping_flags, | 461 | sizeof(so_timestamping)) < 0) |
| 450 | sizeof(so_timestamping_flags)) < 0) | ||
| 451 | bail("setsockopt SO_TIMESTAMPING"); | 462 | bail("setsockopt SO_TIMESTAMPING"); |
| 452 | 463 | ||
| 453 | /* request IP_PKTINFO for debugging purposes */ | 464 | /* request IP_PKTINFO for debugging purposes */ |
| @@ -468,14 +479,18 @@ int main(int argc, char **argv) · 14 unmodified lines | |||
| 468 | else | 479 | else |
| 469 | printf("SO_TIMESTAMPNS %d\n", val); | 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 | printf("%s: %s\n", "getsockopt SO_TIMESTAMPING", | 485 | printf("%s: %s\n", "getsockopt SO_TIMESTAMPING", |
| 473 | strerror(errno)); | 486 | strerror(errno)); |
| 474 | } else { | 487 | } else { |
| 475 | printf("SO_TIMESTAMPING %d\n", val); | 488 | printf("SO_TIMESTAMPING flags %d, bind phc %d\n", |
| 476 | if (val != so_timestamping_flags) | 489 | so_timestamping_get.flags, so_timestamping_get.bind_phc); |
| 477 | printf(" not the expected value %d\n", | 490 | if (so_timestamping_get.flags != so_timestamping.flags || |
| 478 | 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 | /* send packets forever every five seconds */ | 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 | conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \ | 5 | conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \ |
| 6 | nft_concat_range.sh nft_conntrack_helper.sh \ | 6 | nft_concat_range.sh nft_conntrack_helper.sh \ |
| 7 | nft_queue.sh nft_meta.sh nf_nat_edemux.sh \ | 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 | LDLIBS = -lmnl | 10 | LDLIBS = -lmnl |
| 11 | TEST_GEN_FILES = nf-queue | 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 | ||