]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'mlx5-updates-2017-06-27' of git://git.kernel.org/pub/scm/linux/kernel...
authorDavid S. Miller <davem@davemloft.net>
Thu, 29 Jun 2017 16:30:16 +0000 (12:30 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 29 Jun 2017 16:30:16 +0000 (12:30 -0400)
Saeed Mahameed says:

====================
mlx5-updates-2017-06-27 (Innova IPsec offload support)

This patchset adds support for Innova IPSec network interface card.

About Innova device:
--------------------
Innova is a network card with a ConnectX chip and an FPGA chip as a
 bump-on-the-wire.

               Internal
+----------+   Link       +-----------------+
|          +--------------+      FPGA       |  +------+
| ConnectX |              |  Shell          +--+ QSFP |
|          +--------------+    +-------+    |  | Port |
+----------+      I2C     |    |  SBU  |    |  +------+
                          |    +-------+    |
                          +--+----------+---+
                             |          |
                          +--+--+   +---+---+
                          | DDR |   | Flash |
                          +-----+   +-------+

The FPGA synthesized logic is loaded from dedicated flash storage and has
 access to its own dedicated DDR RAM.
The ConnectX chip firmware programs the FPGA by accessing its configuration
space over either the slow internal I2C link or the high-speed internal link.

The FPGA logic is divided into a "Shell" and a "Sandbox Unit" (SBU).
mlx5_core driver (with CONFIG_MLX5_FPGA) handles all shell functionality,
while other components may handle the various SBU functionalities.

The driver opens high-speed reliable communication channels with the shell and
the SBU over the internal link.
These channels may be used for high-bandwidth configuration or for SBU-specific
out-of-band data paths.

About Innova IPSec device:
--------------------------
Innova IPSec is a network card that allows offloading IPSec cryptography operations
from the host CPU to the NIC. It is an Innova card with an IPSec SBU.
The hardware keeps the database of IPSec Security Associations (SADB) in the FPGA's
DDR memory.

               Internal
+----------+   Link       +-----------------+
|          +--------------+      FPGA       |  +------+
| ConnectX |              |  Shell          +--+ QSFP |
|          +--------------+    +-------+    |  | Port |
+----------+ Internal I2C |    | IPSec |    |  +------+
                          |    |  SBU  |    |
                          |    +-------+    |
                          +--+----------+---+
                             |          |
                          +--+--+   +---+---+
                          | DDR |   |       |
                          |     |   | Flash |
                          |SADB |   |       |
                          +-----+   +-------+

Modes and ciphers:
Currently the following modes and ciphers are supported:
IPv4 and IPv6
ESP tunnel and transport modes
AES 128 and 256 bit encryption, with GCM authentication (RFC4106)

IV is generated using seqiv, in sync with Linux's geniv.

More modes and ciphers may be added later.

Notes:
In the future similar functionality will be included in a single-chip NIC.

About the driver:
-----------------
Patches 1-4 prepare some existing driver code for the new feature:
  * Add support for reserved GIDs in the hardware GID table
  * Allow multiple modules to enable hardware RoCE support independently
Patches 5-6 define structs and helper functions for QP work-queues.
Patches 7-11 add various FPGA-related features required for Innova.
IPSec.
Patch 12 adds abstraction layer for Mellanox IPSec-offload capable devices.
atches 13-16 add IPSec offload support to the mlx5 netdevice.

This driver services the new IPSec offload API introduced in commit
d77e38e612a0 ("xfrm: Add an IPsec hardware offloading API")

Configuration Path:
If Innova IPSec device is detected, the mlx5e netdevice gets the new
NETIF_F_HW_ESP feature and the xdo callbacks, indicating ESP offload
capabilities, and also the matching TX checksum and GSO features.

The driver configures offloaded Security Associations (SAs) by sending
an ADD_SA or DEL_SA message to the IPSec SBU, which updates the SADB in DDR.
These messages and their responses are sent over a high-speed channel.
Counters for ethtool are retrieved by the driver from the SBU.

Data path:
On receive path, the SBU decrypts ESP packets which match the offloaded SADB,
but keeps them encapsulated.
The SBU injects metadata (Mellanox owned ethertype) indicating that crypto-offload
has taken place, the SA with which it was done, and the authentication result.

The ConnectX chip performs RX checksum offload on the packet, and RSS using the
ESP SPI value.  The driver detects the special ethertype, and attaches a struct
secpath to the RX SKB, including flags to indicate that crypto offload took place,
the authentication result, and which xfrm_state was used for decryption, in the
olen and ovec members. The RX SKB may have useful CHECKSUM_COMPLETE. A separate
patchset will add support for that in the xfrm stack.

On transmit path, the stack encapsulates the packet but does not encrypt it, and
indicates in the SKB's secpath that crypto offload is to be performed and the SA
to use to do so.
The driver avoids performing crypto-offload for ESP fragments, and packets with
IP options, as the SBU cannot currently do that.  For eligible packets, the driver
prepends a special ethertype with metadata instructing the hardware to perform crypto offload.
The stack builds regular (non-GSO) SKBs so that they contain a placeholder for the ESP trailer.
The driver trims it off, because the SBU automatically appends the trailer for offloaded packets.
The ConnectX chip performs TX checksum offload on inner UDP or TCP packets,
and GSO for TCP packets (duplicating the prepended metadata).
The segmented packets then undergo encryption in the SBU before going on the wire.

Performance:
We measure single stream of TCP on Intel(R) Xeon(R) CPU E5-2643 v2 @3.50GHz
Using AES-NI with ESP GSO we get constant 4.1 Gbps.
Using crypto offload we get constant 18 Gbps.

Note that these numbers require CHECKSUM_COMPLETE support in XFRM, which we submit separately.

-  Ilan Tayari
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
39 files changed:
Documentation/networking/policy-routing.txt [deleted file]
arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
drivers/net/bonding/bond_options.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/netronome/Kconfig
drivers/net/ethernet/netronome/nfp/Makefile
drivers/net/ethernet/netronome/nfp/flower/cmsg.c
drivers/net/ethernet/netronome/nfp/flower/cmsg.h
drivers/net/ethernet/netronome/nfp/flower/main.c
drivers/net/ethernet/netronome/nfp/nfp_app.c
drivers/net/ethernet/netronome/nfp/nfp_app.h
drivers/net/ethernet/netronome/nfp/nfp_main.c
drivers/net/ethernet/netronome/nfp/nfp_main.h
drivers/net/ethernet/netronome/nfp/nfp_net_main.c
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
drivers/net/ethernet/netronome/nfp/nfp_net_repr.h
drivers/net/ethernet/netronome/nfp/nfp_port.c
drivers/net/ethernet/netronome/nfp/nfp_port.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpts.h
drivers/net/ethernet/ti/netcp_ethss.c
drivers/net/vxlan.c
include/net/udp.h
net/ipv4/tcp.c
net/ipv4/udp.c
net/ipv6/udp.c

diff --git a/Documentation/networking/policy-routing.txt b/Documentation/networking/policy-routing.txt
deleted file mode 100644 (file)
index 36f6936..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-Classes
--------
-
-       "Class" is a complete routing table in common sense.
-       I.e. it is tree of nodes (destination prefix, tos, metric)
-       with attached information: gateway, device etc.
-       This tree is looked up as specified in RFC1812 5.2.4.3
-       1. Basic match
-       2. Longest match
-       3. Weak TOS.
-       4. Metric. (should not be in kernel space, but they are)
-       5. Additional pruning rules. (not in kernel space).
-       
-       We have two special type of nodes:
-       REJECT - abort route lookup and return an error value.
-       THROW  - abort route lookup in this class.
-
-
-       Currently the number of classes is limited to 255
-       (0 is reserved for "not specified class")
-
-       Three classes are builtin:
-
-       RT_CLASS_LOCAL=255 - local interface addresses,
-       broadcasts, nat addresses.
-
-       RT_CLASS_MAIN=254  - all normal routes are put there
-       by default.
-
-       RT_CLASS_DEFAULT=253 - if ip_fib_model==1, then
-       normal default routes are put there, if ip_fib_model==2
-       all gateway routes are put there.
-
-
-Rules
------
-       Rule is a record of (src prefix, src interface, tos, dst prefix)
-       with attached information.
-
-       Rule types:
-       RTP_ROUTE - lookup in attached class
-       RTP_NAT   - lookup in attached class and if a match is found,
-                   translate packet source address.
-       RTP_MASQUERADE - lookup in attached class and if a match is found,
-                   masquerade packet as sourced by us.
-       RTP_DROP   - silently drop the packet.
-       RTP_REJECT - drop the packet and send ICMP NET UNREACHABLE.
-       RTP_PROHIBIT - drop the packet and send ICMP COMM. ADM. PROHIBITED.
-
-       Rule flags:
-       RTRF_LOG - log route creations.
-       RTRF_VALVE - One way route (used with masquerading)
-
-Default setup:
-
-root@amber:/pub/ip-routing # iproute -r
-Kernel routing policy rules
-Pref Source             Destination        TOS Iface   Cl
-   0 default            default            00  *       255
- 254 default            default            00  *       254
- 255 default            default            00  *       253
-
-
-Lookup algorithm
-----------------
-
-       We scan rules list, and if a rule is matched, apply it.
-       If a route is found, return it.
-       If it is not found or a THROW node was matched, continue
-       to scan rules.
-
-Applications
-------------
-
-1.     Just ignore classes. All the routes are put into MAIN class
-       (and/or into DEFAULT class).
-
-       HOWTO:  iproute add PREFIX [ tos TOS ] [ gw GW ] [ dev DEV ]
-               [ metric METRIC ] [ reject ] ... (look at iproute utility)
-
-               or use route utility from current net-tools.
-               
-2.     Opposite case. Just forget all that you know about routing
-       tables. Every rule is supplied with its own gateway, device
-       info. record. This approach is not appropriate for automated
-       route maintenance, but it is ideal for manual configuration.
-
-       HOWTO:  iproute addrule [ from PREFIX ] [ to PREFIX ] [ tos TOS ]
-               [ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ]
-               [ dev OUTDEV ] .....
-
-       Warning: As of now the size of the routing table in this
-       approach is limited to 256. If someone likes this model, I'll
-       relax this limitation.
-
-3.     OSPF classes (see RFC1583, RFC1812 E.3.3)
-       Very clean, stable and robust algorithm for OSPF routing
-       domains. Unfortunately, it is not widely used in the Internet.
-
-       Proposed setup:
-       255 local addresses
-       254 interface routes
-       253 ASE routes with external metric
-       252 ASE routes with internal metric
-       251 inter-area routes
-       250 intra-area routes for 1st area
-       249 intra-area routes for 2nd area
-       etc.
-       
-       Rules:
-       iproute addrule class 253
-       iproute addrule class 252
-       iproute addrule class 251
-       iproute addrule to a-prefix-for-1st-area class 250
-       iproute addrule to another-prefix-for-1st-area class 250
-       ...
-       iproute addrule to a-prefix-for-2nd-area class 249
-       ...
-
-       Area classes must be terminated with reject record.
-       iproute add default reject class 250
-       iproute add default reject class 249
-       ...
-
-4.     The Variant Router Requirements Algorithm (RFC1812 E.3.2)
-       Create 16 classes for different TOS values.
-       It is a funny, but pretty useless algorithm.
-       I listed it just to show the power of new routing code.
-
-5.     All the variety of combinations......
-
-
-GATED
------
-
-       Gated does not understand classes, but it will work
-       happily in MAIN+DEFAULT. All policy routes can be set
-       and maintained manually.
-
-IMPORTANT NOTE
---------------
-       route.c has a compilation time switch CONFIG_IP_LOCAL_RT_POLICY.
-       If it is set, locally originated packets are routed
-       using all the policy list. This is not very convenient and
-       pretty ambiguous when used with NAT and masquerading.
-       I set it to FALSE by default.
-
-
-Alexey Kuznetov
-kuznet@ms2.inr.ac.ru
index dd3525a0f06afb80f69143c968f2931fbbef5826..9bd9a0e90034bcba9b031cb6442b42fb7b016cb8 100644 (file)
 
 &emac {
        phy-handle = <&int_mii_phy>;
-       phy-mode = "mii";
+       phy-mode = "internal";
        allwinner,leds-active-low;
        status = "okay";
 };
index 78f6c24952dd128249fd3010d212222832bb060a..5c5ba806e2f17c910de6bde6c325ede698cad8ab 100644 (file)
@@ -49,7 +49,7 @@
 
 &emac {
        phy-handle = <&int_mii_phy>;
-       phy-mode = "mii";
+       phy-mode = "internal";
        allwinner,leds-active-low;
        status = "okay";
 };
index cedd326b608900b8fe08e0dac03adf3d414b2f00..77c861deb658e120fbf7ab18400d8c797fcfe89e 100644 (file)
 
 &emac {
        phy-handle = <&int_mii_phy>;
-       phy-mode = "mii";
+       phy-mode = "internal";
        allwinner,leds-active-low;
        status = "okay";
 };
index 6880268e8b87b0d7385e73dc95c23aaa8f25bd9a..27e7ef4e42f21b61dbc0954977715bca5947e187 100644 (file)
 
 &emac {
        phy-handle = <&int_mii_phy>;
-       phy-mode = "mii";
+       phy-mode = "internal";
        allwinner,leds-active-low;
        status = "okay";
 };
index 52e65755c51a32b0d6a6511c0ee117d85842be46..fecebb43506a7aeae70f5478472f4038b987ce9e 100644 (file)
 
 &emac {
        phy-handle = <&int_mii_phy>;
-       phy-mode = "mii";
+       phy-mode = "internal";
        allwinner,leds-active-low;
        status = "okay";
 };
index 8ca683396fccebd072133f0ae69b8e2db27a6484..a12d603d41c6616ed3cba926b204f94492678ff3 100644 (file)
@@ -464,7 +464,7 @@ const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
 
 /* Searches for a value in opt's values[] table which matches the flagmask */
 static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
-                                                u32 flagmask)
+                                                      u32 flagmask)
 {
        int i;
 
@@ -744,14 +744,14 @@ static int bond_option_mode_set(struct bonding *bond,
                                const struct bond_opt_value *newval)
 {
        if (!bond_mode_uses_arp(newval->value) && bond->params.arp_interval) {
-               netdev_info(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n",
-                           newval->string);
+               netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n",
+                          newval->string);
                /* disable arp monitoring */
                bond->params.arp_interval = 0;
                /* set miimon to default value */
                bond->params.miimon = BOND_DEFAULT_MIIMON;
-               netdev_info(bond->dev, "Setting MII monitoring interval to %d\n",
-                           bond->params.miimon);
+               netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n",
+                          bond->params.miimon);
        }
 
        /* don't cache arp_validate between modes */
@@ -794,7 +794,7 @@ static int bond_option_active_slave_set(struct bonding *bond,
        block_netpoll_tx();
        /* check to see if we are clearing active */
        if (!slave_dev) {
-               netdev_info(bond->dev, "Clearing current active slave\n");
+               netdev_dbg(bond->dev, "Clearing current active slave\n");
                RCU_INIT_POINTER(bond->curr_active_slave, NULL);
                bond_select_active_slave(bond);
        } else {
@@ -805,13 +805,13 @@ static int bond_option_active_slave_set(struct bonding *bond,
 
                if (new_active == old_active) {
                        /* do nothing */
-                       netdev_info(bond->dev, "%s is already the current active slave\n",
-                                   new_active->dev->name);
+                       netdev_dbg(bond->dev, "%s is already the current active slave\n",
+                                  new_active->dev->name);
                } else {
                        if (old_active && (new_active->link == BOND_LINK_UP) &&
                            bond_slave_is_up(new_active)) {
-                               netdev_info(bond->dev, "Setting %s as active slave\n",
-                                           new_active->dev->name);
+                               netdev_dbg(bond->dev, "Setting %s as active slave\n",
+                                          new_active->dev->name);
                                bond_change_active_slave(bond, new_active);
                        } else {
                                netdev_err(bond->dev, "Could not set %s as active slave; either %s is down or the link is down\n",
@@ -833,17 +833,17 @@ static int bond_option_active_slave_set(struct bonding *bond,
 static int bond_option_miimon_set(struct bonding *bond,
                                  const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting MII monitoring interval to %llu\n",
-                   newval->value);
+       netdev_dbg(bond->dev, "Setting MII monitoring interval to %llu\n",
+                  newval->value);
        bond->params.miimon = newval->value;
        if (bond->params.updelay)
-               netdev_info(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n",
-                       bond->params.updelay * bond->params.miimon);
+               netdev_dbg(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n",
+                          bond->params.updelay * bond->params.miimon);
        if (bond->params.downdelay)
-               netdev_info(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
-                           bond->params.downdelay * bond->params.miimon);
+               netdev_dbg(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
+                          bond->params.downdelay * bond->params.miimon);
        if (newval->value && bond->params.arp_interval) {
-               netdev_info(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n");
+               netdev_dbg(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n");
                bond->params.arp_interval = 0;
                if (bond->params.arp_validate)
                        bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
@@ -885,8 +885,8 @@ static int bond_option_updelay_set(struct bonding *bond,
                            bond->params.miimon);
        }
        bond->params.updelay = value / bond->params.miimon;
-       netdev_info(bond->dev, "Setting up delay to %d\n",
-                   bond->params.updelay * bond->params.miimon);
+       netdev_dbg(bond->dev, "Setting up delay to %d\n",
+                  bond->params.updelay * bond->params.miimon);
 
        return 0;
 }
@@ -907,8 +907,8 @@ static int bond_option_downdelay_set(struct bonding *bond,
                            bond->params.miimon);
        }
        bond->params.downdelay = value / bond->params.miimon;
-       netdev_info(bond->dev, "Setting down delay to %d\n",
-                   bond->params.downdelay * bond->params.miimon);
+       netdev_dbg(bond->dev, "Setting down delay to %d\n",
+                  bond->params.downdelay * bond->params.miimon);
 
        return 0;
 }
@@ -916,8 +916,8 @@ static int bond_option_downdelay_set(struct bonding *bond,
 static int bond_option_use_carrier_set(struct bonding *bond,
                                       const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting use_carrier to %llu\n",
-                   newval->value);
+       netdev_dbg(bond->dev, "Setting use_carrier to %llu\n",
+                  newval->value);
        bond->params.use_carrier = newval->value;
 
        return 0;
@@ -930,16 +930,16 @@ static int bond_option_use_carrier_set(struct bonding *bond,
 static int bond_option_arp_interval_set(struct bonding *bond,
                                        const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting ARP monitoring interval to %llu\n",
-                   newval->value);
+       netdev_dbg(bond->dev, "Setting ARP monitoring interval to %llu\n",
+                  newval->value);
        bond->params.arp_interval = newval->value;
        if (newval->value) {
                if (bond->params.miimon) {
-                       netdev_info(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n");
+                       netdev_dbg(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n");
                        bond->params.miimon = 0;
                }
                if (!bond->params.arp_targets[0])
-                       netdev_info(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n");
+                       netdev_dbg(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n");
        }
        if (bond->dev->flags & IFF_UP) {
                /* If the interface is up, we may need to fire off
@@ -1000,7 +1000,7 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
                return -EINVAL;
        }
 
-       netdev_info(bond->dev, "Adding ARP target %pI4\n", &target);
+       netdev_dbg(bond->dev, "Adding ARP target %pI4\n", &target);
 
        _bond_options_arp_ip_target_set(bond, ind, target, jiffies);
 
@@ -1036,7 +1036,7 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
        if (ind == 0 && !targets[1] && bond->params.arp_interval)
                netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
 
-       netdev_info(bond->dev, "Removing ARP target %pI4\n", &target);
+       netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target);
 
        bond_for_each_slave(bond, slave, iter) {
                targets_rx = slave->target_last_arp_rx;
@@ -1088,8 +1088,8 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond,
 static int bond_option_arp_validate_set(struct bonding *bond,
                                        const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting arp_validate to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
+                  newval->string, newval->value);
 
        if (bond->dev->flags & IFF_UP) {
                if (!newval->value)
@@ -1105,8 +1105,8 @@ static int bond_option_arp_validate_set(struct bonding *bond,
 static int bond_option_arp_all_targets_set(struct bonding *bond,
                                           const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting arp_all_targets to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting arp_all_targets to %s (%llu)\n",
+                  newval->string, newval->value);
        bond->params.arp_all_targets = newval->value;
 
        return 0;
@@ -1126,7 +1126,7 @@ static int bond_option_primary_set(struct bonding *bond,
                *p = '\0';
        /* check to see if we are clearing primary */
        if (!strlen(primary)) {
-               netdev_info(bond->dev, "Setting primary slave to None\n");
+               netdev_dbg(bond->dev, "Setting primary slave to None\n");
                RCU_INIT_POINTER(bond->primary_slave, NULL);
                memset(bond->params.primary, 0, sizeof(bond->params.primary));
                bond_select_active_slave(bond);
@@ -1135,8 +1135,8 @@ static int bond_option_primary_set(struct bonding *bond,
 
        bond_for_each_slave(bond, slave, iter) {
                if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
-                       netdev_info(bond->dev, "Setting %s as primary slave\n",
-                                   slave->dev->name);
+                       netdev_dbg(bond->dev, "Setting %s as primary slave\n",
+                                  slave->dev->name);
                        rcu_assign_pointer(bond->primary_slave, slave);
                        strcpy(bond->params.primary, slave->dev->name);
                        bond_select_active_slave(bond);
@@ -1145,15 +1145,15 @@ static int bond_option_primary_set(struct bonding *bond,
        }
 
        if (rtnl_dereference(bond->primary_slave)) {
-               netdev_info(bond->dev, "Setting primary slave to None\n");
+               netdev_dbg(bond->dev, "Setting primary slave to None\n");
                RCU_INIT_POINTER(bond->primary_slave, NULL);
                bond_select_active_slave(bond);
        }
        strncpy(bond->params.primary, primary, IFNAMSIZ);
        bond->params.primary[IFNAMSIZ - 1] = 0;
 
-       netdev_info(bond->dev, "Recording %s as primary, but it has not been enslaved to %s yet\n",
-                   primary, bond->dev->name);
+       netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved to %s yet\n",
+                  primary, bond->dev->name);
 
 out:
        unblock_netpoll_tx();
@@ -1164,8 +1164,8 @@ out:
 static int bond_option_primary_reselect_set(struct bonding *bond,
                                            const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting primary_reselect to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting primary_reselect to %s (%llu)\n",
+                  newval->string, newval->value);
        bond->params.primary_reselect = newval->value;
 
        block_netpoll_tx();
@@ -1178,8 +1178,8 @@ static int bond_option_primary_reselect_set(struct bonding *bond,
 static int bond_option_fail_over_mac_set(struct bonding *bond,
                                         const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting fail_over_mac to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting fail_over_mac to %s (%llu)\n",
+                  newval->string, newval->value);
        bond->params.fail_over_mac = newval->value;
 
        return 0;
@@ -1188,8 +1188,8 @@ static int bond_option_fail_over_mac_set(struct bonding *bond,
 static int bond_option_xmit_hash_policy_set(struct bonding *bond,
                                            const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
+                  newval->string, newval->value);
        bond->params.xmit_policy = newval->value;
 
        return 0;
@@ -1198,8 +1198,8 @@ static int bond_option_xmit_hash_policy_set(struct bonding *bond,
 static int bond_option_resend_igmp_set(struct bonding *bond,
                                       const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting resend_igmp to %llu\n",
-                   newval->value);
+       netdev_dbg(bond->dev, "Setting resend_igmp to %llu\n",
+                  newval->value);
        bond->params.resend_igmp = newval->value;
 
        return 0;
@@ -1237,8 +1237,8 @@ static int bond_option_all_slaves_active_set(struct bonding *bond,
 static int bond_option_min_links_set(struct bonding *bond,
                                     const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting min links value to %llu\n",
-                   newval->value);
+       netdev_dbg(bond->dev, "Setting min links value to %llu\n",
+                  newval->value);
        bond->params.min_links = newval->value;
        bond_set_carrier(bond);
 
@@ -1256,6 +1256,8 @@ static int bond_option_lp_interval_set(struct bonding *bond,
 static int bond_option_pps_set(struct bonding *bond,
                               const struct bond_opt_value *newval)
 {
+       netdev_dbg(bond->dev, "Setting packets per slave to %llu\n",
+                  newval->value);
        bond->params.packets_per_slave = newval->value;
        if (newval->value > 0) {
                bond->params.reciprocal_packets_per_slave =
@@ -1274,8 +1276,8 @@ static int bond_option_pps_set(struct bonding *bond,
 static int bond_option_lacp_rate_set(struct bonding *bond,
                                     const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting LACP rate to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting LACP rate to %s (%llu)\n",
+                  newval->string, newval->value);
        bond->params.lacp_fast = newval->value;
        bond_3ad_update_lacp_rate(bond);
 
@@ -1285,8 +1287,8 @@ static int bond_option_lacp_rate_set(struct bonding *bond,
 static int bond_option_ad_select_set(struct bonding *bond,
                                     const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting ad_select to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting ad_select to %s (%llu)\n",
+                  newval->string, newval->value);
        bond->params.ad_select = newval->value;
 
        return 0;
@@ -1347,7 +1349,7 @@ out:
        return ret;
 
 err_no_cmd:
-       netdev_info(bond->dev, "invalid input for queue_id set\n");
+       netdev_dbg(bond->dev, "invalid input for queue_id set\n");
        ret = -EPERM;
        goto out;
 
@@ -1369,20 +1371,20 @@ static int bond_option_slaves_set(struct bonding *bond,
 
        dev = __dev_get_by_name(dev_net(bond->dev), ifname);
        if (!dev) {
-               netdev_info(bond->dev, "interface %s does not exist!\n",
-                           ifname);
+               netdev_dbg(bond->dev, "interface %s does not exist!\n",
+                          ifname);
                ret = -ENODEV;
                goto out;
        }
 
        switch (command[0]) {
        case '+':
-               netdev_info(bond->dev, "Adding slave %s\n", dev->name);
+               netdev_dbg(bond->dev, "Adding slave %s\n", dev->name);
                ret = bond_enslave(bond->dev, dev);
                break;
 
        case '-':
-               netdev_info(bond->dev, "Removing slave %s\n", dev->name);
+               netdev_dbg(bond->dev, "Removing slave %s\n", dev->name);
                ret = bond_release(bond->dev, dev);
                break;
 
@@ -1402,8 +1404,8 @@ err_no_cmd:
 static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
                                          const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting dynamic-lb to %s (%llu)\n",
-                   newval->string, newval->value);
+       netdev_dbg(bond->dev, "Setting dynamic-lb to %s (%llu)\n",
+                  newval->string, newval->value);
        bond->params.tlb_dynamic_lb = newval->value;
 
        return 0;
@@ -1412,8 +1414,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
 static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
                                             const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting ad_actor_sys_prio to %llu\n",
-                   newval->value);
+       netdev_dbg(bond->dev, "Setting ad_actor_sys_prio to %llu\n",
+                  newval->value);
 
        bond->params.ad_actor_sys_prio = newval->value;
        bond_3ad_update_ad_actor_settings(bond);
@@ -1442,7 +1444,7 @@ static int bond_option_ad_actor_system_set(struct bonding *bond,
        if (!is_valid_ether_addr(mac))
                goto err;
 
-       netdev_info(bond->dev, "Setting ad_actor_system to %pM\n", mac);
+       netdev_dbg(bond->dev, "Setting ad_actor_system to %pM\n", mac);
        ether_addr_copy(bond->params.ad_actor_system, mac);
        bond_3ad_update_ad_actor_settings(bond);
 
@@ -1456,8 +1458,8 @@ err:
 static int bond_option_ad_user_port_key_set(struct bonding *bond,
                                            const struct bond_opt_value *newval)
 {
-       netdev_info(bond->dev, "Setting ad_user_port_key to %llu\n",
-                   newval->value);
+       netdev_dbg(bond->dev, "Setting ad_user_port_key to %llu\n",
+                  newval->value);
 
        bond->params.ad_user_port_key = newval->value;
        return 0;
index 7e913d8331c3082d4720e8a4077a85abd4be17c7..8c9986f3fc0186701bd9ae81f27cbb1519e9f25f 100644 (file)
@@ -2252,7 +2252,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
 
        if (atl1c_tx_map(adapter, skb, tpd, type) < 0) {
                netif_info(adapter, tx_done, adapter->netdev,
-                          "tx-skb droppted due to dma error\n");
+                          "tx-skb dropped due to dma error\n");
                /* roll back tpd/buffer */
                atl1c_tx_rollback(adapter, tpd, type);
                dev_kfree_skb_any(skb);
index 573755b0a51b7f48c8565f6e5d638fbf86f99afd..49b80da51ba7307eb0d7fff8116203723b30cc9b 100644 (file)
@@ -227,15 +227,14 @@ static void  nicvf_handle_mbx_intr(struct nicvf *nic)
                nic->speed = mbx.link_status.speed;
                nic->mac_type = mbx.link_status.mac_type;
                if (nic->link_up) {
-                       netdev_info(nic->netdev, "%s: Link is Up %d Mbps %s\n",
-                                   nic->netdev->name, nic->speed,
+                       netdev_info(nic->netdev, "Link is Up %d Mbps %s duplex\n",
+                                   nic->speed,
                                    nic->duplex == DUPLEX_FULL ?
-                               "Full duplex" : "Half duplex");
+                                   "Full" : "Half");
                        netif_carrier_on(nic->netdev);
                        netif_tx_start_all_queues(nic->netdev);
                } else {
-                       netdev_info(nic->netdev, "%s: Link is Down\n",
-                                   nic->netdev->name);
+                       netdev_info(nic->netdev, "Link is Down\n");
                        netif_carrier_off(nic->netdev);
                        netif_tx_stop_all_queues(nic->netdev);
                }
@@ -721,8 +720,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
                return;
 
        if (netif_msg_pktdata(nic)) {
-               netdev_info(nic->netdev, "%s: skb 0x%p, len=%d\n", netdev->name,
-                           skb, skb->len);
+               netdev_info(nic->netdev, "skb 0x%p, len=%d\n", skb, skb->len);
                print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
                               skb->data, skb->len, true);
        }
@@ -854,10 +852,8 @@ done:
                        netif_tx_wake_queue(txq);
                        nic = nic->pnicvf;
                        this_cpu_inc(nic->drv_stats->txq_wake);
-                       if (netif_msg_tx_err(nic))
-                               netdev_warn(netdev,
-                                           "%s: Transmit queue wakeup SQ%d\n",
-                                           netdev->name, txq_idx);
+                       netif_warn(nic, tx_err, netdev,
+                                  "Transmit queue wakeup SQ%d\n", txq_idx);
                }
        }
 
@@ -928,9 +924,8 @@ static void nicvf_handle_qs_err(unsigned long data)
 
 static void nicvf_dump_intr_status(struct nicvf *nic)
 {
-       if (netif_msg_intr(nic))
-               netdev_info(nic->netdev, "%s: interrupt status 0x%llx\n",
-                           nic->netdev->name, nicvf_reg_read(nic, NIC_VF_INT));
+       netif_info(nic, intr, nic->netdev, "interrupt status 0x%llx\n",
+                  nicvf_reg_read(nic, NIC_VF_INT));
 }
 
 static irqreturn_t nicvf_misc_intr_handler(int irq, void *nicvf_irq)
@@ -1212,10 +1207,8 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
                        netif_tx_wake_queue(txq);
                } else {
                        this_cpu_inc(nic->drv_stats->txq_stop);
-                       if (netif_msg_tx_err(nic))
-                               netdev_warn(netdev,
-                                           "%s: Transmit ring full, stopping SQ%d\n",
-                                           netdev->name, qid);
+                       netif_warn(nic, tx_err, netdev,
+                                  "Transmit ring full, stopping SQ%d\n", qid);
                }
                return NETDEV_TX_BUSY;
        }
@@ -1600,9 +1593,7 @@ static void nicvf_tx_timeout(struct net_device *dev)
 {
        struct nicvf *nic = netdev_priv(dev);
 
-       if (netif_msg_tx_err(nic))
-               netdev_warn(dev, "%s: Transmit timed out, resetting\n",
-                           dev->name);
+       netif_warn(nic, tx_err, dev, "Transmit timed out, resetting\n");
 
        this_cpu_inc(nic->drv_stats->tx_timeout);
        schedule_work(&nic->reset_task);
index 2b181762ad4908476c4fb78acd7ed6ea650762c5..d4496e9afcdf37d12043a9db6beb2dbe76e6daa6 100644 (file)
@@ -1811,11 +1811,9 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)
 /* Check for errors in the receive cmp.queue entry */
 int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
 {
-       if (netif_msg_rx_err(nic))
-               netdev_err(nic->netdev,
-                          "%s: RX error CQE err_level 0x%x err_opcode 0x%x\n",
-                          nic->netdev->name,
-                          cqe_rx->err_level, cqe_rx->err_opcode);
+       netif_err(nic, rx_err, nic->netdev,
+                 "RX error CQE err_level 0x%x err_opcode 0x%x\n",
+                 cqe_rx->err_level, cqe_rx->err_opcode);
 
        switch (cqe_rx->err_opcode) {
        case CQ_RX_ERROP_RE_PARTIAL:
index c1af47e45d3f23221f730f64375b9be771cef7c6..674773b28b2e55284080b3a591bf2ca5581fb7e8 100644 (file)
@@ -3280,7 +3280,7 @@ int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_stat
 
        if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
                mlx4_dbg(dev,
-                        "updating vf %d port %d no link state HW enforcment\n",
+                        "updating vf %d port %d no link state HW enforcement\n",
                         vf, port);
        return 0;
 }
index 0d5a7b9203a41d5235cb8a725ac3a81d4fc4c936..0e331e2f685ad25029aabbcd7112a51b086a7a2c 100644 (file)
@@ -25,6 +25,16 @@ config NFP
          cards working as a advanced Ethernet NIC.  It works with both
          SR-IOV physical and virtual functions.
 
+config NFP_APP_FLOWER
+       bool "NFP4000/NFP6000 TC Flower offload support"
+       depends on NFP
+       depends on NET_SWITCHDEV
+       ---help---
+         Enable driver support for TC Flower offload on NFP4000 and NFP6000.
+         Say Y, if you are planning to make use of TC Flower offload
+         either directly, with Open vSwitch, or any other way.  Note that
+         TC Flower offload requires specific FW to work.
+
 config NFP_DEBUG
        bool "Debug support for Netronome(R) NFP4000/NFP6000 NIC drivers"
        depends on NFP
index 10b556b2c59d277fb73b7b27cbd03c852eec6a36..43bdbc228969129059ca779c7cfb57edd7990ee5 100644 (file)
@@ -27,10 +27,14 @@ nfp-objs := \
            nfp_port.o \
            bpf/main.o \
            bpf/offload.o \
-           flower/cmsg.o \
-           flower/main.o \
            nic/main.o
 
+ifeq ($(CONFIG_NFP_APP_FLOWER),y)
+nfp-objs += \
+           flower/cmsg.o \
+           flower/main.o
+endif
+
 ifeq ($(CONFIG_BPF_SYSCALL),y)
 nfp-objs += \
            bpf/verifier.o \
index 7761be436726da430e0b0c40938a80c39bda2d0c..916a6196d2ba1f02eceb978352432134c8d7458b 100644 (file)
@@ -79,9 +79,8 @@ nfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size,
        return skb;
 }
 
-int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok)
+int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok)
 {
-       struct nfp_repr *repr = netdev_priv(netdev);
        struct nfp_flower_cmsg_portmod *msg;
        struct sk_buff *skb;
 
@@ -94,7 +93,7 @@ int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok)
        msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id);
        msg->reserved = 0;
        msg->info = carrier_ok;
-       msg->mtu = cpu_to_be16(netdev->mtu);
+       msg->mtu = cpu_to_be16(repr->netdev->mtu);
 
        nfp_ctrl_tx(repr->app->ctrl, skb);
 
index 2eeddada7f4dca96e3f168d06e4631a54e15c139..c10ae7631941e69bd288eb482c14c96adaf6a845 100644 (file)
@@ -110,7 +110,7 @@ nfp_flower_cmsg_pcie_port(u8 nfp_pcie, enum nfp_flower_cmsg_port_vnic_type type,
                           NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT);
 }
 
-int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok);
+int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok);
 void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb);
 
 #endif
index 8e5ca6b4bb3367c08762ca38e40ad00c1971b6fa..ab68a8f58862bafe0e2d252b118c030d6c2cdb3d 100644 (file)
@@ -104,51 +104,30 @@ nfp_flower_repr_get(struct nfp_app *app, u32 port_id)
        return reprs->reprs[port];
 }
 
-static void
-nfp_flower_repr_netdev_get_stats64(struct net_device *netdev,
-                                  struct rtnl_link_stats64 *stats)
-{
-       struct nfp_repr *repr = netdev_priv(netdev);
-       enum nfp_repr_type type;
-       u32 port_id;
-       u8 port = 0;
-
-       port_id = repr->dst->u.port_info.port_id;
-       type = nfp_flower_repr_get_type_and_port(repr->app, port_id, &port);
-       nfp_repr_get_stats64(repr->app, type, port, stats);
-}
-
-static int nfp_flower_repr_netdev_open(struct net_device *netdev)
+static int
+nfp_flower_repr_netdev_open(struct nfp_app *app, struct nfp_repr *repr)
 {
        int err;
 
-       err = nfp_flower_cmsg_portmod(netdev, true);
+       err = nfp_flower_cmsg_portmod(repr, true);
        if (err)
                return err;
 
-       netif_carrier_on(netdev);
-       netif_tx_wake_all_queues(netdev);
+       netif_carrier_on(repr->netdev);
+       netif_tx_wake_all_queues(repr->netdev);
 
        return 0;
 }
 
-static int nfp_flower_repr_netdev_stop(struct net_device *netdev)
+static int
+nfp_flower_repr_netdev_stop(struct nfp_app *app, struct nfp_repr *repr)
 {
-       netif_carrier_off(netdev);
-       netif_tx_disable(netdev);
+       netif_carrier_off(repr->netdev);
+       netif_tx_disable(repr->netdev);
 
-       return nfp_flower_cmsg_portmod(netdev, false);
+       return nfp_flower_cmsg_portmod(repr, false);
 }
 
-static const struct net_device_ops nfp_flower_repr_netdev_ops = {
-       .ndo_open               = nfp_flower_repr_netdev_open,
-       .ndo_stop               = nfp_flower_repr_netdev_stop,
-       .ndo_start_xmit         = nfp_repr_xmit,
-       .ndo_get_stats64        = nfp_flower_repr_netdev_get_stats64,
-       .ndo_has_offload_stats  = nfp_repr_has_offload_stats,
-       .ndo_get_offload_stats  = nfp_repr_get_offload_stats,
-};
-
 static void nfp_flower_sriov_disable(struct nfp_app *app)
 {
        nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF);
@@ -162,14 +141,19 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
        u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp);
        struct nfp_flower_priv *priv = app->priv;
        struct nfp_reprs *reprs, *old_reprs;
+       enum nfp_port_type port_type;
        const u8 queue = 0;
        int i, err;
 
+       port_type = repr_type == NFP_REPR_TYPE_PF ? NFP_PORT_PF_PORT :
+                                                   NFP_PORT_VF_PORT;
+
        reprs = nfp_reprs_alloc(cnt);
        if (!reprs)
                return -ENOMEM;
 
        for (i = 0; i < cnt; i++) {
+               struct nfp_port *port;
                u32 port_id;
 
                reprs->reprs[i] = nfp_repr_alloc(app);
@@ -178,15 +162,24 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
                        goto err_reprs_clean;
                }
 
+               port = nfp_port_alloc(app, port_type, reprs->reprs[i]);
+               if (repr_type == NFP_REPR_TYPE_PF) {
+                       port->pf_id = i;
+               } else {
+                       port->pf_id = 0; /* For now we only support 1 PF */
+                       port->vf_id = i;
+               }
+
                eth_hw_addr_random(reprs->reprs[i]);
 
                port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type,
                                                    i, queue);
                err = nfp_repr_init(app, reprs->reprs[i],
-                                   &nfp_flower_repr_netdev_ops,
-                                   port_id, NULL, priv->nn->dp.netdev);
-               if (err)
+                                   port_id, port, priv->nn->dp.netdev);
+               if (err) {
+                       nfp_port_free(port);
                        goto err_reprs_clean;
+               }
 
                nfp_info(app->cpp, "%s%d Representor(%s) created\n",
                         repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i,
@@ -260,7 +253,6 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
 
                cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port);
                err = nfp_repr_init(app, reprs->reprs[phys_port],
-                                   &nfp_flower_repr_netdev_ops,
                                    cmsg_port_id, port, priv->nn->dp.netdev);
                if (err) {
                        nfp_port_free(port);
@@ -296,26 +288,16 @@ static int nfp_flower_start(struct nfp_app *app)
                                           NFP_REPR_TYPE_PF, 1);
 }
 
-static void nfp_flower_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
-{
-       kfree(app->priv);
-       app->priv = NULL;
-}
-
 static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn,
                                unsigned int id)
 {
-       struct nfp_flower_priv *priv;
+       struct nfp_flower_priv *priv = app->priv;
 
        if (id > 0) {
                nfp_warn(app->cpp, "FlowerNIC doesn't support more than one data vNIC\n");
                goto err_invalid_port;
        }
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-       app->priv = priv;
        priv->nn = nn;
 
        eth_hw_addr_random(nn->dp.netdev);
@@ -347,9 +329,19 @@ static int nfp_flower_init(struct nfp_app *app)
                return -EINVAL;
        }
 
+       app->priv = kzalloc(sizeof(struct nfp_flower_priv), GFP_KERNEL);
+       if (!app->priv)
+               return -ENOMEM;
+
        return 0;
 }
 
+static void nfp_flower_clean(struct nfp_app *app)
+{
+       kfree(app->priv);
+       app->priv = NULL;
+}
+
 const struct nfp_app_type app_flower = {
        .id             = NFP_APP_FLOWER_NIC,
        .name           = "flower",
@@ -358,9 +350,12 @@ const struct nfp_app_type app_flower = {
        .extra_cap      = nfp_flower_extra_cap,
 
        .init           = nfp_flower_init,
+       .clean          = nfp_flower_clean,
 
        .vnic_init      = nfp_flower_vnic_init,
-       .vnic_clean     = nfp_flower_vnic_clean,
+
+       .repr_open      = nfp_flower_repr_netdev_open,
+       .repr_stop      = nfp_flower_repr_netdev_stop,
 
        .start          = nfp_flower_start,
        .stop           = nfp_flower_stop,
index 5620de05c9969275681166423ef41eeef79165c4..c704c022574f419ead4f7b4c9a9b54e1b273eb77 100644 (file)
@@ -43,7 +43,9 @@
 static const struct nfp_app_type *apps[] = {
        &app_nic,
        &app_bpf,
+#ifdef CONFIG_NFP_APP_FLOWER
        &app_flower,
+#endif
 };
 
 const char *nfp_app_mip_name(struct nfp_app *app)
index ae2d02753d1a073d03590d4288a26ad454406989..5d714e10d9a947fcabded2642547aab22c3a08c4 100644 (file)
@@ -47,6 +47,7 @@ struct sk_buff;
 struct nfp_app;
 struct nfp_cpp;
 struct nfp_pf;
+struct nfp_repr;
 struct nfp_net;
 
 enum nfp_app_id {
@@ -66,10 +67,13 @@ extern const struct nfp_app_type app_flower;
  * @ctrl_has_meta:  control messages have prepend of type:5/port:CTRL
  *
  * Callbacks
- * @init:      perform basic app checks
+ * @init:      perform basic app checks and init
+ * @clean:     clean app state
  * @extra_cap: extra capabilities string
  * @vnic_init: init vNICs (assign port types, etc.)
  * @vnic_clean:        clean up app's vNIC state
+ * @repr_open: representor netdev open callback
+ * @repr_stop: representor netdev stop callback
  * @start:     start application logic
  * @stop:      stop application logic
  * @ctrl_msg_rx:    control message handler
@@ -88,6 +92,7 @@ struct nfp_app_type {
        bool ctrl_has_meta;
 
        int (*init)(struct nfp_app *app);
+       void (*clean)(struct nfp_app *app);
 
        const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn);
 
@@ -95,6 +100,9 @@ struct nfp_app_type {
                         unsigned int id);
        void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn);
 
+       int (*repr_open)(struct nfp_app *app, struct nfp_repr *repr);
+       int (*repr_stop)(struct nfp_app *app, struct nfp_repr *repr);
+
        int (*start)(struct nfp_app *app);
        void (*stop)(struct nfp_app *app);
 
@@ -144,6 +152,12 @@ static inline int nfp_app_init(struct nfp_app *app)
        return app->type->init(app);
 }
 
+static inline void nfp_app_clean(struct nfp_app *app)
+{
+       if (app->type->clean)
+               app->type->clean(app);
+}
+
 static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn,
                                    unsigned int id)
 {
@@ -156,6 +170,20 @@ static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
                app->type->vnic_clean(app, nn);
 }
 
+static inline int nfp_app_repr_open(struct nfp_app *app, struct nfp_repr *repr)
+{
+       if (!app->type->repr_open)
+               return -EINVAL;
+       return app->type->repr_open(app, repr);
+}
+
+static inline int nfp_app_repr_stop(struct nfp_app *app, struct nfp_repr *repr)
+{
+       if (!app->type->repr_stop)
+               return -EINVAL;
+       return app->type->repr_stop(app, repr);
+}
+
 static inline int nfp_app_start(struct nfp_app *app, struct nfp_net *ctrl)
 {
        app->ctrl = ctrl;
index 748e54cc885e280405bf0e635089c7cb437f79d1..d67969d3e484682c102a965c4abf5908dc1fc6fc 100644 (file)
@@ -107,17 +107,18 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
                goto err_unlock;
        }
 
-       err = nfp_app_sriov_enable(pf->app, num_vfs);
+       err = pci_enable_sriov(pdev, num_vfs);
        if (err) {
-               dev_warn(&pdev->dev, "App specific PCI sriov configuration failed: %d\n",
-                        err);
+               dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err);
                goto err_unlock;
        }
 
-       err = pci_enable_sriov(pdev, num_vfs);
+       err = nfp_app_sriov_enable(pf->app, num_vfs);
        if (err) {
-               dev_warn(&pdev->dev, "Failed to enable PCI sriov: %d\n", err);
-               goto err_app_sriov_disable;
+               dev_warn(&pdev->dev,
+                        "App specific PCI SR-IOV configuration failed: %d\n",
+                        err);
+               goto err_sriov_disable;
        }
 
        pf->num_vfs = num_vfs;
@@ -127,8 +128,8 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs)
        mutex_unlock(&pf->lock);
        return num_vfs;
 
-err_app_sriov_disable:
-       nfp_app_sriov_disable(pf->app);
+err_sriov_disable:
+       pci_disable_sriov(pdev);
 err_unlock:
        mutex_unlock(&pf->lock);
        return err;
@@ -136,17 +137,20 @@ err_unlock:
        return 0;
 }
 
-static int __nfp_pcie_sriov_disable(struct pci_dev *pdev)
+static int nfp_pcie_sriov_disable(struct pci_dev *pdev)
 {
 #ifdef CONFIG_PCI_IOV
        struct nfp_pf *pf = pci_get_drvdata(pdev);
 
+       mutex_lock(&pf->lock);
+
        /* If the VFs are assigned we cannot shut down SR-IOV without
         * causing issues, so just leave the hardware available but
         * disabled
         */
        if (pci_vfs_assigned(pdev)) {
                dev_warn(&pdev->dev, "Disabling while VFs assigned - VFs will not be deallocated\n");
+               mutex_unlock(&pf->lock);
                return -EPERM;
        }
 
@@ -156,20 +160,10 @@ static int __nfp_pcie_sriov_disable(struct pci_dev *pdev)
 
        pci_disable_sriov(pdev);
        dev_dbg(&pdev->dev, "Removed VFs.\n");
-#endif
-       return 0;
-}
-
-static int nfp_pcie_sriov_disable(struct pci_dev *pdev)
-{
-       struct nfp_pf *pf = pci_get_drvdata(pdev);
-       int err;
 
-       mutex_lock(&pf->lock);
-       err = __nfp_pcie_sriov_disable(pdev);
        mutex_unlock(&pf->lock);
-
-       return err;
+#endif
+       return 0;
 }
 
 static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs)
@@ -382,6 +376,12 @@ static int nfp_pci_probe(struct pci_dev *pdev,
        pci_set_drvdata(pdev, pf);
        pf->pdev = pdev;
 
+       pf->wq = alloc_workqueue("nfp-%s", 0, 2, pci_name(pdev));
+       if (!pf->wq) {
+               err = -ENOMEM;
+               goto err_pci_priv_unset;
+       }
+
        pf->cpp = nfp_cpp_from_nfp6000_pcie(pdev);
        if (IS_ERR_OR_NULL(pf->cpp)) {
                err = PTR_ERR(pf->cpp);
@@ -414,6 +414,14 @@ static int nfp_pci_probe(struct pci_dev *pdev,
        if (err)
                goto err_fw_unload;
 
+       pf->num_vfs = pci_num_vf(pdev);
+       if (pf->num_vfs > pf->limit_vfs) {
+               dev_err(&pdev->dev,
+                       "Error: %d VFs already enabled, but loaded FW can only support %d\n",
+                       pf->num_vfs, pf->limit_vfs);
+               goto err_fw_unload;
+       }
+
        err = nfp_net_pci_probe(pf);
        if (err)
                goto err_sriov_unlimit;
@@ -443,6 +451,8 @@ err_hwinfo_free:
        kfree(pf->hwinfo);
        nfp_cpp_free(pf->cpp);
 err_disable_msix:
+       destroy_workqueue(pf->wq);
+err_pci_priv_unset:
        pci_set_drvdata(pdev, NULL);
        mutex_destroy(&pf->lock);
        devlink_free(devlink);
@@ -463,11 +473,11 @@ static void nfp_pci_remove(struct pci_dev *pdev)
 
        devlink = priv_to_devlink(pf);
 
+       nfp_net_pci_remove(pf);
+
        nfp_pcie_sriov_disable(pdev);
        pci_sriov_set_totalvfs(pf->pdev, 0);
 
-       nfp_net_pci_remove(pf);
-
        devlink_unregister(devlink);
 
        kfree(pf->rtbl);
@@ -475,6 +485,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
        if (pf->fw_loaded)
                nfp_fw_unload(pf);
 
+       destroy_workqueue(pf->wq);
        pci_set_drvdata(pdev, NULL);
        kfree(pf->hwinfo);
        nfp_cpp_free(pf->cpp);
index edc14dc78674e9c5d9e960a3b33e449ec1c6dd60..a08cfba7e68ed41c69b6e92a6167d229366f479b 100644 (file)
@@ -89,6 +89,7 @@ struct nfp_rtsym_table;
  * @num_vnics:         Number of vNICs spawned
  * @vnics:             Linked list of vNIC structures (struct nfp_net)
  * @ports:             Linked list of port structures (struct nfp_port)
+ * @wq:                        Workqueue for running works which need to grab @lock
  * @port_refresh_work: Work entry for taking netdevs out
  * @lock:              Protects all fields which may change after probe
  */
@@ -131,7 +132,10 @@ struct nfp_pf {
 
        struct list_head vnics;
        struct list_head ports;
+
+       struct workqueue_struct *wq;
        struct work_struct port_refresh_work;
+
        struct mutex lock;
 };
 
index cfcbc3b9a9aa72b09170cdde5f948534f9554f15..c85a2f18c4df9df095427b33b03f248bce218bc3 100644 (file)
@@ -80,58 +80,6 @@ static int nfp_is_ready(struct nfp_pf *pf)
        return state == 15;
 }
 
-/**
- * nfp_net_map_area() - Help function to map an area
- * @cpp:    NFP CPP handler
- * @name:   Name for the area
- * @target: CPP target
- * @addr:   CPP address
- * @size:   Size of the area
- * @area:   Area handle (returned).
- *
- * This function is primarily to simplify the code in the main probe
- * function. To undo the effect of this functions call
- * @nfp_cpp_area_release_free(*area);
- *
- * Return: Pointer to memory mapped area or ERR_PTR
- */
-static u8 __iomem *nfp_net_map_area(struct nfp_cpp *cpp,
-                                   const char *name, int isl, int target,
-                                   unsigned long long addr, unsigned long size,
-                                   struct nfp_cpp_area **area)
-{
-       u8 __iomem *res;
-       u32 dest;
-       int err;
-
-       dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, isl);
-
-       *area = nfp_cpp_area_alloc_with_name(cpp, dest, name, addr, size);
-       if (!*area) {
-               err = -EIO;
-               goto err_area;
-       }
-
-       err = nfp_cpp_area_acquire(*area);
-       if (err < 0)
-               goto err_acquire;
-
-       res = nfp_cpp_area_iomem(*area);
-       if (!res) {
-               err = -EIO;
-               goto err_map;
-       }
-
-       return res;
-
-err_map:
-       nfp_cpp_area_release(*area);
-err_acquire:
-       nfp_cpp_area_free(*area);
-err_area:
-       return (u8 __iomem *)ERR_PTR(err);
-}
-
 /**
  * nfp_net_get_mac_addr() - Get the MAC address.
  * @pf:       NFP PF handle
@@ -226,31 +174,12 @@ static u8 __iomem *
 nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt,
                     unsigned int min_size, struct nfp_cpp_area **area)
 {
-       const struct nfp_rtsym *sym;
        char pf_symbol[256];
-       u8 __iomem *mem;
 
        snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt,
                 nfp_cppcore_pcie_unit(pf->cpp));
 
-       sym = nfp_rtsym_lookup(pf->rtbl, pf_symbol);
-       if (!sym)
-               return (u8 __iomem *)ERR_PTR(-ENOENT);
-
-       if (sym->size < min_size) {
-               nfp_err(pf->cpp, "PF symbol %s too small\n", pf_symbol);
-               return (u8 __iomem *)ERR_PTR(-EINVAL);
-       }
-
-       mem = nfp_net_map_area(pf->cpp, name, sym->domain, sym->target,
-                              sym->addr, sym->size, area);
-       if (IS_ERR(mem)) {
-               nfp_err(pf->cpp, "Failed to map PF symbol %s: %ld\n",
-                       pf_symbol, PTR_ERR(mem));
-               return mem;
-       }
-
-       return mem;
+       return nfp_rtsym_map(pf->rtbl, pf_symbol, name, min_size, area);
 }
 
 static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn)
@@ -485,7 +414,7 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
        if (IS_ERR(ctrl_bar)) {
                nfp_err(pf->cpp, "Failed to find data vNIC memory symbol\n");
                err = PTR_ERR(ctrl_bar);
-               goto err_free;
+               goto err_app_clean;
        }
 
        pf->ctrl_vnic = nfp_net_pf_alloc_vnic(pf, false, ctrl_bar, qc_bar,
@@ -499,8 +428,11 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride)
 
 err_unmap:
        nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
+err_app_clean:
+       nfp_app_clean(pf->app);
 err_free:
        nfp_app_free(pf->app);
+       pf->app = NULL;
        return err;
 }
 
@@ -510,6 +442,7 @@ static void nfp_net_pf_app_clean(struct nfp_pf *pf)
                nfp_net_pf_free_vnic(pf, pf->ctrl_vnic);
                nfp_cpp_area_release_free(pf->ctrl_vnic_bar);
        }
+       nfp_app_clean(pf->app);
        nfp_app_free(pf->app);
        pf->app = NULL;
 }
@@ -555,8 +488,16 @@ static int nfp_net_pf_app_start(struct nfp_pf *pf)
        if (err)
                goto err_ctrl_stop;
 
+       if (pf->num_vfs) {
+               err = nfp_app_sriov_enable(pf->app, pf->num_vfs);
+               if (err)
+                       goto err_app_stop;
+       }
+
        return 0;
 
+err_app_stop:
+       nfp_app_stop(pf->app);
 err_ctrl_stop:
        nfp_net_pf_app_stop_ctrl(pf);
        return err;
@@ -564,6 +505,8 @@ err_ctrl_stop:
 
 static void nfp_net_pf_app_stop(struct nfp_pf *pf)
 {
+       if (pf->num_vfs)
+               nfp_app_sriov_disable(pf->app);
        nfp_app_stop(pf->app);
        nfp_net_pf_app_stop_ctrl(pf);
 }
@@ -580,26 +523,22 @@ static void nfp_net_pci_unmap_mem(struct nfp_pf *pf)
 
 static int nfp_net_pci_map_mem(struct nfp_pf *pf)
 {
-       u32 ctrl_bar_sz;
        u8 __iomem *mem;
+       u32 min_size;
        int err;
 
-       ctrl_bar_sz = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE;
+       min_size = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE;
        mem = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%d_net_bar0",
-                                  ctrl_bar_sz, &pf->data_vnic_bar);
+                                  min_size, &pf->data_vnic_bar);
        if (IS_ERR(mem)) {
                nfp_err(pf->cpp, "Failed to find data vNIC memory symbol\n");
-               err = PTR_ERR(mem);
-               if (!pf->fw_loaded && err == -ENOENT)
-                       err = -EPROBE_DEFER;
-               return err;
+               return PTR_ERR(mem);
        }
 
-       pf->mac_stats_mem = nfp_net_pf_map_rtsym(pf, "net.macstats",
-                                                "_mac_stats",
-                                                NFP_MAC_STATS_SIZE *
-                                                (pf->eth_tbl->max_index + 1),
-                                                &pf->mac_stats_bar);
+       min_size =  NFP_MAC_STATS_SIZE * (pf->eth_tbl->max_index + 1);
+       pf->mac_stats_mem = nfp_rtsym_map(pf->rtbl, "_mac_stats",
+                                         "net.macstats", min_size,
+                                         &pf->mac_stats_bar);
        if (IS_ERR(pf->mac_stats_mem)) {
                if (PTR_ERR(pf->mac_stats_mem) != -ENOENT) {
                        err = PTR_ERR(pf->mac_stats_mem);
@@ -620,7 +559,7 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf)
                pf->vf_cfg_mem = NULL;
        }
 
-       mem = nfp_net_map_area(pf->cpp, "net.qc", 0, 0,
+       mem = nfp_cpp_map_area(pf->cpp, "net.qc", 0, 0,
                               NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ,
                               &pf->qc_area);
        if (IS_ERR(mem)) {
@@ -743,7 +682,7 @@ void nfp_net_refresh_port_table(struct nfp_port *port)
 
        set_bit(NFP_PORT_CHANGED, &port->flags);
 
-       schedule_work(&pf->port_refresh_work);
+       queue_work(pf->wq, &pf->port_refresh_work);
 }
 
 int nfp_net_refresh_eth_port(struct nfp_port *port)
@@ -786,6 +725,12 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
                return -EINVAL;
        }
 
+       if (!pf->rtbl) {
+               nfp_err(pf->cpp, "No %s, giving up.\n",
+                       pf->fw_loaded ? "symbol table" : "firmware found");
+               return -EPROBE_DEFER;
+       }
+
        mutex_lock(&pf->lock);
        pf->max_data_vnics = nfp_net_pf_get_num_ports(pf);
        if ((int)pf->max_data_vnics < 0) {
index 44adcc5df11ec8ad1f6d0c834a8f6c83d9b6bab3..046b89eb4cf2f396af65f1d56c936796f9b694e8 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/dst_metadata.h>
 
 #include "nfpcore/nfp_cpp.h"
+#include "nfpcore/nfp_nsp.h"
 #include "nfp_app.h"
 #include "nfp_main.h"
 #include "nfp_net_ctrl.h"
@@ -135,25 +136,34 @@ nfp_repr_pf_get_stats64(const struct nfp_app *app, u8 pf,
        stats->rx_dropped = readq(mem + NFP_NET_CFG_STATS_TX_DISCARDS);
 }
 
-void
-nfp_repr_get_stats64(const struct nfp_app *app, enum nfp_repr_type type,
-                    u8 port, struct rtnl_link_stats64 *stats)
+static void
+nfp_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
 {
-       switch (type) {
-       case NFP_REPR_TYPE_PHYS_PORT:
-               nfp_repr_phy_port_get_stats64(app, port, stats);
+       struct nfp_repr *repr = netdev_priv(netdev);
+       struct nfp_eth_table_port *eth_port;
+       struct nfp_app *app = repr->app;
+
+       if (WARN_ON(!repr->port))
+               return;
+
+       switch (repr->port->type) {
+       case NFP_PORT_PHYS_PORT:
+               eth_port = __nfp_port_get_eth_port(repr->port);
+               if (!eth_port)
+                       break;
+               nfp_repr_phy_port_get_stats64(app, eth_port->index, stats);
                break;
-       case NFP_REPR_TYPE_PF:
-               nfp_repr_pf_get_stats64(app, port, stats);
+       case NFP_PORT_PF_PORT:
+               nfp_repr_pf_get_stats64(app, repr->port->pf_id, stats);
                break;
-       case NFP_REPR_TYPE_VF:
-               nfp_repr_vf_get_stats64(app, port, stats);
+       case NFP_PORT_VF_PORT:
+               nfp_repr_vf_get_stats64(app, repr->port->vf_id, stats);
        default:
                break;
        }
 }
 
-bool
+static bool
 nfp_repr_has_offload_stats(const struct net_device *dev, int attr_id)
 {
        switch (attr_id) {
@@ -196,8 +206,9 @@ nfp_repr_get_host_stats64(const struct net_device *netdev,
        return 0;
 }
 
-int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev,
-                              void *stats)
+static int
+nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev,
+                          void *stats)
 {
        switch (attr_id) {
        case IFLA_OFFLOAD_XSTATS_CPU_HIT:
@@ -207,7 +218,7 @@ int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev,
        return -EINVAL;
 }
 
-netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct nfp_repr *repr = netdev_priv(netdev);
        unsigned int len = skb->len;
@@ -224,6 +235,30 @@ netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev)
        return ret;
 }
 
+static int nfp_repr_stop(struct net_device *netdev)
+{
+       struct nfp_repr *repr = netdev_priv(netdev);
+
+       return nfp_app_repr_stop(repr->app, repr);
+}
+
+static int nfp_repr_open(struct net_device *netdev)
+{
+       struct nfp_repr *repr = netdev_priv(netdev);
+
+       return nfp_app_repr_open(repr->app, repr);
+}
+
+const struct net_device_ops nfp_repr_netdev_ops = {
+       .ndo_open               = nfp_repr_open,
+       .ndo_stop               = nfp_repr_stop,
+       .ndo_start_xmit         = nfp_repr_xmit,
+       .ndo_get_stats64        = nfp_repr_get_stats64,
+       .ndo_has_offload_stats  = nfp_repr_has_offload_stats,
+       .ndo_get_offload_stats  = nfp_repr_get_offload_stats,
+       .ndo_get_phys_port_name = nfp_port_get_phys_port_name,
+};
+
 static void nfp_repr_clean(struct nfp_repr *repr)
 {
        unregister_netdev(repr->netdev);
@@ -248,8 +283,8 @@ static void nfp_repr_set_lockdep_class(struct net_device *dev)
 }
 
 int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
-                 const struct net_device_ops *netdev_ops, u32 cmsg_port_id,
-                 struct nfp_port *port, struct net_device *pf_netdev)
+                 u32 cmsg_port_id, struct nfp_port *port,
+                 struct net_device *pf_netdev)
 {
        struct nfp_repr *repr = netdev_priv(netdev);
        int err;
@@ -263,7 +298,7 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
        repr->dst->u.port_info.port_id = cmsg_port_id;
        repr->dst->u.port_info.lower_dev = pf_netdev;
 
-       netdev->netdev_ops = netdev_ops;
+       netdev->netdev_ops = &nfp_repr_netdev_ops;
 
        err = register_netdev(netdev);
        if (err)
index c5ed6611f7087be9288d18695171cf5e0c15a83b..6a6727816010cec9676dca35b9012d2e090c5ef2 100644 (file)
@@ -97,16 +97,15 @@ enum nfp_repr_type {
 };
 #define NFP_REPR_TYPE_MAX (__NFP_REPR_TYPE_MAX - 1)
 
+extern const struct net_device_ops nfp_repr_netdev_ops;
+
+static inline bool nfp_netdev_is_nfp_repr(struct net_device *netdev)
+{
+       return netdev->netdev_ops == &nfp_repr_netdev_ops;
+}
+
 void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len);
-void
-nfp_repr_get_stats64(const struct nfp_app *app, enum nfp_repr_type type,
-                    u8 port, struct rtnl_link_stats64 *stats);
-bool nfp_repr_has_offload_stats(const struct net_device *dev, int attr_id);
-int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev,
-                              void *stats);
-netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev);
 int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
-                 const struct net_device_ops *netdev_ops,
                  u32 cmsg_port_id, struct nfp_port *port,
                  struct net_device *pf_netdev);
 struct net_device *nfp_repr_alloc(struct nfp_app *app);
index 19bceeb822258b4703d8cbca83199551de4336b0..0b44952945d884128e9d0d9026796be671cb9be0 100644 (file)
 
 struct nfp_port *nfp_port_from_netdev(struct net_device *netdev)
 {
-       struct nfp_net *nn;
+       if (nfp_netdev_is_nfp_net(netdev)) {
+               struct nfp_net *nn = netdev_priv(netdev);
 
-       if (WARN_ON(!nfp_netdev_is_nfp_net(netdev)))
-               return NULL;
-       nn = netdev_priv(netdev);
+               return nn->port;
+       }
+
+       if (nfp_netdev_is_nfp_repr(netdev)) {
+               struct nfp_repr *repr = netdev_priv(netdev);
+
+               return repr->port;
+       }
+
+       WARN(1, "Unknown netdev type for nfp_port\n");
 
-       return nn->port;
+       return NULL;
 }
 
 struct nfp_port *
@@ -98,15 +106,31 @@ nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len)
        int n;
 
        port = nfp_port_from_netdev(netdev);
-       eth_port = __nfp_port_get_eth_port(port);
-       if (!eth_port)
+       if (!port)
                return -EOPNOTSUPP;
 
-       if (!eth_port->is_split)
-               n = snprintf(name, len, "p%d", eth_port->label_port);
-       else
-               n = snprintf(name, len, "p%ds%d", eth_port->label_port,
-                            eth_port->label_subport);
+       switch (port->type) {
+       case NFP_PORT_PHYS_PORT:
+               eth_port = __nfp_port_get_eth_port(port);
+               if (!eth_port)
+                       return -EOPNOTSUPP;
+
+               if (!eth_port->is_split)
+                       n = snprintf(name, len, "p%d", eth_port->label_port);
+               else
+                       n = snprintf(name, len, "p%ds%d", eth_port->label_port,
+                                    eth_port->label_subport);
+               break;
+       case NFP_PORT_PF_PORT:
+               n = snprintf(name, len, "pf%d", port->pf_id);
+               break;
+       case NFP_PORT_VF_PORT:
+               n = snprintf(name, len, "pf%dvf%d", port->pf_id, port->vf_id);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
        if (n >= len)
                return -EINVAL;
 
index f472bea4ec2bc3f2b3a40489afb74e7a5d6a3f03..57d852a4ca59c826702a15f9b82f1614a62703a5 100644 (file)
@@ -47,10 +47,14 @@ struct nfp_port;
  *                     state when port disappears because of FW fault or config
  *                     change
  * @NFP_PORT_PHYS_PORT:        external NIC port
+ * @NFP_PORT_PF_PORT:  logical port of PCI PF
+ * @NFP_PORT_VF_PORT:  logical port of PCI VF
  */
 enum nfp_port_type {
        NFP_PORT_INVALID,
        NFP_PORT_PHYS_PORT,
+       NFP_PORT_PF_PORT,
+       NFP_PORT_VF_PORT,
 };
 
 /**
@@ -72,6 +76,8 @@ enum nfp_port_flags {
  * @dl_port:   devlink port structure
  * @eth_id:    for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme
  * @eth_port:  for %NFP_PORT_PHYS_PORT translated ETH Table port entry
+ * @pf_id:     for %NFP_PORT_PF_PORT, %NFP_PORT_VF_PORT ID of the PCI PF (0-3)
+ * @vf_id:     for %NFP_PORT_VF_PORT ID of the PCI VF within @pf_id
  * @port_list: entry on pf's list of ports
  */
 struct nfp_port {
@@ -84,8 +90,18 @@ struct nfp_port {
 
        struct devlink_port dl_port;
 
-       unsigned int eth_id;
-       struct nfp_eth_table_port *eth_port;
+       union {
+               /* NFP_PORT_PHYS_PORT */
+               struct {
+                       unsigned int eth_id;
+                       struct nfp_eth_table_port *eth_port;
+               };
+               /* NFP_PORT_PF_PORT, NFP_PORT_VF_PORT */
+               struct {
+                       unsigned int pf_id;
+                       unsigned int vf_id;
+               };
+       };
 
        struct list_head port_list;
 };
index 25a967158ce9cb6706e617d79d642f05630bcc99..5798adc57cbc9962ec36a74e4f133c5c22d5c78c 100644 (file)
@@ -230,6 +230,9 @@ struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp,
 struct nfp_cpp_area *nfp_cpp_area_alloc(struct nfp_cpp *cpp, u32 cpp_id,
                                        unsigned long long address,
                                        unsigned long size);
+struct nfp_cpp_area *
+nfp_cpp_area_alloc_acquire(struct nfp_cpp *cpp, const char *name, u32 cpp_id,
+                          unsigned long long address, unsigned long size);
 void nfp_cpp_area_free(struct nfp_cpp_area *area);
 int nfp_cpp_area_acquire(struct nfp_cpp_area *area);
 int nfp_cpp_area_acquire_nonblocking(struct nfp_cpp_area *area);
@@ -239,8 +242,6 @@ int nfp_cpp_area_read(struct nfp_cpp_area *area, unsigned long offset,
                      void *buffer, size_t length);
 int nfp_cpp_area_write(struct nfp_cpp_area *area, unsigned long offset,
                       const void *buffer, size_t length);
-int nfp_cpp_area_check_range(struct nfp_cpp_area *area,
-                            unsigned long long offset, unsigned long size);
 const char *nfp_cpp_area_name(struct nfp_cpp_area *cpp_area);
 void *nfp_cpp_area_priv(struct nfp_cpp_area *cpp_area);
 struct nfp_cpp *nfp_cpp_area_cpp(struct nfp_cpp_area *cpp_area);
@@ -278,6 +279,10 @@ int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
 int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
                   unsigned long long address, u64 value);
 
+u8 __iomem *
+nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target,
+                u64 addr, unsigned long size, struct nfp_cpp_area **area);
+
 struct nfp_cpp_mutex;
 
 int nfp_cpp_mutex_init(struct nfp_cpp *cpp, int target,
index 9b69dcf87be934b10d57727626388a2b0b76e958..04dd5758ecf54223cdc80b9632f7e3b7f7d709fe 100644 (file)
@@ -360,6 +360,41 @@ nfp_cpp_area_alloc(struct nfp_cpp *cpp, u32 dest,
        return nfp_cpp_area_alloc_with_name(cpp, dest, NULL, address, size);
 }
 
+/**
+ * nfp_cpp_area_alloc_acquire() - allocate a new CPP area and lock it down
+ * @cpp:       CPP handle
+ * @name:      Name of region
+ * @dest:      CPP id
+ * @address:   Start address on CPP target
+ * @size:      Size of area
+ *
+ * Allocate and initialize a CPP area structure, and lock it down so
+ * that it can be accessed directly.
+ *
+ * NOTE: @address and @size must be 32-bit aligned values.
+ *
+ * NOTE: The area must also be 'released' when the structure is freed.
+ *
+ * Return: NFP CPP Area handle, or NULL
+ */
+struct nfp_cpp_area *
+nfp_cpp_area_alloc_acquire(struct nfp_cpp *cpp, const char *name, u32 dest,
+                          unsigned long long address, unsigned long size)
+{
+       struct nfp_cpp_area *area;
+
+       area = nfp_cpp_area_alloc_with_name(cpp, dest, name, address, size);
+       if (!area)
+               return NULL;
+
+       if (nfp_cpp_area_acquire(area)) {
+               nfp_cpp_area_free(area);
+               return NULL;
+       }
+
+       return area;
+}
+
 /**
  * nfp_cpp_area_free() - free up the CPP area
  * @area:      CPP area handle
@@ -535,27 +570,6 @@ int nfp_cpp_area_write(struct nfp_cpp_area *area,
        return area->cpp->op->area_write(area, kernel_vaddr, offset, length);
 }
 
-/**
- * nfp_cpp_area_check_range() - check if address range fits in CPP area
- * @area:      CPP area handle
- * @offset:    offset into CPP target
- * @length:    size of address range in bytes
- *
- * Check if address range fits within CPP area.  Return 0 if area
- * fits or -EFAULT on error.
- *
- * Return: 0, or -ERRNO
- */
-int nfp_cpp_area_check_range(struct nfp_cpp_area *area,
-                            unsigned long long offset, unsigned long length)
-{
-       if (offset < area->offset ||
-           offset + length > area->offset + area->size)
-               return -EFAULT;
-
-       return 0;
-}
-
 /**
  * nfp_cpp_area_name() - return name of a CPP area
  * @cpp_area:  CPP area handle
index 0ba0379b8f7581bab817b1c5ab65fe024b55451e..ab86bceb93f2dbc907bcf88bb1653a7d8a8b87c4 100644 (file)
@@ -279,3 +279,43 @@ exit_release:
 
        return err;
 }
+
+/**
+ * nfp_cpp_map_area() - Helper function to map an area
+ * @cpp:    NFP CPP handler
+ * @name:   Name for the area
+ * @domain: CPP domain
+ * @target: CPP target
+ * @addr:   CPP address
+ * @size:   Size of the area
+ * @area:   Area handle (output)
+ *
+ * Map an area of IOMEM access.  To undo the effect of this function call
+ * @nfp_cpp_area_release_free(*area).
+ *
+ * Return: Pointer to memory mapped area or ERR_PTR
+ */
+u8 __iomem *
+nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target,
+                u64 addr, unsigned long size, struct nfp_cpp_area **area)
+{
+       u8 __iomem *res;
+       u32 dest;
+
+       dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain);
+
+       *area = nfp_cpp_area_alloc_acquire(cpp, name, dest, addr, size);
+       if (!*area)
+               goto err_eio;
+
+       res = nfp_cpp_area_iomem(*area);
+       if (!res)
+               goto err_release_free;
+
+       return res;
+
+err_release_free:
+       nfp_cpp_area_release_free(*area);
+err_eio:
+       return (u8 __iomem *)ERR_PTR(-EIO);
+}
index d27d29782a1262be31f7e067122ec2f2bcca2f18..c9724fb7ea4b23cf695dc28d6dc1e2922930262a 100644 (file)
@@ -97,7 +97,11 @@ int nfp_rtsym_count(struct nfp_rtsym_table *rtbl);
 const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx);
 const struct nfp_rtsym *
 nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name);
+
 u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
                      int *error);
+u8 __iomem *
+nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
+             unsigned int min_size, struct nfp_cpp_area **area);
 
 #endif /* NFP_NFFW_H */
index 203f9cbae0fbc79271f4e6c724a90acb89a20137..ecda474ac7c3e256730e1319766caf40f44d8053 100644 (file)
@@ -289,3 +289,30 @@ exit:
                return ~0ULL;
        return val;
 }
+
+u8 __iomem *
+nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
+             unsigned int min_size, struct nfp_cpp_area **area)
+{
+       const struct nfp_rtsym *sym;
+       u8 __iomem *mem;
+
+       sym = nfp_rtsym_lookup(rtbl, name);
+       if (!sym)
+               return (u8 __iomem *)ERR_PTR(-ENOENT);
+
+       if (sym->size < min_size) {
+               nfp_err(rtbl->cpp, "Symbol %s too small\n", name);
+               return (u8 __iomem *)ERR_PTR(-EINVAL);
+       }
+
+       mem = nfp_cpp_map_area(rtbl->cpp, id, sym->domain, sym->target,
+                              sym->addr, sym->size, area);
+       if (IS_ERR(mem)) {
+               nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n",
+                       name, PTR_ERR(mem));
+               return mem;
+       }
+
+       return mem;
+}
index fffd6d5fc907b01d2277370f80b23af5a9288e8d..6c2d1da0558889f3361129a77b55cba9df6ab0ee 100644 (file)
@@ -638,7 +638,7 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
 {
        struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
        struct device_node *node = priv->device->of_node;
-       int ret;
+       int ret, phy_interface;
        u32 reg, val;
 
        regmap_read(gmac->regmap, SYSCON_EMAC_REG, &val);
@@ -718,7 +718,11 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
        if (gmac->variant->support_rmii)
                reg &= ~SYSCON_RMII_EN;
 
-       switch (priv->plat->interface) {
+       phy_interface = priv->plat->interface;
+       /* if PHY is internal, select the mode (xMII) used by the SoC */
+       if (gmac->use_internal_phy)
+               phy_interface = gmac->variant->internal_phy;
+       switch (phy_interface) {
        case PHY_INTERFACE_MODE_MII:
                /* default */
                break;
@@ -932,7 +936,7 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
        }
 
        plat_dat->interface = of_get_phy_mode(dev->of_node);
-       if (plat_dat->interface == gmac->variant->internal_phy) {
+       if (plat_dat->interface == PHY_INTERFACE_MODE_INTERNAL) {
                dev_info(&pdev->dev, "Will use internal PHY\n");
                gmac->use_internal_phy = true;
                gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0);
index b7a0f5eeab620b30c5abcf8798f2bd3fdb2fb401..1850e348f5555b67f253c7a8fc9cb927d9694f16 100644 (file)
@@ -1236,6 +1236,7 @@ static inline int cpsw_tx_packet_submit(struct cpsw_priv *priv,
 {
        struct cpsw_common *cpsw = priv->cpsw;
 
+       skb_tx_timestamp(skb);
        return cpdma_chan_submit(txch, skb, skb->data, skb->len,
                                 priv->emac_port + cpsw->data.dual_emac);
 }
@@ -1597,6 +1598,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 {
        struct cpsw_priv *priv = netdev_priv(ndev);
        struct cpsw_common *cpsw = priv->cpsw;
+       struct cpts *cpts = cpsw->cpts;
        struct netdev_queue *txq;
        struct cpdma_chan *txch;
        int ret, q_idx;
@@ -1608,11 +1610,9 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
        }
 
        if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
-           cpts_is_tx_enabled(cpsw->cpts))
+           cpts_is_tx_enabled(cpts) && cpts_can_timestamp(cpts, skb))
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 
-       skb_tx_timestamp(skb);
-
        q_idx = skb_get_queue_mapping(skb);
        if (q_idx >= cpsw->tx_ch_num)
                q_idx = q_idx % cpsw->tx_ch_num;
index c96eca2b1b46033a67198c0bd346b8dbc4929fed..01ea82ba9cdca7e83a03f36d9ef1f43ec4267bc0 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/of.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/skbuff.h>
+#include <linux/ptp_classify.h>
 #include <linux/timecounter.h>
 
 struct cpsw_cpts {
@@ -155,6 +156,16 @@ static inline bool cpts_is_tx_enabled(struct cpts *cpts)
        return !!cpts->tx_enable;
 }
 
+static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb)
+{
+       unsigned int class = ptp_classify_raw(skb);
+
+       if (class == PTP_CLASS_NONE)
+               return false;
+
+       return true;
+}
+
 #else
 struct cpts;
 
@@ -203,6 +214,11 @@ static inline bool cpts_is_tx_enabled(struct cpts *cpts)
 {
        return false;
 }
+
+static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb)
+{
+       return false;
+}
 #endif
 
 
index 0847a8f48cfe1d11d5001c1da2e0a33200a05116..28cb38af1a348799687149e07084cd55cf4aa1a9 100644 (file)
@@ -2503,24 +2503,8 @@ static bool gbe_need_txtstamp(struct gbe_intf *gbe_intf,
                              const struct netcp_packet *p_info)
 {
        struct sk_buff *skb = p_info->skb;
-       unsigned int class = ptp_classify_raw(skb);
 
-       if (class == PTP_CLASS_NONE)
-               return false;
-
-       switch (class) {
-       case PTP_CLASS_V1_IPV4:
-       case PTP_CLASS_V1_IPV6:
-       case PTP_CLASS_V2_IPV4:
-       case PTP_CLASS_V2_IPV6:
-       case PTP_CLASS_V2_L2:
-       case (PTP_CLASS_V2_VLAN | PTP_CLASS_L2):
-       case (PTP_CLASS_V2_VLAN | PTP_CLASS_IPV4):
-       case (PTP_CLASS_V2_VLAN | PTP_CLASS_IPV6):
-               return true;
-       }
-
-       return false;
+       return cpts_can_timestamp(gbe_intf->gbe_dev->cpts, skb);
 }
 
 static int gbe_txtstamp_mark_pkt(struct gbe_intf *gbe_intf,
index 0dafd8e6c6658820c8be6b16cbf75283805898d4..fd0ff97e3d81f3c4249c5a51e3da65b4f04d85f1 100644 (file)
@@ -2727,7 +2727,7 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
        }
 
        if (tb[IFLA_MTU]) {
-               u32 mtu = nla_get_u32(data[IFLA_MTU]);
+               u32 mtu = nla_get_u32(tb[IFLA_MTU]);
 
                if (mtu < ETH_MIN_MTU || mtu > ETH_MAX_MTU)
                        return -EINVAL;
index 1468dbd0f09ad5eeb559fffb545bda6f051f7301..972ce4baab6b2a4b0539624d1a671c632d77514c 100644 (file)
@@ -302,6 +302,67 @@ struct sock *__udp6_lib_lookup(struct net *net,
 struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
                                 __be16 sport, __be16 dport);
 
+/* UDP uses skb->dev_scratch to cache as much information as possible and avoid
+ * possibly multiple cache miss on dequeue()
+ */
+#if BITS_PER_LONG == 64
+
+/* truesize, len and the bit needed to compute skb_csum_unnecessary will be on
+ * cold cache lines at recvmsg time.
+ * skb->len can be stored on 16 bits since the udp header has been already
+ * validated and pulled.
+ */
+struct udp_dev_scratch {
+       u32 truesize;
+       u16 len;
+       bool is_linear;
+       bool csum_unnecessary;
+};
+
+static inline unsigned int udp_skb_len(struct sk_buff *skb)
+{
+       return ((struct udp_dev_scratch *)&skb->dev_scratch)->len;
+}
+
+static inline bool udp_skb_csum_unnecessary(struct sk_buff *skb)
+{
+       return ((struct udp_dev_scratch *)&skb->dev_scratch)->csum_unnecessary;
+}
+
+static inline bool udp_skb_is_linear(struct sk_buff *skb)
+{
+       return ((struct udp_dev_scratch *)&skb->dev_scratch)->is_linear;
+}
+
+#else
+static inline unsigned int udp_skb_len(struct sk_buff *skb)
+{
+       return skb->len;
+}
+
+static inline bool udp_skb_csum_unnecessary(struct sk_buff *skb)
+{
+       return skb_csum_unnecessary(skb);
+}
+
+static inline bool udp_skb_is_linear(struct sk_buff *skb)
+{
+       return !skb_is_nonlinear(skb);
+}
+#endif
+
+static inline int copy_linear_skb(struct sk_buff *skb, int len, int off,
+                                 struct iov_iter *to)
+{
+       int n, copy = len - off;
+
+       n = copy_to_iter(skb->data + off, copy, to);
+       if (n == copy)
+               return 0;
+
+       return -EFAULT;
+}
+
 /*
  *     SNMP statistics for UDP and UDP-Lite
  */
index 058f509ca98ebeb950c286d135f95373c1536dbc..4c88d20d91d4fa7b6b5d43d5791c2c2d100f44ee 100644 (file)
@@ -3062,6 +3062,11 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
                if (get_user(len, optlen))
                        return -EFAULT;
                len = min_t(unsigned int, len, TCP_ULP_NAME_MAX);
+               if (!icsk->icsk_ulp_ops) {
+                       if (put_user(0, optlen))
+                               return -EFAULT;
+                       return 0;
+               }
                if (put_user(len, optlen))
                        return -EFAULT;
                if (copy_to_user(optval, icsk->icsk_ulp_ops->name, len))
index 47c7aa0501af70e53332cc9e4ae79151f548d6f9..86fad2a14ac49ad07ce07c88ca754b9332a075d9 100644 (file)
@@ -1163,24 +1163,7 @@ out:
        return ret;
 }
 
-/* Copy as much information as possible into skb->dev_scratch to avoid
- * possibly multiple cache miss on dequeue();
- */
 #if BITS_PER_LONG == 64
-
-/* we can store multiple info here: truesize, len and the bit needed to
- * compute skb_csum_unnecessary will be on cold cache lines at recvmsg
- * time.
- * skb->len can be stored on 16 bits since the udp header has been already
- * validated and pulled.
- */
-struct udp_dev_scratch {
-       u32 truesize;
-       u16 len;
-       bool is_linear;
-       bool csum_unnecessary;
-};
-
 static void udp_set_dev_scratch(struct sk_buff *skb)
 {
        struct udp_dev_scratch *scratch;
@@ -1197,22 +1180,6 @@ static int udp_skb_truesize(struct sk_buff *skb)
 {
        return ((struct udp_dev_scratch *)&skb->dev_scratch)->truesize;
 }
-
-static unsigned int udp_skb_len(struct sk_buff *skb)
-{
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->len;
-}
-
-static bool udp_skb_csum_unnecessary(struct sk_buff *skb)
-{
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->csum_unnecessary;
-}
-
-static bool udp_skb_is_linear(struct sk_buff *skb)
-{
-       return ((struct udp_dev_scratch *)&skb->dev_scratch)->is_linear;
-}
-
 #else
 static void udp_set_dev_scratch(struct sk_buff *skb)
 {
@@ -1223,21 +1190,6 @@ static int udp_skb_truesize(struct sk_buff *skb)
 {
        return skb->dev_scratch;
 }
-
-static unsigned int udp_skb_len(struct sk_buff *skb)
-{
-       return skb->len;
-}
-
-static bool udp_skb_csum_unnecessary(struct sk_buff *skb)
-{
-       return skb_csum_unnecessary(skb);
-}
-
-static bool udp_skb_is_linear(struct sk_buff *skb)
-{
-       return !skb_is_nonlinear(skb);
-}
 #endif
 
 /* fully reclaim rmem/fwd memory allocated for skb */
@@ -1598,18 +1550,6 @@ busy_check:
 }
 EXPORT_SYMBOL_GPL(__skb_recv_udp);
 
-static int copy_linear_skb(struct sk_buff *skb, int len, int off,
-                          struct iov_iter *to)
-{
-       int n, copy = len - off;
-
-       n = copy_to_iter(skb->data + off, copy, to);
-       if (n == copy)
-               return 0;
-
-       return -EFAULT;
-}
-
 /*
  *     This should be easy, if there is something there we
  *     return it, otherwise we block.
index d1d72880572938ad99a4779f4216ccb4f14a8f92..450829dd6384fb250d6caf4840092c189f5b9715 100644 (file)
@@ -362,7 +362,7 @@ try_again:
        if (!skb)
                return err;
 
-       ulen = skb->len;
+       ulen = udp_skb_len(skb);
        copied = len;
        if (copied > ulen - off)
                copied = ulen - off;
@@ -379,14 +379,18 @@ try_again:
 
        if (copied < ulen || peeking ||
            (is_udplite && UDP_SKB_CB(skb)->partial_cov)) {
-               checksum_valid = !udp_lib_checksum_complete(skb);
+               checksum_valid = udp_skb_csum_unnecessary(skb) ||
+                               !__udp_lib_checksum_complete(skb);
                if (!checksum_valid)
                        goto csum_copy_err;
        }
 
-       if (checksum_valid || skb_csum_unnecessary(skb))
-               err = skb_copy_datagram_msg(skb, off, msg, copied);
-       else {
+       if (checksum_valid || udp_skb_csum_unnecessary(skb)) {
+               if (udp_skb_is_linear(skb))
+                       err = copy_linear_skb(skb, copied, off, &msg->msg_iter);
+               else
+                       err = skb_copy_datagram_msg(skb, off, msg, copied);
+       } else {
                err = skb_copy_and_csum_datagram_msg(skb, off, msg);
                if (err == -EINVAL)
                        goto csum_copy_err;