diff options
Diffstat (limited to 'drivers/net/ethernet')
228 files changed, 5355 insertions, 2668 deletions
diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c index 8cafd06ff0c4..b762176a1406 100644 --- a/drivers/net/ethernet/3com/3c509.c +++ b/drivers/net/ethernet/3com/3c509.c @@ -60,8 +60,6 @@ */ #define DRV_NAME "3c509" -#define DRV_VERSION "1.20" -#define DRV_RELDATE "04Feb2008" /* A few values that may be tweaked. */ @@ -87,13 +85,12 @@ #include <linux/device.h> #include <linux/eisa.h> #include <linux/bitops.h> +#include <linux/vermagic.h> #include <linux/uaccess.h> #include <asm/io.h> #include <asm/irq.h> -static char version[] = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n"; - #ifdef EL3_DEBUG static int el3_debug = EL3_DEBUG; #else @@ -547,8 +544,6 @@ static int el3_common_init(struct net_device *dev) dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], dev->dev_addr, dev->irq); - if (el3_debug > 0) - pr_info("%s", version); return 0; } @@ -1143,7 +1138,6 @@ el3_netdev_set_ecmd(struct net_device *dev, static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); } static int el3_get_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c index 1e233e2f0a5a..90312fcd6319 100644 --- a/drivers/net/ethernet/3com/3c515.c +++ b/drivers/net/ethernet/3com/3c515.c @@ -22,12 +22,8 @@ */ +#include <linux/vermagic.h> #define DRV_NAME "3c515" -#define DRV_VERSION "0.99t-ac" -#define DRV_RELDATE "28-Oct-2002" - -static char *version = -DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " becker@scyld.com and others\n"; #define CORKSCREW 1 @@ -84,7 +80,6 @@ static int max_interrupt_work = 20; MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); /* "Knobs" for adjusting internal parameters. */ /* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */ @@ -418,8 +413,6 @@ int init_module(void) int found = 0; if (debug >= 0) corkscrew_debug = debug; - if (corkscrew_debug) - pr_debug("%s", version); while (corkscrew_scan(-1)) found++; return found ? 0 : -ENODEV; @@ -429,16 +422,10 @@ int init_module(void) struct net_device *tc515_probe(int unit) { struct net_device *dev = corkscrew_scan(unit); - static int printed; if (!dev) return ERR_PTR(-ENODEV); - if (corkscrew_debug > 0 && !printed) { - printed = 1; - pr_debug("%s", version); - } - return dev; } #endif /* not MODULE */ @@ -1540,7 +1527,6 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); snprintf(info->bus_info, sizeof(info->bus_info), "ISA 0x%lx", dev->base_addr); } diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index d47cde6c5f08..09816e84314d 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c @@ -23,7 +23,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define DRV_NAME "3c589_cs" -#define DRV_VERSION "1.162-ac" #include <linux/module.h> #include <linux/kernel.h> @@ -482,7 +481,6 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx", dev->base_addr); } diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c index 14fce6658106..4383ee615793 100644 --- a/drivers/net/ethernet/3com/typhoon.c +++ b/drivers/net/ethernet/3com/typhoon.c @@ -127,7 +127,6 @@ static const int multicast_filter_limit = 32; #include "typhoon.h" MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); -MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(FIRMWARE_NAME); MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)"); diff --git a/drivers/net/ethernet/adaptec/starfire.c b/drivers/net/ethernet/adaptec/starfire.c index 165d18405b0c..2db42211329f 100644 --- a/drivers/net/ethernet/adaptec/starfire.c +++ b/drivers/net/ethernet/adaptec/starfire.c @@ -27,8 +27,6 @@ */ #define DRV_NAME "starfire" -#define DRV_VERSION "2.1" -#define DRV_RELDATE "July 6, 2008" #include <linux/interrupt.h> #include <linux/module.h> @@ -47,6 +45,7 @@ #include <asm/processor.h> /* Processor type for cache alignment. */ #include <linux/uaccess.h> #include <asm/io.h> +#include <linux/vermagic.h> /* * The current frame processor firmware fails to checksum a fragment @@ -165,15 +164,9 @@ static int rx_copybreak /* = 0 */; #define FIRMWARE_RX "adaptec/starfire_rx.bin" #define FIRMWARE_TX "adaptec/starfire_tx.bin" -/* These identify the driver base version and may not be removed. */ -static const char version[] = -KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n" -" (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; - MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); MODULE_FIRMWARE(FIRMWARE_RX); MODULE_FIRMWARE(FIRMWARE_TX); @@ -654,13 +647,6 @@ static int starfire_init_one(struct pci_dev *pdev, int drv_flags, io_size; int boguscnt; -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); -#endif - if (pci_enable_device (pdev)) return -EIO; @@ -1853,7 +1839,6 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct netdev_private *np = netdev_priv(dev); strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); } @@ -2073,8 +2058,6 @@ static int __init starfire_init (void) { /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE - printk(version); - printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n"); #endif diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index 2a9f8643629c..bf546118dbc6 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -1114,9 +1114,7 @@ static void greth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in strlcpy(info->driver, dev_driver_string(greth->dev), sizeof(info->driver)); - strlcpy(info->version, "revision: 1.0", sizeof(info->version)); strlcpy(info->bus_info, greth->dev->bus->name, sizeof(info->bus_info)); - strlcpy(info->fw_version, "N/A", sizeof(info->fw_version)); } static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index cb6a761d5c11..1b19385ad8a9 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -2958,7 +2958,6 @@ static void et131x_get_drvinfo(struct net_device *netdev, struct et131x_adapter *adapter = netdev_priv(netdev); strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); - strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); strlcpy(info->bus_info, pci_name(adapter->pdev), sizeof(info->bus_info)); } diff --git a/drivers/net/ethernet/agere/et131x.h b/drivers/net/ethernet/agere/et131x.h index be9a11c02526..d0e922584d8a 100644 --- a/drivers/net/ethernet/agere/et131x.h +++ b/drivers/net/ethernet/agere/et131x.h @@ -46,7 +46,6 @@ */ #define DRIVER_NAME "et131x" -#define DRIVER_VERSION "v2.0" /* EEPROM registers */ diff --git a/drivers/net/ethernet/alacritech/slicoss.c b/drivers/net/ethernet/alacritech/slicoss.c index 9daef4c8feef..6234fcd844ee 100644 --- a/drivers/net/ethernet/alacritech/slicoss.c +++ b/drivers/net/ethernet/alacritech/slicoss.c @@ -26,7 +26,6 @@ #include "slic.h" #define DRV_NAME "slicoss" -#define DRV_VERSION "1.0" static const struct pci_device_id slic_id_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_ALACRITECH, @@ -1533,7 +1532,6 @@ static void slic_get_drvinfo(struct net_device *dev, struct slic_device *sdev = netdev_priv(dev); strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); strlcpy(info->bus_info, pci_name(sdev->pdev), sizeof(info->bus_info)); } @@ -1852,4 +1850,3 @@ module_pci_driver(slic_driver); MODULE_DESCRIPTION("Alacritech non-accelerated SLIC driver"); MODULE_AUTHOR("Lino Sanfilippo <LinoSanfilippo@gmx.de>"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index 22cadfbeedfb..18d3b4340bd4 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -33,7 +33,6 @@ #include "sun4i-emac.h" #define DRV_NAME "sun4i-emac" -#define DRV_VERSION "1.02" #define EMAC_MAX_FRAME_LEN 0x0600 @@ -212,7 +211,6 @@ static void emac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info)); } diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c index f366faf88eee..5d192d551623 100644 --- a/drivers/net/ethernet/alteon/acenic.c +++ b/drivers/net/ethernet/alteon/acenic.c @@ -2699,9 +2699,8 @@ static void ace_get_drvinfo(struct net_device *dev, struct ace_private *ap = netdev_priv(dev); strlcpy(info->driver, "acenic", sizeof(info->driver)); - snprintf(info->version, sizeof(info->version), "%i.%i.%i", - ap->firmware_major, ap->firmware_minor, - ap->firmware_fix); + snprintf(info->fw_version, sizeof(info->version), "%i.%i.%i", + ap->firmware_major, ap->firmware_minor, ap->firmware_fix); if (ap->pdev) strlcpy(info->bus_info, pci_name(ap->pdev), diff --git a/drivers/net/ethernet/altera/altera_tse_ethtool.c b/drivers/net/ethernet/altera/altera_tse_ethtool.c index 23823464f2e7..4299f1301149 100644 --- a/drivers/net/ethernet/altera/altera_tse_ethtool.c +++ b/drivers/net/ethernet/altera/altera_tse_ethtool.c @@ -67,7 +67,6 @@ static void tse_get_drvinfo(struct net_device *dev, u32 rev = ioread32(&priv->mac_dev->megacore_revision); strcpy(info->driver, "altera_tse"); - strcpy(info->version, "v8.0"); snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d", rev & 0xFFFF, (rev & 0xFFFF0000) >> 16); sprintf(info->bus_info, "platform"); diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 1fb58f9ad80b..a250046b8e18 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -1067,18 +1067,14 @@ static void ena_com_hash_key_fill_default_key(struct ena_com_dev *ena_dev) static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) { struct ena_rss *rss = &ena_dev->rss; - struct ena_admin_feature_rss_flow_hash_control *hash_key; struct ena_admin_get_feat_resp get_resp; int rc; - hash_key = (ena_dev->rss).hash_key; - rc = ena_com_get_feature_ex(ena_dev, &get_resp, ENA_ADMIN_RSS_HASH_FUNCTION, ena_dev->rss.hash_key_dma_addr, sizeof(ena_dev->rss.hash_key), 0); if (unlikely(rc)) { - hash_key = NULL; return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index ced1d577b62a..868265a2ec00 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -404,7 +404,6 @@ static void ena_get_drvinfo(struct net_device *dev, struct ena_adapter *adapter = netdev_priv(dev); strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); strlcpy(info->bus_info, pci_name(adapter->pdev), sizeof(info->bus_info)); } @@ -674,7 +673,6 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, * supports getting/setting the hash function. */ rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func, key); - if (rc) { if (rc == -EOPNOTSUPP) { key = NULL; @@ -685,9 +683,6 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, return rc; } - if (rc) - return rc; - switch (ena_func) { case ENA_ADMIN_TOEPLITZ: func = ETH_RSS_HASH_TOP; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 0b2fd96b93d7..555c7273d712 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -49,12 +49,9 @@ #include <linux/bpf_trace.h> #include "ena_pci_id_tbl.h" -static char version[] = DEVICE_NAME " v" DRV_MODULE_VERSION "\n"; - MODULE_AUTHOR("Amazon.com, Inc. or its affiliates"); MODULE_DESCRIPTION(DEVICE_NAME); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (5 * HZ) @@ -3094,9 +3091,9 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev, strncpy(host_info->os_dist_str, utsname()->release, sizeof(host_info->os_dist_str) - 1); host_info->driver_version = - (DRV_MODULE_VER_MAJOR) | - (DRV_MODULE_VER_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) | - (DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) | + (DRV_MODULE_GEN_MAJOR) | + (DRV_MODULE_GEN_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) | + (DRV_MODULE_GEN_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) | ("K"[0] << ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT); host_info->num_cpus = num_online_cpus(); @@ -3476,9 +3473,7 @@ static int ena_restore_device(struct ena_adapter *adapter) netif_carrier_on(adapter->netdev); mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ)); - dev_err(&pdev->dev, - "Device reset completed successfully, Driver info: %s\n", - version); + dev_err(&pdev->dev, "Device reset completed successfully\n"); return rc; err_disable_msix: @@ -4116,8 +4111,6 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_dbg(&pdev->dev, "%s\n", __func__); - dev_info_once(&pdev->dev, "%s", version); - rc = pci_enable_device_mem(pdev); if (rc) { dev_err(&pdev->dev, "pci_enable_device_mem() failed!\n"); @@ -4429,8 +4422,6 @@ static struct pci_driver ena_pci_driver = { static int __init ena_init(void) { - pr_info("%s", version); - ena_wq = create_singlethread_workqueue(DRV_MODULE_NAME); if (!ena_wq) { pr_err("Failed to create workqueue\n"); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 8795e0b1dc3c..97dfd0c67e84 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -45,16 +45,16 @@ #include "ena_com.h" #include "ena_eth_com.h" -#define DRV_MODULE_VER_MAJOR 2 -#define DRV_MODULE_VER_MINOR 1 -#define DRV_MODULE_VER_SUBMINOR 0 +#define DRV_MODULE_GEN_MAJOR 2 +#define DRV_MODULE_GEN_MINOR 1 +#define DRV_MODULE_GEN_SUBMINOR 0 #define DRV_MODULE_NAME "ena" -#ifndef DRV_MODULE_VERSION -#define DRV_MODULE_VERSION \ - __stringify(DRV_MODULE_VER_MAJOR) "." \ - __stringify(DRV_MODULE_VER_MINOR) "." \ - __stringify(DRV_MODULE_VER_SUBMINOR) "K" +#ifndef DRV_MODULE_GENERATION +#define DRV_MODULE_GENERATION \ + __stringify(DRV_MODULE_GEN_MAJOR) "." \ + __stringify(DRV_MODULE_GEN_MINOR) "." \ + __stringify(DRV_MODULE_GEN_SUBMINOR) "K" #endif #define DEVICE_NAME "Elastic Network Adapter (ENA)" diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 0f3b743425e8..7a1286f8e983 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -84,9 +84,8 @@ Revision History: #include "amd8111e.h" #define MODULE_NAME "amd8111e" -#define MODULE_VERS "3.0.7" MODULE_AUTHOR("Advanced Micro Devices, Inc."); -MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "MODULE_VERS); +MODULE_DESCRIPTION("AMD8111 based 10/100 Ethernet Controller."); MODULE_LICENSE("GPL"); module_param_array(speed_duplex, int, NULL, 0); MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); @@ -1366,7 +1365,6 @@ static void amd8111e_get_drvinfo(struct net_device *dev, struct amd8111e_priv *lp = netdev_priv(dev); struct pci_dev *pci_dev = lp->pci_dev; strlcpy(info->driver, MODULE_NAME, sizeof(info->driver)); - strlcpy(info->version, MODULE_VERS, sizeof(info->version)); snprintf(info->fw_version, sizeof(info->fw_version), "%u", chip_version); strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info)); @@ -1875,7 +1873,6 @@ static int amd8111e_probe_one(struct pci_dev *pdev, /* display driver and device information */ chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; - dev_info(&pdev->dev, "AMD-8111e Driver Version: %s\n", MODULE_VERS); dev_info(&pdev->dev, "[ Rev %x ] PCI 10/100BaseT Ethernet %pM\n", chip_version, dev->dev_addr); if (lp->ext_phy_id) diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c index 089a4fbc61a0..9f6e3cc2ce80 100644 --- a/drivers/net/ethernet/amd/au1000_eth.c +++ b/drivers/net/ethernet/amd/au1000_eth.c @@ -63,14 +63,12 @@ static int au1000_debug = 3; NETIF_MSG_LINK) #define DRV_NAME "au1000_eth" -#define DRV_VERSION "1.7" #define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>" #define DRV_DESC "Au1xxx on-chip Ethernet driver" MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION(DRV_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); /* AU1000 MAC registers and bits */ #define MAC_CONTROL 0x0 @@ -656,7 +654,6 @@ au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) struct au1000_private *aup = netdev_priv(dev); strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME, aup->mac_id); } @@ -1290,8 +1287,6 @@ static int au1000_probe(struct platform_device *pdev) netdev_info(dev, "Au1xx0 Ethernet found at 0x%lx, irq %d\n", (unsigned long)base->start, irq); - pr_info_once("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR); - return 0; err_out: diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c index 023aecf6ab30..11c0b13edd30 100644 --- a/drivers/net/ethernet/amd/nmclan_cs.c +++ b/drivers/net/ethernet/amd/nmclan_cs.c @@ -114,8 +114,6 @@ Log: nmclan_cs.c,v #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define DRV_NAME "nmclan_cs" -#define DRV_VERSION "0.16" - /* ---------------------------------------------------------------------------- Conditional Compilation Options @@ -367,7 +365,7 @@ typedef struct _mace_private { char tx_free_frames; /* Number of free transmit frame buffers */ char tx_irq_disabled; /* MACE TX interrupt disabled */ - + spinlock_t bank_lock; /* Must be held if you step off bank 0 */ } mace_private; @@ -444,7 +442,7 @@ static int nmclan_probe(struct pcmcia_device *link) lp = netdev_priv(dev); lp->p_dev = link; link->priv = dev; - + spin_lock_init(&lp->bank_lock); link->resource[0]->end = 32; link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; @@ -817,7 +815,6 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx", dev->base_addr); } @@ -1110,7 +1107,7 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) if (pkt_len & 1) *(skb_tail_pointer(skb) - 1) = inb(ioaddr + AM2150_RCV); skb->protocol = eth_type_trans(skb, dev); - + netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ dev->stats.rx_packets++; diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index dc7d88227e76..07e8211eea51 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -24,13 +24,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.35" #define DRV_RELDATE "21.Apr.2008" #define PFX DRV_NAME ": " -static const char *const version = - DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; - #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -809,7 +805,6 @@ static void pcnet32_get_drvinfo(struct net_device *dev, struct pcnet32_private *lp = netdev_priv(dev); strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); if (lp->pci_dev) strlcpy(info->bus_info, pci_name(lp->pci_dev), sizeof(info->bus_info)); @@ -3006,8 +3001,6 @@ MODULE_LICENSE("GPL"); static int __init pcnet32_init_module(void) { - pr_info("%s", version); - pcnet32_debug = netif_msg_init(debug, PCNET32_MSG_DEFAULT); if ((tx_start_pt >= 0) && (tx_start_pt <= 3)) diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c index b00e00881253..a21b2e60157e 100644 --- a/drivers/net/ethernet/amd/sunlance.c +++ b/drivers/net/ethernet/amd/sunlance.c @@ -105,14 +105,9 @@ static char lancestr[] = "LANCE"; #include <asm/irq.h> #define DRV_NAME "sunlance" -#define DRV_VERSION "2.02" #define DRV_RELDATE "8/24/03" #define DRV_AUTHOR "Miguel de Icaza (miguel@nuclecu.unam.mx)" -static char version[] = - DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; - -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION("Sun Lance ethernet driver"); MODULE_LICENSE("GPL"); @@ -1282,7 +1277,6 @@ static void lance_free_hwresources(struct lance_private *lp) static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strlcpy(info->driver, "sunlance", sizeof(info->driver)); - strlcpy(info->version, "2.02", sizeof(info->version)); } static const struct ethtool_ops sparc_lance_ethtool_ops = { @@ -1305,7 +1299,6 @@ static int sparc_lance_probe_one(struct platform_device *op, struct platform_device *lebuffer) { struct device_node *dp = op->dev.of_node; - static unsigned version_printed; struct lance_private *lp; struct net_device *dev; int i; @@ -1316,9 +1309,6 @@ static int sparc_lance_probe_one(struct platform_device *op, lp = netdev_priv(dev); - if (sparc_lance_debug && version_printed++ == 0) - printk (KERN_INFO "%s", version); - spin_lock_init(&lp->lock); /* Copy the IDPROM ethernet address to the device structure, later we diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 8083173f1a8f..b23c8ee24ee3 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -405,7 +405,6 @@ static void xgbe_get_drvinfo(struct net_device *netdev, struct xgbe_hw_features *hw_feat = &pdata->hw_feat; strlcpy(drvinfo->driver, XGBE_DRV_NAME, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, XGBE_DRV_VERSION, sizeof(drvinfo->version)); strlcpy(drvinfo->bus_info, dev_name(pdata->dev), sizeof(drvinfo->bus_info)); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d", diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 7ce9c69e9c44..2a70714a791d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -127,7 +127,6 @@ MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(XGBE_DRV_VERSION); MODULE_DESCRIPTION(XGBE_DRV_DESC); static int debug = -1; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 47bcbcf58048..5897e46faca5 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -135,7 +135,6 @@ #include <linux/list.h> #define XGBE_DRV_NAME "amd-xgbe" -#define XGBE_DRV_VERSION "1.0.3" #define XGBE_DRV_DESC "AMD 10 Gigabit Ethernet Driver" /* Descriptor related defines */ diff --git a/drivers/net/ethernet/apm/xgene-v2/ethtool.c b/drivers/net/ethernet/apm/xgene-v2/ethtool.c index a58250c1b57a..b78d1a99fe81 100644 --- a/drivers/net/ethernet/apm/xgene-v2/ethtool.c +++ b/drivers/net/ethernet/apm/xgene-v2/ethtool.c @@ -89,8 +89,6 @@ static void xge_get_drvinfo(struct net_device *ndev, struct platform_device *pdev = pdata->pdev; strcpy(info->driver, "xgene-enet-v2"); - strcpy(info->version, XGENE_ENET_V2_VERSION); - snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); sprintf(info->bus_info, "%s", pdev->name); } diff --git a/drivers/net/ethernet/apm/xgene-v2/main.c b/drivers/net/ethernet/apm/xgene-v2/main.c index c48f60996761..860c18fb7aae 100644 --- a/drivers/net/ethernet/apm/xgene-v2/main.c +++ b/drivers/net/ethernet/apm/xgene-v2/main.c @@ -741,5 +741,4 @@ module_platform_driver(xge_driver); MODULE_DESCRIPTION("APM X-Gene SoC Ethernet v2 driver"); MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>"); -MODULE_VERSION(XGENE_ENET_V2_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/apm/xgene-v2/main.h b/drivers/net/ethernet/apm/xgene-v2/main.h index d41439d2709d..b3985a7be59d 100644 --- a/drivers/net/ethernet/apm/xgene-v2/main.h +++ b/drivers/net/ethernet/apm/xgene-v2/main.h @@ -28,7 +28,6 @@ #include "ring.h" #include "ethtool.h" -#define XGENE_ENET_V2_VERSION "v1.0" #define XGENE_ENET_STD_MTU 1536 #define XGENE_ENET_MIN_FRAME 60 #define IRQ_ID_SIZE 16 diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 246dec27140d..ada70425b48c 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -103,8 +103,6 @@ static void xgene_get_drvinfo(struct net_device *ndev, struct platform_device *pdev = pdata->pdev; strcpy(info->driver, "xgene_enet"); - strcpy(info->version, XGENE_DRV_VERSION); - snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); sprintf(info->bus_info, "%s", pdev->name); } diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 6aee2f0fc0db..5f1fc6582d74 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -2179,7 +2179,6 @@ static struct platform_driver xgene_enet_driver = { module_platform_driver(xgene_enet_driver); MODULE_DESCRIPTION("APM X-Gene SoC Ethernet driver"); -MODULE_VERSION(XGENE_DRV_VERSION); MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>"); MODULE_AUTHOR("Keyur Chudgar <kchudgar@apm.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 18f4923b1723..d35a338120cf 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -28,7 +28,6 @@ #include "xgene_enet_ring2.h" #include "../../../phy/mdio-xgene.h" -#define XGENE_DRV_VERSION "v1.0" #define ETHER_MIN_PACKET 64 #define ETHER_STD_PACKET 1518 #define XGENE_ENET_STD_MTU 1536 diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index f0c41f7408e5..7560f5506e55 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h @@ -9,8 +9,6 @@ #ifndef AQ_CFG_H #define AQ_CFG_H -#include <generated/utsrelease.h> - #define AQ_CFG_VECS_DEF 8U #define AQ_CFG_TCS_DEF 1U @@ -85,7 +83,5 @@ #define AQ_CFG_DRV_AUTHOR "aQuantia" #define AQ_CFG_DRV_DESC "aQuantia Corporation(R) Network Driver" #define AQ_CFG_DRV_NAME "atlantic" -#define AQ_CFG_DRV_VERSION UTS_RELEASE \ - AQ_CFG_DRV_VERSION_SUFFIX #endif /* AQ_CFG_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h b/drivers/net/ethernet/aquantia/atlantic/aq_common.h index 42ea8d8daa46..c8c402b013bb 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h @@ -12,7 +12,6 @@ #include <linux/etherdevice.h> #include <linux/pci.h> #include <linux/if_vlan.h> -#include "ver.h" #include "aq_cfg.h" #include "aq_utils.h" diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 7b55633d2cb9..0bdaa0d785b7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -132,7 +132,6 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev, regs_count = aq_nic_get_regs_count(aq_nic); strlcat(drvinfo->driver, AQ_CFG_DRV_NAME, sizeof(drvinfo->driver)); - strlcat(drvinfo->version, AQ_CFG_DRV_VERSION, sizeof(drvinfo->version)); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%u.%u.%u", firmware_version >> 24, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index 538f460a3da7..9fcab646cbd5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -19,7 +19,6 @@ #include <linux/udp.h> MODULE_LICENSE("GPL v2"); -MODULE_VERSION(AQ_CFG_DRV_VERSION); MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR); MODULE_DESCRIPTION(AQ_CFG_DRV_DESC); diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h b/drivers/net/ethernet/aquantia/atlantic/ver.h deleted file mode 100644 index 597654b51e01..000000000000 --- a/drivers/net/ethernet/aquantia/atlantic/ver.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved - */ - -#ifndef VER_H -#define VER_H - -#define AQ_CFG_DRV_VERSION_SUFFIX "-kern" - -#endif /* VER_H */ diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h index d9efbc8d783b..d820ae03a966 100644 --- a/drivers/net/ethernet/arc/emac.h +++ b/drivers/net/ethernet/arc/emac.h @@ -130,7 +130,6 @@ struct arc_emac_mdio_bus_data { */ struct arc_emac_priv { const char *drv_name; - const char *drv_version; void (*set_mac_speed)(void *priv, unsigned int speed); /* Devices */ diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c index 539166112993..1c7736b7eaf7 100644 --- a/drivers/net/ethernet/arc/emac_arc.c +++ b/drivers/net/ethernet/arc/emac_arc.c @@ -15,7 +15,6 @@ #include "emac.h" #define DRV_NAME "emac_arc" -#define DRV_VERSION "1.0" static int emac_arc_probe(struct platform_device *pdev) { @@ -36,7 +35,6 @@ static int emac_arc_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->drv_name = DRV_NAME; - priv->drv_version = DRV_VERSION; err = of_get_phy_mode(dev->of_node, &interface); if (err) { diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index 17bda4e8cc45..38cd968b6a3b 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -92,7 +92,6 @@ static void arc_emac_get_drvinfo(struct net_device *ndev, struct arc_emac_priv *priv = netdev_priv(ndev); strlcpy(info->driver, priv->drv_name, sizeof(info->driver)); - strlcpy(info->version, priv->drv_version, sizeof(info->version)); } static const struct ethtool_ops arc_emac_ethtool_ops = { diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c index aae231c5224f..48ecdf15eddc 100644 --- a/drivers/net/ethernet/arc/emac_rockchip.c +++ b/drivers/net/ethernet/arc/emac_rockchip.c @@ -16,7 +16,6 @@ #include "emac.h" #define DRV_NAME "rockchip_emac" -#define DRV_VERSION "1.1" struct emac_rockchip_soc_data { unsigned int grf_offset; @@ -112,7 +111,6 @@ static int emac_rockchip_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->emac.drv_name = DRV_NAME; - priv->emac.drv_version = DRV_VERSION; priv->emac.set_mac_speed = emac_rockchip_set_mac_speed; err = of_get_phy_mode(dev->of_node, &interface); diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 1dcbc486eca9..b9b4edb913c1 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1416,10 +1416,7 @@ static int alx_tso(struct sk_buff *skb, struct alx_txd *first) 0, IPPROTO_TCP, 0); first->word1 |= 1 << TPD_IPV4_SHIFT; } else if (skb_is_gso_v6(skb)) { - ipv6_hdr(skb)->payload_len = 0; - tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); /* LSOv2: the first TPD only provides the packet length */ first->adrl.l.pkt_len = skb->len; first->word1 |= 1 << TPD_LSO_V2_SHIFT; diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h index 60b2febd7315..a0562a90fb6d 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h @@ -583,7 +583,6 @@ struct atl1c_adapter { readl(((a)->hw_addr + reg) + ((offset) << 2))) extern char atl1c_driver_name[]; -extern char atl1c_driver_version[]; void atl1c_reinit_locked(struct atl1c_adapter *adapter); s32 atl1c_reset_hw(struct atl1c_hw *hw); diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c index b5a70a36fa04..e2eb7b8c63a0 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c @@ -221,8 +221,6 @@ static void atl1c_get_drvinfo(struct net_device *netdev, struct atl1c_adapter *adapter = netdev_priv(netdev); strlcpy(drvinfo->driver, atl1c_driver_name, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, atl1c_driver_version, - sizeof(drvinfo->version)); strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), sizeof(drvinfo->bus_info)); } diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 4c0b1f8551dd..00bd7bd55794 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -8,9 +8,7 @@ #include "atl1c.h" -#define ATL1C_DRV_VERSION "1.0.1.1-NAPI" char atl1c_driver_name[] = "atl1c"; -char atl1c_driver_version[] = ATL1C_DRV_VERSION; /* * atl1c_pci_tbl - PCI Device ID Table @@ -37,7 +35,6 @@ MODULE_AUTHOR("Jie Yang"); MODULE_AUTHOR("Qualcomm Atheros Inc., <nic-devel@qualcomm.com>"); MODULE_DESCRIPTION("Qualcomm Atheros 100/1000M Ethernet Network Driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(ATL1C_DRV_VERSION); static int atl1c_stop_mac(struct atl1c_hw *hw); static void atl1c_disable_l0s_l1(struct atl1c_hw *hw); @@ -2025,10 +2022,8 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter, "IPV6 tso with zero data??\n"); goto check_sum; } else - tcp_hdr(skb)->check = ~csum_ipv6_magic( - &ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); + etpd->word1 |= 1 << TPD_LSO_EN_SHIFT; etpd->word1 |= 1 << TPD_LSO_VER_SHIFT; etpd->pkt_len = cpu_to_le32(skb->len); @@ -2644,8 +2639,6 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_register; } - if (netif_msg_probe(adapter)) - dev_info(&pdev->dev, "version %s\n", ATL1C_DRV_VERSION); cards_found++; return 0; diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e.h b/drivers/net/ethernet/atheros/atl1e/atl1e.h index e9893da50995..9fcad783c939 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e.h +++ b/drivers/net/ethernet/atheros/atl1e/atl1e.h @@ -482,7 +482,6 @@ struct atl1e_adapter { readl(((a)->hw_addr + reg) + ((offset) << 2))) extern char atl1e_driver_name[]; -extern char atl1e_driver_version[]; void atl1e_check_options(struct atl1e_adapter *adapter); int atl1e_up(struct atl1e_adapter *adapter); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c index c6b9e7ea8e38..0cbde352d1ba 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c @@ -307,8 +307,6 @@ static void atl1e_get_drvinfo(struct net_device *netdev, struct atl1e_adapter *adapter = netdev_priv(netdev); strlcpy(drvinfo->driver, atl1e_driver_name, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, atl1e_driver_version, - sizeof(drvinfo->version)); strlcpy(drvinfo->fw_version, "L1e", sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), sizeof(drvinfo->bus_info)); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index e0d89942d537..223ef846123e 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -8,10 +8,7 @@ #include "atl1e.h" -#define DRV_VERSION "1.0.0.7-NAPI" - char atl1e_driver_name[] = "ATL1E"; -char atl1e_driver_version[] = DRV_VERSION; #define PCI_DEVICE_ID_ATTANSIC_L1E 0x1026 /* * atl1e_pci_tbl - PCI Device ID Table @@ -33,7 +30,6 @@ MODULE_DEVICE_TABLE(pci, atl1e_pci_tbl); MODULE_AUTHOR("Atheros Corporation, <xiong.huang@atheros.com>, Jie Yang <jie.yang@atheros.com>"); MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter); diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index b498fd6a47d0..271e7034fa70 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -65,12 +65,10 @@ #include "atl1.h" -#define ATLX_DRIVER_VERSION "2.1.3" MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, " "Chris Snook <csnook@redhat.com>, " "Jay Cliburn <jcliburn@gmail.com>"); MODULE_LICENSE("GPL"); -MODULE_VERSION(ATLX_DRIVER_VERSION); /* Temporary hack for merging atl1 and atl2 */ #include "atlx.c" @@ -2965,8 +2963,6 @@ static int atl1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* get device revision number */ adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2)); - if (netif_msg_probe(adapter)) - dev_info(&pdev->dev, "version %s\n", ATLX_DRIVER_VERSION); /* set default ring resource counts */ adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD; @@ -3344,8 +3340,6 @@ static void atl1_get_drvinfo(struct net_device *netdev, struct atl1_adapter *adapter = netdev_priv(netdev); strlcpy(drvinfo->driver, ATLX_DRIVER_NAME, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, ATLX_DRIVER_VERSION, - sizeof(drvinfo->version)); strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), sizeof(drvinfo->bus_info)); } diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index b81a4e0c5b57..7c52b92b599d 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -36,18 +36,13 @@ #include "atl2.h" -#define ATL2_DRV_VERSION "2.2.3" - static const char atl2_driver_name[] = "atl2"; static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver"; -static const char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation."; -static const char atl2_driver_version[] = ATL2_DRV_VERSION; static const struct ethtool_ops atl2_ethtool_ops; MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>"); MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(ATL2_DRV_VERSION); /* * atl2_pci_tbl - PCI Device ID Table @@ -1688,9 +1683,6 @@ static struct pci_driver atl2_driver = { */ static int __init atl2_init_module(void) { - printk(KERN_INFO "%s - version %s\n", atl2_driver_string, - atl2_driver_version); - printk(KERN_INFO "%s\n", atl2_copyright); return pci_register_driver(&atl2_driver); } module_init(atl2_init_module); @@ -2011,8 +2003,6 @@ static void atl2_get_drvinfo(struct net_device *netdev, struct atl2_adapter *adapter = netdev_priv(netdev); strlcpy(drvinfo->driver, atl2_driver_name, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, atl2_driver_version, - sizeof(drvinfo->version)); strlcpy(drvinfo->fw_version, "L2", sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), sizeof(drvinfo->bus_info)); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index e50a15397e11..80feb20a2e53 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "bcmgenet: " fmt +#include <linux/acpi.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> @@ -2771,6 +2772,21 @@ static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, bcmgenet_umac_writel(priv, (addr[4] << 8) | addr[5], UMAC_MAC1); } +static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, + unsigned char *addr) +{ + u32 addr_tmp; + + addr_tmp = bcmgenet_umac_readl(priv, UMAC_MAC0); + addr[0] = addr_tmp >> 24; + addr[1] = (addr_tmp >> 16) & 0xff; + addr[2] = (addr_tmp >> 8) & 0xff; + addr[3] = addr_tmp & 0xff; + addr_tmp = bcmgenet_umac_readl(priv, UMAC_MAC1); + addr[4] = (addr_tmp >> 8) & 0xff; + addr[5] = addr_tmp & 0xff; +} + /* Returns a reusable dma control register value */ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) { @@ -3466,10 +3482,8 @@ static int bcmgenet_probe(struct platform_device *pdev) const struct bcmgenet_plat_data *pdata; struct bcmgenet_priv *priv; struct net_device *dev; - const void *macaddr; unsigned int i; int err = -EIO; - const char *phy_mode_str; /* Up to GENET_MAX_MQ_CNT + 1 TX queues and RX queues */ dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1, @@ -3498,11 +3512,6 @@ static int bcmgenet_probe(struct platform_device *pdev) } priv->wol_irq = platform_get_irq_optional(pdev, 2); - if (dn) - macaddr = of_get_mac_address(dn); - else - macaddr = pd->mac_address; - priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { err = PTR_ERR(priv->base); @@ -3513,12 +3522,6 @@ static int bcmgenet_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); dev_set_drvdata(&pdev->dev, dev); - if (IS_ERR_OR_NULL(macaddr) || !is_valid_ether_addr(macaddr)) { - dev_warn(&pdev->dev, "using random Ethernet MAC\n"); - eth_hw_addr_random(dev); - } else { - ether_addr_copy(dev->dev_addr, macaddr); - } dev->watchdog_timeo = 2 * HZ; dev->ethtool_ops = &bcmgenet_ethtool_ops; dev->netdev_ops = &bcmgenet_netdev_ops; @@ -3547,8 +3550,9 @@ static int bcmgenet_probe(struct platform_device *pdev) priv->dev = dev; priv->pdev = pdev; - if (of_id) { - pdata = of_id->data; + + pdata = device_get_match_data(&pdev->dev); + if (pdata) { priv->version = pdata->version; priv->dma_max_burst_length = pdata->dma_max_burst_length; } else { @@ -3558,7 +3562,7 @@ static int bcmgenet_probe(struct platform_device *pdev) priv->clk = devm_clk_get(&priv->pdev->dev, "enet"); if (IS_ERR(priv->clk)) { - dev_warn(&priv->pdev->dev, "failed to get enet clock\n"); + dev_dbg(&priv->pdev->dev, "failed to get enet clock\n"); priv->clk = NULL; } @@ -3582,23 +3586,34 @@ static int bcmgenet_probe(struct platform_device *pdev) priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol"); if (IS_ERR(priv->clk_wol)) { - dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n"); + dev_dbg(&priv->pdev->dev, "failed to get enet-wol clock\n"); priv->clk_wol = NULL; } priv->clk_eee = devm_clk_get(&priv->pdev->dev, "enet-eee"); if (IS_ERR(priv->clk_eee)) { - dev_warn(&priv->pdev->dev, "failed to get enet-eee clock\n"); + dev_dbg(&priv->pdev->dev, "failed to get enet-eee clock\n"); priv->clk_eee = NULL; } /* If this is an internal GPHY, power it on now, before UniMAC is * brought out of reset as absolutely no UniMAC activity is allowed */ - if (dn && !of_property_read_string(dn, "phy-mode", &phy_mode_str) && - !strcasecmp(phy_mode_str, "internal")) + if (device_get_phy_mode(&pdev->dev) == PHY_INTERFACE_MODE_INTERNAL) bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + if ((pd) && (!IS_ERR_OR_NULL(pd->mac_address))) + ether_addr_copy(dev->dev_addr, pd->mac_address); + else + if (!device_get_mac_address(&pdev->dev, dev->dev_addr, ETH_ALEN)) + if (has_acpi_companion(&pdev->dev)) + bcmgenet_get_hw_addr(priv, dev->dev_addr); + + if (!is_valid_ether_addr(dev->dev_addr)) { + dev_warn(&pdev->dev, "using random Ethernet MAC\n"); + eth_hw_addr_random(dev); + } + reset_umac(priv); err = bcmgenet_mii_init(dev); @@ -3771,6 +3786,12 @@ static int bcmgenet_suspend(struct device *d) static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); +static const struct acpi_device_id genet_acpi_match[] = { + { "BCM6E4E", (kernel_ulong_t)&bcm2711_plat_data }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, genet_acpi_match); + static struct platform_driver bcmgenet_driver = { .probe = bcmgenet_probe, .remove = bcmgenet_remove, @@ -3779,6 +3800,7 @@ static struct platform_driver bcmgenet_driver = { .name = "bcmgenet", .of_match_table = bcmgenet_match, .pm = &bcmgenet_pm_ops, + .acpi_match_table = ACPI_PTR(genet_acpi_match), }, }; module_platform_driver(bcmgenet_driver); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 10244941a7a6..d3003cb1bb09 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -5,7 +5,7 @@ * Copyright (c) 2014-2017 Broadcom */ - +#include <linux/acpi.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/wait.h> @@ -312,7 +312,8 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) int bcmgenet_mii_probe(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); - struct device_node *dn = priv->pdev->dev.of_node; + struct device *kdev = &priv->pdev->dev; + struct device_node *dn = kdev->of_node; struct phy_device *phydev; u32 phy_flags = 0; int ret; @@ -335,7 +336,27 @@ int bcmgenet_mii_probe(struct net_device *dev) return -ENODEV; } } else { - phydev = dev->phydev; + if (has_acpi_companion(kdev)) { + char mdio_bus_id[MII_BUS_ID_SIZE]; + struct mii_bus *unimacbus; + + snprintf(mdio_bus_id, MII_BUS_ID_SIZE, "%s-%d", + UNIMAC_MDIO_DRV_NAME, priv->pdev->id); + + unimacbus = mdio_find_bus(mdio_bus_id); + if (!unimacbus) { + pr_err("Unable to find mii\n"); + return -ENODEV; + } + phydev = phy_find_first(unimacbus); + put_device(&unimacbus->dev); + if (!phydev) { + pr_err("Unable to find PHY\n"); + return -ENODEV; + } + } else { + phydev = dev->phydev; + } phydev->dev_flags = phy_flags; ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup, @@ -456,9 +477,12 @@ static int bcmgenet_mii_register(struct bcmgenet_priv *priv) /* Retain this platform_device pointer for later cleanup */ priv->mii_pdev = ppdev; ppdev->dev.parent = &pdev->dev; - ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv); - if (pdata) + if (dn) + ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv); + else if (pdata) bcmgenet_mii_pdata_init(priv, &ppd); + else + ppd.phy_mask = ~0; ret = platform_device_add_resources(ppdev, &res, 1); if (ret) @@ -478,12 +502,33 @@ out: return ret; } +static int bcmgenet_phy_interface_init(struct bcmgenet_priv *priv) +{ + struct device *kdev = &priv->pdev->dev; + int phy_mode = device_get_phy_mode(kdev); + + if (phy_mode < 0) { + dev_err(kdev, "invalid PHY mode property\n"); + return phy_mode; + } + + priv->phy_interface = phy_mode; + + /* We need to specifically look up whether this PHY interface is + * internal or not *before* we even try to probe the PHY driver + * over MDIO as we may have shut down the internal PHY for power + * saving purposes. + */ + if (priv->phy_interface == PHY_INTERFACE_MODE_INTERNAL) + priv->internal_phy = true; + + return 0; +} + static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) { struct device_node *dn = priv->pdev->dev.of_node; - struct device *kdev = &priv->pdev->dev; struct phy_device *phydev; - phy_interface_t phy_mode; int ret; /* Fetch the PHY phandle */ @@ -501,23 +546,12 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) } /* Get the link mode */ - ret = of_get_phy_mode(dn, &phy_mode); - if (ret) { - dev_err(kdev, "invalid PHY mode property\n"); + ret = bcmgenet_phy_interface_init(priv); + if (ret) return ret; - } - - priv->phy_interface = phy_mode; - - /* We need to specifically look up whether this PHY interface is internal - * or not *before* we even try to probe the PHY driver over MDIO as we - * may have shut down the internal PHY for power saving purposes. - */ - if (priv->phy_interface == PHY_INTERFACE_MODE_INTERNAL) - priv->internal_phy = true; /* Make sure we initialize MoCA PHYs with a link down */ - if (phy_mode == PHY_INTERFACE_MODE_MOCA) { + if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { phydev = of_phy_find_device(dn); if (phydev) { phydev->link = 0; @@ -582,10 +616,13 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) static int bcmgenet_mii_bus_init(struct bcmgenet_priv *priv) { - struct device_node *dn = priv->pdev->dev.of_node; + struct device *kdev = &priv->pdev->dev; + struct device_node *dn = kdev->of_node; if (dn) return bcmgenet_mii_of_init(priv); + else if (has_acpi_companion(kdev)) + return bcmgenet_phy_interface_init(priv); else return bcmgenet_mii_pd_init(priv); } diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 01a50a4b2113..d6588502a050 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -2504,12 +2504,7 @@ bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb) IPPROTO_TCP, 0); BNAD_UPDATE_CTR(bnad, tso4); } else { - struct ipv6hdr *ipv6h = ipv6_hdr(skb); - - ipv6h->payload_len = 0; - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, 0, - IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); BNAD_UPDATE_CTR(bnad, tso6); } diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index a3f0f27fc79a..ab827fb4b6b9 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -1200,7 +1200,6 @@ struct macb { unsigned int dma_burst_length; phy_interface_t phy_interface; - int speed; /* AT91RM9200 transmit */ struct sk_buff *skb; /* holds skb until xmit interrupt completes */ diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 2c28da1737fe..3a7c26b08607 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -571,37 +571,20 @@ static void macb_mac_config(struct phylink_config *config, unsigned int mode, old_ctrl = ctrl = macb_or_gem_readl(bp, NCFGR); - /* Clear all the bits we might set later */ - ctrl &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | MACB_BIT(PAE)); - if (bp->caps & MACB_CAPS_MACB_IS_EMAC) { if (state->interface == PHY_INTERFACE_MODE_RMII) ctrl |= MACB_BIT(RM9200_RMII); } else { - ctrl &= ~(GEM_BIT(GBE) | GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL)); - - /* We do not support MLO_PAUSE_RX yet */ - if (state->pause & MLO_PAUSE_TX) - ctrl |= MACB_BIT(PAE); + ctrl &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL)); if (state->interface == PHY_INTERFACE_MODE_SGMII) ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); } - if (state->speed == SPEED_1000) - ctrl |= GEM_BIT(GBE); - else if (state->speed == SPEED_100) - ctrl |= MACB_BIT(SPD); - - if (state->duplex) - ctrl |= MACB_BIT(FD); - /* Apply the new configuration, if any */ if (old_ctrl ^ ctrl) macb_or_gem_writel(bp, NCFGR, ctrl); - bp->speed = state->speed; - spin_unlock_irqrestore(&bp->lock, flags); } @@ -626,16 +609,42 @@ static void macb_mac_link_down(struct phylink_config *config, unsigned int mode, netif_tx_stop_all_queues(ndev); } -static void macb_mac_link_up(struct phylink_config *config, unsigned int mode, - phy_interface_t interface, struct phy_device *phy) +static void macb_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) { struct net_device *ndev = to_net_dev(config->dev); struct macb *bp = netdev_priv(ndev); struct macb_queue *queue; + unsigned long flags; unsigned int q; + u32 ctrl; + + spin_lock_irqsave(&bp->lock, flags); + + ctrl = macb_or_gem_readl(bp, NCFGR); + + ctrl &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); + + if (speed == SPEED_100) + ctrl |= MACB_BIT(SPD); + + if (duplex) + ctrl |= MACB_BIT(FD); if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) { - macb_set_tx_clk(bp->tx_clk, bp->speed, ndev); + ctrl &= ~(GEM_BIT(GBE) | MACB_BIT(PAE)); + + if (speed == SPEED_1000) + ctrl |= GEM_BIT(GBE); + + /* We do not support MLO_PAUSE_RX yet */ + if (tx_pause) + ctrl |= MACB_BIT(PAE); + + macb_set_tx_clk(bp->tx_clk, speed, ndev); /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down * cleared the pipeline and control registers. @@ -648,6 +657,10 @@ static void macb_mac_link_up(struct phylink_config *config, unsigned int mode, bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP)); } + macb_or_gem_writel(bp, NCFGR, ctrl); + + spin_unlock_irqrestore(&bp->lock, flags); + /* Enable Rx and Tx */ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE)); @@ -4429,8 +4442,6 @@ static int macb_probe(struct platform_device *pdev) else bp->phy_interface = interface; - bp->speed = SPEED_UNKNOWN; - /* IP specific init */ err = init(pdev); if (err) diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h index b19e4376ba76..401827b82aa1 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h @@ -79,7 +79,7 @@ struct ch_mem_range { uint32_t addr; uint32_t len; uint32_t version; - uint8_t buf[0]; + uint8_t buf[]; }; struct ch_qset_params { diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h b/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h index 852c399a8b0a..68bb5f39f3f1 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h +++ b/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h @@ -1448,7 +1448,7 @@ struct cpl_rdma_terminate { #endif __be32 msn; __be32 mo; - __u8 data[0]; + __u8 data[]; }; /* cpl_rdma_terminate.tid_len fields */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h index a0e0ae19649f..290c1058069a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h @@ -29,7 +29,7 @@ struct clip_tbl { atomic_t nfree; struct list_head ce_free_head; void *cl_list; - struct list_head hash_list[0]; + struct list_head hash_list[]; }; enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h index f5be3ee1bdb4..dcab94cc2dee 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h @@ -82,7 +82,7 @@ struct cudbg_ulprx_la { struct cudbg_tp_la { u32 size; u32 mode; - u8 data[0]; + u8 data[]; }; static const char * const cudbg_region[] = { @@ -134,7 +134,7 @@ struct cudbg_meminfo { struct cudbg_cim_pif_la { int size; - u8 data[0]; + u8 data[]; }; struct cudbg_clk_info { @@ -339,13 +339,13 @@ struct cudbg_qdesc_entry { u32 qid; u32 desc_size; u32 num_desc; - u8 data[0]; /* Must be last */ + u8 data[]; /* Must be last */ }; struct cudbg_qdesc_info { u32 qdesc_entry_size; u32 num_queues; - u8 data[0]; /* Must be last */ + u8 data[]; /* Must be last */ }; #define IREG_NUM_ELEM 4 diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index de30d61af065..fe883cb1a7af 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -984,7 +984,7 @@ static const char * const devlog_facility_strings[] = { struct devlog_info { unsigned int nentries; /* number of entries in log[] */ unsigned int first; /* first [temporal] entry in log[] */ - struct fw_devlog_e log[0]; /* Firmware Device Log */ + struct fw_devlog_e log[]; /* Firmware Device Log */ }; /* Dump a Firmaware Device Log entry. diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h index ba95e13d52da..1471cf0deb58 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h @@ -49,7 +49,7 @@ struct seq_tab { unsigned int rows; /* # of entries */ unsigned char width; /* size in bytes of each entry */ unsigned char skip_first; /* whether the first line is a header */ - char data[0]; /* the table data */ + char data[]; /* the table data */ }; static inline unsigned int hex2val(char c) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32_parse.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32_parse.h index a4b99edcc339..125868c6770a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32_parse.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32_parse.h @@ -289,6 +289,6 @@ struct cxgb4_link { struct cxgb4_tc_u32_table { unsigned int size; /* number of entries in table */ - struct cxgb4_link table[0]; /* Jump table */ + struct cxgb4_link table[]; /* Jump table */ }; #endif /* __CXGB4_TC_U32_PARSE_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 1a16449e9deb..12c3354172cd 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -59,7 +59,7 @@ struct l2t_data { rwlock_t lock; atomic_t nfree; /* number of free entries */ struct l2t_entry *rover; /* starting point for next allocation */ - struct l2t_entry l2tab[0]; /* MUST BE LAST */ + struct l2t_entry l2tab[]; /* MUST BE LAST */ }; static inline unsigned int vlan_prio(const struct l2t_entry *e) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.h b/drivers/net/ethernet/chelsio/cxgb4/sched.h index 5cc74a5a1774..5f8b871d79af 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.h +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.h @@ -82,7 +82,7 @@ struct sched_class { struct sched_table { /* per port scheduling table */ u8 sched_size; - struct sched_class tab[0]; + struct sched_class tab[]; }; static inline bool can_sched(struct net_device *dev) diff --git a/drivers/net/ethernet/chelsio/cxgb4/smt.h b/drivers/net/ethernet/chelsio/cxgb4/smt.h index 1268d6e93a47..541249d78914 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/smt.h +++ b/drivers/net/ethernet/chelsio/cxgb4/smt.h @@ -66,7 +66,7 @@ struct smt_entry { struct smt_data { unsigned int smt_size; rwlock_t lock; - struct smt_entry smtab[0]; + struct smt_entry smtab[]; }; struct smt_data *t4_init_smt(void); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 575c6abcdae7..7d874f03d6c5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -1511,7 +1511,7 @@ struct ulptx_sgl { __be32 cmd_nsge; __be32 len0; __be64 addr0; - struct ulptx_sge_pair sge[0]; + struct ulptx_sge_pair sge[]; }; struct ulptx_idata { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index accad1101ad1..703effc00a05 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -737,7 +737,7 @@ struct fw_flowc_mnemval { struct fw_flowc_wr { __be32 op_to_nparams; __be32 flowid_len16; - struct fw_flowc_mnemval mnemval[0]; + struct fw_flowc_mnemval mnemval[]; }; #define FW_FLOWC_WR_NPARAMS_S 0 diff --git a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h index 7b02c200dd1e..1b4156461ba1 100644 --- a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h +++ b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h @@ -122,7 +122,7 @@ struct cxgbi_ppm_pool { unsigned int base; /* base index */ unsigned int next; /* next possible free index */ spinlock_t lock; /* ppm pool lock */ - unsigned long bmap[0]; + unsigned long bmap[]; } ____cacheline_aligned_in_smp; struct cxgbi_ppm { @@ -145,7 +145,7 @@ struct cxgbi_ppm { unsigned int next; unsigned int max_index_in_edram; unsigned long *ppod_bmap; - struct cxgbi_ppod_data ppod_data[0]; + struct cxgbi_ppod_data ppod_data[]; }; #define DDP_THRESHOLD 512 diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index ddf60dc9ad16..3fc858b2c87b 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -696,8 +696,7 @@ static void enic_preload_tcp_csum(struct sk_buff *skb) tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } else if (skb->protocol == cpu_to_be16(ETH_P_IPV6)) { - tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); } } diff --git a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h index fef5a0a0663d..fcc4a3ccdd94 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h +++ b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h @@ -541,7 +541,7 @@ struct vnic_devcmd_notify { struct vnic_devcmd_provinfo { u8 oui[3]; u8 type; - u8 data[0]; + u8 data[]; }; /* These are used in flags field of different filters to denote @@ -648,9 +648,9 @@ enum { #define FILTER_MAX_BUF_SIZE 100 struct filter_tlv { - u_int32_t type; - u_int32_t length; - u_int32_t val[0]; + u32 type; + u32 length; + u32 val[]; }; enum { diff --git a/drivers/net/ethernet/cisco/enic/vnic_vic.h b/drivers/net/ethernet/cisco/enic/vnic_vic.h index 9ef81f148351..057776908828 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_vic.h +++ b/drivers/net/ethernet/cisco/enic/vnic_vic.h @@ -59,7 +59,7 @@ struct vic_provinfo { u16 type; u16 length; u8 value[0]; - } tlv[0]; + } tlv[]; } __packed; #define VIC_PROVINFO_ADD_TLV(vp, tlvtype, tlvlen, data) \ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 7ff147e89426..b6c46639aa4c 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1704,10 +1704,15 @@ static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct dpaa2_eth_priv *priv = netdev_priv(dev); + if (cmd == SIOCSHWTSTAMP) return dpaa2_eth_ts_ioctl(dev, rq, cmd); - return -EINVAL; + if (priv->mac) + return phylink_mii_ioctl(priv->mac->phylink, rq, cmd); + + return -EOPNOTSUPP; } static bool xdp_mtu_valid(struct dpaa2_eth_priv *priv, int mtu) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index 96676abcebd5..94347c695233 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -79,6 +79,16 @@ static void dpaa2_eth_get_drvinfo(struct net_device *net_dev, sizeof(drvinfo->bus_info)); } +static int dpaa2_eth_nway_reset(struct net_device *net_dev) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + + if (priv->mac) + return phylink_ethtool_nway_reset(priv->mac->phylink); + + return -EOPNOTSUPP; +} + static int dpaa2_eth_get_link_ksettings(struct net_device *net_dev, struct ethtool_link_ksettings *link_settings) @@ -761,6 +771,7 @@ static int dpaa2_eth_get_ts_info(struct net_device *dev, const struct ethtool_ops dpaa2_ethtool_ops = { .get_drvinfo = dpaa2_eth_get_drvinfo, + .nway_reset = dpaa2_eth_nway_reset, .get_link = ethtool_op_get_link, .get_link_ksettings = dpaa2_eth_get_link_ksettings, .set_link_ksettings = dpaa2_eth_set_link_ksettings, diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index 84233e467ed1..3ee236c5fc37 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -123,49 +123,60 @@ static void dpaa2_mac_config(struct phylink_config *config, unsigned int mode, struct dpmac_link_state *dpmac_state = &mac->state; int err; - if (state->speed != SPEED_UNKNOWN) - dpmac_state->rate = state->speed; - - if (state->duplex != DUPLEX_UNKNOWN) { - if (!state->duplex) - dpmac_state->options |= DPMAC_LINK_OPT_HALF_DUPLEX; - else - dpmac_state->options &= ~DPMAC_LINK_OPT_HALF_DUPLEX; - } - if (state->an_enabled) dpmac_state->options |= DPMAC_LINK_OPT_AUTONEG; else dpmac_state->options &= ~DPMAC_LINK_OPT_AUTONEG; - if (state->pause & MLO_PAUSE_RX) - dpmac_state->options |= DPMAC_LINK_OPT_PAUSE; - else - dpmac_state->options &= ~DPMAC_LINK_OPT_PAUSE; - - if (!!(state->pause & MLO_PAUSE_RX) ^ !!(state->pause & MLO_PAUSE_TX)) - dpmac_state->options |= DPMAC_LINK_OPT_ASYM_PAUSE; - else - dpmac_state->options &= ~DPMAC_LINK_OPT_ASYM_PAUSE; - err = dpmac_set_link_state(mac->mc_io, 0, mac->mc_dev->mc_handle, dpmac_state); if (err) - netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err); + netdev_err(mac->net_dev, "%s: dpmac_set_link_state() = %d\n", + __func__, err); } -static void dpaa2_mac_link_up(struct phylink_config *config, unsigned int mode, - phy_interface_t interface, struct phy_device *phy) +static void dpaa2_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) { struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config); struct dpmac_link_state *dpmac_state = &mac->state; int err; dpmac_state->up = 1; + + if (mac->if_link_type == DPMAC_LINK_TYPE_PHY) { + /* If the DPMAC is configured for PHY mode, we need + * to pass the link parameters to the MC firmware. + */ + dpmac_state->rate = speed; + + if (duplex == DUPLEX_HALF) + dpmac_state->options |= DPMAC_LINK_OPT_HALF_DUPLEX; + else if (duplex == DUPLEX_FULL) + dpmac_state->options &= ~DPMAC_LINK_OPT_HALF_DUPLEX; + + /* This is lossy; the firmware really should take the pause + * enablement status rather than pause/asym pause status. + */ + if (rx_pause) + dpmac_state->options |= DPMAC_LINK_OPT_PAUSE; + else + dpmac_state->options &= ~DPMAC_LINK_OPT_PAUSE; + + if (rx_pause ^ tx_pause) + dpmac_state->options |= DPMAC_LINK_OPT_ASYM_PAUSE; + else + dpmac_state->options &= ~DPMAC_LINK_OPT_ASYM_PAUSE; + } + err = dpmac_set_link_state(mac->mc_io, 0, mac->mc_dev->mc_handle, dpmac_state); if (err) - netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err); + netdev_err(mac->net_dev, "%s: dpmac_set_link_state() = %d\n", + __func__, err); } static void dpaa2_mac_link_down(struct phylink_config *config, @@ -238,6 +249,8 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac) goto err_close_dpmac; } + mac->if_link_type = attr.link_type; + dpmac_node = dpaa2_mac_get_node(attr.id); if (!dpmac_node) { netdev_err(net_dev, "No dpmac@%d node found.\n", attr.id); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h index 4da8079b9155..2130d9c7d40e 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h @@ -20,6 +20,7 @@ struct dpaa2_mac { struct phylink_config phylink_config; struct phylink *phylink; phy_interface_t if_mode; + enum dpmac_link_type if_link_type; }; bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev, diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index fe942de19597..f86283411f4d 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config FSL_ENETC tristate "ENETC PF driver" - depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST) + depends on PCI && PCI_MSI select FSL_ENETC_MDIO select PHYLIB help @@ -13,7 +13,7 @@ config FSL_ENETC config FSL_ENETC_VF tristate "ENETC VF driver" - depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST) + depends on PCI && PCI_MSI select PHYLIB help This driver supports NXP ENETC gigabit ethernet controller PCIe @@ -23,7 +23,7 @@ config FSL_ENETC_VF config FSL_ENETC_MDIO tristate "ENETC MDIO driver" - depends on PCI && (ARCH_LAYERSCAPE || COMPILE_TEST) + depends on PCI help This driver supports NXP ENETC Central MDIO controller as a PCIe physical function (PF) device. diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index dd4a227ffc7a..9938f7a5fc0a 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -163,7 +163,7 @@ struct enetc_int_vector { char name[ENETC_INT_NAME_MAX]; struct enetc_bdr rx_ring ____cacheline_aligned_in_smp; - struct enetc_bdr tx_ring[0]; + struct enetc_bdr tx_ring[]; }; struct enetc_cls_rule { diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index 62554f28ce07..da134e211c1a 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -588,7 +588,7 @@ struct tgs_gcl_data { __le32 bth; __le32 ct; __le32 cte; - struct gce entry[0]; + struct gce entry[]; }; struct enetc_cbd { diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index f79e57f735b3..bd898f5b4da5 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -584,7 +584,7 @@ struct fec_enet_private { int pps_enable; unsigned int next_counter; - u64 ethtool_stats[0]; + u64 ethtool_stats[]; }; void fec_ptp_init(struct platform_device *pdev, int irq_idx); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 4432a59904c7..12edd4e358f8 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3793,6 +3793,7 @@ static struct platform_driver fec_driver = { .name = DRIVER_NAME, .pm = &fec_pm_ops, .of_match_table = fec_dt_ids, + .suppress_bind_attrs = true, }, .id_table = fec_devtype, .probe = fec_probe, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h index 2721f1f1ab42..0f0e16f9afc0 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h @@ -92,7 +92,7 @@ struct ppe_common_cb { u8 comm_index; /*ppe_common index*/ u32 ppe_num; - struct hns_ppe_cb ppe_cb[0]; + struct hns_ppe_cb ppe_cb[]; }; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h index 3741befb914e..a9f805925699 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h @@ -108,7 +108,7 @@ struct rcb_common_cb { u32 ring_num; u32 desc_num; /* desc num per queue*/ - struct ring_pair_cb ring_pair_cb[0]; + struct ring_pair_cb ring_pair_cb[]; }; int hns_rcb_buf_size2type(u32 buf_size); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 1d4ffc5f408a..e1d88095a77e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -260,6 +260,8 @@ static void hns3_dbg_help(struct hnae3_handle *h) dev_info(&h->pdev->dev, "dump m7 info\n"); dev_info(&h->pdev->dev, "dump ncl_config <offset> <length>(in hex)\n"); dev_info(&h->pdev->dev, "dump mac tnl status\n"); + dev_info(&h->pdev->dev, "dump loopback\n"); + dev_info(&h->pdev->dev, "dump qs shaper [qs id]\n"); memset(printf_buf, 0, HNS3_DBG_BUF_LEN); strncat(printf_buf, "dump reg [[bios common] [ssu <port_id>]", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index c03856e63320..3f59a1924390 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -736,7 +736,7 @@ static int hns3_check_ksettings_param(const struct net_device *netdev, if (ops->get_media_type) ops->get_media_type(handle, &media_type, &module_type); - if (cmd->base.duplex != DUPLEX_FULL && + if (cmd->base.duplex == DUPLEX_HALF && media_type != HNAE3_MEDIA_TYPE_COPPER) { netdev_err(netdev, "only copper port supports half duplex!"); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 67fad80035d3..6295cf93c350 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -310,8 +310,9 @@ static void hclge_title_idx_print(struct hclge_dev *hdev, bool flag, int index, char *false_buf) { if (flag) - dev_info(&hdev->pdev->dev, "%s(%d): %s\n", title_buf, index, - true_buf); + dev_info(&hdev->pdev->dev, "%s(%d): %s weight: %u\n", + title_buf, index, true_buf, + hdev->tm_info.pg_info[0].tc_dwrr[index]); else dev_info(&hdev->pdev->dev, "%s(%d): %s\n", title_buf, index, false_buf); @@ -339,7 +340,8 @@ static void hclge_dbg_dump_tc(struct hclge_dev *hdev) ets_weight = (struct hclge_ets_tc_weight_cmd *)desc.data; - dev_info(&hdev->pdev->dev, "dump tc\n"); + dev_info(&hdev->pdev->dev, "dump tc: %u tc enabled\n", + hdev->tm_info.num_tc); dev_info(&hdev->pdev->dev, "weight_offset: %u\n", ets_weight->weight_offset); @@ -1169,6 +1171,57 @@ static void hclge_dbg_dump_ncl_config(struct hclge_dev *hdev, } } +static void hclge_dbg_dump_loopback(struct hclge_dev *hdev, + const char *cmd_buf) +{ + struct phy_device *phydev = hdev->hw.mac.phydev; + struct hclge_config_mac_mode_cmd *req_app; + struct hclge_serdes_lb_cmd *req_serdes; + struct hclge_desc desc; + u8 loopback_en; + int ret; + + req_app = (struct hclge_config_mac_mode_cmd *)desc.data; + req_serdes = (struct hclge_serdes_lb_cmd *)desc.data; + + dev_info(&hdev->pdev->dev, "mac id: %u\n", hdev->hw.mac.mac_id); + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, true); + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to dump app loopback status, ret = %d\n", ret); + return; + } + + loopback_en = hnae3_get_bit(le32_to_cpu(req_app->txrx_pad_fcs_loop_en), + HCLGE_MAC_APP_LP_B); + dev_info(&hdev->pdev->dev, "app loopback: %s\n", + loopback_en ? "on" : "off"); + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK, true); + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to dump serdes loopback status, ret = %d\n", + ret); + return; + } + + loopback_en = req_serdes->enable & HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B; + dev_info(&hdev->pdev->dev, "serdes serial loopback: %s\n", + loopback_en ? "on" : "off"); + + loopback_en = req_serdes->enable & + HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B; + dev_info(&hdev->pdev->dev, "serdes parallel loopback: %s\n", + loopback_en ? "on" : "off"); + + if (phydev) + dev_info(&hdev->pdev->dev, "phy loopback: %s\n", + phydev->loopback_enabled ? "on" : "off"); +} + /* hclge_dbg_dump_mac_tnl_status: print message about mac tnl interrupt * @hdev: pointer to struct hclge_dev */ @@ -1269,6 +1322,7 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf) { #define DUMP_REG "dump reg" #define DUMP_TM_MAP "dump tm map" +#define DUMP_LOOPBACK "dump loopback" struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; @@ -1302,6 +1356,9 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf) &cmd_buf[sizeof("dump ncl_config")]); } else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) { hclge_dbg_dump_mac_tnl_status(hdev); + } else if (strncmp(cmd_buf, DUMP_LOOPBACK, + strlen(DUMP_LOOPBACK)) == 0) { + hclge_dbg_dump_loopback(hdev, &cmd_buf[sizeof(DUMP_LOOPBACK)]); } else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) { hclge_dbg_dump_qs_shaper(hdev, &cmd_buf[sizeof("dump qs shaper")]); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 492bc9446463..89d352385260 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -824,6 +824,8 @@ static void hclge_get_mac_stat(struct hnae3_handle *handle, static int hclge_parse_func_status(struct hclge_dev *hdev, struct hclge_func_status_cmd *status) { +#define HCLGE_MAC_ID_MASK 0xF + if (!(status->pf_state & HCLGE_PF_STATE_DONE)) return -EINVAL; @@ -833,6 +835,7 @@ static int hclge_parse_func_status(struct hclge_dev *hdev, else hdev->flag &= ~HCLGE_FLAG_MAIN; + hdev->hw.mac.mac_id = status->mac_id & HCLGE_MAC_ID_MASK; return 0; } @@ -9073,8 +9076,8 @@ init_nic_err: static int hclge_init_roce_client_instance(struct hnae3_ae_dev *ae_dev, struct hclge_vport *vport) { - struct hnae3_client *client = vport->roce.client; struct hclge_dev *hdev = ae_dev->priv; + struct hnae3_client *client; int rst_cnt; int ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index f78cbb4cc85e..71df23d5f1b4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -249,6 +249,7 @@ enum HCLGE_MAC_DUPLEX { #define QUERY_ACTIVE_SPEED 1 struct hclge_mac { + u8 mac_id; u8 phy_addr; u8 flag; u8 media_type; /* port media type, e.g. fibre/copper/backplane */ diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 2bced34c19ba..f7103356ef56 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -2715,11 +2715,7 @@ static int e1000_tso(struct e1000_adapter *adapter, cmd_length = E1000_TXD_CMD_IP; ipcse = skb_transport_offset(skb) - 1; } else if (skb_is_gso_v6(skb)) { - ipv6_hdr(skb)->payload_len = 0; - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); ipcse = 0; } ipcss = skb_network_offset(skb); diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index adce7e319b9e..9e7881db7859 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -897,6 +897,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) case e1000_pch_cnp: /* fall through */ case e1000_pch_tgp: + case e1000_pch_adp: mask |= BIT(18); break; default: @@ -1561,6 +1562,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: fext_nvm11 = er32(FEXTNVM11); fext_nvm11 &= ~E1000_FEXTNVM11_DISABLE_MULR_FIX; ew32(FEXTNVM11, fext_nvm11); diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index f556163481cb..b1447221669e 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -97,6 +97,11 @@ struct e1000_hw; #define E1000_DEV_ID_PCH_TGP_I219_LM14 0x15F9 #define E1000_DEV_ID_PCH_TGP_I219_V14 0x15FA #define E1000_DEV_ID_PCH_TGP_I219_LM15 0x15F4 +#define E1000_DEV_ID_PCH_TGP_I219_V15 0x15F5 +#define E1000_DEV_ID_PCH_ADP_I219_LM16 0x1A1E +#define E1000_DEV_ID_PCH_ADP_I219_V16 0x1A1F +#define E1000_DEV_ID_PCH_ADP_I219_LM17 0x1A1C +#define E1000_DEV_ID_PCH_ADP_I219_V17 0x1A1D #define E1000_REVISION_4 4 @@ -121,6 +126,7 @@ enum e1000_mac_type { e1000_pch_spt, e1000_pch_cnp, e1000_pch_tgp, + e1000_pch_adp, }; enum e1000_media_type { diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index b4135c50e905..735bf25952fc 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -317,6 +317,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: if (e1000_phy_is_accessible_pchlan(hw)) break; @@ -460,6 +461,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: /* In case the PHY needs to be in mdio slow mode, * set slow mode and try to get the PHY id again. */ @@ -703,6 +705,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: case e1000_pchlan: /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; @@ -1642,6 +1645,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: rc = e1000_init_phy_params_pchlan(hw); break; default: @@ -2095,6 +2099,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; break; default: @@ -3133,6 +3138,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: bank1_offset = nvm->flash_bank_size; act_offset = E1000_ICH_NVM_SIG_WORD; @@ -4077,6 +4083,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: word = NVM_COMPAT; valid_csum_mask = NVM_COMPAT_VALID_CSUM; break; diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index e531976f8a67..51512a73fdd0 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -1363,7 +1363,7 @@ s32 e1000e_get_hw_semaphore(struct e1000_hw *hw) if (!(swsm & E1000_SWSM_SMBI)) break; - usleep_range(50, 100); + udelay(100); i++; } @@ -1381,7 +1381,7 @@ s32 e1000e_get_hw_semaphore(struct e1000_hw *hw) if (er32(SWSM) & E1000_SWSM_SWESMBI) break; - usleep_range(50, 100); + udelay(100); } if (i == timeout) { diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index db4ea58bac82..1e1625122596 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3536,6 +3536,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) break; case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { /* Stable 24MHz frequency */ incperiod = INCPERIOD_24MHZ; @@ -3807,7 +3808,7 @@ static void e1000_flush_tx_ring(struct e1000_adapter *adapter) tdt = er32(TDT(0)); BUG_ON(tdt != tx_ring->next_to_use); tx_desc = E1000_TX_DESC(*tx_ring, tx_ring->next_to_use); - tx_desc->buffer_addr = tx_ring->dma; + tx_desc->buffer_addr = cpu_to_le64(tx_ring->dma); tx_desc->lower.data = cpu_to_le32(txd_lower | size); tx_desc->upper.data = 0; @@ -4049,6 +4050,7 @@ void e1000e_reset(struct e1000_adapter *adapter) case e1000_pch_cnp: /* fall-through */ case e1000_pch_tgp: + case e1000_pch_adp: fc->refresh_time = 0xFFFF; fc->pause_time = 0xFFFF; @@ -5462,10 +5464,7 @@ static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb, cmd_length = E1000_TXD_CMD_IP; ipcse = skb_transport_offset(skb) - 1; } else if (skb_is_gso_v6(skb)) { - ipv6_hdr(skb)->payload_len = 0; - tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); ipcse = 0; } ipcss = skb_network_offset(skb); @@ -7760,6 +7759,11 @@ static const struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM14), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V15), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_cnp }, { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */ }; diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index eaa5a0fb99f0..439fda2f5368 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -297,6 +297,7 @@ void e1000e_ptp_init(struct e1000_adapter *adapter) case e1000_pch_cnp: /* fall-through */ case e1000_pch_tgp: + case e1000_pch_adp: if ((hw->mac.type < e1000_pch_lpt) || (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) { adapter->ptp_clock_info.max_adj = 24000000 - 1; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index f306084ca12c..5b78362b82ac 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h @@ -41,7 +41,7 @@ struct fm10k_l2_accel { u16 count; u16 dglort; struct rcu_head rcu; - struct net_device *macvlan[0]; + struct net_device *macvlan[]; }; enum fm10k_ring_state_t { @@ -198,7 +198,7 @@ struct fm10k_q_vector { struct rcu_head rcu; /* to avoid race with update stats on free */ /* for dynamic allocation of rings associated with this q_vector */ - struct fm10k_ring ring[0] ____cacheline_internodealigned_in_smp; + struct fm10k_ring ring[] ____cacheline_internodealigned_in_smp; }; enum fm10k_ring_f_enum { @@ -218,7 +218,7 @@ struct fm10k_iov_data { unsigned int num_vfs; unsigned int next_vf_mbx; struct rcu_head rcu; - struct fm10k_vf_info vf_info[0]; + struct fm10k_vf_info vf_info[]; }; struct fm10k_udp_port { diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 4833187bd259..e95b8da45e07 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -334,13 +334,13 @@ int i40e_ddp_flash(struct net_device *netdev, struct ethtool_flash *flash); struct i40e_ddp_profile_list { u32 p_count; - struct i40e_profile_info p_info[0]; + struct i40e_profile_info p_info[]; }; struct i40e_ddp_old_profile_list { struct list_head list; size_t old_ddp_size; - u8 old_ddp_buf[0]; + u8 old_ddp_buf[]; }; /* macros related to FLX_PIT */ diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 62fe56ddcb6e..76361bd468db 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -3061,9 +3061,6 @@ static int iavf_delete_clsflower(struct iavf_adapter *adapter, static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter, struct flow_cls_offload *cls_flower) { - if (cls_flower->common.chain_index) - return -EOPNOTSUPP; - switch (cls_flower->command) { case FLOW_CLS_REPLACE: return iavf_configure_clsflower(adapter, cls_flower); @@ -3087,6 +3084,11 @@ static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter, static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) { + struct iavf_adapter *adapter = cb_priv; + + if (!tc_cls_can_offload_and_chain0(adapter->netdev, type_data)) + return -EOPNOTSUPP; + switch (type) { case TC_SETUP_CLSFLOWER: return iavf_setup_tc_cls_flower(cb_priv, type_data); diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index cb10abb14e11..2d51ceaa2c8c 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -212,6 +212,7 @@ enum ice_state { __ICE_SERVICE_SCHED, __ICE_SERVICE_DIS, __ICE_OICR_INTR_DIS, /* Global OICR interrupt disabled */ + __ICE_MDD_VF_PRINT_PENDING, /* set when MDD event handle */ __ICE_STATE_NBITS /* must be last */ }; @@ -340,6 +341,7 @@ enum ice_pf_flags { ICE_FLAG_FW_LLDP_AGENT, ICE_FLAG_ETHTOOL_CTXT, /* set when ethtool holds RTNL lock */ ICE_FLAG_LEGACY_RX, + ICE_FLAG_MDD_AUTO_RESET_VF, ICE_PF_FLAGS_NBITS /* must be last */ }; @@ -363,6 +365,8 @@ struct ice_pf { u16 num_vfs_supported; /* num VFs supported for this PF */ u16 num_vf_qps; /* num queue pairs per VF */ u16 num_vf_msix; /* num vectors per VF */ + /* used to ratelimit the MDD event logging */ + unsigned long last_printed_mdd_jiffies; DECLARE_BITMAP(state, __ICE_STATE_NBITS); DECLARE_BITMAP(flags, ICE_PF_FLAGS_NBITS); unsigned long *avail_txqs; /* bitmap to track PF Tx queue usage */ diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 6873998cf145..38b6ffb6ad2e 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1661,6 +1661,13 @@ struct ice_aqc_get_pkg_info_resp { struct ice_aqc_get_pkg_info pkg_info[1]; }; +/* Lan Queue Overflow Event (direct, 0x1001) */ +struct ice_aqc_event_lan_overflow { + __le32 prtdcb_ruptq; + __le32 qtx_ctl; + u8 reserved[8]; +}; + /** * struct ice_aq_desc - Admin Queue (AQ) descriptor * @flags: ICE_AQ_FLAG_* flags @@ -1730,6 +1737,7 @@ struct ice_aq_desc { struct ice_aqc_alloc_free_res_cmd sw_res_ctrl; struct ice_aqc_set_event_mask set_event_mask; struct ice_aqc_get_link_status get_link_status; + struct ice_aqc_event_lan_overflow lan_overflow; } params; }; @@ -1860,6 +1868,9 @@ enum ice_adminq_opc { ice_aqc_opc_update_pkg = 0x0C42, ice_aqc_opc_get_pkg_info_list = 0x0C43, + /* Standalone Commands/Events */ + ice_aqc_opc_event_lan_overflow = 0x1001, + /* debug commands */ ice_aqc_opc_fw_logging = 0xFF09, ice_aqc_opc_fw_logging_info = 0xFF10, diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 81885efadc7a..a19cd6f5436b 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -203,8 +203,7 @@ static void ice_cfg_itr_gran(struct ice_hw *hw) */ static u16 ice_calc_q_handle(struct ice_vsi *vsi, struct ice_ring *ring, u8 tc) { - WARN_ONCE(ice_ring_is_xdp(ring) && tc, - "XDP ring can't belong to TC other than 0"); + WARN_ONCE(ice_ring_is_xdp(ring) && tc, "XDP ring can't belong to TC other than 0\n"); /* Idea here for calculation is that we subtract the number of queue * count from TC that ring belongs to from it's absolute queue index @@ -247,7 +246,6 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) */ switch (vsi->type) { case ICE_VSI_LB: - /* fall through */ case ICE_VSI_PF: tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; break; @@ -387,8 +385,8 @@ int ice_setup_rx_ctx(struct ice_ring *ring) /* Enable Flexible Descriptors in the queue context which * allows this driver to select a specific receive descriptor format */ + regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); if (vsi->type != ICE_VSI_VF) { - regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & QRXFLXP_CNTXT_RXDID_IDX_M; @@ -399,8 +397,12 @@ int ice_setup_rx_ctx(struct ice_ring *ring) regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) & QRXFLXP_CNTXT_RXDID_PRIO_M; - wr32(hw, QRXFLXP_CNTXT(pf_q), regval); + } else { + regval &= ~(QRXFLXP_CNTXT_RXDID_IDX_M | + QRXFLXP_CNTXT_RXDID_PRIO_M | + QRXFLXP_CNTXT_TS_M); } + wr32(hw, QRXFLXP_CNTXT(pf_q), regval); /* Absolute queue number out of 2K needs to be passed */ err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q); @@ -459,17 +461,20 @@ int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg) } /** - * ice_vsi_ctrl_rx_ring - Start or stop a VSI's Rx ring + * ice_vsi_ctrl_one_rx_ring - start/stop VSI's Rx ring with no busy wait * @vsi: the VSI being configured - * @ena: start or stop the Rx rings - * @rxq_idx: Rx queue index + * @ena: start or stop the Rx ring + * @rxq_idx: 0-based Rx queue index for the VSI passed in + * @wait: wait or don't wait for configuration to finish in hardware + * + * Return 0 on success and negative on error. */ -int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx) +int +ice_vsi_ctrl_one_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx, bool wait) { int pf_q = vsi->rxq_map[rxq_idx]; struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; - int ret = 0; u32 rx_reg; rx_reg = rd32(hw, QRX_CTRL(pf_q)); @@ -485,13 +490,30 @@ int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx) rx_reg &= ~QRX_CTRL_QENA_REQ_M; wr32(hw, QRX_CTRL(pf_q), rx_reg); - /* wait for the change to finish */ - ret = ice_pf_rxq_wait(pf, pf_q, ena); - if (ret) - dev_err(ice_pf_to_dev(pf), "VSI idx %d Rx ring %d %sable timeout\n", - vsi->idx, pf_q, (ena ? "en" : "dis")); + if (!wait) + return 0; + + ice_flush(hw); + return ice_pf_rxq_wait(pf, pf_q, ena); +} - return ret; +/** + * ice_vsi_wait_one_rx_ring - wait for a VSI's Rx ring to be stopped/started + * @vsi: the VSI being configured + * @ena: true/false to verify Rx ring has been enabled/disabled respectively + * @rxq_idx: 0-based Rx queue index for the VSI passed in + * + * This routine will wait for the given Rx queue of the VSI to reach the + * enabled or disabled state. Returns -ETIMEDOUT in case of failing to reach + * the requested state after multiple retries; else will return 0 in case of + * success. + */ +int ice_vsi_wait_one_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx) +{ + int pf_q = vsi->rxq_map[rxq_idx]; + struct ice_pf *pf = vsi->back; + + return ice_pf_rxq_wait(pf, pf_q, ena); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h index 407995e8e944..44efdb627043 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.h +++ b/drivers/net/ethernet/intel/ice/ice_base.h @@ -8,7 +8,9 @@ int ice_setup_rx_ctx(struct ice_ring *ring); int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg); -int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx); +int +ice_vsi_ctrl_one_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx, bool wait); +int ice_vsi_wait_one_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx); int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi); void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); void ice_vsi_free_q_vectors(struct ice_vsi *vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 04d5db0a25bf..1fe54f08f162 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -6,7 +6,7 @@ #include "ice_adminq_cmd.h" #include "ice_flow.h" -#define ICE_PF_RESET_WAIT_COUNT 200 +#define ICE_PF_RESET_WAIT_COUNT 300 /** * ice_set_mac_type - Sets MAC type @@ -1181,7 +1181,7 @@ ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf, case ice_aqc_opc_release_res: if (le16_to_cpu(cmd->res_id) == ICE_AQC_RES_ID_GLBL_LOCK) break; - /* fall-through */ + fallthrough; default: mutex_lock(&ice_global_cfg_lock_sw); lock_acquired = true; @@ -2703,7 +2703,7 @@ __ice_aq_get_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M; break; } - /* fall-through */ + fallthrough; default: status = ICE_ERR_PARAM; goto ice_aq_get_set_rss_lut_exit; diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 7108fb41b604..16656b6c3d09 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -63,6 +63,26 @@ u8 ice_dcb_get_ena_tc(struct ice_dcbx_cfg *dcbcfg) } /** + * ice_dcb_get_mode - gets the DCB mode + * @port_info: pointer to port info structure + * @host: if set it's HOST if not it's MANAGED + */ +static u8 ice_dcb_get_mode(struct ice_port_info *port_info, bool host) +{ + u8 mode; + + if (host) + mode = DCB_CAP_DCBX_HOST; + else + mode = DCB_CAP_DCBX_LLD_MANAGED; + + if (port_info->local_dcbx_cfg.dcbx_mode & ICE_DCBX_MODE_CEE) + return (mode | DCB_CAP_DCBX_VER_CEE); + else + return (mode | DCB_CAP_DCBX_VER_IEEE); +} + +/** * ice_dcb_get_num_tc - Get the number of TCs from DCBX config * @dcbcfg: config to retrieve number of TCs from */ @@ -149,6 +169,43 @@ void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi) } /** + * ice_dcb_bwchk - check if ETS bandwidth input parameters are correct + * @pf: pointer to the PF struct + * @dcbcfg: pointer to DCB config structure + */ +int ice_dcb_bwchk(struct ice_pf *pf, struct ice_dcbx_cfg *dcbcfg) +{ + struct ice_dcb_ets_cfg *etscfg = &dcbcfg->etscfg; + u8 num_tc, total_bw = 0; + int i; + + /* returns number of contigous TCs and 1 TC for non-contigous TCs, + * since at least 1 TC has to be configured + */ + num_tc = ice_dcb_get_num_tc(dcbcfg); + + /* no bandwidth checks required if there's only one TC, so assign + * all bandwidth to TC0 and return + */ + if (num_tc == 1) { + etscfg->tcbwtable[0] = ICE_TC_MAX_BW; + return 0; + } + + for (i = 0; i < num_tc; i++) + total_bw += etscfg->tcbwtable[i]; + + if (!total_bw) { + etscfg->tcbwtable[0] = ICE_TC_MAX_BW; + } else if (total_bw != ICE_TC_MAX_BW) { + dev_err(ice_pf_to_dev(pf), "Invalid config, total bandwidth must equal 100\n"); + return -EINVAL; + } + + return 0; +} + +/** * ice_pf_dcb_cfg - Apply new DCB configuration * @pf: pointer to the PF struct * @new_cfg: DCBX config to apply @@ -182,6 +239,9 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) return ret; } + if (ice_dcb_bwchk(pf, new_cfg)) + return -EINVAL; + /* Store old config in case FW config fails */ old_cfg = kmemdup(curr_cfg, sizeof(*old_cfg), GFP_KERNEL); if (!old_cfg) @@ -605,14 +665,14 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) ice_cfg_sw_lldp(pf_vsi, false, true); - pf->dcbx_cap = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; + pf->dcbx_cap = ice_dcb_get_mode(port_info, true); return 0; } set_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags); - /* DCBX in FW and LLDP enabled in FW */ - pf->dcbx_cap = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_IEEE; + /* DCBX/LLDP enabled in FW, set DCBNL mode advertisement */ + pf->dcbx_cap = ice_dcb_get_mode(port_info, false); err = ice_dcb_init_cfg(pf, locked); if (err) @@ -772,6 +832,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, /* No change detected in DCBX configs */ if (!memcmp(&tmp_dcbx_cfg, &pi->local_dcbx_cfg, sizeof(tmp_dcbx_cfg))) { dev_dbg(dev, "No change detected in DCBX configuration.\n"); + pf->dcbx_cap = ice_dcb_get_mode(pi, false); goto out; } diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h index f15e5776f287..37680e815b02 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h @@ -20,6 +20,7 @@ u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg); u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index); int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked); +int ice_dcb_bwchk(struct ice_pf *pf, struct ice_dcbx_cfg *dcbcfg); void ice_pf_dcb_recfg(struct ice_pf *pf); void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi); int ice_init_pf_dcb(struct ice_pf *pf, bool locked); diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c index b61aba428adb..c4c12414083a 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c @@ -95,14 +95,12 @@ static int ice_dcbnl_setets(struct net_device *netdev, struct ieee_ets *ets) new_cfg->etsrec.prio_table[i] = ets->reco_prio_tc[i]; } - /* max_tc is a 1-8 value count of number of TC's, not a 0-7 value - * for the TC's index number. Add one to value if not zero, and - * for zero set it to the FW's default value - */ - if (max_tc) - max_tc++; - else - max_tc = IEEE_8021QAZ_MAX_TCS; + if (ice_dcb_bwchk(pf, new_cfg)) { + err = -EINVAL; + goto ets_out; + } + + max_tc = pf->hw.func_caps.common_cap.maxtc; new_cfg->etscfg.maxtcs = max_tc; @@ -119,6 +117,7 @@ static int ice_dcbnl_setets(struct net_device *netdev, struct ieee_ets *ets) if (err == ICE_DCB_NO_HW_CHG) err = ICE_DCB_HW_CHG_RST; +ets_out: mutex_unlock(&pf->tc_mutex); return err; } @@ -535,6 +534,30 @@ ice_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int prio, } /** + * ice_dcbnl_set_pg_tc_cfg_rx + * @netdev: relevant netdev struct + * @prio: corresponding user priority + * @prio_type: the traffic priority type + * @pgid: the PG ID + * @bw_pct: BW percentage for corresponding BWG + * @up_map: prio mapped to corresponding TC + * + * lldpad requires this function pointer to be non-NULL to complete CEE config. + */ +static void +ice_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, + int __always_unused prio, + u8 __always_unused prio_type, + u8 __always_unused pgid, + u8 __always_unused bw_pct, + u8 __always_unused up_map) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + dev_dbg(ice_pf_to_dev(pf), "Rx TC PG Config Not Supported.\n"); +} + +/** * ice_dcbnl_get_pg_bwg_cfg_rx - Get CEE PG BW Rx config * @netdev: pointer to netdev struct * @pgid: the corresponding traffic class @@ -554,6 +577,23 @@ ice_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int __always_unused pgid, } /** + * ice_dcbnl_set_pg_bwg_cfg_rx + * @netdev: the corresponding netdev + * @pgid: corresponding TC + * @bw_pct: BW percentage for given TC + * + * lldpad requires this function pointer to be non-NULL to complete CEE config. + */ +static void +ice_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int __always_unused pgid, + u8 __always_unused bw_pct) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + dev_dbg(ice_pf_to_dev(pf), "Rx BWG PG Config Not Supported.\n"); +} + +/** * ice_dcbnl_get_cap - Get DCBX capabilities of adapter * @netdev: pointer to netdev struct * @capid: the capability type @@ -799,6 +839,8 @@ static const struct dcbnl_rtnl_ops dcbnl_ops = { .getpermhwaddr = ice_dcbnl_get_perm_hw_addr, .setpgtccfgtx = ice_dcbnl_set_pg_tc_cfg_tx, .setpgbwgcfgtx = ice_dcbnl_set_pg_bwg_cfg_tx, + .setpgtccfgrx = ice_dcbnl_set_pg_tc_cfg_rx, + .setpgbwgcfgrx = ice_dcbnl_set_pg_bwg_cfg_rx, .getpgtccfgtx = ice_dcbnl_get_pg_tc_cfg_tx, .getpgbwgcfgtx = ice_dcbnl_get_pg_bwg_cfg_tx, .getpgtccfgrx = ice_dcbnl_get_pg_tc_cfg_rx, diff --git a/drivers/net/ethernet/intel/ice/ice_devids.h b/drivers/net/ethernet/intel/ice/ice_devids.h index ce63017c56c7..9d8194671f6a 100644 --- a/drivers/net/ethernet/intel/ice/ice_devids.h +++ b/drivers/net/ethernet/intel/ice/ice_devids.h @@ -5,12 +5,34 @@ #define _ICE_DEVIDS_H_ /* Device IDs */ +/* Intel(R) Ethernet Connection E823-L for backplane */ +#define ICE_DEV_ID_E823L_BACKPLANE 0x124C +/* Intel(R) Ethernet Connection E823-L for SFP */ +#define ICE_DEV_ID_E823L_SFP 0x124D +/* Intel(R) Ethernet Connection E823-L/X557-AT 10GBASE-T */ +#define ICE_DEV_ID_E823L_10G_BASE_T 0x124E +/* Intel(R) Ethernet Connection E823-L 1GbE */ +#define ICE_DEV_ID_E823L_1GBE 0x124F +/* Intel(R) Ethernet Connection E823-L for QSFP */ +#define ICE_DEV_ID_E823L_QSFP 0x151D /* Intel(R) Ethernet Controller E810-C for backplane */ #define ICE_DEV_ID_E810C_BACKPLANE 0x1591 /* Intel(R) Ethernet Controller E810-C for QSFP */ #define ICE_DEV_ID_E810C_QSFP 0x1592 /* Intel(R) Ethernet Controller E810-C for SFP */ #define ICE_DEV_ID_E810C_SFP 0x1593 +/* Intel(R) Ethernet Controller E810-XXV for SFP */ +#define ICE_DEV_ID_E810_XXV_SFP 0x159B +/* Intel(R) Ethernet Connection E823-C for backplane */ +#define ICE_DEV_ID_E823C_BACKPLANE 0x188A +/* Intel(R) Ethernet Connection E823-C for QSFP */ +#define ICE_DEV_ID_E823C_QSFP 0x188B +/* Intel(R) Ethernet Connection E823-C for SFP */ +#define ICE_DEV_ID_E823C_SFP 0x188C +/* Intel(R) Ethernet Connection E823-C/X557-AT 10GBASE-T */ +#define ICE_DEV_ID_E823C_10G_BASE_T 0x188D +/* Intel(R) Ethernet Connection E823-C 1GbE */ +#define ICE_DEV_ID_E823C_SGMII 0x188E /* Intel(R) Ethernet Connection E822-C for backplane */ #define ICE_DEV_ID_E822C_BACKPLANE 0x1890 /* Intel(R) Ethernet Connection E822-C for QSFP */ @@ -21,8 +43,8 @@ #define ICE_DEV_ID_E822C_10G_BASE_T 0x1893 /* Intel(R) Ethernet Connection E822-C 1GbE */ #define ICE_DEV_ID_E822C_SGMII 0x1894 -/* Intel(R) Ethernet Connection E822-X for backplane */ -#define ICE_DEV_ID_E822X_BACKPLANE 0x1897 +/* Intel(R) Ethernet Connection E822-L for backplane */ +#define ICE_DEV_ID_E822L_BACKPLANE 0x1897 /* Intel(R) Ethernet Connection E822-L for SFP */ #define ICE_DEV_ID_E822L_SFP 0x1898 /* Intel(R) Ethernet Connection E822-L/X557-AT 10GBASE-T */ diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 77c412a7e7a4..ab37dddb225b 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -157,6 +157,7 @@ struct ice_priv_flag { static const struct ice_priv_flag ice_gstrings_priv_flags[] = { ICE_PRIV_FLAG("link-down-on-close", ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA), ICE_PRIV_FLAG("fw-lldp-agent", ICE_FLAG_FW_LLDP_AGENT), + ICE_PRIV_FLAG("mdd-auto-reset-vf", ICE_FLAG_MDD_AUTO_RESET_VF), ICE_PRIV_FLAG("legacy-rx", ICE_FLAG_LEGACY_RX), }; @@ -462,7 +463,7 @@ static int ice_lbtest_prepare_rings(struct ice_vsi *vsi) if (status) goto err_setup_rx_ring; - status = ice_vsi_start_rx_rings(vsi); + status = ice_vsi_start_all_rx_rings(vsi); if (status) goto err_start_rx_ring; @@ -494,7 +495,7 @@ static int ice_lbtest_disable_rings(struct ice_vsi *vsi) netdev_err(vsi->netdev, "Failed to stop Tx rings, VSI %d error %d\n", vsi->vsi_num, status); - status = ice_vsi_stop_rx_rings(vsi); + status = ice_vsi_stop_all_rx_rings(vsi); if (status) netdev_err(vsi->netdev, "Failed to stop Rx rings, VSI %d error %d\n", vsi->vsi_num, status); @@ -672,7 +673,7 @@ static u64 ice_loopback_test(struct net_device *netdev) test_vsi = ice_lb_vsi_setup(pf, pf->hw.port_info); if (!test_vsi) { - netdev_err(netdev, "Failed to create a VSI for the loopback test"); + netdev_err(netdev, "Failed to create a VSI for the loopback test\n"); return 1; } @@ -731,7 +732,7 @@ lbtest_free_frame: devm_kfree(dev, tx_frame); remove_mac_filters: if (ice_remove_mac(&pf->hw, &tmp_list)) - netdev_err(netdev, "Could not remove MAC filter for the test VSI"); + netdev_err(netdev, "Could not remove MAC filter for the test VSI\n"); free_mac_list: ice_free_fltr_list(dev, &tmp_list); lbtest_mac_dis: @@ -744,7 +745,7 @@ lbtest_rings_dis: lbtest_vsi_close: test_vsi->netdev = NULL; if (ice_vsi_release(test_vsi)) - netdev_err(netdev, "Failed to remove the test VSI"); + netdev_err(netdev, "Failed to remove the test VSI\n"); return ret; } @@ -834,7 +835,7 @@ ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, int status = ice_open(netdev); if (status) { - dev_err(dev, "Could not open device %s, err %d", + dev_err(dev, "Could not open device %s, err %d\n", pf->int_name, status); } } @@ -1091,7 +1092,6 @@ ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) fecparam->active_fec = ETHTOOL_FEC_BASER; break; case ICE_AQ_LINK_25G_RS_528_FEC_EN: - /* fall through */ case ICE_AQ_LINK_25G_RS_544_FEC_EN: fecparam->active_fec = ETHTOOL_FEC_RS; break; @@ -1781,7 +1781,6 @@ ice_get_settings_link_up(struct ethtool_link_ksettings *ks, Asym_Pause); break; case ICE_FC_PFC: - /* fall through */ default: ethtool_link_ksettings_del_link_mode(ks, lp_advertising, Pause); ethtool_link_ksettings_del_link_mode(ks, lp_advertising, diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c index 99208946224c..42bac3ec5526 100644 --- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c +++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c @@ -3471,6 +3471,24 @@ ice_move_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig, } /** + * ice_rem_chg_tcam_ent - remove a specific TCAM entry from change list + * @hw: pointer to the HW struct + * @idx: the index of the TCAM entry to remove + * @chg: the list of change structures to search + */ +static void +ice_rem_chg_tcam_ent(struct ice_hw *hw, u16 idx, struct list_head *chg) +{ + struct ice_chs_chg *pos, *tmp; + + list_for_each_entry_safe(tmp, pos, chg, list_entry) + if (tmp->type == ICE_TCAM_ADD && tmp->tcam_idx == idx) { + list_del(&tmp->list_entry); + devm_kfree(ice_hw_to_dev(hw), tmp); + } +} + +/** * ice_prof_tcam_ena_dis - add enable or disable TCAM change * @hw: pointer to the HW struct * @blk: hardware block @@ -3489,14 +3507,19 @@ ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable, enum ice_status status; struct ice_chs_chg *p; - /* Default: enable means change the low flag bit to don't care */ - u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 }; + u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0x00, 0x00, 0x00 }; u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; - u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 }; /* if disabling, free the TCAM */ if (!enable) { - status = ice_free_tcam_ent(hw, blk, tcam->tcam_idx); + status = ice_rel_tcam_idx(hw, blk, tcam->tcam_idx); + + /* if we have already created a change for this TCAM entry, then + * we need to remove that entry, in order to prevent writing to + * a TCAM entry we no longer will have ownership of. + */ + ice_rem_chg_tcam_ent(hw, tcam->tcam_idx, chg); tcam->tcam_idx = 0; tcam->in_use = 0; return status; @@ -3612,11 +3635,12 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig, * @blk: hardware block * @vsig: the VSIG to which this profile is to be added * @hdl: the profile handle indicating the profile to add + * @rev: true to add entries to the end of the list * @chg: the change list */ static enum ice_status ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, - struct list_head *chg) + bool rev, struct list_head *chg) { /* Masks that ignore flags */ u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -3625,7 +3649,7 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, struct ice_prof_map *map; struct ice_vsig_prof *t; struct ice_chs_chg *p; - u16 i; + u16 vsig_idx, i; /* Get the details on the profile specified by the handle ID */ map = ice_search_prof_id(hw, blk, hdl); @@ -3687,8 +3711,13 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, } /* add profile to VSIG */ - list_add(&t->list, - &hw->blk[blk].xlt2.vsig_tbl[(vsig & ICE_VSIG_IDX_M)].prop_lst); + vsig_idx = vsig & ICE_VSIG_IDX_M; + if (rev) + list_add_tail(&t->list, + &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst); + else + list_add(&t->list, + &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst); return 0; @@ -3728,7 +3757,7 @@ ice_create_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl, if (status) goto err_ice_create_prof_id_vsig; - status = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, chg); + status = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, false, chg); if (status) goto err_ice_create_prof_id_vsig; @@ -3753,11 +3782,13 @@ err_ice_create_prof_id_vsig: * @blk: hardware block * @vsi: the initial VSI that will be in VSIG * @lst: the list of profile that will be added to the VSIG + * @new_vsig: return of new VSIG * @chg: the change list */ static enum ice_status ice_create_vsig_from_lst(struct ice_hw *hw, enum ice_block blk, u16 vsi, - struct list_head *lst, struct list_head *chg) + struct list_head *lst, u16 *new_vsig, + struct list_head *chg) { struct ice_vsig_prof *t; enum ice_status status; @@ -3772,12 +3803,15 @@ ice_create_vsig_from_lst(struct ice_hw *hw, enum ice_block blk, u16 vsi, return status; list_for_each_entry(t, lst, list) { + /* Reverse the order here since we are copying the list */ status = ice_add_prof_id_vsig(hw, blk, vsig, t->profile_cookie, - chg); + true, chg); if (status) return status; } + *new_vsig = vsig; + return 0; } @@ -3899,7 +3933,8 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl) * not sharing entries and we can simply add the new * profile to the VSIG. */ - status = ice_add_prof_id_vsig(hw, blk, vsig, hdl, &chg); + status = ice_add_prof_id_vsig(hw, blk, vsig, hdl, false, + &chg); if (status) goto err_ice_add_prof_id_flow; @@ -3910,7 +3945,8 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl) } else { /* No match, so we need a new VSIG */ status = ice_create_vsig_from_lst(hw, blk, vsi, - &union_lst, &chg); + &union_lst, &vsig, + &chg); if (status) goto err_ice_add_prof_id_flow; @@ -4076,7 +4112,8 @@ ice_rem_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl) * new VSIG and TCAM entries */ status = ice_create_vsig_from_lst(hw, blk, vsi, - ©, &chg); + ©, &vsig, + &chg); if (status) goto err_ice_rem_prof_id_flow; diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 6db3d0494127..1d37a9f02c1c 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -85,6 +85,7 @@ #define QRXFLXP_CNTXT_RXDID_IDX_M ICE_M(0x3F, 0) #define QRXFLXP_CNTXT_RXDID_PRIO_S 8 #define QRXFLXP_CNTXT_RXDID_PRIO_M ICE_M(0x7, 8) +#define QRXFLXP_CNTXT_TS_M BIT(11) #define GLGEN_RSTAT 0x000B8188 #define GLGEN_RSTAT_DEVSTATE_M ICE_M(0x3, 0) #define GLGEN_RSTCTL 0x000B8180 @@ -217,6 +218,8 @@ #define VPLAN_TX_QBASE_VFNUMQ_M ICE_M(0xFF, 16) #define VPLAN_TXQ_MAPENA(_VF) (0x00073800 + ((_VF) * 4)) #define VPLAN_TXQ_MAPENA_TX_ENA_M BIT(0) +#define GL_MDCK_TX_TDPU 0x00049348 +#define GL_MDCK_TX_TDPU_RCU_ANTISPOOF_ITR_DIS_M BIT(1) #define GL_MDET_RX 0x00294C00 #define GL_MDET_RX_QNUM_S 0 #define GL_MDET_RX_QNUM_M ICE_M(0x7FFF, 0) @@ -286,6 +289,8 @@ #define GL_PWR_MODE_CTL 0x000B820C #define GL_PWR_MODE_CTL_CAR_MAX_BW_S 30 #define GL_PWR_MODE_CTL_CAR_MAX_BW_M ICE_M(0x3, 30) +#define GLDCB_RTCTQ_RXQNUM_S 0 +#define GLDCB_RTCTQ_RXQNUM_M ICE_M(0x7FF, 0) #define GLPRT_BPRCL(_i) (0x00381380 + ((_i) * 8)) #define GLPRT_BPTCL(_i) (0x00381240 + ((_i) * 8)) #define GLPRT_CRCERRS(_i) (0x00380100 + ((_i) * 8)) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index d974e2fa3e63..ff72a6d1c978 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -26,16 +26,26 @@ const char *ice_vsi_type_str(enum ice_vsi_type type) } /** - * ice_vsi_ctrl_rx_rings - Start or stop a VSI's Rx rings + * ice_vsi_ctrl_all_rx_rings - Start or stop a VSI's Rx rings * @vsi: the VSI being configured * @ena: start or stop the Rx rings + * + * First enable/disable all of the Rx rings, flush any remaining writes, and + * then verify that they have all been enabled/disabled successfully. This will + * let all of the register writes complete when enabling/disabling the Rx rings + * before waiting for the change in hardware to complete. */ -static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) +static int ice_vsi_ctrl_all_rx_rings(struct ice_vsi *vsi, bool ena) { int i, ret = 0; + for (i = 0; i < vsi->num_rxq; i++) + ice_vsi_ctrl_one_rx_ring(vsi, ena, i, false); + + ice_flush(&vsi->back->hw); + for (i = 0; i < vsi->num_rxq; i++) { - ret = ice_vsi_ctrl_rx_ring(vsi, ena, i); + ret = ice_vsi_wait_one_rx_ring(vsi, ena, i); if (ret) break; } @@ -111,7 +121,6 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi) { switch (vsi->type) { case ICE_VSI_PF: - /* fall through */ case ICE_VSI_LB: vsi->num_rx_desc = ICE_DFLT_NUM_RX_DESC; vsi->num_tx_desc = ICE_DFLT_NUM_TX_DESC; @@ -433,7 +442,7 @@ static int ice_vsi_get_qs(struct ice_vsi *vsi) .scatter_count = ICE_MAX_SCATTER_TXQS, .vsi_map = vsi->txq_map, .vsi_map_offset = 0, - .mapping_mode = vsi->tx_mapping_mode + .mapping_mode = ICE_VSI_MAP_CONTIG }; struct ice_qs_cfg rx_qs_cfg = { .qs_mutex = &pf->avail_q_mutex, @@ -443,18 +452,21 @@ static int ice_vsi_get_qs(struct ice_vsi *vsi) .scatter_count = ICE_MAX_SCATTER_RXQS, .vsi_map = vsi->rxq_map, .vsi_map_offset = 0, - .mapping_mode = vsi->rx_mapping_mode + .mapping_mode = ICE_VSI_MAP_CONTIG }; - int ret = 0; - - vsi->tx_mapping_mode = ICE_VSI_MAP_CONTIG; - vsi->rx_mapping_mode = ICE_VSI_MAP_CONTIG; + int ret; ret = __ice_vsi_get_qs(&tx_qs_cfg); - if (!ret) - ret = __ice_vsi_get_qs(&rx_qs_cfg); + if (ret) + return ret; + vsi->tx_mapping_mode = tx_qs_cfg.mapping_mode; - return ret; + ret = __ice_vsi_get_qs(&rx_qs_cfg); + if (ret) + return ret; + vsi->rx_mapping_mode = rx_qs_cfg.mapping_mode; + + return 0; } /** @@ -804,7 +816,6 @@ static int ice_vsi_init(struct ice_vsi *vsi, bool init_vsi) ctxt->info = vsi->info; switch (vsi->type) { case ICE_VSI_LB: - /* fall through */ case ICE_VSI_PF: ctxt->flags = ICE_AQ_VSI_TYPE_PF; break; @@ -1348,7 +1359,9 @@ int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) list_add(&tmp->list_entry, &tmp_add_list); status = ice_add_vlan(&pf->hw, &tmp_add_list); - if (status) { + if (!status) { + vsi->num_vlan++; + } else { err = -ENODEV; dev_err(dev, "Failure Adding VLAN %d on VSI %i\n", vid, vsi->vsi_num); @@ -1390,10 +1403,12 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) list_add(&list->list_entry, &tmp_add_list); status = ice_remove_vlan(&pf->hw, &tmp_add_list); - if (status == ICE_ERR_DOES_NOT_EXIST) { + if (!status) { + vsi->num_vlan--; + } else if (status == ICE_ERR_DOES_NOT_EXIST) { dev_dbg(dev, "Failed to remove VLAN %d on VSI %i, it does not exist, status: %d\n", vid, vsi->vsi_num, status); - } else if (status) { + } else { dev_err(dev, "Error removing VLAN %d on vsi %i error: %d\n", vid, vsi->vsi_num, status); err = -EIO; @@ -1678,25 +1693,25 @@ out: } /** - * ice_vsi_start_rx_rings - start VSI's Rx rings - * @vsi: the VSI whose rings are to be started + * ice_vsi_start_all_rx_rings - start/enable all of a VSI's Rx rings + * @vsi: the VSI whose rings are to be enabled * * Returns 0 on success and a negative value on error */ -int ice_vsi_start_rx_rings(struct ice_vsi *vsi) +int ice_vsi_start_all_rx_rings(struct ice_vsi *vsi) { - return ice_vsi_ctrl_rx_rings(vsi, true); + return ice_vsi_ctrl_all_rx_rings(vsi, true); } /** - * ice_vsi_stop_rx_rings - stop VSI's Rx rings - * @vsi: the VSI + * ice_vsi_stop_all_rx_rings - stop/disable all of a VSI's Rx rings + * @vsi: the VSI whose rings are to be disabled * * Returns 0 on success and a negative value on error */ -int ice_vsi_stop_rx_rings(struct ice_vsi *vsi) +int ice_vsi_stop_all_rx_rings(struct ice_vsi *vsi) { - return ice_vsi_ctrl_rx_rings(vsi, false); + return ice_vsi_ctrl_all_rx_rings(vsi, false); } /** @@ -1756,6 +1771,26 @@ int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi) } /** + * ice_vsi_is_vlan_pruning_ena - check if VLAN pruning is enabled or not + * @vsi: VSI to check whether or not VLAN pruning is enabled. + * + * returns true if Rx VLAN pruning and Tx VLAN anti-spoof is enabled and false + * otherwise. + */ +bool ice_vsi_is_vlan_pruning_ena(struct ice_vsi *vsi) +{ + u8 rx_pruning = ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + u8 tx_pruning = ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << + ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S; + + if (!vsi) + return false; + + return ((vsi->info.sw_flags2 & rx_pruning) && + (vsi->info.sec_flags & tx_pruning)); +} + +/** * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI * @vsi: VSI to enable or disable VLAN pruning on * @ena: set to true to enable VLAN pruning and false to disable it @@ -2025,6 +2060,17 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, if (ret) goto unroll_vector_base; + /* Always add VLAN ID 0 switch rule by default. This is needed + * in order to allow all untagged and 0 tagged priority traffic + * if Rx VLAN pruning is enabled. Also there are cases where we + * don't get the call to add VLAN 0 via ice_vlan_rx_add_vid() + * so this handles those cases (i.e. adding the PF to a bridge + * without the 8021q module loaded). + */ + ret = ice_vsi_add_vlan(vsi, 0); + if (ret) + goto unroll_clear_rings; + ice_vsi_map_rings_to_vectors(vsi); /* Do not exit if configuring RSS had an issue, at least @@ -2104,6 +2150,8 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, return vsi; +unroll_clear_rings: + ice_vsi_clear_rings(vsi); unroll_vector_base: /* reclaim SW interrupts back to the common pool */ ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index e2c0dadce920..585f1350403f 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -30,9 +30,9 @@ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi); int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena); -int ice_vsi_start_rx_rings(struct ice_vsi *vsi); +int ice_vsi_start_all_rx_rings(struct ice_vsi *vsi); -int ice_vsi_stop_rx_rings(struct ice_vsi *vsi); +int ice_vsi_stop_all_rx_rings(struct ice_vsi *vsi); int ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, @@ -42,6 +42,8 @@ int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi); int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi); +bool ice_vsi_is_vlan_pruning_ena(struct ice_vsi *vsi); + int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc); void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 5ef28052c0f8..3aa3fc37c70e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -706,7 +706,6 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup) /* Get FEC mode based on negotiated link info */ switch (vsi->port_info->phy.link_info.fec_info) { case ICE_AQ_LINK_25G_RS_528_FEC_EN: - /* fall through */ case ICE_AQ_LINK_25G_RS_544_FEC_EN: fec = "RS-FEC"; break; @@ -1029,6 +1028,9 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) if (ice_handle_link_event(pf, &event)) dev_err(dev, "Could not handle link event\n"); break; + case ice_aqc_opc_event_lan_overflow: + ice_vf_lan_overflow_event(pf, &event); + break; case ice_mbx_opc_send_msg_to_pf: ice_vc_process_vf_msg(pf, &event); break; @@ -1185,20 +1187,28 @@ static void ice_service_timer(struct timer_list *t) * ice_handle_mdd_event - handle malicious driver detect event * @pf: pointer to the PF structure * - * Called from service task. OICR interrupt handler indicates MDD event + * Called from service task. OICR interrupt handler indicates MDD event. + * VF MDD logging is guarded by net_ratelimit. Additional PF and VF log + * messages are wrapped by netif_msg_[rx|tx]_err. Since VF Rx MDD events + * disable the queue, the PF can be configured to reset the VF using ethtool + * private flag mdd-auto-reset-vf. */ static void ice_handle_mdd_event(struct ice_pf *pf) { struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; - bool mdd_detected = false; u32 reg; int i; - if (!test_and_clear_bit(__ICE_MDD_EVENT_PENDING, pf->state)) + if (!test_and_clear_bit(__ICE_MDD_EVENT_PENDING, pf->state)) { + /* Since the VF MDD event logging is rate limited, check if + * there are pending MDD events. + */ + ice_print_vfs_mdd_events(pf); return; + } - /* find what triggered the MDD event */ + /* find what triggered an MDD event */ reg = rd32(hw, GL_MDET_TX_PQM); if (reg & GL_MDET_TX_PQM_VALID_M) { u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >> @@ -1214,7 +1224,6 @@ static void ice_handle_mdd_event(struct ice_pf *pf) dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", event, queue, pf_num, vf_num); wr32(hw, GL_MDET_TX_PQM, 0xffffffff); - mdd_detected = true; } reg = rd32(hw, GL_MDET_TX_TCLAN); @@ -1232,7 +1241,6 @@ static void ice_handle_mdd_event(struct ice_pf *pf) dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", event, queue, pf_num, vf_num); wr32(hw, GL_MDET_TX_TCLAN, 0xffffffff); - mdd_detected = true; } reg = rd32(hw, GL_MDET_RX); @@ -1250,85 +1258,85 @@ static void ice_handle_mdd_event(struct ice_pf *pf) dev_info(dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n", event, queue, pf_num, vf_num); wr32(hw, GL_MDET_RX, 0xffffffff); - mdd_detected = true; } - if (mdd_detected) { - bool pf_mdd_detected = false; - - reg = rd32(hw, PF_MDET_TX_PQM); - if (reg & PF_MDET_TX_PQM_VALID_M) { - wr32(hw, PF_MDET_TX_PQM, 0xFFFF); - dev_info(dev, "TX driver issue detected, PF reset issued\n"); - pf_mdd_detected = true; - } + /* check to see if this PF caused an MDD event */ + reg = rd32(hw, PF_MDET_TX_PQM); + if (reg & PF_MDET_TX_PQM_VALID_M) { + wr32(hw, PF_MDET_TX_PQM, 0xFFFF); + if (netif_msg_tx_err(pf)) + dev_info(dev, "Malicious Driver Detection event TX_PQM detected on PF\n"); + } - reg = rd32(hw, PF_MDET_TX_TCLAN); - if (reg & PF_MDET_TX_TCLAN_VALID_M) { - wr32(hw, PF_MDET_TX_TCLAN, 0xFFFF); - dev_info(dev, "TX driver issue detected, PF reset issued\n"); - pf_mdd_detected = true; - } + reg = rd32(hw, PF_MDET_TX_TCLAN); + if (reg & PF_MDET_TX_TCLAN_VALID_M) { + wr32(hw, PF_MDET_TX_TCLAN, 0xFFFF); + if (netif_msg_tx_err(pf)) + dev_info(dev, "Malicious Driver Detection event TX_TCLAN detected on PF\n"); + } - reg = rd32(hw, PF_MDET_RX); - if (reg & PF_MDET_RX_VALID_M) { - wr32(hw, PF_MDET_RX, 0xFFFF); - dev_info(dev, "RX driver issue detected, PF reset issued\n"); - pf_mdd_detected = true; - } - /* Queue belongs to the PF initiate a reset */ - if (pf_mdd_detected) { - set_bit(__ICE_NEEDS_RESTART, pf->state); - ice_service_task_schedule(pf); - } + reg = rd32(hw, PF_MDET_RX); + if (reg & PF_MDET_RX_VALID_M) { + wr32(hw, PF_MDET_RX, 0xFFFF); + if (netif_msg_rx_err(pf)) + dev_info(dev, "Malicious Driver Detection event RX detected on PF\n"); } - /* check to see if one of the VFs caused the MDD */ + /* Check to see if one of the VFs caused an MDD event, and then + * increment counters and set print pending + */ ice_for_each_vf(pf, i) { struct ice_vf *vf = &pf->vf[i]; - bool vf_mdd_detected = false; - reg = rd32(hw, VP_MDET_TX_PQM(i)); if (reg & VP_MDET_TX_PQM_VALID_M) { wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF); - vf_mdd_detected = true; - dev_info(dev, "TX driver issue detected on VF %d\n", - i); + vf->mdd_tx_events.count++; + set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); + if (netif_msg_tx_err(pf)) + dev_info(dev, "Malicious Driver Detection event TX_PQM detected on VF %d\n", + i); } reg = rd32(hw, VP_MDET_TX_TCLAN(i)); if (reg & VP_MDET_TX_TCLAN_VALID_M) { wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF); - vf_mdd_detected = true; - dev_info(dev, "TX driver issue detected on VF %d\n", - i); + vf->mdd_tx_events.count++; + set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); + if (netif_msg_tx_err(pf)) + dev_info(dev, "Malicious Driver Detection event TX_TCLAN detected on VF %d\n", + i); } reg = rd32(hw, VP_MDET_TX_TDPU(i)); if (reg & VP_MDET_TX_TDPU_VALID_M) { wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF); - vf_mdd_detected = true; - dev_info(dev, "TX driver issue detected on VF %d\n", - i); + vf->mdd_tx_events.count++; + set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); + if (netif_msg_tx_err(pf)) + dev_info(dev, "Malicious Driver Detection event TX_TDPU detected on VF %d\n", + i); } reg = rd32(hw, VP_MDET_RX(i)); if (reg & VP_MDET_RX_VALID_M) { wr32(hw, VP_MDET_RX(i), 0xFFFF); - vf_mdd_detected = true; - dev_info(dev, "RX driver issue detected on VF %d\n", - i); - } - - if (vf_mdd_detected) { - vf->num_mdd_events++; - if (vf->num_mdd_events && - vf->num_mdd_events <= ICE_MDD_EVENTS_THRESHOLD) - dev_info(dev, "VF %d has had %llu MDD events since last boot, Admin might need to reload AVF driver with this number of events\n", - i, vf->num_mdd_events); + vf->mdd_rx_events.count++; + set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); + if (netif_msg_rx_err(pf)) + dev_info(dev, "Malicious Driver Detection event RX detected on VF %d\n", + i); + + /* Since the queue is disabled on VF Rx MDD events, the + * PF can be configured to reset the VF through ethtool + * private flag mdd-auto-reset-vf. + */ + if (test_bit(ICE_FLAG_MDD_AUTO_RESET_VF, pf->flags)) + ice_reset_vf(&pf->vf[i], false); } } + + ice_print_vfs_mdd_events(pf); } /** @@ -1916,8 +1924,7 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, if (if_running && !test_and_set_bit(__ICE_DOWN, vsi->state)) { ret = ice_down(vsi); if (ret) { - NL_SET_ERR_MSG_MOD(extack, - "Preparing device for XDP attach failed"); + NL_SET_ERR_MSG_MOD(extack, "Preparing device for XDP attach failed"); return ret; } } @@ -1926,13 +1933,11 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, vsi->num_xdp_txq = vsi->alloc_txq; xdp_ring_err = ice_prepare_xdp_rings(vsi, prog); if (xdp_ring_err) - NL_SET_ERR_MSG_MOD(extack, - "Setting up XDP Tx resources failed"); + NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Tx resources failed"); } else if (ice_is_xdp_ena_vsi(vsi) && !prog) { xdp_ring_err = ice_destroy_xdp_rings(vsi); if (xdp_ring_err) - NL_SET_ERR_MSG_MOD(extack, - "Freeing XDP Tx resources failed"); + NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Tx resources failed"); } else { ice_vsi_assign_bpf_prog(vsi, prog); } @@ -1965,8 +1970,7 @@ static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp) struct ice_vsi *vsi = np->vsi; if (vsi->type != ICE_VSI_PF) { - NL_SET_ERR_MSG_MOD(xdp->extack, - "XDP can be loaded only on PF VSI"); + NL_SET_ERR_MSG_MOD(xdp->extack, "XDP can be loaded only on PF VSI"); return -EINVAL; } @@ -1993,6 +1997,14 @@ static void ice_ena_misc_vector(struct ice_pf *pf) struct ice_hw *hw = &pf->hw; u32 val; + /* Disable anti-spoof detection interrupt to prevent spurious event + * interrupts during a function reset. Anti-spoof functionally is + * still supported. + */ + val = rd32(hw, GL_MDCK_TX_TDPU); + val |= GL_MDCK_TX_TDPU_RCU_ANTISPOOF_ITR_DIS_M; + wr32(hw, GL_MDCK_TX_TDPU, val); + /* clear things first */ wr32(hw, PFINT_OICR_ENA, 0); /* disable all */ rd32(hw, PFINT_OICR); /* read to clear */ @@ -2461,16 +2473,19 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto, if (vsi->info.pvid) return -EINVAL; - /* Enable VLAN pruning when VLAN 0 is added */ - if (unlikely(!vid)) { + /* VLAN 0 is added by default during load/reset */ + if (!vid) + return 0; + + /* Enable VLAN pruning when a VLAN other than 0 is added */ + if (!ice_vsi_is_vlan_pruning_ena(vsi)) { ret = ice_cfg_vlan_pruning(vsi, true, false); if (ret) return ret; } - /* Add all VLAN IDs including 0 to the switch filter. VLAN ID 0 is - * needed to continue allowing all untagged packets since VLAN prune - * list is applied to all packets by the switch + /* Add a switch rule for this VLAN ID so its corresponding VLAN tagged + * packets aren't pruned by the device's internal switch on Rx */ ret = ice_vsi_add_vlan(vsi, vid); if (!ret) { @@ -2500,6 +2515,10 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, if (vsi->info.pvid) return -EINVAL; + /* don't allow removal of VLAN 0 */ + if (!vid) + return 0; + /* Make sure ice_vsi_kill_vlan is successful before updating VLAN * information */ @@ -2507,8 +2526,8 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, if (ret) return ret; - /* Disable VLAN pruning when VLAN 0 is removed */ - if (unlikely(!vid)) + /* Disable pruning when VLAN 0 is the only VLAN rule */ + if (vsi->num_vlan == 1 && ice_vsi_is_vlan_pruning_ena(vsi)) ret = ice_cfg_vlan_pruning(vsi, false, false); vsi->vlan_ena = false; @@ -2945,7 +2964,6 @@ ice_log_pkg_init(struct ice_hw *hw, enum ice_status *status) } break; case ICE_ERR_BUF_TOO_SHORT: - /* fall-through */ case ICE_ERR_CFG: dev_err(dev, "The DDP package file is invalid. Entering Safe Mode.\n"); break; @@ -2977,7 +2995,7 @@ ice_log_pkg_init(struct ice_hw *hw, enum ice_status *status) default: break; } - /* fall-through */ + fallthrough; default: dev_err(dev, "An unknown error (%d) occurred when loading the DDP package. Entering Safe Mode.\n", *status); @@ -3534,15 +3552,26 @@ static const struct pci_device_id ice_pci_tbl[] = { { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_BACKPLANE), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_QSFP), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_SFP), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_SFP), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_BACKPLANE), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_QSFP), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SFP), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_10G_BASE_T), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SGMII), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_BACKPLANE), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_QSFP), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SFP), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_10G_BASE_T), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SGMII), 0 }, - { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822X_BACKPLANE), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_BACKPLANE), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SFP), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_10G_BASE_T), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SGMII), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_BACKPLANE), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_SFP), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_10G_BASE_T), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE), 0 }, + { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP), 0 }, /* required last entry */ { 0, } }; @@ -3961,7 +3990,7 @@ static int ice_up_complete(struct ice_vsi *vsi) * Tx queue group list was configured and the context bits were * programmed using ice_vsi_cfg_txqs */ - err = ice_vsi_start_rx_rings(vsi); + err = ice_vsi_start_all_rx_rings(vsi); if (err) return err; @@ -4340,7 +4369,7 @@ int ice_down(struct ice_vsi *vsi) vsi->vsi_num, tx_err); } - rx_err = ice_vsi_stop_rx_rings(vsi); + rx_err = ice_vsi_stop_all_rx_rings(vsi); if (rx_err) netdev_err(vsi->netdev, "Failed stop Rx rings, VSI %d error %d\n", vsi->vsi_num, rx_err); @@ -5027,6 +5056,7 @@ ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, /** * ice_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure + * @txqueue: Tx queue */ static void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue) { diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c index 7525ac50742e..f6e25db22c23 100644 --- a/drivers/net/ethernet/intel/ice/ice_nvm.c +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c @@ -289,17 +289,31 @@ enum ice_status ice_init_nvm(struct ice_hw *hw) nvm->eetrack = (eetrack_hi << 16) | eetrack_lo; + switch (hw->device_id) { /* the following devices do not have boot_cfg_tlv yet */ - if (hw->device_id == ICE_DEV_ID_E822C_BACKPLANE || - hw->device_id == ICE_DEV_ID_E822C_QSFP || - hw->device_id == ICE_DEV_ID_E822C_10G_BASE_T || - hw->device_id == ICE_DEV_ID_E822C_SGMII || - hw->device_id == ICE_DEV_ID_E822C_SFP || - hw->device_id == ICE_DEV_ID_E822X_BACKPLANE || - hw->device_id == ICE_DEV_ID_E822L_SFP || - hw->device_id == ICE_DEV_ID_E822L_10G_BASE_T || - hw->device_id == ICE_DEV_ID_E822L_SGMII) + case ICE_DEV_ID_E823C_BACKPLANE: + case ICE_DEV_ID_E823C_QSFP: + case ICE_DEV_ID_E823C_SFP: + case ICE_DEV_ID_E823C_10G_BASE_T: + case ICE_DEV_ID_E823C_SGMII: + case ICE_DEV_ID_E822C_BACKPLANE: + case ICE_DEV_ID_E822C_QSFP: + case ICE_DEV_ID_E822C_10G_BASE_T: + case ICE_DEV_ID_E822C_SGMII: + case ICE_DEV_ID_E822C_SFP: + case ICE_DEV_ID_E822L_BACKPLANE: + case ICE_DEV_ID_E822L_SFP: + case ICE_DEV_ID_E822L_10G_BASE_T: + case ICE_DEV_ID_E822L_SGMII: + case ICE_DEV_ID_E823L_BACKPLANE: + case ICE_DEV_ID_E823L_SFP: + case ICE_DEV_ID_E823L_10G_BASE_T: + case ICE_DEV_ID_E823L_1GBE: + case ICE_DEV_ID_E823L_QSFP: return status; + default: + break; + } status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len, ICE_SR_BOOT_CFG_PTR); diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index d2db0d04e117..554f567476f3 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -121,9 +121,7 @@ u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed) speed = (u32)VIRTCHNL_LINK_SPEED_25GB; break; case ICE_AQ_LINK_SPEED_40GB: - /* fall through */ case ICE_AQ_LINK_SPEED_50GB: - /* fall through */ case ICE_AQ_LINK_SPEED_100GB: speed = (u32)VIRTCHNL_LINK_SPEED_40GB; break; diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 431266081a80..4d96abfd05d6 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -760,7 +760,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, break; case ICE_SW_LKUP_ETHERTYPE_MAC: daddr = f_info->l_data.ethertype_mac.mac_addr; - /* fall-through */ + fallthrough; case ICE_SW_LKUP_ETHERTYPE: off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); *off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype); @@ -771,7 +771,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, break; case ICE_SW_LKUP_PROMISC_VLAN: vlan_id = f_info->l_data.mac_vlan.vlan_id; - /* fall-through */ + fallthrough; case ICE_SW_LKUP_PROMISC: daddr = f_info->l_data.mac_vlan.mac_addr; break; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 4de61dbedd36..f67e8362958c 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -453,10 +453,10 @@ ice_run_xdp(struct ice_ring *rx_ring, struct xdp_buff *xdp, break; default: bpf_warn_invalid_xdp_action(act); - /* fallthrough -- not supported action */ + fallthrough; case XDP_ABORTED: trace_xdp_exception(rx_ring->netdev, xdp_prog, act); - /* fallthrough -- handle aborts by dropping frame */ + fallthrough; case XDP_DROP: result = ICE_XDP_CONSUMED; break; @@ -1188,7 +1188,6 @@ ice_adjust_itr_by_size_and_speed(struct ice_port_info *port_info, avg_pkt_size + 640); break; case ICE_AQ_LINK_SPEED_10GB: - /* fall through */ default: itr += DIV_ROUND_UP(170 * (avg_pkt_size + 24), avg_pkt_size + 640); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 75c70d432c72..6bedfa4676ae 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -91,6 +91,39 @@ ice_set_pfe_link(struct ice_vf *vf, struct virtchnl_pf_event *pfe, } /** + * ice_vf_has_no_qs_ena - check if the VF has any Rx or Tx queues enabled + * @vf: the VF to check + * + * Returns true if the VF has no Rx and no Tx queues enabled and returns false + * otherwise + */ +static bool ice_vf_has_no_qs_ena(struct ice_vf *vf) +{ + return (!bitmap_weight(vf->rxq_ena, ICE_MAX_BASE_QS_PER_VF) && + !bitmap_weight(vf->txq_ena, ICE_MAX_BASE_QS_PER_VF)); +} + +/** + * ice_is_vf_link_up - check if the VF's link is up + * @vf: VF to check if link is up + */ +static bool ice_is_vf_link_up(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + + if (ice_check_vf_init(pf, vf)) + return false; + + if (ice_vf_has_no_qs_ena(vf)) + return false; + else if (vf->link_forced) + return vf->link_up; + else + return pf->hw.port_info->phy.link_info.link_info & + ICE_AQ_LINK_UP; +} + +/** * ice_vc_notify_vf_link_state - Inform a VF of link status * @vf: pointer to the VF structure * @@ -99,28 +132,16 @@ ice_set_pfe_link(struct ice_vf *vf, struct virtchnl_pf_event *pfe, static void ice_vc_notify_vf_link_state(struct ice_vf *vf) { struct virtchnl_pf_event pfe = { 0 }; - struct ice_link_status *ls; - struct ice_pf *pf = vf->pf; - struct ice_hw *hw; - - hw = &pf->hw; - ls = &hw->port_info->phy.link_info; + struct ice_hw *hw = &vf->pf->hw; pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; pfe.severity = PF_EVENT_SEVERITY_INFO; - /* Always report link is down if the VF queues aren't enabled */ - if (!vf->num_qs_ena) { + if (ice_is_vf_link_up(vf)) + ice_set_pfe_link(vf, &pfe, + hw->port_info->phy.link_info.link_speed, true); + else ice_set_pfe_link(vf, &pfe, ICE_AQ_LINK_SPEED_UNKNOWN, false); - } else if (vf->link_forced) { - u16 link_speed = vf->link_up ? - ls->link_speed : ICE_AQ_LINK_SPEED_UNKNOWN; - - ice_set_pfe_link(vf, &pfe, link_speed, vf->link_up); - } else { - ice_set_pfe_link(vf, &pfe, ls->link_speed, - ls->link_info & ICE_AQ_LINK_UP); - } ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, VIRTCHNL_STATUS_SUCCESS, (u8 *)&pfe, @@ -150,6 +171,11 @@ static void ice_free_vf_res(struct ice_vf *vf) } last_vector_idx = vf->first_vector_idx + pf->num_vf_msix - 1; + + /* clear VF MDD event information */ + memset(&vf->mdd_tx_events, 0, sizeof(vf->mdd_tx_events)); + memset(&vf->mdd_rx_events, 0, sizeof(vf->mdd_rx_events)); + /* Disable interrupts so that VF starts in a known state */ for (i = vf->first_vector_idx; i <= last_vector_idx; i++) { wr32(&pf->hw, GLINT_DYN_CTL(i), GLINT_DYN_CTL_CLEARPBA_M); @@ -247,7 +273,6 @@ void ice_set_vf_state_qs_dis(struct ice_vf *vf) /* Clear Rx/Tx enabled queues flag */ bitmap_zero(vf->txq_ena, ICE_MAX_BASE_QS_PER_VF); bitmap_zero(vf->rxq_ena, ICE_MAX_BASE_QS_PER_VF); - vf->num_qs_ena = 0; clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); } @@ -263,7 +288,7 @@ static void ice_dis_vf_qs(struct ice_vf *vf) vsi = pf->vsi[vf->lan_vsi_idx]; ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, vf->vf_id); - ice_vsi_stop_rx_rings(vsi); + ice_vsi_stop_all_rx_rings(vsi); ice_set_vf_state_qs_dis(vf); } @@ -407,43 +432,15 @@ static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr, bool is_pfr) } /** - * ice_vsi_set_pvid_fill_ctxt - Set VSI ctxt for add PVID - * @ctxt: the VSI ctxt to fill - * @vid: the VLAN ID to set as a PVID - */ -static void ice_vsi_set_pvid_fill_ctxt(struct ice_vsi_ctx *ctxt, u16 vid) -{ - ctxt->info.vlan_flags = (ICE_AQ_VSI_VLAN_MODE_UNTAGGED | - ICE_AQ_VSI_PVLAN_INSERT_PVID | - ICE_AQ_VSI_VLAN_EMOD_STR); - ctxt->info.pvid = cpu_to_le16(vid); - ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; - ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID | - ICE_AQ_VSI_PROP_SW_VALID); -} - -/** - * ice_vsi_kill_pvid_fill_ctxt - Set VSI ctx for remove PVID - * @ctxt: the VSI ctxt to fill - */ -static void ice_vsi_kill_pvid_fill_ctxt(struct ice_vsi_ctx *ctxt) -{ - ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING; - ctxt->info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; - ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; - ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID | - ICE_AQ_VSI_PROP_SW_VALID); -} - -/** * ice_vsi_manage_pvid - Enable or disable port VLAN for VSI * @vsi: the VSI to update - * @vid: the VLAN ID to set as a PVID + * @pvid_info: VLAN ID and QoS used to set the PVID VSI context field * @enable: true for enable PVID false for disable */ -static int ice_vsi_manage_pvid(struct ice_vsi *vsi, u16 vid, bool enable) +static int ice_vsi_manage_pvid(struct ice_vsi *vsi, u16 pvid_info, bool enable) { struct ice_hw *hw = &vsi->back->hw; + struct ice_aqc_vsi_props *info; struct ice_vsi_ctx *ctxt; enum ice_status status; int ret = 0; @@ -453,20 +450,33 @@ static int ice_vsi_manage_pvid(struct ice_vsi *vsi, u16 vid, bool enable) return -ENOMEM; ctxt->info = vsi->info; - if (enable) - ice_vsi_set_pvid_fill_ctxt(ctxt, vid); - else - ice_vsi_kill_pvid_fill_ctxt(ctxt); + info = &ctxt->info; + if (enable) { + info->vlan_flags = ICE_AQ_VSI_VLAN_MODE_UNTAGGED | + ICE_AQ_VSI_PVLAN_INSERT_PVID | + ICE_AQ_VSI_VLAN_EMOD_STR; + info->sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + } else { + info->vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING | + ICE_AQ_VSI_VLAN_MODE_ALL; + info->sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + } + + info->pvid = cpu_to_le16(pvid_info); + info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID | + ICE_AQ_VSI_PROP_SW_VALID); status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (status) { - dev_info(ice_pf_to_dev(vsi->back), "update VSI for port VLAN failed, err %d aq_err %d\n", + dev_info(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %d\n", status, hw->adminq.sq_last_status); ret = -EIO; goto out; } - vsi->info = ctxt->info; + vsi->info.vlan_flags = info->vlan_flags; + vsi->info.sw_flags2 = info->sw_flags2; + vsi->info.pvid = info->pvid; out: kfree(ctxt); return ret; @@ -533,9 +543,20 @@ static int ice_alloc_vsi_res(struct ice_vf *vf) vf->lan_vsi_num = vsi->vsi_num; /* Check if port VLAN exist before, and restore it accordingly */ - if (vf->port_vlan_id) { - ice_vsi_manage_pvid(vsi, vf->port_vlan_id, true); - ice_vsi_add_vlan(vsi, vf->port_vlan_id & ICE_VLAN_M); + if (vf->port_vlan_info) { + ice_vsi_manage_pvid(vsi, vf->port_vlan_info, true); + if (ice_vsi_add_vlan(vsi, vf->port_vlan_info & VLAN_VID_MASK)) + dev_warn(ice_pf_to_dev(pf), "Failed to add Port VLAN %d filter for VF %d\n", + vf->port_vlan_info & VLAN_VID_MASK, vf->vf_id); + } else { + /* set VLAN 0 filter by default when no port VLAN is + * enabled. If a port VLAN is enabled we don't want + * untagged broadcast/multicast traffic seen on the VF + * interface. + */ + if (ice_vsi_add_vlan(vsi, 0)) + dev_warn(ice_pf_to_dev(pf), "Failed to add VLAN 0 filter for VF %d, MDD events will trigger. Reset the VF, disable spoofchk, or enable 8021q module on the guest\n", + vf->vf_id); } eth_broadcast_addr(broadcast); @@ -943,17 +964,9 @@ static void ice_cleanup_and_realloc_vf(struct ice_vf *vf) /* reallocate VF resources to finish resetting the VSI state */ if (!ice_alloc_vf_res(vf)) { - struct ice_vsi *vsi; - ice_ena_vf_mappings(vf); set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); clear_bit(ICE_VF_STATE_DIS, vf->vf_states); - - vsi = pf->vsi[vf->lan_vsi_idx]; - if (ice_vsi_add_vlan(vsi, 0)) - dev_warn(ice_pf_to_dev(pf), - "Failed to add VLAN 0 filter for VF %d, MDD events will trigger. Reset the VF, disable spoofchk, or enable 8021q module on the guest", - vf->vf_id); } /* Tell the VF driver the reset is done. This needs to be done only @@ -985,13 +998,13 @@ ice_vf_set_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m, if (vsi->num_vlan) { status = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_m, rm_promisc); - } else if (vf->port_vlan_id) { + } else if (vf->port_vlan_info) { if (rm_promisc) status = ice_clear_vsi_promisc(hw, vsi->idx, promisc_m, - vf->port_vlan_id); + vf->port_vlan_info); else status = ice_set_vsi_promisc(hw, vsi->idx, promisc_m, - vf->port_vlan_id); + vf->port_vlan_info); } else { if (rm_promisc) status = ice_clear_vsi_promisc(hw, vsi->idx, promisc_m, @@ -1167,7 +1180,7 @@ static bool ice_is_vf_disabled(struct ice_vf *vf) * * Returns true if the VF is reset, false otherwise. */ -static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) +bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) { struct ice_pf *pf = vf->pf; struct ice_vsi *vsi; @@ -1231,7 +1244,7 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) */ if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) || test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) { - if (vf->port_vlan_id || vsi->num_vlan) + if (vf->port_vlan_info || vsi->num_vlan) promisc_m = ICE_UCAST_VLAN_PROMISC_BITS; else promisc_m = ICE_UCAST_PROMISC_BITS; @@ -1518,6 +1531,72 @@ static void ice_vc_reset_vf(struct ice_vf *vf) } /** + * ice_get_vf_from_pfq - get the VF who owns the PF space queue passed in + * @pf: PF used to index all VFs + * @pfq: queue index relative to the PF's function space + * + * If no VF is found who owns the pfq then return NULL, otherwise return a + * pointer to the VF who owns the pfq + */ +static struct ice_vf *ice_get_vf_from_pfq(struct ice_pf *pf, u16 pfq) +{ + int vf_id; + + ice_for_each_vf(pf, vf_id) { + struct ice_vf *vf = &pf->vf[vf_id]; + struct ice_vsi *vsi; + u16 rxq_idx; + + vsi = pf->vsi[vf->lan_vsi_idx]; + + ice_for_each_rxq(vsi, rxq_idx) + if (vsi->rxq_map[rxq_idx] == pfq) + return vf; + } + + return NULL; +} + +/** + * ice_globalq_to_pfq - convert from global queue index to PF space queue index + * @pf: PF used for conversion + * @globalq: global queue index used to convert to PF space queue index + */ +static u32 ice_globalq_to_pfq(struct ice_pf *pf, u32 globalq) +{ + return globalq - pf->hw.func_caps.common_cap.rxq_first_id; +} + +/** + * ice_vf_lan_overflow_event - handle LAN overflow event for a VF + * @pf: PF that the LAN overflow event happened on + * @event: structure holding the event information for the LAN overflow event + * + * Determine if the LAN overflow event was caused by a VF queue. If it was not + * caused by a VF, do nothing. If a VF caused this LAN overflow event trigger a + * reset on the offending VF. + */ +void +ice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event) +{ + u32 gldcb_rtctq, queue; + struct ice_vf *vf; + + gldcb_rtctq = le32_to_cpu(event->desc.params.lan_overflow.prtdcb_ruptq); + dev_dbg(ice_pf_to_dev(pf), "GLDCB_RTCTQ: 0x%08x\n", gldcb_rtctq); + + /* event returns device global Rx queue number */ + queue = (gldcb_rtctq & GLDCB_RTCTQ_RXQNUM_M) >> + GLDCB_RTCTQ_RXQNUM_S; + + vf = ice_get_vf_from_pfq(pf, ice_globalq_to_pfq(pf, queue)); + if (!vf) + return; + + ice_vc_reset_vf(vf); +} + +/** * ice_vc_send_msg_to_vf - Send message to VF * @vf: pointer to the VF info * @v_opcode: virtual channel opcode @@ -1981,7 +2060,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) status = ice_update_vsi(&pf->hw, vf_vsi->idx, ctx, NULL); if (status) { - dev_err(dev, "Failed to %sable spoofchk on VF %d VSI %d\n error %d", + dev_err(dev, "Failed to %sable spoofchk on VF %d VSI %d\n error %d\n", ena ? "en" : "dis", vf->vf_id, vf_vsi->vsi_num, status); ret = -EIO; goto out; @@ -2039,6 +2118,22 @@ error_param: } /** + * ice_vc_validate_vqs_bitmaps - validate Rx/Tx queue bitmaps from VIRTCHNL + * @vqs: virtchnl_queue_select structure containing bitmaps to validate + * + * Return true on successful validation, else false + */ +static bool ice_vc_validate_vqs_bitmaps(struct virtchnl_queue_select *vqs) +{ + if ((!vqs->rx_queues && !vqs->tx_queues) || + vqs->rx_queues >= BIT(ICE_MAX_BASE_QS_PER_VF) || + vqs->tx_queues >= BIT(ICE_MAX_BASE_QS_PER_VF)) + return false; + + return true; +} + +/** * ice_vc_ena_qs_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer @@ -2065,13 +2160,7 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) goto error_param; } - if (!vqs->rx_queues && !vqs->tx_queues) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (vqs->rx_queues > ICE_MAX_BASE_QS_PER_VF || - vqs->tx_queues > ICE_MAX_BASE_QS_PER_VF) { + if (!ice_vc_validate_vqs_bitmaps(vqs)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } @@ -2097,7 +2186,7 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) if (test_bit(vf_q_id, vf->rxq_ena)) continue; - if (ice_vsi_ctrl_rx_ring(vsi, true, vf_q_id)) { + if (ice_vsi_ctrl_one_rx_ring(vsi, true, vf_q_id, true)) { dev_err(ice_pf_to_dev(vsi->back), "Failed to enable Rx ring %d on VSI %d\n", vf_q_id, vsi->vsi_num); v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2105,7 +2194,6 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) } set_bit(vf_q_id, vf->rxq_ena); - vf->num_qs_ena++; } vsi = pf->vsi[vf->lan_vsi_idx]; @@ -2121,7 +2209,6 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) continue; set_bit(vf_q_id, vf->txq_ena); - vf->num_qs_ena++; } /* Set flag to indicate that queues are enabled */ @@ -2163,7 +2250,7 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) goto error_param; } - if (!vqs->rx_queues && !vqs->tx_queues) { + if (!ice_vc_validate_vqs_bitmaps(vqs)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } @@ -2208,13 +2295,22 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) /* Clear enabled queues flag */ clear_bit(vf_q_id, vf->txq_ena); - vf->num_qs_ena--; } } - if (vqs->rx_queues) { - q_map = vqs->rx_queues; + q_map = vqs->rx_queues; + /* speed up Rx queue disable by batching them if possible */ + if (q_map && + bitmap_equal(&q_map, vf->rxq_ena, ICE_MAX_BASE_QS_PER_VF)) { + if (ice_vsi_stop_all_rx_rings(vsi)) { + dev_err(ice_pf_to_dev(vsi->back), "Failed to stop all Rx rings on VSI %d\n", + vsi->vsi_num); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + bitmap_zero(vf->rxq_ena, ICE_MAX_BASE_QS_PER_VF); + } else if (q_map) { for_each_set_bit(vf_q_id, &q_map, ICE_MAX_BASE_QS_PER_VF) { if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2225,7 +2321,8 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) if (!test_bit(vf_q_id, vf->rxq_ena)) continue; - if (ice_vsi_ctrl_rx_ring(vsi, false, vf_q_id)) { + if (ice_vsi_ctrl_one_rx_ring(vsi, false, vf_q_id, + true)) { dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx ring %d on VSI %d\n", vf_q_id, vsi->vsi_num); v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2234,12 +2331,11 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) /* Clear enabled queues flag */ clear_bit(vf_q_id, vf->rxq_ena); - vf->num_qs_ena--; } } /* Clear enabled queues flag */ - if (v_ret == VIRTCHNL_STATUS_SUCCESS && !vf->num_qs_ena) + if (v_ret == VIRTCHNL_STATUS_SUCCESS && ice_vf_has_no_qs_ena(vf)) clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); error_param: @@ -2733,19 +2829,20 @@ int ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, __be16 vlan_proto) { - u16 vlanprio = vlan_id | (qos << ICE_VLAN_PRIORITY_S); struct ice_pf *pf = ice_netdev_to_pf(netdev); struct ice_vsi *vsi; struct device *dev; struct ice_vf *vf; + u16 vlanprio; int ret; dev = ice_pf_to_dev(pf); if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; - if (vlan_id > ICE_MAX_VLANID || qos > 7) { - dev_err(dev, "Invalid VF Parameters\n"); + if (vlan_id >= VLAN_N_VID || qos > 7) { + dev_err(dev, "Invalid Port VLAN parameters for VF %d, ID %d, QoS %d\n", + vf_id, vlan_id, qos); return -EINVAL; } @@ -2761,40 +2858,52 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, if (ret) return ret; - if (le16_to_cpu(vsi->info.pvid) == vlanprio) { + vlanprio = vlan_id | (qos << VLAN_PRIO_SHIFT); + + if (vf->port_vlan_info == vlanprio) { /* duplicate request, so just return success */ dev_dbg(dev, "Duplicate pvid %d request\n", vlanprio); return 0; } - /* If PVID, then remove all filters on the old VLAN */ - if (vsi->info.pvid) - ice_vsi_kill_vlan(vsi, (le16_to_cpu(vsi->info.pvid) & - VLAN_VID_MASK)); - if (vlan_id || qos) { + /* remove VLAN 0 filter set by default when transitioning from + * no port VLAN to a port VLAN. No change to old port VLAN on + * failure. + */ + ret = ice_vsi_kill_vlan(vsi, 0); + if (ret) + return ret; ret = ice_vsi_manage_pvid(vsi, vlanprio, true); if (ret) return ret; } else { - ice_vsi_manage_pvid(vsi, 0, false); - vsi->info.pvid = 0; + /* add VLAN 0 filter back when transitioning from port VLAN to + * no port VLAN. No change to old port VLAN on failure. + */ + ret = ice_vsi_add_vlan(vsi, 0); + if (ret) + return ret; + ret = ice_vsi_manage_pvid(vsi, 0, false); + if (ret) + return ret; } if (vlan_id) { dev_info(dev, "Setting VLAN %d, QoS 0x%x on VF %d\n", vlan_id, qos, vf_id); - /* add new VLAN filter for each MAC */ + /* add VLAN filter for the port VLAN */ ret = ice_vsi_add_vlan(vsi, vlan_id); if (ret) return ret; } + /* remove old port VLAN filter with valid VLAN ID or QoS fields */ + if (vf->port_vlan_info) + ice_vsi_kill_vlan(vsi, vf->port_vlan_info & VLAN_VID_MASK); - /* The Port VLAN needs to be saved across resets the same as the - * default LAN MAC address. - */ - vf->port_vlan_id = le16_to_cpu(vsi->info.pvid); + /* keep port VLAN information persistent on resets */ + vf->port_vlan_info = le16_to_cpu(vsi->info.pvid); return 0; } @@ -2849,7 +2958,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) } for (i = 0; i < vfl->num_elements; i++) { - if (vfl->vlan_id[i] > ICE_MAX_VLANID) { + if (vfl->vlan_id[i] >= VLAN_N_VID) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; dev_err(dev, "invalid VF VLAN id %d\n", vfl->vlan_id[i]); @@ -2911,9 +3020,9 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) goto error_param; } - vsi->num_vlan++; - /* Enable VLAN pruning when VLAN is added */ - if (!vlan_promisc) { + /* Enable VLAN pruning when non-zero VLAN is added */ + if (!vlan_promisc && vid && + !ice_vsi_is_vlan_pruning_ena(vsi)) { status = ice_cfg_vlan_pruning(vsi, true, false); if (status) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2921,7 +3030,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) vid, status); goto error_param; } - } else { + } else if (vlan_promisc) { /* Enable Ucast/Mcast VLAN promiscuous mode */ promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX; @@ -2965,9 +3074,9 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) goto error_param; } - vsi->num_vlan--; - /* Disable VLAN pruning when the last VLAN is removed */ - if (!vsi->num_vlan) + /* Disable VLAN pruning when only VLAN 0 is left */ + if (vsi->num_vlan == 1 && + ice_vsi_is_vlan_pruning_ena(vsi)) ice_cfg_vlan_pruning(vsi, false, false); /* Disable Unicast/Multicast VLAN promiscuous mode */ @@ -3246,14 +3355,12 @@ int ice_get_vf_cfg(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi) { struct ice_pf *pf = ice_netdev_to_pf(netdev); - struct ice_vsi *vsi; struct ice_vf *vf; if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; vf = &pf->vf[vf_id]; - vsi = pf->vsi[vf->lan_vsi_idx]; if (ice_check_vf_init(pf, vf)) return -EBUSY; @@ -3262,9 +3369,8 @@ ice_get_vf_cfg(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi) ether_addr_copy(ivi->mac, vf->dflt_lan_addr.addr); /* VF configuration for VLAN and applicable QoS */ - ivi->vlan = le16_to_cpu(vsi->info.pvid) & ICE_VLAN_M; - ivi->qos = (le16_to_cpu(vsi->info.pvid) & ICE_PRIORITY_M) >> - ICE_VLAN_PRIORITY_S; + ivi->vlan = vf->port_vlan_info & VLAN_VID_MASK; + ivi->qos = (vf->port_vlan_info & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; ivi->trusted = vf->trusted; ivi->spoofchk = vf->spoofchk; @@ -3442,3 +3548,52 @@ int ice_get_vf_stats(struct net_device *netdev, int vf_id, return 0; } + +/** + * ice_print_vfs_mdd_event - print VFs malicious driver detect event + * @pf: pointer to the PF structure + * + * Called from ice_handle_mdd_event to rate limit and print VFs MDD events. + */ +void ice_print_vfs_mdd_events(struct ice_pf *pf) +{ + struct device *dev = ice_pf_to_dev(pf); + struct ice_hw *hw = &pf->hw; + int i; + + /* check that there are pending MDD events to print */ + if (!test_and_clear_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state)) + return; + + /* VF MDD event logs are rate limited to one second intervals */ + if (time_is_after_jiffies(pf->last_printed_mdd_jiffies + HZ * 1)) + return; + + pf->last_printed_mdd_jiffies = jiffies; + + ice_for_each_vf(pf, i) { + struct ice_vf *vf = &pf->vf[i]; + + /* only print Rx MDD event message if there are new events */ + if (vf->mdd_rx_events.count != vf->mdd_rx_events.last_printed) { + vf->mdd_rx_events.last_printed = + vf->mdd_rx_events.count; + + dev_info(dev, "%d Rx Malicious Driver Detection events detected on PF %d VF %d MAC %pM. mdd-auto-reset-vfs=%s\n", + vf->mdd_rx_events.count, hw->pf_id, i, + vf->dflt_lan_addr.addr, + test_bit(ICE_FLAG_MDD_AUTO_RESET_VF, pf->flags) + ? "on" : "off"); + } + + /* only print Tx MDD event message if there are new events */ + if (vf->mdd_tx_events.count != vf->mdd_tx_events.last_printed) { + vf->mdd_tx_events.last_printed = + vf->mdd_tx_events.count; + + dev_info(dev, "%d Tx Malicious Driver Detection events detected on PF %d VF %d MAC %pM.\n", + vf->mdd_tx_events.count, hw->pf_id, i, + vf->dflt_lan_addr.addr); + } + } +} diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index ac67982751df..36dad0eba3db 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -5,11 +5,6 @@ #define _ICE_VIRTCHNL_PF_H_ #include "ice.h" -#define ICE_MAX_VLANID 4095 -#define ICE_VLAN_PRIORITY_S 12 -#define ICE_VLAN_M 0xFFF -#define ICE_PRIORITY_M 0x7000 - /* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */ #define ICE_MAX_VLAN_PER_VF 8 #define ICE_MAX_MACADDR_PER_VF 12 @@ -61,6 +56,13 @@ enum ice_virtchnl_cap { ICE_VIRTCHNL_VF_CAP_PRIVILEGE, }; +/* VF MDD events print structure */ +struct ice_mdd_vf_events { + u16 count; /* total count of Rx|Tx events */ + /* count number of the last printed event */ + u16 last_printed; +}; + /* VF information structure */ struct ice_vf { struct ice_pf *pf; @@ -75,7 +77,7 @@ struct ice_vf { struct virtchnl_ether_addr dflt_lan_addr; DECLARE_BITMAP(txq_ena, ICE_MAX_BASE_QS_PER_VF); DECLARE_BITMAP(rxq_ena, ICE_MAX_BASE_QS_PER_VF); - u16 port_vlan_id; + u16 port_vlan_info; /* Port VLAN ID and QoS */ u8 pf_set_mac:1; /* VF MAC address set by VMM admin */ u8 trusted:1; u8 spoofchk:1; @@ -89,14 +91,14 @@ struct ice_vf { unsigned int tx_rate; /* Tx bandwidth limit in Mbps */ DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */ - u64 num_mdd_events; /* number of MDD events detected */ u64 num_inval_msgs; /* number of continuous invalid msgs */ u64 num_valid_msgs; /* number of valid msgs detected */ unsigned long vf_caps; /* VF's adv. capabilities */ u8 num_req_qs; /* num of queue pairs requested by VF */ u16 num_mac; u16 num_vf_qs; /* num of queue configured per VF */ - u16 num_qs_ena; /* total num of Tx/Rx queue enabled */ + struct ice_mdd_vf_events mdd_rx_events; + struct ice_mdd_vf_events mdd_tx_events; }; #ifdef CONFIG_PCI_IOV @@ -111,6 +113,7 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event); void ice_vc_notify_link_state(struct ice_pf *pf); void ice_vc_notify_reset(struct ice_pf *pf); bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr); +bool ice_reset_vf(struct ice_vf *vf, bool is_vflr); int ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, @@ -128,6 +131,9 @@ void ice_set_vf_state_qs_dis(struct ice_vf *vf); int ice_get_vf_stats(struct net_device *netdev, int vf_id, struct ifla_vf_stats *vf_stats); +void +ice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event); +void ice_print_vfs_mdd_events(struct ice_pf *pf); #else /* CONFIG_PCI_IOV */ #define ice_process_vflr_event(pf) do {} while (0) #define ice_free_vfs(pf) do {} while (0) @@ -135,6 +141,8 @@ ice_get_vf_stats(struct net_device *netdev, int vf_id, #define ice_vc_notify_link_state(pf) do {} while (0) #define ice_vc_notify_reset(pf) do {} while (0) #define ice_set_vf_state_qs_dis(vf) do {} while (0) +#define ice_vf_lan_overflow_event(pf, event) do {} while (0) +#define ice_print_vfs_mdd_events(pf) do {} while (0) static inline bool ice_reset_all_vfs(struct ice_pf __always_unused *pf, @@ -143,6 +151,12 @@ ice_reset_all_vfs(struct ice_pf __always_unused *pf, return true; } +static inline bool +ice_reset_vf(struct ice_vf __always_unused *vf, bool __always_unused is_vflr) +{ + return true; +} + static inline int ice_sriov_configure(struct pci_dev __always_unused *pdev, int __always_unused num_vfs) diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index 4d3407bbd4c4..8279db15e870 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -183,7 +183,7 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx) if (err) return err; } - err = ice_vsi_ctrl_rx_ring(vsi, false, q_idx); + err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, true); if (err) return err; @@ -243,7 +243,7 @@ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx) ice_qvec_cfg_msix(vsi, q_vector); - err = ice_vsi_ctrl_rx_ring(vsi, true, q_idx); + err = ice_vsi_ctrl_one_rx_ring(vsi, true, q_idx, true); if (err) goto free_buf; @@ -457,7 +457,7 @@ int ice_xsk_umem_setup(struct ice_vsi *vsi, struct xdp_umem *umem, u16 qid) if (if_running) { ret = ice_qp_dis(vsi, qid); if (ret) { - netdev_err(vsi->netdev, "ice_qp_dis error = %d", ret); + netdev_err(vsi->netdev, "ice_qp_dis error = %d\n", ret); goto xsk_umem_if_up; } } @@ -471,11 +471,11 @@ xsk_umem_if_up: if (!ret && umem_present) napi_schedule(&vsi->xdp_rings[qid]->q_vector->napi); else if (ret) - netdev_err(vsi->netdev, "ice_qp_ena error = %d", ret); + netdev_err(vsi->netdev, "ice_qp_ena error = %d\n", ret); } if (umem_failure) { - netdev_err(vsi->netdev, "Could not %sable UMEM, error = %d", + netdev_err(vsi->netdev, "Could not %sable UMEM, error = %d\n", umem_present ? "en" : "dis", umem_failure); return umem_failure; } @@ -609,7 +609,7 @@ ice_alloc_buf_slow_zc(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf) */ static bool ice_alloc_rx_bufs_zc(struct ice_ring *rx_ring, int count, - bool alloc(struct ice_ring *, struct ice_rx_buf *)) + bool (*alloc)(struct ice_ring *, struct ice_rx_buf *)) { union ice_32b_rx_flex_desc *rx_desc; u16 ntu = rx_ring->next_to_use; @@ -816,10 +816,10 @@ ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp) break; default: bpf_warn_invalid_xdp_action(act); - /* fallthrough -- not supported action */ + fallthrough; case XDP_ABORTED: trace_xdp_exception(rx_ring->netdev, xdp_prog, act); - /* fallthrough -- handle aborts by dropping frame */ + fallthrough; case XDP_DROP: result = ICE_XDP_CONSUMED; break; @@ -841,8 +841,8 @@ int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget) unsigned int total_rx_bytes = 0, total_rx_packets = 0; u16 cleaned_count = ICE_DESC_UNUSED(rx_ring); unsigned int xdp_xmit = 0; + bool failure = false; struct xdp_buff xdp; - bool failure = 0; xdp.rxq = &rx_ring->xdp_rxq; @@ -937,6 +937,15 @@ int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget) ice_finalize_xdp_rx(rx_ring, xdp_xmit); ice_update_rx_ring_stats(rx_ring, total_rx_packets, total_rx_bytes); + if (xsk_umem_uses_need_wakeup(rx_ring->xsk_umem)) { + if (failure || rx_ring->next_to_clean == rx_ring->next_to_use) + xsk_set_rx_need_wakeup(rx_ring->xsk_umem); + else + xsk_clear_rx_need_wakeup(rx_ring->xsk_umem); + + return (int)total_rx_packets; + } + return failure ? budget : (int)total_rx_packets; } @@ -988,6 +997,8 @@ static bool ice_xmit_zc(struct ice_ring *xdp_ring, int budget) if (tx_desc) { ice_xdp_ring_update_tail(xdp_ring); xsk_umem_consume_tx_done(xdp_ring->xsk_umem); + if (xsk_umem_uses_need_wakeup(xdp_ring->xsk_umem)) + xsk_clear_tx_need_wakeup(xdp_ring->xsk_umem); } return budget > 0 && work_done; @@ -1063,6 +1074,13 @@ bool ice_clean_tx_irq_zc(struct ice_ring *xdp_ring, int budget) if (xsk_frames) xsk_umem_complete_tx(xdp_ring->xsk_umem, xsk_frames); + if (xsk_umem_uses_need_wakeup(xdp_ring->xsk_umem)) { + if (xdp_ring->next_to_clean == xdp_ring->next_to_use) + xsk_set_tx_need_wakeup(xdp_ring->xsk_umem); + else + xsk_clear_tx_need_wakeup(xdp_ring->xsk_umem); + } + ice_update_tx_ring_stats(xdp_ring, total_packets, total_bytes); xmit_done = ice_xmit_zc(xdp_ring, ICE_DFLT_IRQ_WORK); diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 49b5fa9d4783..0c9282e2aaec 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -306,7 +306,7 @@ struct igb_q_vector { char name[IFNAMSIZ + 9]; /* for dynamic allocation of rings associated with this q_vector */ - struct igb_ring ring[0] ____cacheline_internodealigned_in_smp; + struct igb_ring ring[] ____cacheline_internodealigned_in_smp; }; enum e1000_ring_flags_t { diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 49fb1e1965cd..e3c164c12e10 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -8,4 +8,4 @@ obj-$(CONFIG_IGC) += igc.o igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o \ -igc_ethtool.o igc_ptp.o +igc_ethtool.o igc_ptp.o igc_dump.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 52066bdbbad0..a1f845a2aa80 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -42,6 +42,10 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter, const u8 *addr, u8 queue, u8 flags); void igc_update_stats(struct igc_adapter *adapter); +/* igc_dump declarations */ +void igc_rings_dump(struct igc_adapter *adapter); +void igc_regs_dump(struct igc_adapter *adapter); + extern char igc_driver_name[]; extern char igc_driver_version[]; @@ -53,10 +57,13 @@ extern char igc_driver_version[]; /* Interrupt defines */ #define IGC_START_ITR 648 /* ~6000 ints/sec */ + +/* Flags definitions */ #define IGC_FLAG_HAS_MSI BIT(0) #define IGC_FLAG_QUEUE_PAIRS BIT(3) #define IGC_FLAG_DMAC BIT(4) #define IGC_FLAG_PTP BIT(8) +#define IGC_FLAG_WOL_SUPPORTED BIT(8) #define IGC_FLAG_NEED_LINK_UPDATE BIT(9) #define IGC_FLAG_MEDIA_RESET BIT(10) #define IGC_FLAG_MAS_ENABLE BIT(12) @@ -108,7 +115,7 @@ extern char igc_driver_version[]; #define IGC_RX_HDR_LEN IGC_RXBUFFER_256 /* Transmit and receive latency (for PTP timestamps) */ -/* FIXME: These values were estimated using the ones that i210 has as +/* FIXME: These values were estimated using the ones that i225 has as * basis, they seem to provide good numbers with ptp4l/phc2sys, but we * need to confirm them. */ @@ -319,7 +326,7 @@ struct igc_q_vector { struct net_device poll_dev; /* for dynamic allocation of rings associated with this q_vector */ - struct igc_ring ring[0] ____cacheline_internodealigned_in_smp; + struct igc_ring ring[] ____cacheline_internodealigned_in_smp; }; #define MAX_ETYPE_FILTER (4 - 1) @@ -552,6 +559,7 @@ int igc_erase_filter(struct igc_adapter *adapter, void igc_ptp_init(struct igc_adapter *adapter); void igc_ptp_reset(struct igc_adapter *adapter); +void igc_ptp_suspend(struct igc_adapter *adapter); void igc_ptp_stop(struct igc_adapter *adapter); void igc_ptp_rx_rgtstamp(struct igc_q_vector *q_vector, struct sk_buff *skb); void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, void *va, diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 58efa7a02c68..4ddccccf42cc 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -16,7 +16,10 @@ /* Wake Up Filter Control */ #define IGC_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define IGC_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define IGC_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ #define IGC_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define IGC_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ #define IGC_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */ @@ -259,6 +262,9 @@ #define IGC_GPIE_EIAME 0x40000000 #define IGC_GPIE_PBA 0x80000000 +/* Receive Descriptor bit definitions */ +#define IGC_RXD_STAT_DD 0x01 /* Descriptor Done */ + /* Transmit Descriptor bit definitions */ #define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */ #define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */ diff --git a/drivers/net/ethernet/intel/igc/igc_dump.c b/drivers/net/ethernet/intel/igc/igc_dump.c new file mode 100644 index 000000000000..657ab50ae296 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_dump.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include "igc.h" + +struct igc_reg_info { + u32 ofs; + char *name; +}; + +static const struct igc_reg_info igc_reg_info_tbl[] = { + /* General Registers */ + {IGC_CTRL, "CTRL"}, + {IGC_STATUS, "STATUS"}, + {IGC_CTRL_EXT, "CTRL_EXT"}, + {IGC_MDIC, "MDIC"}, + + /* Interrupt Registers */ + {IGC_ICR, "ICR"}, + + /* RX Registers */ + {IGC_RCTL, "RCTL"}, + {IGC_RDLEN(0), "RDLEN"}, + {IGC_RDH(0), "RDH"}, + {IGC_RDT(0), "RDT"}, + {IGC_RXDCTL(0), "RXDCTL"}, + {IGC_RDBAL(0), "RDBAL"}, + {IGC_RDBAH(0), "RDBAH"}, + + /* TX Registers */ + {IGC_TCTL, "TCTL"}, + {IGC_TDBAL(0), "TDBAL"}, + {IGC_TDBAH(0), "TDBAH"}, + {IGC_TDLEN(0), "TDLEN"}, + {IGC_TDH(0), "TDH"}, + {IGC_TDT(0), "TDT"}, + {IGC_TXDCTL(0), "TXDCTL"}, + {IGC_TDFH, "TDFH"}, + {IGC_TDFT, "TDFT"}, + {IGC_TDFHS, "TDFHS"}, + {IGC_TDFPC, "TDFPC"}, + + /* List Terminator */ + {} +}; + +/* igc_regdump - register printout routine */ +static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo) +{ + int n = 0; + char rname[16]; + u32 regs[8]; + + switch (reginfo->ofs) { + case IGC_RDLEN(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDLEN(n)); + break; + case IGC_RDH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDH(n)); + break; + case IGC_RDT(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDT(n)); + break; + case IGC_RXDCTL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RXDCTL(n)); + break; + case IGC_RDBAL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDBAL(n)); + break; + case IGC_RDBAH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDBAH(n)); + break; + case IGC_TDBAL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDBAL(n)); + break; + case IGC_TDBAH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDBAH(n)); + break; + case IGC_TDLEN(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDLEN(n)); + break; + case IGC_TDH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDH(n)); + break; + case IGC_TDT(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDT(n)); + break; + case IGC_TXDCTL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TXDCTL(n)); + break; + default: + pr_info("%-15s %08x\n", reginfo->name, rd32(reginfo->ofs)); + return; + } + + snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]"); + pr_info("%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1], + regs[2], regs[3]); +} + +/* igc_rings_dump - Tx-rings and Rx-rings */ +void igc_rings_dump(struct igc_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct my_u0 { u64 a; u64 b; } *u0; + union igc_adv_tx_desc *tx_desc; + union igc_adv_rx_desc *rx_desc; + struct igc_ring *tx_ring; + struct igc_ring *rx_ring; + u32 staterr; + u16 i, n; + + if (!netif_msg_hw(adapter)) + return; + + /* Print netdevice Info */ + if (netdev) { + dev_info(&adapter->pdev->dev, "Net device Info\n"); + pr_info("Device Name state trans_start\n"); + pr_info("%-15s %016lX %016lX\n", netdev->name, + netdev->state, dev_trans_start(netdev)); + } + + /* Print TX Ring Summary */ + if (!netdev || !netif_running(netdev)) + goto exit; + + dev_info(&adapter->pdev->dev, "TX Rings Summary\n"); + pr_info("Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n"); + for (n = 0; n < adapter->num_tx_queues; n++) { + struct igc_tx_buffer *buffer_info; + + tx_ring = adapter->tx_ring[n]; + buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean]; + + pr_info(" %5d %5X %5X %016llX %04X %p %016llX\n", + n, tx_ring->next_to_use, tx_ring->next_to_clean, + (u64)dma_unmap_addr(buffer_info, dma), + dma_unmap_len(buffer_info, len), + buffer_info->next_to_watch, + (u64)buffer_info->time_stamp); + } + + /* Print TX Rings */ + if (!netif_msg_tx_done(adapter)) + goto rx_ring_summary; + + dev_info(&adapter->pdev->dev, "TX Rings Dump\n"); + + /* Transmit Descriptor Formats + * + * Advanced Transmit Descriptor + * +--------------------------------------------------------------+ + * 0 | Buffer Address [63:0] | + * +--------------------------------------------------------------+ + * 8 | PAYLEN | PORTS |CC|IDX | STA | DCMD |DTYP|MAC|RSV| DTALEN | + * +--------------------------------------------------------------+ + * 63 46 45 40 39 38 36 35 32 31 24 15 0 + */ + + for (n = 0; n < adapter->num_tx_queues; n++) { + tx_ring = adapter->tx_ring[n]; + pr_info("------------------------------------\n"); + pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index); + pr_info("------------------------------------\n"); + pr_info("T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n"); + + for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) { + const char *next_desc; + struct igc_tx_buffer *buffer_info; + + tx_desc = IGC_TX_DESC(tx_ring, i); + buffer_info = &tx_ring->tx_buffer_info[i]; + u0 = (struct my_u0 *)tx_desc; + if (i == tx_ring->next_to_use && + i == tx_ring->next_to_clean) + next_desc = " NTC/U"; + else if (i == tx_ring->next_to_use) + next_desc = " NTU"; + else if (i == tx_ring->next_to_clean) + next_desc = " NTC"; + else + next_desc = ""; + + pr_info("T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n", + i, le64_to_cpu(u0->a), + le64_to_cpu(u0->b), + (u64)dma_unmap_addr(buffer_info, dma), + dma_unmap_len(buffer_info, len), + buffer_info->next_to_watch, + (u64)buffer_info->time_stamp, + buffer_info->skb, next_desc); + + if (netif_msg_pktdata(adapter) && buffer_info->skb) + print_hex_dump(KERN_INFO, "", + DUMP_PREFIX_ADDRESS, + 16, 1, buffer_info->skb->data, + dma_unmap_len(buffer_info, len), + true); + } + } + + /* Print RX Rings Summary */ +rx_ring_summary: + dev_info(&adapter->pdev->dev, "RX Rings Summary\n"); + pr_info("Queue [NTU] [NTC]\n"); + for (n = 0; n < adapter->num_rx_queues; n++) { + rx_ring = adapter->rx_ring[n]; + pr_info(" %5d %5X %5X\n", + n, rx_ring->next_to_use, rx_ring->next_to_clean); + } + + /* Print RX Rings */ + if (!netif_msg_rx_status(adapter)) + goto exit; + + dev_info(&adapter->pdev->dev, "RX Rings Dump\n"); + + /* Advanced Receive Descriptor (Read) Format + * 63 1 0 + * +-----------------------------------------------------+ + * 0 | Packet Buffer Address [63:1] |A0/NSE| + * +----------------------------------------------+------+ + * 8 | Header Buffer Address [63:1] | DD | + * +-----------------------------------------------------+ + * + * + * Advanced Receive Descriptor (Write-Back) Format + * + * 63 48 47 32 31 30 21 20 17 16 4 3 0 + * +------------------------------------------------------+ + * 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS | + * | Checksum Ident | | | | Type | Type | + * +------------------------------------------------------+ + * 8 | VLAN Tag | Length | Extended Error | Extended Status | + * +------------------------------------------------------+ + * 63 48 47 32 31 20 19 0 + */ + + for (n = 0; n < adapter->num_rx_queues; n++) { + rx_ring = adapter->rx_ring[n]; + pr_info("------------------------------------\n"); + pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index); + pr_info("------------------------------------\n"); + pr_info("R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n"); + pr_info("RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n"); + + for (i = 0; i < rx_ring->count; i++) { + const char *next_desc; + struct igc_rx_buffer *buffer_info; + + buffer_info = &rx_ring->rx_buffer_info[i]; + rx_desc = IGC_RX_DESC(rx_ring, i); + u0 = (struct my_u0 *)rx_desc; + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + + if (i == rx_ring->next_to_use) + next_desc = " NTU"; + else if (i == rx_ring->next_to_clean) + next_desc = " NTC"; + else + next_desc = ""; + + if (staterr & IGC_RXD_STAT_DD) { + /* Descriptor Done */ + pr_info("%s[0x%03X] %016llX %016llX ---------------- %s\n", + "RWB", i, + le64_to_cpu(u0->a), + le64_to_cpu(u0->b), + next_desc); + } else { + pr_info("%s[0x%03X] %016llX %016llX %016llX %s\n", + "R ", i, + le64_to_cpu(u0->a), + le64_to_cpu(u0->b), + (u64)buffer_info->dma, + next_desc); + + if (netif_msg_pktdata(adapter) && + buffer_info->dma && buffer_info->page) { + print_hex_dump(KERN_INFO, "", + DUMP_PREFIX_ADDRESS, + 16, 1, + page_address + (buffer_info->page) + + buffer_info->page_offset, + igc_rx_bufsz(rx_ring), + true); + } + } + } + } + +exit: + return; +} + +/* igc_regs_dump - registers dump */ +void igc_regs_dump(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + struct igc_reg_info *reginfo; + + /* Print Registers */ + dev_info(&adapter->pdev->dev, "Register Dump\n"); + pr_info(" Register Name Value\n"); + for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl; + reginfo->name; reginfo++) { + igc_regdump(hw, reginfo); + } +} diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index ee07011e13e9..69f50b8e2af3 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -308,6 +308,65 @@ static void igc_get_regs(struct net_device *netdev, regs_buff[168 + i] = rd32(IGC_TXDCTL(i)); } +static void igc_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + wol->wolopts = 0; + + if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) + return; + + wol->supported = WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC | + WAKE_PHY; + + /* apply any specific unsupported masks here */ + switch (adapter->hw.device_id) { + default: + break; + } + + if (adapter->wol & IGC_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & IGC_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & IGC_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & IGC_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + if (adapter->wol & IGC_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; +} + +static int igc_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER)) + return -EOPNOTSUPP; + + if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) + return wol->wolopts ? -EOPNOTSUPP : 0; + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= IGC_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= IGC_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= IGC_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= IGC_WUFC_MAG; + if (wol->wolopts & WAKE_PHY) + adapter->wol |= IGC_WUFC_LNKC; + device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + + return 0; +} + static u32 igc_get_msglevel(struct net_device *netdev) { struct igc_adapter *adapter = netdev_priv(netdev); @@ -1859,6 +1918,8 @@ static const struct ethtool_ops igc_ethtool_ops = { .get_drvinfo = igc_get_drvinfo, .get_regs_len = igc_get_regs_len, .get_regs = igc_get_regs, + .get_wol = igc_get_wol, + .set_wol = igc_set_wol, .get_msglevel = igc_get_msglevel, .set_msglevel = igc_set_msglevel, .nway_reset = igc_nway_reset, diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index d9d5425fe8d9..69fa1ce1f927 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3546,6 +3546,8 @@ static void igc_reset_task(struct work_struct *work) adapter = container_of(work, struct igc_adapter, reset_task); + igc_rings_dump(adapter); + igc_regs_dump(adapter); netdev_err(adapter->netdev, "Reset adapter\n"); igc_reinit_locked(adapter); } @@ -4029,6 +4031,9 @@ static void igc_watchdog_task(struct work_struct *work) } } if (link) { + /* Cancel scheduled suspend requests. */ + pm_runtime_resume(netdev->dev.parent); + if (!netif_carrier_ok(netdev)) { u32 ctrl; @@ -4114,6 +4119,8 @@ no_wait: return; } } + pm_schedule_suspend(netdev->dev.parent, + MSEC_PER_SEC * 5); /* also check for alternate media here */ } else if (!netif_carrier_ok(netdev) && @@ -4337,6 +4344,7 @@ request_done: static int __igc_open(struct net_device *netdev, bool resuming) { struct igc_adapter *adapter = netdev_priv(netdev); + struct pci_dev *pdev = adapter->pdev; struct igc_hw *hw = &adapter->hw; int err = 0; int i = 0; @@ -4348,6 +4356,9 @@ static int __igc_open(struct net_device *netdev, bool resuming) return -EBUSY; } + if (!resuming) + pm_runtime_get_sync(&pdev->dev); + netif_carrier_off(netdev); /* allocate transmit descriptors */ @@ -4386,6 +4397,9 @@ static int __igc_open(struct net_device *netdev, bool resuming) rd32(IGC_ICR); igc_irq_enable(adapter); + if (!resuming) + pm_runtime_put(&pdev->dev); + netif_tx_start_all_queues(netdev); /* start the watchdog. */ @@ -4404,6 +4418,8 @@ err_setup_rx: igc_free_all_tx_resources(adapter); err_setup_tx: igc_reset(adapter); + if (!resuming) + pm_runtime_put(&pdev->dev); return err; } @@ -4428,9 +4444,13 @@ static int igc_open(struct net_device *netdev) static int __igc_close(struct net_device *netdev, bool suspending) { struct igc_adapter *adapter = netdev_priv(netdev); + struct pci_dev *pdev = adapter->pdev; WARN_ON(test_bit(__IGC_RESETTING, &adapter->state)); + if (!suspending) + pm_runtime_get_sync(&pdev->dev); + igc_down(adapter); igc_release_hw_control(adapter); @@ -4440,6 +4460,9 @@ static int __igc_close(struct net_device *netdev, bool suspending) igc_free_all_tx_resources(adapter); igc_free_all_rx_resources(adapter); + if (!suspending) + pm_runtime_put_sync(&pdev->dev); + return 0; } @@ -4766,6 +4789,16 @@ static int igc_probe(struct pci_dev *pdev, hw->fc.requested_mode = igc_fc_default; hw->fc.current_mode = igc_fc_default; + /* By default, support wake on port A */ + adapter->flags |= IGC_FLAG_WOL_SUPPORTED; + + /* initialize the wol settings based on the eeprom settings */ + if (adapter->flags & IGC_FLAG_WOL_SUPPORTED) + adapter->wol |= IGC_WUFC_MAG; + + device_set_wakeup_enable(&adapter->pdev->dev, + adapter->flags & IGC_FLAG_WOL_SUPPORTED); + /* reset the hardware with the new settings */ igc_reset(adapter); @@ -4792,6 +4825,10 @@ static int igc_probe(struct pci_dev *pdev, pcie_print_link_status(pdev); netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr); + dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP); + + pm_runtime_put_noidle(&pdev->dev); + return 0; err_register: @@ -4826,6 +4863,8 @@ static void igc_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct igc_adapter *adapter = netdev_priv(netdev); + pm_runtime_get_noresume(&pdev->dev); + igc_ptp_stop(adapter); set_bit(__IGC_DOWN, &adapter->state); @@ -4870,6 +4909,8 @@ static int __igc_shutdown(struct pci_dev *pdev, bool *enable_wake, if (netif_running(netdev)) __igc_close(netdev, true); + igc_ptp_suspend(adapter); + igc_clear_interrupt_scheme(adapter); rtnl_unlock(); @@ -5045,6 +5086,108 @@ static void igc_shutdown(struct pci_dev *pdev) } } +/** + * igc_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current PCI connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + **/ +static pci_ers_result_t igc_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + + netif_device_detach(netdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (netif_running(netdev)) + igc_down(adapter); + pci_disable_device(pdev); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * igc_io_slot_reset - called after the PCI bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. Implementation + * resembles the first-half of the igc_resume routine. + **/ +static pci_ers_result_t igc_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + pci_ers_result_t result; + + if (pci_enable_device_mem(pdev)) { + dev_err(&pdev->dev, + "Could not re-enable PCI device after reset.\n"); + result = PCI_ERS_RESULT_DISCONNECT; + } else { + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + /* In case of PCI error, adapter loses its HW address + * so we should re-assign it here. + */ + hw->hw_addr = adapter->io_addr; + + igc_reset(adapter); + wr32(IGC_WUS, ~0); + result = PCI_ERS_RESULT_RECOVERED; + } + + return result; +} + +/** + * igc_io_resume - called when traffic can start to flow again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. Implementation resembles the + * second-half of the igc_resume routine. + */ +static void igc_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + + rtnl_lock(); + if (netif_running(netdev)) { + if (igc_open(netdev)) { + dev_err(&pdev->dev, "igc_open failed after reset\n"); + return; + } + } + + netif_device_attach(netdev); + + /* let the f/w know that the h/w is now under the control of the + * driver. + */ + igc_get_hw_control(adapter); + rtnl_unlock(); +} + +static const struct pci_error_handlers igc_err_handler = { + .error_detected = igc_io_error_detected, + .slot_reset = igc_io_slot_reset, + .resume = igc_io_resume, +}; + #ifdef CONFIG_PM static const struct dev_pm_ops igc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(igc_suspend, igc_resume) @@ -5062,6 +5205,7 @@ static struct pci_driver igc_driver = { .driver.pm = &igc_pm_ops, #endif .shutdown = igc_shutdown, + .err_handler = &igc_err_handler, }; /** diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 693506587198..f99c514ad0f4 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -509,7 +509,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) * This work function polls the TSYNCTXCTL valid bit to determine when a * timestamp has been taken for the current stored skb. */ -void igc_ptp_tx_work(struct work_struct *work) +static void igc_ptp_tx_work(struct work_struct *work) { struct igc_adapter *adapter = container_of(work, struct igc_adapter, ptp_tx_work); diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index c9029b549b90..d4af53a80f11 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -17,6 +17,11 @@ /* Internal Packet Buffer Size Registers */ #define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ #define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */ +#define IGC_TDFH 0x03410 /* Tx Data FIFO Head - RW */ +#define IGC_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ +#define IGC_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ +#define IGC_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */ +#define IGC_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */ /* NVM Register Descriptions */ #define IGC_EERD 0x12014 /* EEprom mode read - RW */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 39e73ad60352..2833e4f041ce 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -462,7 +462,7 @@ struct ixgbe_q_vector { char name[IFNAMSIZ + 9]; /* for dynamic allocation of rings associated with this q_vector */ - struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp; + struct ixgbe_ring ring[] ____cacheline_internodealigned_in_smp; }; #ifdef CONFIG_IXGBE_HWMON diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 2e4975572e9f..de3c7ce9353c 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -2077,12 +2077,7 @@ jme_tx_tso(struct sk_buff *skb, __le16 *mss, u8 *flags) IPPROTO_TCP, 0); } else { - struct ipv6hdr *ip6h = ipv6_hdr(skb); - - tcp_hdr(skb)->check = ~csum_ipv6_magic(&ip6h->saddr, - &ip6h->daddr, 0, - IPPROTO_TCP, - 0); + tcp_v6_gso_csum_prep(skb); } return 0; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 98017e7d5dd0..b22eeb5f8700 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -341,6 +341,11 @@ enum { ETHTOOL_STAT_EEE_WAKEUP, ETHTOOL_STAT_SKB_ALLOC_ERR, ETHTOOL_STAT_REFILL_ERR, + ETHTOOL_XDP_REDIRECT, + ETHTOOL_XDP_PASS, + ETHTOOL_XDP_DROP, + ETHTOOL_XDP_XMIT, + ETHTOOL_XDP_TX, ETHTOOL_MAX_STATS, }; @@ -354,10 +359,10 @@ struct mvneta_statistic { #define T_REG_64 64 #define T_SW 1 -#define MVNETA_XDP_PASS BIT(0) -#define MVNETA_XDP_DROPPED BIT(1) -#define MVNETA_XDP_TX BIT(2) -#define MVNETA_XDP_REDIR BIT(3) +#define MVNETA_XDP_PASS 0 +#define MVNETA_XDP_DROPPED BIT(0) +#define MVNETA_XDP_TX BIT(1) +#define MVNETA_XDP_REDIR BIT(2) static const struct mvneta_statistic mvneta_statistics[] = { { 0x3000, T_REG_64, "good_octets_received", }, @@ -395,16 +400,38 @@ static const struct mvneta_statistic mvneta_statistics[] = { { ETHTOOL_STAT_EEE_WAKEUP, T_SW, "eee_wakeup_errors", }, { ETHTOOL_STAT_SKB_ALLOC_ERR, T_SW, "skb_alloc_errors", }, { ETHTOOL_STAT_REFILL_ERR, T_SW, "refill_errors", }, + { ETHTOOL_XDP_REDIRECT, T_SW, "rx_xdp_redirect", }, + { ETHTOOL_XDP_PASS, T_SW, "rx_xdp_pass", }, + { ETHTOOL_XDP_DROP, T_SW, "rx_xdp_drop", }, + { ETHTOOL_XDP_TX, T_SW, "rx_xdp_tx", }, + { ETHTOOL_XDP_XMIT, T_SW, "tx_xdp_xmit", }, }; -struct mvneta_pcpu_stats { - struct u64_stats_sync syncp; +struct mvneta_stats { u64 rx_packets; u64 rx_bytes; - u64 rx_dropped; - u64 rx_errors; u64 tx_packets; u64 tx_bytes; + /* xdp */ + u64 xdp_redirect; + u64 xdp_pass; + u64 xdp_drop; + u64 xdp_xmit; + u64 xdp_tx; +}; + +struct mvneta_ethtool_stats { + struct mvneta_stats ps; + u64 skb_alloc_error; + u64 refill_error; +}; + +struct mvneta_pcpu_stats { + struct u64_stats_sync syncp; + + struct mvneta_ethtool_stats es; + u64 rx_dropped; + u64 rx_errors; }; struct mvneta_pcpu_port { @@ -660,10 +687,6 @@ struct mvneta_rx_queue { /* pointer to uncomplete skb buffer */ struct sk_buff *skb; int left_size; - - /* error counters */ - u32 skb_alloc_err; - u32 refill_err; }; static enum cpuhp_state online_hpstate; @@ -748,12 +771,12 @@ mvneta_get_stats64(struct net_device *dev, cpu_stats = per_cpu_ptr(pp->stats, cpu); do { start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); - rx_packets = cpu_stats->rx_packets; - rx_bytes = cpu_stats->rx_bytes; + rx_packets = cpu_stats->es.ps.rx_packets; + rx_bytes = cpu_stats->es.ps.rx_bytes; rx_dropped = cpu_stats->rx_dropped; rx_errors = cpu_stats->rx_errors; - tx_packets = cpu_stats->tx_packets; - tx_bytes = cpu_stats->tx_bytes; + tx_packets = cpu_stats->es.ps.tx_packets; + tx_bytes = cpu_stats->es.ps.tx_bytes; } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); stats->rx_packets += rx_packets; @@ -1933,7 +1956,7 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp, if (!data || !(rx_desc->buf_phys_addr)) continue; - page_pool_put_page(rxq->page_pool, data, false); + page_pool_put_full_page(rxq->page_pool, data, false); } if (xdp_rxq_info_is_reg(&rxq->xdp_rxq)) xdp_rxq_info_unreg(&rxq->xdp_rxq); @@ -1942,19 +1965,18 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp, } static void -mvneta_update_stats(struct mvneta_port *pp, u32 pkts, - u32 len, bool tx) +mvneta_update_stats(struct mvneta_port *pp, + struct mvneta_stats *ps) { struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); u64_stats_update_begin(&stats->syncp); - if (tx) { - stats->tx_packets += pkts; - stats->tx_bytes += len; - } else { - stats->rx_packets += pkts; - stats->rx_bytes += len; - } + stats->es.ps.rx_packets += ps->rx_packets; + stats->es.ps.rx_bytes += ps->rx_bytes; + /* xdp */ + stats->es.ps.xdp_redirect += ps->xdp_redirect; + stats->es.ps.xdp_pass += ps->xdp_pass; + stats->es.ps.xdp_drop += ps->xdp_drop; u64_stats_update_end(&stats->syncp); } @@ -1969,9 +1991,15 @@ int mvneta_rx_refill_queue(struct mvneta_port *pp, struct mvneta_rx_queue *rxq) rx_desc = rxq->descs + curr_desc; if (!(rx_desc->buf_phys_addr)) { if (mvneta_rx_refill(pp, rx_desc, rxq, GFP_ATOMIC)) { + struct mvneta_pcpu_stats *stats; + pr_err("Can't refill queue %d. Done %d from %d\n", rxq->id, i, rxq->refill_num); - rxq->refill_err++; + + stats = this_cpu_ptr(pp->stats); + u64_stats_update_begin(&stats->syncp); + stats->es.refill_error++; + u64_stats_update_end(&stats->syncp); break; } } @@ -2021,7 +2049,6 @@ mvneta_xdp_submit_frame(struct mvneta_port *pp, struct mvneta_tx_queue *txq, tx_desc->buf_phys_addr = dma_addr; tx_desc->data_size = xdpf->len; - mvneta_update_stats(pp, 1, xdpf->len, true); mvneta_txq_inc_put(txq); txq->pending++; txq->count++; @@ -2048,8 +2075,17 @@ mvneta_xdp_xmit_back(struct mvneta_port *pp, struct xdp_buff *xdp) __netif_tx_lock(nq, cpu); ret = mvneta_xdp_submit_frame(pp, txq, xdpf, false); - if (ret == MVNETA_XDP_TX) + if (ret == MVNETA_XDP_TX) { + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + + u64_stats_update_begin(&stats->syncp); + stats->es.ps.tx_bytes += xdpf->len; + stats->es.ps.tx_packets++; + stats->es.ps.xdp_tx++; + u64_stats_update_end(&stats->syncp); + mvneta_txq_pend_desc_add(pp, txq, 0); + } __netif_tx_unlock(nq); return ret; @@ -2060,10 +2096,11 @@ mvneta_xdp_xmit(struct net_device *dev, int num_frame, struct xdp_frame **frames, u32 flags) { struct mvneta_port *pp = netdev_priv(dev); + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + int i, nxmit_byte = 0, nxmit = num_frame; int cpu = smp_processor_id(); struct mvneta_tx_queue *txq; struct netdev_queue *nq; - int i, drops = 0; u32 ret; if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) @@ -2075,9 +2112,11 @@ mvneta_xdp_xmit(struct net_device *dev, int num_frame, __netif_tx_lock(nq, cpu); for (i = 0; i < num_frame; i++) { ret = mvneta_xdp_submit_frame(pp, txq, frames[i], true); - if (ret != MVNETA_XDP_TX) { + if (ret == MVNETA_XDP_TX) { + nxmit_byte += frames[i]->len; + } else { xdp_return_frame_rx_napi(frames[i]); - drops++; + nxmit--; } } @@ -2085,12 +2124,19 @@ mvneta_xdp_xmit(struct net_device *dev, int num_frame, mvneta_txq_pend_desc_add(pp, txq, 0); __netif_tx_unlock(nq); - return num_frame - drops; + u64_stats_update_begin(&stats->syncp); + stats->es.ps.tx_bytes += nxmit_byte; + stats->es.ps.tx_packets += nxmit; + stats->es.ps.xdp_xmit += nxmit; + u64_stats_update_end(&stats->syncp); + + return nxmit; } static int mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, - struct bpf_prog *prog, struct xdp_buff *xdp) + struct bpf_prog *prog, struct xdp_buff *xdp, + struct mvneta_stats *stats) { unsigned int len; u32 ret, act; @@ -2100,28 +2146,29 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, switch (act) { case XDP_PASS: - ret = MVNETA_XDP_PASS; - break; + stats->xdp_pass++; + return MVNETA_XDP_PASS; case XDP_REDIRECT: { int err; err = xdp_do_redirect(pp->dev, xdp, prog); if (err) { ret = MVNETA_XDP_DROPPED; - __page_pool_put_page(rxq->page_pool, - virt_to_head_page(xdp->data), - len, true); + page_pool_put_page(rxq->page_pool, + virt_to_head_page(xdp->data), len, + true); } else { ret = MVNETA_XDP_REDIR; + stats->xdp_redirect++; } break; } case XDP_TX: ret = mvneta_xdp_xmit_back(pp, xdp); if (ret != MVNETA_XDP_TX) - __page_pool_put_page(rxq->page_pool, - virt_to_head_page(xdp->data), - len, true); + page_pool_put_page(rxq->page_pool, + virt_to_head_page(xdp->data), len, + true); break; default: bpf_warn_invalid_xdp_action(act); @@ -2130,13 +2177,16 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, trace_xdp_exception(pp->dev, prog, act); /* fall through */ case XDP_DROP: - __page_pool_put_page(rxq->page_pool, - virt_to_head_page(xdp->data), - len, true); + page_pool_put_page(rxq->page_pool, + virt_to_head_page(xdp->data), len, true); ret = MVNETA_XDP_DROPPED; + stats->xdp_drop++; break; } + stats->rx_bytes += xdp->data_end - xdp->data; + stats->rx_packets++; + return ret; } @@ -2146,12 +2196,14 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, struct xdp_buff *xdp, struct bpf_prog *xdp_prog, - struct page *page, u32 *xdp_ret) + struct page *page, + struct mvneta_stats *stats) { unsigned char *data = page_address(page); int data_len = -MVNETA_MH_SIZE, len; struct net_device *dev = pp->dev; enum dma_data_direction dma_dir; + int ret = 0; if (MVNETA_SKB_SIZE(rx_desc->data_size) > PAGE_SIZE) { len = MVNETA_MAX_RX_BUF_SIZE; @@ -2175,17 +2227,9 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, xdp_set_data_meta_invalid(xdp); if (xdp_prog) { - u32 ret; - - ret = mvneta_run_xdp(pp, rxq, xdp_prog, xdp); - if (ret != MVNETA_XDP_PASS) { - mvneta_update_stats(pp, 1, - xdp->data_end - xdp->data, - false); - rx_desc->buf_phys_addr = 0; - *xdp_ret |= ret; - return ret; - } + ret = mvneta_run_xdp(pp, rxq, xdp_prog, xdp, stats); + if (ret) + goto out; } rxq->skb = build_skb(xdp->data_hard_start, PAGE_SIZE); @@ -2193,9 +2237,9 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); netdev_err(dev, "Can't allocate skb on queue %d\n", rxq->id); - rxq->skb_alloc_err++; u64_stats_update_begin(&stats->syncp); + stats->es.skb_alloc_error++; stats->rx_dropped++; u64_stats_update_end(&stats->syncp); @@ -2209,9 +2253,11 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, mvneta_rx_csum(pp, rx_desc->status, rxq->skb); rxq->left_size = rx_desc->data_size - len; + +out: rx_desc->buf_phys_addr = 0; - return 0; + return ret; } static void @@ -2252,12 +2298,11 @@ static int mvneta_rx_swbm(struct napi_struct *napi, struct mvneta_port *pp, int budget, struct mvneta_rx_queue *rxq) { - int rcvd_pkts = 0, rcvd_bytes = 0, rx_proc = 0; + int rx_proc = 0, rx_todo, refill; struct net_device *dev = pp->dev; + struct mvneta_stats ps = {}; struct bpf_prog *xdp_prog; struct xdp_buff xdp_buf; - int rx_todo, refill; - u32 xdp_ret = 0; /* Get number of received packets */ rx_todo = mvneta_rxq_busy_desc_num_get(pp, rxq); @@ -2290,7 +2335,7 @@ static int mvneta_rx_swbm(struct napi_struct *napi, } err = mvneta_swbm_rx_frame(pp, rx_desc, rxq, &xdp_buf, - xdp_prog, page, &xdp_ret); + xdp_prog, page, &ps); if (err) continue; } else { @@ -2314,8 +2359,9 @@ static int mvneta_rx_swbm(struct napi_struct *napi, rxq->skb = NULL; continue; } - rcvd_pkts++; - rcvd_bytes += rxq->skb->len; + + ps.rx_bytes += rxq->skb->len; + ps.rx_packets++; /* Linux processing */ rxq->skb->protocol = eth_type_trans(rxq->skb, dev); @@ -2327,11 +2373,11 @@ static int mvneta_rx_swbm(struct napi_struct *napi, } rcu_read_unlock(); - if (xdp_ret & MVNETA_XDP_REDIR) + if (ps.xdp_redirect) xdp_do_flush_map(); - if (rcvd_pkts) - mvneta_update_stats(pp, rcvd_pkts, rcvd_bytes, false); + if (ps.rx_packets) + mvneta_update_stats(pp, &ps); /* return some buffers to hardware queue, one at a time is too slow */ refill = mvneta_rx_refill_queue(pp, rxq); @@ -2339,7 +2385,7 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* Update rxq management counters */ mvneta_rxq_desc_num_update(pp, rxq, rx_proc, refill); - return rcvd_pkts; + return ps.rx_packets; } /* Main rx processing when using hardware buffer management */ @@ -2423,8 +2469,15 @@ err_drop_frame: /* Refill processing */ err = hwbm_pool_refill(&bm_pool->hwbm_pool, GFP_ATOMIC); if (err) { + struct mvneta_pcpu_stats *stats; + netdev_err(dev, "Linux processing - Can't refill\n"); - rxq->refill_err++; + + stats = this_cpu_ptr(pp->stats); + u64_stats_update_begin(&stats->syncp); + stats->es.refill_error++; + u64_stats_update_end(&stats->syncp); + goto err_drop_frame_ret_pool; } @@ -2454,8 +2507,14 @@ err_drop_frame: napi_gro_receive(napi, skb); } - if (rcvd_pkts) - mvneta_update_stats(pp, rcvd_pkts, rcvd_bytes, false); + if (rcvd_pkts) { + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + + u64_stats_update_begin(&stats->syncp); + stats->es.ps.rx_packets += rcvd_pkts; + stats->es.ps.rx_bytes += rcvd_bytes; + u64_stats_update_end(&stats->syncp); + } /* Update rxq management counters */ mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done); @@ -2711,6 +2770,7 @@ static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) out: if (frags > 0) { struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id); + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); netdev_tx_sent_queue(nq, len); @@ -2724,7 +2784,10 @@ out: else txq->pending += frags; - mvneta_update_stats(pp, 1, len, true); + u64_stats_update_begin(&stats->syncp); + stats->es.ps.tx_bytes += len; + stats->es.ps.tx_packets++; + u64_stats_update_end(&stats->syncp); } else { dev->stats.tx_dropped++; dev_kfree_skb_any(skb); @@ -3767,13 +3830,9 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode, new_clk = gmac_clk & ~MVNETA_GMAC_1MS_CLOCK_ENABLE; new_an = gmac_an & ~(MVNETA_GMAC_INBAND_AN_ENABLE | MVNETA_GMAC_INBAND_RESTART_AN | - MVNETA_GMAC_CONFIG_MII_SPEED | - MVNETA_GMAC_CONFIG_GMII_SPEED | MVNETA_GMAC_AN_SPEED_EN | MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL | - MVNETA_GMAC_CONFIG_FLOW_CTRL | MVNETA_GMAC_AN_FLOW_CTRL_EN | - MVNETA_GMAC_CONFIG_FULL_DUPLEX | MVNETA_GMAC_AN_DUPLEX_EN); /* Even though it might look weird, when we're configured in @@ -3788,24 +3847,20 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode, if (phylink_test(state->advertising, Pause)) new_an |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL; - if (state->pause & MLO_PAUSE_TXRX_MASK) - new_an |= MVNETA_GMAC_CONFIG_FLOW_CTRL; if (!phylink_autoneg_inband(mode)) { - /* Phy or fixed speed */ - if (state->duplex) - new_an |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; - - if (state->speed == SPEED_1000 || state->speed == SPEED_2500) - new_an |= MVNETA_GMAC_CONFIG_GMII_SPEED; - else if (state->speed == SPEED_100) - new_an |= MVNETA_GMAC_CONFIG_MII_SPEED; + /* Phy or fixed speed - nothing to do, leave the + * configured speed, duplex and flow control as-is. + */ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { /* SGMII mode receives the state from the PHY */ new_ctrl2 |= MVNETA_GMAC2_INBAND_AN_ENABLE; new_clk |= MVNETA_GMAC_1MS_CLOCK_ENABLE; new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN | - MVNETA_GMAC_FORCE_LINK_PASS)) | + MVNETA_GMAC_FORCE_LINK_PASS | + MVNETA_GMAC_CONFIG_MII_SPEED | + MVNETA_GMAC_CONFIG_GMII_SPEED | + MVNETA_GMAC_CONFIG_FULL_DUPLEX)) | MVNETA_GMAC_INBAND_AN_ENABLE | MVNETA_GMAC_AN_SPEED_EN | MVNETA_GMAC_AN_DUPLEX_EN; @@ -3814,7 +3869,8 @@ static void mvneta_mac_config(struct phylink_config *config, unsigned int mode, new_ctrl0 |= MVNETA_GMAC0_PORT_1000BASE_X; new_clk |= MVNETA_GMAC_1MS_CLOCK_ENABLE; new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN | - MVNETA_GMAC_FORCE_LINK_PASS)) | + MVNETA_GMAC_FORCE_LINK_PASS | + MVNETA_GMAC_CONFIG_MII_SPEED)) | MVNETA_GMAC_INBAND_AN_ENABLE | MVNETA_GMAC_CONFIG_GMII_SPEED | /* The MAC only supports FD mode */ @@ -3902,9 +3958,11 @@ static void mvneta_mac_link_down(struct phylink_config *config, mvneta_set_eee(pp, false); } -static void mvneta_mac_link_up(struct phylink_config *config, unsigned int mode, - phy_interface_t interface, - struct phy_device *phy) +static void mvneta_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) { struct net_device *ndev = to_net_dev(config->dev); struct mvneta_port *pp = netdev_priv(ndev); @@ -3912,8 +3970,36 @@ static void mvneta_mac_link_up(struct phylink_config *config, unsigned int mode, if (!phylink_autoneg_inband(mode)) { val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); - val &= ~MVNETA_GMAC_FORCE_LINK_DOWN; + val &= ~(MVNETA_GMAC_FORCE_LINK_DOWN | + MVNETA_GMAC_CONFIG_MII_SPEED | + MVNETA_GMAC_CONFIG_GMII_SPEED | + MVNETA_GMAC_CONFIG_FLOW_CTRL | + MVNETA_GMAC_CONFIG_FULL_DUPLEX); val |= MVNETA_GMAC_FORCE_LINK_PASS; + + if (speed == SPEED_1000 || speed == SPEED_2500) + val |= MVNETA_GMAC_CONFIG_GMII_SPEED; + else if (speed == SPEED_100) + val |= MVNETA_GMAC_CONFIG_MII_SPEED; + + if (duplex == DUPLEX_FULL) + val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; + + if (tx_pause || rx_pause) + val |= MVNETA_GMAC_CONFIG_FLOW_CTRL; + + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); + } else { + /* When inband doesn't cover flow control or flow control is + * disabled, we need to manually configure it. This bit will + * only have effect if MVNETA_GMAC_AN_FLOW_CTRL_EN is unset. + */ + val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); + val &= ~MVNETA_GMAC_CONFIG_FLOW_CTRL; + + if (tx_pause || rx_pause) + val |= MVNETA_GMAC_CONFIG_FLOW_CTRL; + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); } @@ -4420,45 +4506,100 @@ static void mvneta_ethtool_get_strings(struct net_device *netdev, u32 sset, } } +static void +mvneta_ethtool_update_pcpu_stats(struct mvneta_port *pp, + struct mvneta_ethtool_stats *es) +{ + unsigned int start; + int cpu; + + for_each_possible_cpu(cpu) { + struct mvneta_pcpu_stats *stats; + u64 skb_alloc_error; + u64 refill_error; + u64 xdp_redirect; + u64 xdp_pass; + u64 xdp_drop; + u64 xdp_xmit; + u64 xdp_tx; + + stats = per_cpu_ptr(pp->stats, cpu); + do { + start = u64_stats_fetch_begin_irq(&stats->syncp); + skb_alloc_error = stats->es.skb_alloc_error; + refill_error = stats->es.refill_error; + xdp_redirect = stats->es.ps.xdp_redirect; + xdp_pass = stats->es.ps.xdp_pass; + xdp_drop = stats->es.ps.xdp_drop; + xdp_xmit = stats->es.ps.xdp_xmit; + xdp_tx = stats->es.ps.xdp_tx; + } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); + + es->skb_alloc_error += skb_alloc_error; + es->refill_error += refill_error; + es->ps.xdp_redirect += xdp_redirect; + es->ps.xdp_pass += xdp_pass; + es->ps.xdp_drop += xdp_drop; + es->ps.xdp_xmit += xdp_xmit; + es->ps.xdp_tx += xdp_tx; + } +} + static void mvneta_ethtool_update_stats(struct mvneta_port *pp) { + struct mvneta_ethtool_stats stats = {}; const struct mvneta_statistic *s; void __iomem *base = pp->base; u32 high, low; u64 val; int i; + mvneta_ethtool_update_pcpu_stats(pp, &stats); for (i = 0, s = mvneta_statistics; s < mvneta_statistics + ARRAY_SIZE(mvneta_statistics); s++, i++) { - val = 0; - switch (s->type) { case T_REG_32: val = readl_relaxed(base + s->offset); + pp->ethtool_stats[i] += val; break; case T_REG_64: /* Docs say to read low 32-bit then high */ low = readl_relaxed(base + s->offset); high = readl_relaxed(base + s->offset + 4); val = (u64)high << 32 | low; + pp->ethtool_stats[i] += val; break; case T_SW: switch (s->offset) { case ETHTOOL_STAT_EEE_WAKEUP: val = phylink_get_eee_err(pp->phylink); + pp->ethtool_stats[i] += val; break; case ETHTOOL_STAT_SKB_ALLOC_ERR: - val = pp->rxqs[0].skb_alloc_err; + pp->ethtool_stats[i] = stats.skb_alloc_error; break; case ETHTOOL_STAT_REFILL_ERR: - val = pp->rxqs[0].refill_err; + pp->ethtool_stats[i] = stats.refill_error; + break; + case ETHTOOL_XDP_REDIRECT: + pp->ethtool_stats[i] = stats.ps.xdp_redirect; + break; + case ETHTOOL_XDP_PASS: + pp->ethtool_stats[i] = stats.ps.xdp_pass; + break; + case ETHTOOL_XDP_DROP: + pp->ethtool_stats[i] = stats.ps.xdp_drop; + break; + case ETHTOOL_XDP_TX: + pp->ethtool_stats[i] = stats.ps.xdp_tx; + break; + case ETHTOOL_XDP_XMIT: + pp->ethtool_stats[i] = stats.ps.xdp_xmit; break; } break; } - - pp->ethtool_stats[i] += val; } } diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 72133cbe55d4..6b9c7ed2547e 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -58,8 +58,11 @@ static struct { */ static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state); -static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode, - phy_interface_t interface, struct phy_device *phy); +static void mvpp2_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause); /* Queue modes */ #define MVPP2_QDIST_SINGLE_MODE 0 @@ -3473,8 +3476,9 @@ static void mvpp2_start_dev(struct mvpp2_port *port) .interface = port->phy_interface, }; mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state); - mvpp2_mac_link_up(&port->phylink_config, MLO_AN_INBAND, - port->phy_interface, NULL); + mvpp2_mac_link_up(&port->phylink_config, NULL, + MLO_AN_INBAND, port->phy_interface, + SPEED_UNKNOWN, DUPLEX_UNKNOWN, false, false); } netif_tx_start_all_queues(port->dev); @@ -4972,15 +4976,13 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode, old_ctrl2 = ctrl2 = readl(port->base + MVPP2_GMAC_CTRL_2_REG); old_ctrl4 = ctrl4 = readl(port->base + MVPP22_GMAC_CTRL_4_REG); - an &= ~(MVPP2_GMAC_CONFIG_MII_SPEED | MVPP2_GMAC_CONFIG_GMII_SPEED | - MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_FC_ADV_EN | + an &= ~(MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_FC_ADV_EN | MVPP2_GMAC_FC_ADV_ASM_EN | MVPP2_GMAC_FLOW_CTRL_AUTONEG | - MVPP2_GMAC_CONFIG_FULL_DUPLEX | MVPP2_GMAC_AN_DUPLEX_EN | - MVPP2_GMAC_IN_BAND_AUTONEG | MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS); + MVPP2_GMAC_AN_DUPLEX_EN | MVPP2_GMAC_IN_BAND_AUTONEG | + MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS); ctrl0 &= ~MVPP2_GMAC_PORT_TYPE_MASK; ctrl2 &= ~(MVPP2_GMAC_INBAND_AN_MASK | MVPP2_GMAC_PORT_RESET_MASK | MVPP2_GMAC_PCS_ENABLE_MASK); - ctrl4 &= ~(MVPP22_CTRL4_RX_FC_EN | MVPP22_CTRL4_TX_FC_EN); /* Configure port type */ if (phy_interface_mode_is_8023z(state->interface)) { @@ -5010,31 +5012,20 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode, /* Configure negotiation style */ if (!phylink_autoneg_inband(mode)) { - /* Phy or fixed speed - no in-band AN */ - if (state->duplex) - an |= MVPP2_GMAC_CONFIG_FULL_DUPLEX; - - if (state->speed == SPEED_1000 || state->speed == SPEED_2500) - an |= MVPP2_GMAC_CONFIG_GMII_SPEED; - else if (state->speed == SPEED_100) - an |= MVPP2_GMAC_CONFIG_MII_SPEED; - - if (state->pause & MLO_PAUSE_TX) - ctrl4 |= MVPP22_CTRL4_TX_FC_EN; - if (state->pause & MLO_PAUSE_RX) - ctrl4 |= MVPP22_CTRL4_RX_FC_EN; + /* Phy or fixed speed - no in-band AN, nothing to do, leave the + * configured speed, duplex and flow control as-is. + */ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { /* SGMII in-band mode receives the speed and duplex from * the PHY. Flow control information is not received. */ - an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN | MVPP2_GMAC_FORCE_LINK_PASS); + an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN | + MVPP2_GMAC_FORCE_LINK_PASS | + MVPP2_GMAC_CONFIG_MII_SPEED | + MVPP2_GMAC_CONFIG_GMII_SPEED | + MVPP2_GMAC_CONFIG_FULL_DUPLEX); an |= MVPP2_GMAC_IN_BAND_AUTONEG | MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_AN_DUPLEX_EN; - - if (state->pause & MLO_PAUSE_TX) - ctrl4 |= MVPP22_CTRL4_TX_FC_EN; - if (state->pause & MLO_PAUSE_RX) - ctrl4 |= MVPP22_CTRL4_RX_FC_EN; } else if (phy_interface_mode_is_8023z(state->interface)) { /* 1000BaseX and 2500BaseX ports cannot negotiate speed nor can * they negotiate duplex: they are always operating with a fixed @@ -5042,19 +5033,17 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode, * speed and full duplex here. */ ctrl0 |= MVPP2_GMAC_PORT_TYPE_MASK; - an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN | MVPP2_GMAC_FORCE_LINK_PASS); + an &= ~(MVPP2_GMAC_FORCE_LINK_DOWN | + MVPP2_GMAC_FORCE_LINK_PASS | + MVPP2_GMAC_CONFIG_MII_SPEED | + MVPP2_GMAC_CONFIG_GMII_SPEED | + MVPP2_GMAC_CONFIG_FULL_DUPLEX); an |= MVPP2_GMAC_IN_BAND_AUTONEG | MVPP2_GMAC_CONFIG_GMII_SPEED | MVPP2_GMAC_CONFIG_FULL_DUPLEX; - if (state->pause & MLO_PAUSE_AN && state->an_enabled) { + if (state->pause & MLO_PAUSE_AN && state->an_enabled) an |= MVPP2_GMAC_FLOW_CTRL_AUTONEG; - } else { - if (state->pause & MLO_PAUSE_TX) - ctrl4 |= MVPP22_CTRL4_TX_FC_EN; - if (state->pause & MLO_PAUSE_RX) - ctrl4 |= MVPP22_CTRL4_RX_FC_EN; - } } /* Some fields of the auto-negotiation register require the port to be down when @@ -5141,25 +5130,54 @@ static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode, mvpp2_port_enable(port); } -static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode, - phy_interface_t interface, struct phy_device *phy) +static void mvpp2_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) { struct net_device *dev = to_net_dev(config->dev); struct mvpp2_port *port = netdev_priv(dev); u32 val; - if (!phylink_autoneg_inband(mode)) { - if (mvpp2_is_xlg(interface)) { + if (mvpp2_is_xlg(interface)) { + if (!phylink_autoneg_inband(mode)) { val = readl(port->base + MVPP22_XLG_CTRL0_REG); val &= ~MVPP22_XLG_CTRL0_FORCE_LINK_DOWN; val |= MVPP22_XLG_CTRL0_FORCE_LINK_PASS; writel(val, port->base + MVPP22_XLG_CTRL0_REG); - } else { + } + } else { + if (!phylink_autoneg_inband(mode)) { val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG); - val &= ~MVPP2_GMAC_FORCE_LINK_DOWN; + val &= ~(MVPP2_GMAC_FORCE_LINK_DOWN | + MVPP2_GMAC_CONFIG_MII_SPEED | + MVPP2_GMAC_CONFIG_GMII_SPEED | + MVPP2_GMAC_CONFIG_FULL_DUPLEX); val |= MVPP2_GMAC_FORCE_LINK_PASS; + + if (speed == SPEED_1000 || speed == SPEED_2500) + val |= MVPP2_GMAC_CONFIG_GMII_SPEED; + else if (speed == SPEED_100) + val |= MVPP2_GMAC_CONFIG_MII_SPEED; + + if (duplex == DUPLEX_FULL) + val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX; + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); } + + /* We can always update the flow control enable bits; + * these will only be effective if flow control AN + * (MVPP2_GMAC_FLOW_CTRL_AUTONEG) is disabled. + */ + val = readl(port->base + MVPP22_GMAC_CTRL_4_REG); + val &= ~(MVPP22_CTRL4_RX_FC_EN | MVPP22_CTRL4_TX_FC_EN); + if (tx_pause) + val |= MVPP22_CTRL4_TX_FC_EN; + if (rx_pause) + val |= MVPP22_CTRL4_RX_FC_EN; + writel(val, port->base + MVPP22_GMAC_CTRL_4_REG); } mvpp2_port_enable(port); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 5ca788691911..9f5b7229574e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -113,7 +113,6 @@ int cgx_get_cgxcnt_max(void) return idmax + 1; } -EXPORT_SYMBOL(cgx_get_cgxcnt_max); int cgx_get_lmac_cnt(void *cgxd) { @@ -124,7 +123,6 @@ int cgx_get_lmac_cnt(void *cgxd) return cgx->lmac_count; } -EXPORT_SYMBOL(cgx_get_lmac_cnt); void *cgx_get_pdata(int cgx_id) { @@ -136,7 +134,6 @@ void *cgx_get_pdata(int cgx_id) } return NULL; } -EXPORT_SYMBOL(cgx_get_pdata); int cgx_get_cgxid(void *cgxd) { @@ -164,7 +161,6 @@ int cgx_get_link_info(void *cgxd, int lmac_id, *linfo = lmac->link_info; return 0; } -EXPORT_SYMBOL(cgx_get_link_info); static u64 mac2u64 (u8 *mac_addr) { @@ -195,7 +191,6 @@ int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr) return 0; } -EXPORT_SYMBOL(cgx_lmac_addr_set); u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) { @@ -205,7 +200,6 @@ u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8); return cfg & CGX_RX_DMAC_ADR_MASK; } -EXPORT_SYMBOL(cgx_lmac_addr_get); int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind) { @@ -217,7 +211,6 @@ int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind) cgx_write(cgx, lmac_id, CGXX_CMRX_RX_ID_MAP, (pkind & 0x3F)); return 0; } -EXPORT_SYMBOL(cgx_set_pkind); static inline u8 cgx_get_lmac_type(struct cgx *cgx, int lmac_id) { @@ -255,7 +248,6 @@ int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable) } return 0; } -EXPORT_SYMBOL(cgx_lmac_internal_loopback); void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) { @@ -289,7 +281,6 @@ void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); } } -EXPORT_SYMBOL(cgx_lmac_promisc_config); /* Enable or disable forwarding received pause frames to Tx block */ void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable) @@ -318,7 +309,6 @@ void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable) cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg); } } -EXPORT_SYMBOL(cgx_lmac_enadis_rx_pause_fwding); int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) { @@ -329,7 +319,6 @@ int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) *rx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_STAT0 + (idx * 8)); return 0; } -EXPORT_SYMBOL(cgx_get_rx_stats); int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat) { @@ -340,7 +329,6 @@ int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat) *tx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_TX_STAT0 + (idx * 8)); return 0; } -EXPORT_SYMBOL(cgx_get_tx_stats); int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) { @@ -358,7 +346,6 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); return 0; } -EXPORT_SYMBOL(cgx_lmac_rx_tx_enable); int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable) { @@ -379,7 +366,6 @@ int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable) cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); return !!(last & DATA_PKT_TX_EN); } -EXPORT_SYMBOL(cgx_lmac_tx_enable); /* CGX Firmware interface low level support */ static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac) @@ -610,7 +596,6 @@ int cgx_get_mkex_prfl_info(u64 *addr, u64 *size) return 0; } -EXPORT_SYMBOL(cgx_get_mkex_prfl_info); static irqreturn_t cgx_fwi_event_handler(int irq, void *data) { @@ -676,7 +661,6 @@ int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id) return 0; } -EXPORT_SYMBOL(cgx_lmac_evh_register); int cgx_lmac_evh_unregister(void *cgxd, int lmac_id) { @@ -695,7 +679,6 @@ int cgx_lmac_evh_unregister(void *cgxd, int lmac_id) return 0; } -EXPORT_SYMBOL(cgx_lmac_evh_unregister); static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable) { @@ -769,7 +752,6 @@ int cgx_lmac_linkup_start(void *cgxd) return 0; } -EXPORT_SYMBOL(cgx_lmac_linkup_start); static int cgx_lmac_init(struct cgx *cgx) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 51c206f4fe6f..7afb7caad873 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -432,7 +432,7 @@ int rvu_nix_reserve_mark_format(struct rvu *rvu, struct nix_hw *nix_hw, void rvu_nix_freemem(struct rvu *rvu); int rvu_get_nixlf_count(struct rvu *rvu); void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int npalf); -int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf); +int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf, int *nix_blkaddr); /* NPC APIs */ int rvu_npc_init(struct rvu *rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 11e5921c55b9..b8e8f337316f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -350,6 +350,18 @@ int rvu_cgx_exit(struct rvu *rvu) return 0; } +/* Most of the CGX configuration is restricted to the mapped PF only, + * VF's of mapped PF and other PFs are not allowed. This fn() checks + * whether a PFFUNC is permitted to do the config or not. + */ +static bool is_cgx_config_permitted(struct rvu *rvu, u16 pcifunc) +{ + if ((pcifunc & RVU_PFVF_FUNC_MASK) || + !is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc))) + return false; + return true; +} + void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable) { u8 cgx_id, lmac_id; @@ -373,11 +385,8 @@ int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start) int pf = rvu_get_pf(pcifunc); u8 cgx_id, lmac_id; - /* This msg is expected only from PFs that are mapped to CGX LMACs, - * if received from other PF/VF simply ACK, nothing to do. - */ - if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) - return -ENODEV; + if (!is_cgx_config_permitted(rvu, pcifunc)) + return -EPERM; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); @@ -409,8 +418,7 @@ int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req, u8 cgx_idx, lmac; void *cgxd; - if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) || - !is_pf_cgxmapped(rvu, pf)) + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) return -ENODEV; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac); @@ -477,12 +485,8 @@ int rvu_mbox_handler_cgx_promisc_enable(struct rvu *rvu, struct msg_req *req, int pf = rvu_get_pf(pcifunc); u8 cgx_id, lmac_id; - /* This msg is expected only from PFs that are mapped to CGX LMACs, - * if received from other PF/VF simply ACK, nothing to do. - */ - if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) || - !is_pf_cgxmapped(rvu, pf)) - return -ENODEV; + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) + return -EPERM; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); @@ -493,16 +497,11 @@ int rvu_mbox_handler_cgx_promisc_enable(struct rvu *rvu, struct msg_req *req, int rvu_mbox_handler_cgx_promisc_disable(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp) { - u16 pcifunc = req->hdr.pcifunc; - int pf = rvu_get_pf(pcifunc); + int pf = rvu_get_pf(req->hdr.pcifunc); u8 cgx_id, lmac_id; - /* This msg is expected only from PFs that are mapped to CGX LMACs, - * if received from other PF/VF simply ACK, nothing to do. - */ - if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) || - !is_pf_cgxmapped(rvu, pf)) - return -ENODEV; + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) + return -EPERM; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); @@ -515,11 +514,8 @@ static int rvu_cgx_config_linkevents(struct rvu *rvu, u16 pcifunc, bool en) int pf = rvu_get_pf(pcifunc); u8 cgx_id, lmac_id; - /* This msg is expected only from PFs that are mapped to CGX LMACs, - * if received from other PF/VF simply ACK, nothing to do. - */ - if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) - return -ENODEV; + if (!is_cgx_config_permitted(rvu, pcifunc)) + return -EPERM; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); @@ -571,11 +567,8 @@ static int rvu_cgx_config_intlbk(struct rvu *rvu, u16 pcifunc, bool en) int pf = rvu_get_pf(pcifunc); u8 cgx_id, lmac_id; - /* This msg is expected only from PFs that are mapped to CGX LMACs, - * if received from other PF/VF simply ACK, nothing to do. - */ - if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) - return -ENODEV; + if (!is_cgx_config_permitted(rvu, pcifunc)) + return -EPERM; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index eb5e542424e7..a29e5c7c8cfc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -90,6 +90,26 @@ int rvu_get_nixlf_count(struct rvu *rvu) return block->lf.max; } +int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf, int *nix_blkaddr) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); + struct rvu_hwinfo *hw = rvu->hw; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + if (!pfvf->nixlf || blkaddr < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + *nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); + if (*nixlf < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + if (nix_blkaddr) + *nix_blkaddr = blkaddr; + + return 0; +} + static void nix_mce_list_init(struct nix_mce_list *list, int max) { INIT_HLIST_HEAD(&list->head); @@ -1667,13 +1687,9 @@ int rvu_mbox_handler_nix_txschq_cfg(struct rvu *rvu, req->num_regs > MAX_REGS_PER_MBOX_MSG) return NIX_AF_INVAL_TXSCHQ_CFG; - err = nix_get_nixlf(rvu, pcifunc, &nixlf); + err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr); if (err) - return NIX_AF_ERR_AF_LF_INVALID; - - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; + return err; nix_hw = get_nix_hw(rvu->hw, blkaddr); if (!nix_hw) @@ -1767,17 +1783,12 @@ int rvu_mbox_handler_nix_vtag_cfg(struct rvu *rvu, struct nix_vtag_config *req, struct msg_rsp *rsp) { - struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; int blkaddr, nixlf, err; - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; - - nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); - if (nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; + err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr); + if (err) + return err; if (req->cfg_type) { err = nix_rx_vtag_cfg(rvu, nixlf, blkaddr, req); @@ -2119,18 +2130,13 @@ static int nix_af_mark_format_setup(struct rvu *rvu, struct nix_hw *nix_hw, int rvu_mbox_handler_nix_stats_rst(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp) { - struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; - int i, nixlf, blkaddr; + int i, nixlf, blkaddr, err; u64 stats; - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; - - nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); - if (nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; + err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr); + if (err) + return err; /* Get stats count supported by HW */ stats = rvu_read64(rvu, blkaddr, NIX_AF_CONST1); @@ -2418,18 +2424,14 @@ int rvu_mbox_handler_nix_rss_flowkey_cfg(struct rvu *rvu, struct nix_rss_flowkey_cfg *req, struct nix_rss_flowkey_cfg_rsp *rsp) { - struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; int alg_idx, nixlf, blkaddr; struct nix_hw *nix_hw; + int err; - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; - - nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); - if (nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; + err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr); + if (err) + return err; nix_hw = get_nix_hw(rvu->hw, blkaddr); if (!nix_hw) @@ -2522,19 +2524,15 @@ int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu, struct nix_set_mac_addr *req, struct msg_rsp *rsp) { - struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; + int blkaddr, nixlf, err; struct rvu_pfvf *pfvf; - int blkaddr, nixlf; - pfvf = rvu_get_pfvf(rvu, pcifunc); - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (!pfvf->nixlf || blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; + err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr); + if (err) + return err; - nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); - if (nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; + pfvf = rvu_get_pfvf(rvu, pcifunc); ether_addr_copy(pfvf->mac_addr, req->mac_addr); @@ -2567,19 +2565,15 @@ int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req, struct msg_rsp *rsp) { bool allmulti = false, disable_promisc = false; - struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; + int blkaddr, nixlf, err; struct rvu_pfvf *pfvf; - int blkaddr, nixlf; - pfvf = rvu_get_pfvf(rvu, pcifunc); - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (!pfvf->nixlf || blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; + err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr); + if (err) + return err; - nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); - if (nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; + pfvf = rvu_get_pfvf(rvu, pcifunc); if (req->mode & NIX_RX_MODE_PROMISC) allmulti = false; @@ -2794,22 +2788,12 @@ free_entry: int rvu_mbox_handler_nix_set_rx_cfg(struct rvu *rvu, struct nix_rx_cfg *req, struct msg_rsp *rsp) { - struct rvu_hwinfo *hw = rvu->hw; - u16 pcifunc = req->hdr.pcifunc; - struct rvu_block *block; - struct rvu_pfvf *pfvf; - int nixlf, blkaddr; + int nixlf, blkaddr, err; u64 cfg; - pfvf = rvu_get_pfvf(rvu, pcifunc); - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (!pfvf->nixlf || blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; - - block = &hw->block[blkaddr]; - nixlf = rvu_get_lf(rvu, block, pcifunc, 0); - if (nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; + err = nix_get_nixlf(rvu, req->hdr.pcifunc, &nixlf, &blkaddr); + if (err) + return err; cfg = rvu_read64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf)); /* Set the interface configuration */ @@ -3114,30 +3098,13 @@ void rvu_nix_freemem(struct rvu *rvu) } } -int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf) -{ - struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); - struct rvu_hwinfo *hw = rvu->hw; - int blkaddr; - - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (!pfvf->nixlf || blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; - - *nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); - if (*nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; - - return 0; -} - int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp) { u16 pcifunc = req->hdr.pcifunc; int nixlf, err; - err = nix_get_nixlf(rvu, pcifunc, &nixlf); + err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL); if (err) return err; @@ -3152,7 +3119,7 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req, u16 pcifunc = req->hdr.pcifunc; int nixlf, err; - err = nix_get_nixlf(rvu, pcifunc, &nixlf); + err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL); if (err) return err; diff --git a/drivers/net/ethernet/marvell/skge.h b/drivers/net/ethernet/marvell/skge.h index 6fa7b6a34c08..a1313d57e283 100644 --- a/drivers/net/ethernet/marvell/skge.h +++ b/drivers/net/ethernet/marvell/skge.h @@ -2426,7 +2426,7 @@ struct skge_hw { spinlock_t phy_lock; struct tasklet_struct phy_task; - char irq_name[0]; /* skge@pci:000:04:00.0 */ + char irq_name[]; /* skge@pci:000:04:00.0 */ }; enum pause_control { diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h index b02b6523083c..ada1ca60f088 100644 --- a/drivers/net/ethernet/marvell/sky2.h +++ b/drivers/net/ethernet/marvell/sky2.h @@ -2309,7 +2309,7 @@ struct sky2_hw { struct work_struct restart_work; wait_queue_head_t msi_wait; - char irq_name[0]; + char irq_name[]; }; static inline int sky2_is_copper(const struct sky2_hw *hw) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 8c6cfd15481c..8d28f90acfe7 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -412,9 +412,10 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); } -static void mtk_mac_link_up(struct phylink_config *config, unsigned int mode, - phy_interface_t interface, - struct phy_device *phy) +static void mtk_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) { struct mtk_mac *mac = container_of(config, struct mtk_mac, phylink_config); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index d3e06cec8317..e0bb8e12356e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -16,7 +16,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \ fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \ lib/devcom.o lib/pci_vsc.o lib/dm.o diag/fs_tracepoint.o \ - diag/fw_tracer.o diag/crdump.o devlink.o + diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o # # Netdev basic diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c index 94d7b69a95c7..c9c9b479bda5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c @@ -188,7 +188,7 @@ static int mlx5_fw_tracer_create_mkey(struct mlx5_fw_tracer *tracer) MLX5_SET(create_mkey_in, in, translations_octword_actual_size, DIV_ROUND_UP(TRACER_BUFFER_PAGE_NUM, 2)); - mtt = (u64 *)MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt); + mtt = (__be64 *)MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt); for (i = 0 ; i < TRACER_BUFFER_PAGE_NUM ; i++) mtt[i] = cpu_to_be64(tracer->buff.dma + i * PAGE_SIZE); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/rsc_dump.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/rsc_dump.c new file mode 100644 index 000000000000..17ab7efe693d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/rsc_dump.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include "rsc_dump.h" +#include "lib/mlx5.h" + +#define MLX5_SGMT_TYPE(SGMT) MLX5_SGMT_TYPE_##SGMT +#define MLX5_SGMT_STR_ASSING(SGMT)[MLX5_SGMT_TYPE(SGMT)] = #SGMT +static const char *const mlx5_rsc_sgmt_name[] = { + MLX5_SGMT_STR_ASSING(HW_CQPC), + MLX5_SGMT_STR_ASSING(HW_SQPC), + MLX5_SGMT_STR_ASSING(HW_RQPC), + MLX5_SGMT_STR_ASSING(FULL_SRQC), + MLX5_SGMT_STR_ASSING(FULL_CQC), + MLX5_SGMT_STR_ASSING(FULL_EQC), + MLX5_SGMT_STR_ASSING(FULL_QPC), + MLX5_SGMT_STR_ASSING(SND_BUFF), + MLX5_SGMT_STR_ASSING(RCV_BUFF), + MLX5_SGMT_STR_ASSING(SRQ_BUFF), + MLX5_SGMT_STR_ASSING(CQ_BUFF), + MLX5_SGMT_STR_ASSING(EQ_BUFF), + MLX5_SGMT_STR_ASSING(SX_SLICE), + MLX5_SGMT_STR_ASSING(SX_SLICE_ALL), + MLX5_SGMT_STR_ASSING(RDB), + MLX5_SGMT_STR_ASSING(RX_SLICE_ALL), +}; + +struct mlx5_rsc_dump { + u32 pdn; + struct mlx5_core_mkey mkey; + u16 fw_segment_type[MLX5_SGMT_TYPE_NUM]; +}; + +struct mlx5_rsc_dump_cmd { + u64 mem_size; + u8 cmd[MLX5_ST_SZ_BYTES(resource_dump)]; +}; + +static int mlx5_rsc_dump_sgmt_get_by_name(char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mlx5_rsc_sgmt_name); i++) + if (!strcmp(name, mlx5_rsc_sgmt_name[i])) + return i; + + return -EINVAL; +} + +static void mlx5_rsc_dump_read_menu_sgmt(struct mlx5_rsc_dump *rsc_dump, struct page *page) +{ + void *data = page_address(page); + enum mlx5_sgmt_type sgmt_idx; + int num_of_items; + char *sgmt_name; + void *member; + void *menu; + int i; + + menu = MLX5_ADDR_OF(menu_resource_dump_response, data, menu); + num_of_items = MLX5_GET(resource_dump_menu_segment, menu, num_of_records); + + for (i = 0; i < num_of_items; i++) { + member = MLX5_ADDR_OF(resource_dump_menu_segment, menu, record[i]); + sgmt_name = MLX5_ADDR_OF(resource_dump_menu_record, member, segment_name); + sgmt_idx = mlx5_rsc_dump_sgmt_get_by_name(sgmt_name); + if (sgmt_idx == -EINVAL) + continue; + rsc_dump->fw_segment_type[sgmt_idx] = MLX5_GET(resource_dump_menu_record, + member, segment_type); + } +} + +static int mlx5_rsc_dump_trigger(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd, + struct page *page) +{ + struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump; + struct device *ddev = &dev->pdev->dev; + u32 out_seq_num; + u32 in_seq_num; + dma_addr_t dma; + int err; + + dma = dma_map_page(ddev, page, 0, cmd->mem_size, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ddev, dma))) + return -ENOMEM; + + in_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num); + MLX5_SET(resource_dump, cmd->cmd, mkey, rsc_dump->mkey.key); + MLX5_SET64(resource_dump, cmd->cmd, address, dma); + + err = mlx5_core_access_reg(dev, cmd->cmd, sizeof(cmd->cmd), cmd->cmd, + sizeof(cmd->cmd), MLX5_REG_RESOURCE_DUMP, 0, 1); + if (err) { + mlx5_core_err(dev, "Resource dump: Failed to access err %d\n", err); + goto out; + } + out_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num); + if (out_seq_num && (in_seq_num + 1 != out_seq_num)) + err = -EIO; +out: + dma_unmap_page(ddev, dma, cmd->mem_size, DMA_FROM_DEVICE); + return err; +} + +struct mlx5_rsc_dump_cmd *mlx5_rsc_dump_cmd_create(struct mlx5_core_dev *dev, + struct mlx5_rsc_key *key) +{ + struct mlx5_rsc_dump_cmd *cmd; + int sgmt_type; + + if (IS_ERR_OR_NULL(dev->rsc_dump)) + return ERR_PTR(-EOPNOTSUPP); + + sgmt_type = dev->rsc_dump->fw_segment_type[key->rsc]; + if (!sgmt_type && key->rsc != MLX5_SGMT_TYPE_MENU) + return ERR_PTR(-EOPNOTSUPP); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + mlx5_core_err(dev, "Resource dump: Failed to allocate command\n"); + return ERR_PTR(-ENOMEM); + } + MLX5_SET(resource_dump, cmd->cmd, segment_type, sgmt_type); + MLX5_SET(resource_dump, cmd->cmd, index1, key->index1); + MLX5_SET(resource_dump, cmd->cmd, index2, key->index2); + MLX5_SET(resource_dump, cmd->cmd, num_of_obj1, key->num_of_obj1); + MLX5_SET(resource_dump, cmd->cmd, num_of_obj2, key->num_of_obj2); + MLX5_SET(resource_dump, cmd->cmd, size, key->size); + cmd->mem_size = key->size; + return cmd; +} + +void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd) +{ + kfree(cmd); +} + +int mlx5_rsc_dump_next(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd, + struct page *page, int *size) +{ + bool more_dump; + int err; + + if (IS_ERR_OR_NULL(dev->rsc_dump)) + return -EOPNOTSUPP; + + err = mlx5_rsc_dump_trigger(dev, cmd, page); + if (err) { + mlx5_core_err(dev, "Resource dump: Failed to trigger dump, %d\n", err); + return err; + } + *size = MLX5_GET(resource_dump, cmd->cmd, size); + more_dump = MLX5_GET(resource_dump, cmd->cmd, more_dump); + + return more_dump; +} + +#define MLX5_RSC_DUMP_MENU_SEGMENT 0xffff +static int mlx5_rsc_dump_menu(struct mlx5_core_dev *dev) +{ + struct mlx5_rsc_dump_cmd *cmd = NULL; + struct mlx5_rsc_key key = {}; + struct page *page; + int size; + int err; + + page = alloc_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + key.rsc = MLX5_SGMT_TYPE_MENU; + key.size = PAGE_SIZE; + cmd = mlx5_rsc_dump_cmd_create(dev, &key); + if (IS_ERR(cmd)) { + err = PTR_ERR(cmd); + goto free_page; + } + MLX5_SET(resource_dump, cmd->cmd, segment_type, MLX5_RSC_DUMP_MENU_SEGMENT); + + do { + err = mlx5_rsc_dump_next(dev, cmd, page, &size); + if (err < 0) + goto destroy_cmd; + + mlx5_rsc_dump_read_menu_sgmt(dev->rsc_dump, page); + + } while (err > 0); + +destroy_cmd: + mlx5_rsc_dump_cmd_destroy(cmd); +free_page: + __free_page(page); + + return err; +} + +static int mlx5_rsc_dump_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, + struct mlx5_core_mkey *mkey) +{ + int inlen = MLX5_ST_SZ_BYTES(create_mkey_in); + void *mkc; + u32 *in; + int err; + + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); + MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA); + MLX5_SET(mkc, mkc, lw, 1); + MLX5_SET(mkc, mkc, lr, 1); + + MLX5_SET(mkc, mkc, pd, pdn); + MLX5_SET(mkc, mkc, length64, 1); + MLX5_SET(mkc, mkc, qpn, 0xffffff); + + err = mlx5_core_create_mkey(mdev, mkey, in, inlen); + + kvfree(in); + return err; +} + +struct mlx5_rsc_dump *mlx5_rsc_dump_create(struct mlx5_core_dev *dev) +{ + struct mlx5_rsc_dump *rsc_dump; + + if (!MLX5_CAP_DEBUG(dev, resource_dump)) { + mlx5_core_dbg(dev, "Resource dump: capability not present\n"); + return NULL; + } + rsc_dump = kzalloc(sizeof(*rsc_dump), GFP_KERNEL); + if (!rsc_dump) + return ERR_PTR(-ENOMEM); + + return rsc_dump; +} + +void mlx5_rsc_dump_destroy(struct mlx5_core_dev *dev) +{ + if (IS_ERR_OR_NULL(dev->rsc_dump)) + return; + kfree(dev->rsc_dump); +} + +int mlx5_rsc_dump_init(struct mlx5_core_dev *dev) +{ + struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump; + int err; + + if (IS_ERR_OR_NULL(dev->rsc_dump)) + return 0; + + err = mlx5_core_alloc_pd(dev, &rsc_dump->pdn); + if (err) { + mlx5_core_warn(dev, "Resource dump: Failed to allocate PD %d\n", err); + return err; + } + err = mlx5_rsc_dump_create_mkey(dev, rsc_dump->pdn, &rsc_dump->mkey); + if (err) { + mlx5_core_err(dev, "Resource dump: Failed to create mkey, %d\n", err); + goto free_pd; + } + err = mlx5_rsc_dump_menu(dev); + if (err) { + mlx5_core_err(dev, "Resource dump: Failed to read menu, %d\n", err); + goto destroy_mkey; + } + return err; + +destroy_mkey: + mlx5_core_destroy_mkey(dev, &rsc_dump->mkey); +free_pd: + mlx5_core_dealloc_pd(dev, rsc_dump->pdn); + return err; +} + +void mlx5_rsc_dump_cleanup(struct mlx5_core_dev *dev) +{ + if (IS_ERR_OR_NULL(dev->rsc_dump)) + return; + + mlx5_core_destroy_mkey(dev, &dev->rsc_dump->mkey); + mlx5_core_dealloc_pd(dev, dev->rsc_dump->pdn); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/rsc_dump.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/rsc_dump.h new file mode 100644 index 000000000000..148270073e71 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/rsc_dump.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019 Mellanox Technologies. */ + +#ifndef __MLX5_RSC_DUMP_H +#define __MLX5_RSC_DUMP_H + +#include <linux/mlx5/driver.h> +#include "mlx5_core.h" + +enum mlx5_sgmt_type { + MLX5_SGMT_TYPE_HW_CQPC, + MLX5_SGMT_TYPE_HW_SQPC, + MLX5_SGMT_TYPE_HW_RQPC, + MLX5_SGMT_TYPE_FULL_SRQC, + MLX5_SGMT_TYPE_FULL_CQC, + MLX5_SGMT_TYPE_FULL_EQC, + MLX5_SGMT_TYPE_FULL_QPC, + MLX5_SGMT_TYPE_SND_BUFF, + MLX5_SGMT_TYPE_RCV_BUFF, + MLX5_SGMT_TYPE_SRQ_BUFF, + MLX5_SGMT_TYPE_CQ_BUFF, + MLX5_SGMT_TYPE_EQ_BUFF, + MLX5_SGMT_TYPE_SX_SLICE, + MLX5_SGMT_TYPE_SX_SLICE_ALL, + MLX5_SGMT_TYPE_RDB, + MLX5_SGMT_TYPE_RX_SLICE_ALL, + MLX5_SGMT_TYPE_MENU, + MLX5_SGMT_TYPE_TERMINATE, + + MLX5_SGMT_TYPE_NUM, /* Keep last */ +}; + +struct mlx5_rsc_key { + enum mlx5_sgmt_type rsc; + int index1; + int index2; + int num_of_obj1; + int num_of_obj2; + int size; +}; + +#define MLX5_RSC_DUMP_ALL 0xFFFF +struct mlx5_rsc_dump_cmd; +struct mlx5_rsc_dump; + +struct mlx5_rsc_dump *mlx5_rsc_dump_create(struct mlx5_core_dev *dev); +void mlx5_rsc_dump_destroy(struct mlx5_core_dev *dev); + +int mlx5_rsc_dump_init(struct mlx5_core_dev *dev); +void mlx5_rsc_dump_cleanup(struct mlx5_core_dev *dev); + +struct mlx5_rsc_dump_cmd *mlx5_rsc_dump_cmd_create(struct mlx5_core_dev *dev, + struct mlx5_rsc_key *key); +void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd); + +int mlx5_rsc_dump_next(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd, + struct page *page, int *size); +#endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 220ef9f06f84..3cc439ab3253 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -737,7 +737,6 @@ struct mlx5e_channel { DECLARE_BITMAP(state, MLX5E_CHANNEL_NUM_STATES); int ix; int cpu; - cpumask_var_t xps_cpumask; }; struct mlx5e_channels { @@ -813,6 +812,15 @@ struct mlx5e_xsk { bool ever_used; }; +/* Temporary storage for variables that are allocated when struct mlx5e_priv is + * initialized, and used where we can't allocate them because that functions + * must not fail. Use with care and make sure the same variable is not used + * simultaneously by multiple users. + */ +struct mlx5e_scratchpad { + cpumask_var_t cpumask; +}; + struct mlx5e_priv { /* priv data path fields - start */ struct mlx5e_txqsq *txq2sq[MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC]; @@ -876,6 +884,7 @@ struct mlx5e_priv { #if IS_ENABLED(CONFIG_PCI_HYPERV_INTERFACE) struct mlx5e_hv_vhca_stats_agent stats_agent; #endif + struct mlx5e_scratchpad scratchpad; }; struct mlx5e_profile { @@ -1035,14 +1044,22 @@ int mlx5e_open_channels(struct mlx5e_priv *priv, struct mlx5e_channels *chs); void mlx5e_close_channels(struct mlx5e_channels *chs); -/* Function pointer to be used to modify WH settings while +/* Function pointer to be used to modify HW or kernel settings while * switching channels */ -typedef int (*mlx5e_fp_hw_modify)(struct mlx5e_priv *priv); +typedef int (*mlx5e_fp_preactivate)(struct mlx5e_priv *priv, void *context); +#define MLX5E_DEFINE_PREACTIVATE_WRAPPER_CTX(fn) \ +int fn##_ctx(struct mlx5e_priv *priv, void *context) \ +{ \ + return fn(priv); \ +} int mlx5e_safe_reopen_channels(struct mlx5e_priv *priv); int mlx5e_safe_switch_channels(struct mlx5e_priv *priv, struct mlx5e_channels *new_chs, - mlx5e_fp_hw_modify hw_modify); + mlx5e_fp_preactivate preactivate, + void *context); +int mlx5e_num_channels_changed(struct mlx5e_priv *priv); +int mlx5e_num_channels_changed_ctx(struct mlx5e_priv *priv, void *context); void mlx5e_activate_priv_channels(struct mlx5e_priv *priv); void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv); @@ -1122,10 +1139,10 @@ void mlx5e_update_ndo_stats(struct mlx5e_priv *priv); void mlx5e_queue_update_stats(struct mlx5e_priv *priv); int mlx5e_bits_invert(unsigned long a, int size); -typedef int (*change_hw_mtu_cb)(struct mlx5e_priv *priv); int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv); +int mlx5e_set_dev_port_mtu_ctx(struct mlx5e_priv *priv, void *context); int mlx5e_change_mtu(struct net_device *netdev, int new_mtu, - change_hw_mtu_cb set_mtu_cb); + mlx5e_fp_preactivate preactivate); /* ethtool helpers */ void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/health.c b/drivers/net/ethernet/mellanox/mlx5/core/en/health.c index 20b907dc1e29..3a199a03d929 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/health.c @@ -3,6 +3,7 @@ #include "health.h" #include "lib/eq.h" +#include "lib/mlx5.h" int mlx5e_reporter_named_obj_nest_start(struct devlink_fmsg *fmsg, char *name) { @@ -197,10 +198,114 @@ int mlx5e_health_report(struct mlx5e_priv *priv, struct devlink_health_reporter *reporter, char *err_str, struct mlx5e_err_ctx *err_ctx) { - netdev_err(priv->netdev, err_str); + netdev_err(priv->netdev, "%s\n", err_str); if (!reporter) return err_ctx->recover(err_ctx->ctx); return devlink_health_report(reporter, err_str, err_ctx); } + +#define MLX5_HEALTH_DEVLINK_MAX_SIZE 1024 +static int mlx5e_health_rsc_fmsg_binary(struct devlink_fmsg *fmsg, + const void *value, u32 value_len) + +{ + u32 data_size; + u32 offset; + int err; + + for (offset = 0; offset < value_len; offset += data_size) { + data_size = value_len - offset; + if (data_size > MLX5_HEALTH_DEVLINK_MAX_SIZE) + data_size = MLX5_HEALTH_DEVLINK_MAX_SIZE; + err = devlink_fmsg_binary_put(fmsg, value + offset, data_size); + if (err) + break; + } + return err; +} + +int mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv *priv, struct mlx5_rsc_key *key, + struct devlink_fmsg *fmsg) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5_rsc_dump_cmd *cmd; + struct page *page; + int cmd_err, err; + int end_err; + int size; + + if (IS_ERR_OR_NULL(mdev->rsc_dump)) + return -EOPNOTSUPP; + + page = alloc_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + err = devlink_fmsg_binary_pair_nest_start(fmsg, "data"); + if (err) + return err; + + cmd = mlx5_rsc_dump_cmd_create(mdev, key); + if (IS_ERR(cmd)) { + err = PTR_ERR(cmd); + goto free_page; + } + + do { + cmd_err = mlx5_rsc_dump_next(mdev, cmd, page, &size); + if (cmd_err < 0) { + err = cmd_err; + goto destroy_cmd; + } + + err = mlx5e_health_rsc_fmsg_binary(fmsg, page_address(page), size); + if (err) + goto destroy_cmd; + + } while (cmd_err > 0); + +destroy_cmd: + mlx5_rsc_dump_cmd_destroy(cmd); + end_err = devlink_fmsg_binary_pair_nest_end(fmsg); + if (end_err) + err = end_err; +free_page: + __free_page(page); + return err; +} + +int mlx5e_health_queue_dump(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg, + int queue_idx, char *lbl) +{ + struct mlx5_rsc_key key = {}; + int err; + + key.rsc = MLX5_SGMT_TYPE_FULL_QPC; + key.index1 = queue_idx; + key.size = PAGE_SIZE; + key.num_of_obj1 = 1; + + err = devlink_fmsg_obj_nest_start(fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, lbl); + if (err) + return err; + + err = devlink_fmsg_u32_pair_put(fmsg, "index", queue_idx); + if (err) + return err; + + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + return devlink_fmsg_obj_nest_end(fmsg); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/health.h b/drivers/net/ethernet/mellanox/mlx5/core/en/health.h index d3693fa547ac..e90e3aec422f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/health.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/health.h @@ -5,6 +5,7 @@ #define __MLX5E_EN_HEALTH_H #include "en.h" +#include "diag/rsc_dump.h" #define MLX5E_RX_ERR_CQE(cqe) (get_cqe_opcode(cqe) != MLX5_CQE_RESP_SEND) @@ -36,6 +37,7 @@ void mlx5e_reporter_rx_timeout(struct mlx5e_rq *rq); struct mlx5e_err_ctx { int (*recover)(void *ctx); + int (*dump)(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg, void *ctx); void *ctx; }; @@ -48,6 +50,8 @@ int mlx5e_health_report(struct mlx5e_priv *priv, int mlx5e_health_create_reporters(struct mlx5e_priv *priv); void mlx5e_health_destroy_reporters(struct mlx5e_priv *priv); void mlx5e_health_channels_update(struct mlx5e_priv *priv); - - +int mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv *priv, struct mlx5_rsc_key *key, + struct devlink_fmsg *fmsg); +int mlx5e_health_queue_dump(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg, + int queue_idx, char *lbl); #endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c index fce6eccdcf8b..2c4a670c8ffd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c @@ -343,64 +343,76 @@ out: return err; } -static u32 fec_supported_speeds[] = { - 10000, - 40000, - 25000, - 50000, - 56000, - 100000 +enum mlx5e_fec_supported_link_mode { + MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G, + MLX5E_FEC_SUPPORTED_LINK_MODES_25G, + MLX5E_FEC_SUPPORTED_LINK_MODES_50G, + MLX5E_FEC_SUPPORTED_LINK_MODES_56G, + MLX5E_FEC_SUPPORTED_LINK_MODES_100G, + MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X, + MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X, + MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X, + MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X, + MLX5E_MAX_FEC_SUPPORTED_LINK_MODE, }; -#define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds) +#define MLX5E_FEC_FIRST_50G_PER_LANE_MODE MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X + +#define MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, policy, write, link) \ + do { \ + u16 *_policy = &(policy); \ + u32 *_buf = buf; \ + \ + if (write) \ + MLX5_SET(pplm_reg, _buf, fec_override_admin_##link, *_policy); \ + else \ + *_policy = MLX5_GET(pplm_reg, _buf, fec_override_admin_##link); \ + } while (0) + +#define MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(buf, policy, write, link) \ + do { \ + u16 *__policy = &(policy); \ + bool _write = (write); \ + \ + if (_write && *__policy) \ + *__policy = find_first_bit((u_long *)__policy, \ + sizeof(u16) * BITS_PER_BYTE);\ + MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, *__policy, _write, link); \ + if (!_write && *__policy) \ + *__policy = 1 << *__policy; \ + } while (0) /* get/set FEC admin field for a given speed */ -static int mlx5e_fec_admin_field(u32 *pplm, - u8 *fec_policy, - bool write, - u32 speed) +static int mlx5e_fec_admin_field(u32 *pplm, u16 *fec_policy, bool write, + enum mlx5e_fec_supported_link_mode link_mode) { - switch (speed) { - case 10000: - case 40000: - if (!write) - *fec_policy = MLX5_GET(pplm_reg, pplm, - fec_override_admin_10g_40g); - else - MLX5_SET(pplm_reg, pplm, - fec_override_admin_10g_40g, *fec_policy); + switch (link_mode) { + case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G: + MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 10g_40g); break; - case 25000: - if (!write) - *fec_policy = MLX5_GET(pplm_reg, pplm, - fec_override_admin_25g); - else - MLX5_SET(pplm_reg, pplm, - fec_override_admin_25g, *fec_policy); + case MLX5E_FEC_SUPPORTED_LINK_MODES_25G: + MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 25g); break; - case 50000: - if (!write) - *fec_policy = MLX5_GET(pplm_reg, pplm, - fec_override_admin_50g); - else - MLX5_SET(pplm_reg, pplm, - fec_override_admin_50g, *fec_policy); + case MLX5E_FEC_SUPPORTED_LINK_MODES_50G: + MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g); break; - case 56000: - if (!write) - *fec_policy = MLX5_GET(pplm_reg, pplm, - fec_override_admin_56g); - else - MLX5_SET(pplm_reg, pplm, - fec_override_admin_56g, *fec_policy); + case MLX5E_FEC_SUPPORTED_LINK_MODES_56G: + MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 56g); break; - case 100000: - if (!write) - *fec_policy = MLX5_GET(pplm_reg, pplm, - fec_override_admin_100g); - else - MLX5_SET(pplm_reg, pplm, - fec_override_admin_100g, *fec_policy); + case MLX5E_FEC_SUPPORTED_LINK_MODES_100G: + MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X: + MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 50g_1x); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X: + MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 100g_2x); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X: + MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 200g_4x); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X: + MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 400g_8x); break; default: return -EINVAL; @@ -408,32 +420,40 @@ static int mlx5e_fec_admin_field(u32 *pplm, return 0; } +#define MLX5E_GET_FEC_OVERRIDE_CAP(buf, link) \ + MLX5_GET(pplm_reg, buf, fec_override_cap_##link) + /* returns FEC capabilities for a given speed */ -static int mlx5e_get_fec_cap_field(u32 *pplm, - u8 *fec_cap, - u32 speed) +static int mlx5e_get_fec_cap_field(u32 *pplm, u16 *fec_cap, + enum mlx5e_fec_supported_link_mode link_mode) { - switch (speed) { - case 10000: - case 40000: - *fec_cap = MLX5_GET(pplm_reg, pplm, - fec_override_cap_10g_40g); + switch (link_mode) { + case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 10g_40g); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODES_25G: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 25g); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODES_50G: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODES_56G: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 56g); + break; + case MLX5E_FEC_SUPPORTED_LINK_MODES_100G: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g); break; - case 25000: - *fec_cap = MLX5_GET(pplm_reg, pplm, - fec_override_cap_25g); + case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g_1x); break; - case 50000: - *fec_cap = MLX5_GET(pplm_reg, pplm, - fec_override_cap_50g); + case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g_2x); break; - case 56000: - *fec_cap = MLX5_GET(pplm_reg, pplm, - fec_override_cap_56g); + case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 200g_4x); break; - case 100000: - *fec_cap = MLX5_GET(pplm_reg, pplm, - fec_override_cap_100g); + case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X: + *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 400g_8x); break; default: return -EINVAL; @@ -441,13 +461,14 @@ static int mlx5e_get_fec_cap_field(u32 *pplm, return 0; } -int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps) +bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy) { + bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm); u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; int sz = MLX5_ST_SZ_BYTES(pplm_reg); - u32 current_fec_speed; int err; + int i; if (!MLX5_CAP_GEN(dev, pcam_reg)) return -EOPNOTSUPP; @@ -458,23 +479,30 @@ int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps) MLX5_SET(pplm_reg, in, local_port, 1); err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); if (err) - return err; + return false; - err = mlx5e_port_linkspeed(dev, ¤t_fec_speed); - if (err) - return err; + for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) { + u16 fec_caps; - return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed); + if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane) + break; + + mlx5e_get_fec_cap_field(out, &fec_caps, i); + if (fec_caps & fec_policy) + return true; + } + return false; } int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, - u8 *fec_configured_mode) + u16 *fec_configured_mode) { + bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm); u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; int sz = MLX5_ST_SZ_BYTES(pplm_reg); - u32 link_speed; int err; + int i; if (!MLX5_CAP_GEN(dev, pcam_reg)) return -EOPNOTSUPP; @@ -490,24 +518,28 @@ int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active); if (!fec_configured_mode) - return 0; + goto out; - err = mlx5e_port_linkspeed(dev, &link_speed); - if (err) - return err; + *fec_configured_mode = 0; + for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) { + if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane) + break; - return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed); + mlx5e_fec_admin_field(out, fec_configured_mode, 0, i); + if (*fec_configured_mode != 0) + goto out; + } +out: + return 0; } -int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) +int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy) { - u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC); - bool fec_mode_not_supp_in_speed = false; + bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm); u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; int sz = MLX5_ST_SZ_BYTES(pplm_reg); - u8 fec_policy_auto = 0; - u8 fec_caps = 0; + u16 fec_policy_auto = 0; int err; int i; @@ -517,6 +549,9 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) if (!MLX5_CAP_PCAM_REG(dev, pplm)) return -EOPNOTSUPP; + if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane) + return -EOPNOTSUPP; + MLX5_SET(pplm_reg, in, local_port, 1); err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); if (err) @@ -524,25 +559,31 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) MLX5_SET(pplm_reg, out, local_port, 1); - for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) { - mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]); - /* policy supported for link speed, or policy is auto */ - if (fec_caps & fec_policy || fec_policy == fec_policy_auto) { - mlx5e_fec_admin_field(out, &fec_policy, 1, - fec_supported_speeds[i]); - } else { - /* turn off FEC if supported. Else, leave it the same */ - if (fec_caps & fec_policy_nofec) - mlx5e_fec_admin_field(out, &fec_policy_nofec, 1, - fec_supported_speeds[i]); - fec_mode_not_supp_in_speed = true; - } - } + for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) { + u16 conf_fec = fec_policy; + u16 fec_caps = 0; + + if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane) + break; - if (fec_mode_not_supp_in_speed) - mlx5_core_dbg(dev, - "FEC policy 0x%x is not supported for some speeds", - fec_policy); + /* RS fec in ethtool is mapped to MLX5E_FEC_RS_528_514 + * to link modes up to 25G per lane and to + * MLX5E_FEC_RS_544_514 in the new link modes based on + * 50 G per lane + */ + if (conf_fec == (1 << MLX5E_FEC_RS_528_514) && + i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE) + conf_fec = (1 << MLX5E_FEC_RS_544_514); + + mlx5e_get_fec_cap_field(out, &fec_caps, i); + + /* policy supported for link speed */ + if (fec_caps & conf_fec) + mlx5e_fec_admin_field(out, &conf_fec, 1, i); + else + /* set FEC to auto*/ + mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i); + } return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.h b/drivers/net/ethernet/mellanox/mlx5/core/en/port.h index 4a7f4497692b..a2ddd446dd59 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.h @@ -60,15 +60,17 @@ int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in); int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer); int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer); -int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps); +bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy); int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, - u8 *fec_configured_mode); -int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy); + u16 *fec_configured_mode); +int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy); enum { MLX5E_FEC_NOFEC, MLX5E_FEC_FIRECODE, MLX5E_FEC_RS_528_514, + MLX5E_FEC_RS_544_514 = 7, + MLX5E_FEC_LLRS_272_257_1 = 9, }; #endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c index 6c72b592315b..ce2b41c61090 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c @@ -102,19 +102,6 @@ out: return err; } -void mlx5e_reporter_icosq_cqe_err(struct mlx5e_icosq *icosq) -{ - struct mlx5e_priv *priv = icosq->channel->priv; - char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; - struct mlx5e_err_ctx err_ctx = {}; - - err_ctx.ctx = icosq; - err_ctx.recover = mlx5e_rx_reporter_err_icosq_cqe_recover; - sprintf(err_str, "ERR CQE on ICOSQ: 0x%x", icosq->sqn); - - mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx); -} - static int mlx5e_rq_to_ready(struct mlx5e_rq *rq, int curr_state) { struct net_device *dev = rq->netdev; @@ -171,19 +158,6 @@ out: return err; } -void mlx5e_reporter_rq_cqe_err(struct mlx5e_rq *rq) -{ - struct mlx5e_priv *priv = rq->channel->priv; - char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; - struct mlx5e_err_ctx err_ctx = {}; - - err_ctx.ctx = rq; - err_ctx.recover = mlx5e_rx_reporter_err_rq_cqe_recover; - sprintf(err_str, "ERR CQE on RQ: 0x%x", rq->rqn); - - mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx); -} - static int mlx5e_rx_reporter_timeout_recover(void *ctx) { struct mlx5e_icosq *icosq; @@ -201,21 +175,6 @@ static int mlx5e_rx_reporter_timeout_recover(void *ctx) return err; } -void mlx5e_reporter_rx_timeout(struct mlx5e_rq *rq) -{ - struct mlx5e_icosq *icosq = &rq->channel->icosq; - struct mlx5e_priv *priv = rq->channel->priv; - char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; - struct mlx5e_err_ctx err_ctx = {}; - - err_ctx.ctx = rq; - err_ctx.recover = mlx5e_rx_reporter_timeout_recover; - sprintf(err_str, "RX timeout on channel: %d, ICOSQ: 0x%x RQ: 0x%x, CQ: 0x%x\n", - icosq->channel->ix, icosq->sqn, rq->rqn, rq->cq.mcq.cqn); - - mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx); -} - static int mlx5e_rx_reporter_recover_from_ctx(struct mlx5e_err_ctx *err_ctx) { return err_ctx->recover(err_ctx->ctx); @@ -371,10 +330,235 @@ unlock: return err; } +static int mlx5e_rx_reporter_dump_icosq(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg, + void *ctx) +{ + struct mlx5e_txqsq *icosq = ctx; + struct mlx5_rsc_key key = {}; + int err; + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + return 0; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "SX Slice"); + if (err) + return err; + + key.size = PAGE_SIZE; + key.rsc = MLX5_SGMT_TYPE_SX_SLICE_ALL; + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "ICOSQ"); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "QPC"); + if (err) + return err; + + key.rsc = MLX5_SGMT_TYPE_FULL_QPC; + key.index1 = icosq->sqn; + key.num_of_obj1 = 1; + + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "send_buff"); + if (err) + return err; + + key.rsc = MLX5_SGMT_TYPE_SND_BUFF; + key.num_of_obj2 = MLX5_RSC_DUMP_ALL; + + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + return mlx5e_reporter_named_obj_nest_end(fmsg); +} + +static int mlx5e_rx_reporter_dump_rq(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg, + void *ctx) +{ + struct mlx5_rsc_key key = {}; + struct mlx5e_rq *rq = ctx; + int err; + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + return 0; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "RX Slice"); + if (err) + return err; + + key.size = PAGE_SIZE; + key.rsc = MLX5_SGMT_TYPE_RX_SLICE_ALL; + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "RQ"); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "QPC"); + if (err) + return err; + + key.rsc = MLX5_SGMT_TYPE_FULL_QPC; + key.index1 = rq->rqn; + key.num_of_obj1 = 1; + + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "receive_buff"); + if (err) + return err; + + key.rsc = MLX5_SGMT_TYPE_RCV_BUFF; + key.num_of_obj2 = MLX5_RSC_DUMP_ALL; + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + return mlx5e_reporter_named_obj_nest_end(fmsg); +} + +static int mlx5e_rx_reporter_dump_all_rqs(struct mlx5e_priv *priv, + struct devlink_fmsg *fmsg) +{ + struct mlx5_rsc_key key = {}; + int i, err; + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + return 0; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "RX Slice"); + if (err) + return err; + + key.size = PAGE_SIZE; + key.rsc = MLX5_SGMT_TYPE_RX_SLICE_ALL; + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "RQs"); + if (err) + return err; + + for (i = 0; i < priv->channels.num; i++) { + struct mlx5e_rq *rq = &priv->channels.c[i]->rq; + + err = mlx5e_health_queue_dump(priv, fmsg, rq->rqn, "RQ"); + if (err) + return err; + } + + return devlink_fmsg_arr_pair_nest_end(fmsg); +} + +static int mlx5e_rx_reporter_dump_from_ctx(struct mlx5e_priv *priv, + struct mlx5e_err_ctx *err_ctx, + struct devlink_fmsg *fmsg) +{ + return err_ctx->dump(priv, fmsg, err_ctx->ctx); +} + +static int mlx5e_rx_reporter_dump(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, void *context, + struct netlink_ext_ack *extack) +{ + struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); + struct mlx5e_err_ctx *err_ctx = context; + + return err_ctx ? mlx5e_rx_reporter_dump_from_ctx(priv, err_ctx, fmsg) : + mlx5e_rx_reporter_dump_all_rqs(priv, fmsg); +} + +void mlx5e_reporter_rx_timeout(struct mlx5e_rq *rq) +{ + struct mlx5e_icosq *icosq = &rq->channel->icosq; + struct mlx5e_priv *priv = rq->channel->priv; + char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; + struct mlx5e_err_ctx err_ctx = {}; + + err_ctx.ctx = rq; + err_ctx.recover = mlx5e_rx_reporter_timeout_recover; + err_ctx.dump = mlx5e_rx_reporter_dump_rq; + snprintf(err_str, sizeof(err_str), + "RX timeout on channel: %d, ICOSQ: 0x%x RQ: 0x%x, CQ: 0x%x", + icosq->channel->ix, icosq->sqn, rq->rqn, rq->cq.mcq.cqn); + + mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx); +} + +void mlx5e_reporter_rq_cqe_err(struct mlx5e_rq *rq) +{ + struct mlx5e_priv *priv = rq->channel->priv; + char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; + struct mlx5e_err_ctx err_ctx = {}; + + err_ctx.ctx = rq; + err_ctx.recover = mlx5e_rx_reporter_err_rq_cqe_recover; + err_ctx.dump = mlx5e_rx_reporter_dump_rq; + snprintf(err_str, sizeof(err_str), "ERR CQE on RQ: 0x%x", rq->rqn); + + mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx); +} + +void mlx5e_reporter_icosq_cqe_err(struct mlx5e_icosq *icosq) +{ + struct mlx5e_priv *priv = icosq->channel->priv; + char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; + struct mlx5e_err_ctx err_ctx = {}; + + err_ctx.ctx = icosq; + err_ctx.recover = mlx5e_rx_reporter_err_icosq_cqe_recover; + err_ctx.dump = mlx5e_rx_reporter_dump_icosq; + snprintf(err_str, sizeof(err_str), "ERR CQE on ICOSQ: 0x%x", icosq->sqn); + + mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx); +} + static const struct devlink_health_reporter_ops mlx5_rx_reporter_ops = { .name = "rx", .recover = mlx5e_rx_reporter_recover, .diagnose = mlx5e_rx_reporter_diagnose, + .dump = mlx5e_rx_reporter_dump, }; #define MLX5E_REPORTER_RX_GRACEFUL_PERIOD 500 diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c index b468549e96ff..2028ce9b151f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c @@ -82,19 +82,6 @@ out: return err; } -void mlx5e_reporter_tx_err_cqe(struct mlx5e_txqsq *sq) -{ - struct mlx5e_priv *priv = sq->channel->priv; - char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; - struct mlx5e_err_ctx err_ctx = {0}; - - err_ctx.ctx = sq; - err_ctx.recover = mlx5e_tx_reporter_err_cqe_recover; - sprintf(err_str, "ERR CQE on SQ: 0x%x", sq->sqn); - - mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx); -} - static int mlx5e_tx_reporter_timeout_recover(void *ctx) { struct mlx5_eq_comp *eq; @@ -110,22 +97,6 @@ static int mlx5e_tx_reporter_timeout_recover(void *ctx) return err; } -int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq) -{ - struct mlx5e_priv *priv = sq->channel->priv; - char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; - struct mlx5e_err_ctx err_ctx; - - err_ctx.ctx = sq; - err_ctx.recover = mlx5e_tx_reporter_timeout_recover; - sprintf(err_str, - "TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x, usecs since last trans: %u\n", - sq->channel->ix, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc, - jiffies_to_usecs(jiffies - sq->txq->trans_start)); - - return mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx); -} - /* state lock cannot be grabbed within this function. * It can cause a dead lock or a read-after-free. */ @@ -275,10 +246,162 @@ unlock: return err; } +static int mlx5e_tx_reporter_dump_sq(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg, + void *ctx) +{ + struct mlx5_rsc_key key = {}; + struct mlx5e_txqsq *sq = ctx; + int err; + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + return 0; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "SX Slice"); + if (err) + return err; + + key.size = PAGE_SIZE; + key.rsc = MLX5_SGMT_TYPE_SX_SLICE_ALL; + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "SQ"); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "QPC"); + if (err) + return err; + + key.rsc = MLX5_SGMT_TYPE_FULL_QPC; + key.index1 = sq->sqn; + key.num_of_obj1 = 1; + + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "send_buff"); + if (err) + return err; + + key.rsc = MLX5_SGMT_TYPE_SND_BUFF; + key.num_of_obj2 = MLX5_RSC_DUMP_ALL; + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + return mlx5e_reporter_named_obj_nest_end(fmsg); +} + +static int mlx5e_tx_reporter_dump_all_sqs(struct mlx5e_priv *priv, + struct devlink_fmsg *fmsg) +{ + struct mlx5_rsc_key key = {}; + int i, tc, err; + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + return 0; + + err = mlx5e_reporter_named_obj_nest_start(fmsg, "SX Slice"); + if (err) + return err; + + key.size = PAGE_SIZE; + key.rsc = MLX5_SGMT_TYPE_SX_SLICE_ALL; + err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg); + if (err) + return err; + + err = mlx5e_reporter_named_obj_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "SQs"); + if (err) + return err; + + for (i = 0; i < priv->channels.num; i++) { + struct mlx5e_channel *c = priv->channels.c[i]; + + for (tc = 0; tc < priv->channels.params.num_tc; tc++) { + struct mlx5e_txqsq *sq = &c->sq[tc]; + + err = mlx5e_health_queue_dump(priv, fmsg, sq->sqn, "SQ"); + if (err) + return err; + } + } + return devlink_fmsg_arr_pair_nest_end(fmsg); +} + +static int mlx5e_tx_reporter_dump_from_ctx(struct mlx5e_priv *priv, + struct mlx5e_err_ctx *err_ctx, + struct devlink_fmsg *fmsg) +{ + return err_ctx->dump(priv, fmsg, err_ctx->ctx); +} + +static int mlx5e_tx_reporter_dump(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, void *context, + struct netlink_ext_ack *extack) +{ + struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); + struct mlx5e_err_ctx *err_ctx = context; + + return err_ctx ? mlx5e_tx_reporter_dump_from_ctx(priv, err_ctx, fmsg) : + mlx5e_tx_reporter_dump_all_sqs(priv, fmsg); +} + +void mlx5e_reporter_tx_err_cqe(struct mlx5e_txqsq *sq) +{ + struct mlx5e_priv *priv = sq->channel->priv; + char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; + struct mlx5e_err_ctx err_ctx = {}; + + err_ctx.ctx = sq; + err_ctx.recover = mlx5e_tx_reporter_err_cqe_recover; + err_ctx.dump = mlx5e_tx_reporter_dump_sq; + snprintf(err_str, sizeof(err_str), "ERR CQE on SQ: 0x%x", sq->sqn); + + mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx); +} + +int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq) +{ + struct mlx5e_priv *priv = sq->channel->priv; + char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN]; + struct mlx5e_err_ctx err_ctx = {}; + + err_ctx.ctx = sq; + err_ctx.recover = mlx5e_tx_reporter_timeout_recover; + err_ctx.dump = mlx5e_tx_reporter_dump_sq; + snprintf(err_str, sizeof(err_str), + "TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x, usecs since last trans: %u", + sq->channel->ix, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc, + jiffies_to_usecs(jiffies - sq->txq->trans_start)); + + return mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx); +} + static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = { .name = "tx", .recover = mlx5e_tx_reporter_recover, .diagnose = mlx5e_tx_reporter_diagnose, + .dump = mlx5e_tx_reporter_dump, }; #define MLX5_REPORTER_TX_GRACEFUL_PERIOD 500 diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index cf58c9637904..29626c6c9c25 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -433,7 +433,6 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) if (!ipsec) return; - drain_workqueue(ipsec->wq); destroy_workqueue(ipsec->wq); ida_destroy(&ipsec->halloc); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index 01f2918063af..47874d34156b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c @@ -1098,49 +1098,59 @@ void mlx5e_dcbnl_delete_app(struct mlx5e_priv *priv) mlx5e_dcbnl_dscp_app(priv, DELETE); } -static void mlx5e_trust_update_tx_min_inline_mode(struct mlx5e_priv *priv, - struct mlx5e_params *params) +static void mlx5e_params_calc_trust_tx_min_inline_mode(struct mlx5_core_dev *mdev, + struct mlx5e_params *params, + u8 trust_state) { - mlx5_query_min_inline(priv->mdev, ¶ms->tx_min_inline_mode); - if (priv->dcbx_dp.trust_state == MLX5_QPTS_TRUST_DSCP && + mlx5_query_min_inline(mdev, ¶ms->tx_min_inline_mode); + if (trust_state == MLX5_QPTS_TRUST_DSCP && params->tx_min_inline_mode == MLX5_INLINE_MODE_L2) params->tx_min_inline_mode = MLX5_INLINE_MODE_IP; } -static void mlx5e_trust_update_sq_inline_mode(struct mlx5e_priv *priv) +static int mlx5e_update_trust_state_hw(struct mlx5e_priv *priv, void *context) +{ + u8 *trust_state = context; + int err; + + err = mlx5_set_trust_state(priv->mdev, *trust_state); + if (err) + return err; + priv->dcbx_dp.trust_state = *trust_state; + + return 0; +} + +static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state) { struct mlx5e_channels new_channels = {}; + bool reset_channels = true; + int err = 0; mutex_lock(&priv->state_lock); new_channels.params = priv->channels.params; - mlx5e_trust_update_tx_min_inline_mode(priv, &new_channels.params); + mlx5e_params_calc_trust_tx_min_inline_mode(priv->mdev, &new_channels.params, + trust_state); if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { priv->channels.params = new_channels.params; - goto out; + reset_channels = false; } /* Skip if tx_min_inline is the same */ if (new_channels.params.tx_min_inline_mode == priv->channels.params.tx_min_inline_mode) - goto out; + reset_channels = false; - mlx5e_safe_switch_channels(priv, &new_channels, NULL); + if (reset_channels) + err = mlx5e_safe_switch_channels(priv, &new_channels, + mlx5e_update_trust_state_hw, + &trust_state); + else + err = mlx5e_update_trust_state_hw(priv, &trust_state); -out: mutex_unlock(&priv->state_lock); -} - -static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state) -{ - int err; - - err = mlx5_set_trust_state(priv->mdev, trust_state); - if (err) - return err; - priv->dcbx_dp.trust_state = trust_state; - mlx5e_trust_update_sq_inline_mode(priv); return err; } @@ -1171,7 +1181,8 @@ static int mlx5e_trust_initialize(struct mlx5e_priv *priv) if (err) return err; - mlx5e_trust_update_tx_min_inline_mode(priv, &priv->channels.params); + mlx5e_params_calc_trust_tx_min_inline_mode(priv->mdev, &priv->channels.params, + priv->dcbx_dp.trust_state); err = mlx5_query_dscp2prio(priv->mdev, priv->dcbx_dp.dscp2prio); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index d674cb679895..06f6f08ff5eb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -357,7 +357,7 @@ int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv, goto unlock; } - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); unlock: mutex_unlock(&priv->state_lock); @@ -432,9 +432,7 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv, if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { *cur_params = new_channels.params; - if (!netif_is_rxfh_configured(priv->netdev)) - mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt, - MLX5E_INDIR_RQT_SIZE, count); + mlx5e_num_channels_changed(priv); goto out; } @@ -442,12 +440,9 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv, if (arfs_enabled) mlx5e_arfs_disable(priv); - if (!netif_is_rxfh_configured(priv->netdev)) - mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt, - MLX5E_INDIR_RQT_SIZE, count); - /* Switch to new channels, set new parameters and close old ones */ - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, + mlx5e_num_channels_changed_ctx, NULL); if (arfs_enabled) { int err2 = mlx5e_arfs_enable(priv); @@ -580,7 +575,7 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, goto out; } - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); out: mutex_unlock(&priv->state_lock); @@ -633,6 +628,8 @@ static const u32 pplm_fec_2_ethtool[] = { [MLX5E_FEC_NOFEC] = ETHTOOL_FEC_OFF, [MLX5E_FEC_FIRECODE] = ETHTOOL_FEC_BASER, [MLX5E_FEC_RS_528_514] = ETHTOOL_FEC_RS, + [MLX5E_FEC_RS_544_514] = ETHTOOL_FEC_RS, + [MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_FEC_LLRS, }; static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size) @@ -650,45 +647,48 @@ static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size) return 0; } -/* we use ETHTOOL_FEC_* offset and apply it to ETHTOOL_LINK_MODE_FEC_*_BIT */ -static u32 ethtool_fec2ethtool_caps(u_long ethtool_fec_code) -{ - u32 offset; - - offset = find_first_bit(ðtool_fec_code, sizeof(u32)); - offset -= ETHTOOL_FEC_OFF_BIT; - offset += ETHTOOL_LINK_MODE_FEC_NONE_BIT; +#define MLX5E_ADVERTISE_SUPPORTED_FEC(mlx5_fec, ethtool_fec) \ + do { \ + if (mlx5e_fec_in_caps(dev, 1 << (mlx5_fec))) \ + __set_bit(ethtool_fec, \ + link_ksettings->link_modes.supported);\ + } while (0) - return offset; -} +static const u32 pplm_fec_2_ethtool_linkmodes[] = { + [MLX5E_FEC_NOFEC] = ETHTOOL_LINK_MODE_FEC_NONE_BIT, + [MLX5E_FEC_FIRECODE] = ETHTOOL_LINK_MODE_FEC_BASER_BIT, + [MLX5E_FEC_RS_528_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT, + [MLX5E_FEC_RS_544_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT, + [MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_LINK_MODE_FEC_LLRS_BIT, +}; static int get_fec_supported_advertised(struct mlx5_core_dev *dev, struct ethtool_link_ksettings *link_ksettings) { - u_long fec_caps = 0; - u32 active_fec = 0; - u32 offset; + u_long active_fec = 0; u32 bitn; int err; - err = mlx5e_get_fec_caps(dev, (u8 *)&fec_caps); + err = mlx5e_get_fec_mode(dev, (u32 *)&active_fec, NULL); if (err) return (err == -EOPNOTSUPP) ? 0 : err; - err = mlx5e_get_fec_mode(dev, &active_fec, NULL); - if (err) - return err; - - for_each_set_bit(bitn, &fec_caps, ARRAY_SIZE(pplm_fec_2_ethtool)) { - u_long ethtool_bitmask = pplm_fec_2_ethtool[bitn]; - - offset = ethtool_fec2ethtool_caps(ethtool_bitmask); - __set_bit(offset, link_ksettings->link_modes.supported); - } - - active_fec = pplm2ethtool_fec(active_fec, sizeof(u32) * BITS_PER_BYTE); - offset = ethtool_fec2ethtool_caps(active_fec); - __set_bit(offset, link_ksettings->link_modes.advertising); + MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_NOFEC, + ETHTOOL_LINK_MODE_FEC_NONE_BIT); + MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_FIRECODE, + ETHTOOL_LINK_MODE_FEC_BASER_BIT); + MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_RS_528_514, + ETHTOOL_LINK_MODE_FEC_RS_BIT); + MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_LLRS_272_257_1, + ETHTOOL_LINK_MODE_FEC_LLRS_BIT); + + /* active fec is a bit set, find out which bit is set and + * advertise the corresponding ethtool bit + */ + bitn = find_first_bit(&active_fec, sizeof(u32) * BITS_PER_BYTE); + if (bitn < ARRAY_SIZE(pplm_fec_2_ethtool_linkmodes)) + __set_bit(pplm_fec_2_ethtool_linkmodes[bitn], + link_ksettings->link_modes.advertising); return 0; } @@ -1511,7 +1511,7 @@ static int mlx5e_get_fecparam(struct net_device *netdev, { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; - u8 fec_configured = 0; + u16 fec_configured = 0; u32 fec_active = 0; int err; @@ -1527,7 +1527,7 @@ static int mlx5e_get_fecparam(struct net_device *netdev, return -EOPNOTSUPP; fecparam->fec = pplm2ethtool_fec((u_long)fec_configured, - sizeof(u8) * BITS_PER_BYTE); + sizeof(u16) * BITS_PER_BYTE); return 0; } @@ -1537,10 +1537,14 @@ static int mlx5e_set_fecparam(struct net_device *netdev, { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; - u8 fec_policy = 0; + u16 fec_policy = 0; int mode; int err; + if (bitmap_weight((unsigned long *)&fecparam->fec, + ETHTOOL_FEC_LLRS_BIT + 1) > 1) + return -EOPNOTSUPP; + for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) { if (!(pplm_fec_2_ethtool[mode] & fecparam->fec)) continue; @@ -1739,7 +1743,7 @@ static int set_pflag_cqe_based_moder(struct net_device *netdev, bool enable, return 0; } - return mlx5e_safe_switch_channels(priv, &new_channels, NULL); + return mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); } static int set_pflag_tx_cqe_based_moder(struct net_device *netdev, bool enable) @@ -1772,7 +1776,7 @@ int mlx5e_modify_rx_cqe_compression_locked(struct mlx5e_priv *priv, bool new_val return 0; } - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); if (err) return err; @@ -1829,7 +1833,7 @@ static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable) return 0; } - return mlx5e_safe_switch_channels(priv, &new_channels, NULL); + return mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); } static int set_pflag_rx_no_csum_complete(struct net_device *netdev, bool enable) @@ -1873,7 +1877,7 @@ static int set_pflag_xdp_tx_mpwqe(struct net_device *netdev, bool enable) return 0; } - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 21de4764d4c0..a230df2a45aa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1794,29 +1794,6 @@ static int mlx5e_set_tx_maxrate(struct net_device *dev, int index, u32 rate) return err; } -static int mlx5e_alloc_xps_cpumask(struct mlx5e_channel *c, - struct mlx5e_params *params) -{ - int num_comp_vectors = mlx5_comp_vectors_count(c->mdev); - int irq; - - if (!zalloc_cpumask_var(&c->xps_cpumask, GFP_KERNEL)) - return -ENOMEM; - - for (irq = c->ix; irq < num_comp_vectors; irq += params->num_channels) { - int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(c->mdev, irq)); - - cpumask_set_cpu(cpu, c->xps_cpumask); - } - - return 0; -} - -static void mlx5e_free_xps_cpumask(struct mlx5e_channel *c) -{ - free_cpumask_var(c->xps_cpumask); -} - static int mlx5e_open_queues(struct mlx5e_channel *c, struct mlx5e_params *params, struct mlx5e_channel_param *cparam) @@ -1967,10 +1944,6 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, c->irq_desc = irq_to_desc(irq); c->lag_port = mlx5e_enumerate_lag_port(priv->mdev, ix); - err = mlx5e_alloc_xps_cpumask(c, params); - if (err) - goto err_free_channel; - netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64); err = mlx5e_open_queues(c, params, cparam); @@ -1993,9 +1966,7 @@ err_close_queues: err_napi_del: netif_napi_del(&c->napi); - mlx5e_free_xps_cpumask(c); -err_free_channel: kvfree(c); return err; @@ -2009,7 +1980,6 @@ static void mlx5e_activate_channel(struct mlx5e_channel *c) mlx5e_activate_txqsq(&c->sq[tc]); mlx5e_activate_icosq(&c->icosq); mlx5e_activate_rq(&c->rq); - netif_set_xps_queue(c->netdev, c->xps_cpumask, c->ix); if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state)) mlx5e_activate_xsk(c); @@ -2034,7 +2004,6 @@ static void mlx5e_close_channel(struct mlx5e_channel *c) mlx5e_close_xsk(c); mlx5e_close_queues(c); netif_napi_del(&c->napi); - mlx5e_free_xps_cpumask(c); kvfree(c); } @@ -2784,6 +2753,8 @@ free_in: return err; } +static MLX5E_DEFINE_PREACTIVATE_WRAPPER_CTX(mlx5e_modify_tirs_lro); + static int mlx5e_set_mtu(struct mlx5_core_dev *mdev, struct mlx5e_params *params, u16 mtu) { @@ -2833,6 +2804,8 @@ int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv) return 0; } +MLX5E_DEFINE_PREACTIVATE_WRAPPER_CTX(mlx5e_set_dev_port_mtu); + void mlx5e_set_netdev_mtu_boundaries(struct mlx5e_priv *priv) { struct mlx5e_params *params = &priv->channels.params; @@ -2869,6 +2842,54 @@ static void mlx5e_netdev_set_tcs(struct net_device *netdev) netdev_set_tc_queue(netdev, tc, nch, 0); } +static void mlx5e_update_netdev_queues(struct mlx5e_priv *priv, u16 count) +{ + int num_txqs = count * priv->channels.params.num_tc; + int num_rxqs = count * priv->profile->rq_groups; + struct net_device *netdev = priv->netdev; + + mlx5e_netdev_set_tcs(netdev); + netif_set_real_num_tx_queues(netdev, num_txqs); + netif_set_real_num_rx_queues(netdev, num_rxqs); +} + +static void mlx5e_set_default_xps_cpumasks(struct mlx5e_priv *priv, + struct mlx5e_params *params) +{ + struct mlx5_core_dev *mdev = priv->mdev; + int num_comp_vectors, ix, irq; + + num_comp_vectors = mlx5_comp_vectors_count(mdev); + + for (ix = 0; ix < params->num_channels; ix++) { + cpumask_clear(priv->scratchpad.cpumask); + + for (irq = ix; irq < num_comp_vectors; irq += params->num_channels) { + int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(mdev, irq)); + + cpumask_set_cpu(cpu, priv->scratchpad.cpumask); + } + + netif_set_xps_queue(priv->netdev, priv->scratchpad.cpumask, ix); + } +} + +int mlx5e_num_channels_changed(struct mlx5e_priv *priv) +{ + u16 count = priv->channels.params.num_channels; + + mlx5e_update_netdev_queues(priv, count); + mlx5e_set_default_xps_cpumasks(priv, &priv->channels.params); + + if (!netif_is_rxfh_configured(priv->netdev)) + mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt, + MLX5E_INDIR_RQT_SIZE, count); + + return 0; +} + +MLX5E_DEFINE_PREACTIVATE_WRAPPER_CTX(mlx5e_num_channels_changed); + static void mlx5e_build_txq_maps(struct mlx5e_priv *priv) { int i, ch; @@ -2890,14 +2911,6 @@ static void mlx5e_build_txq_maps(struct mlx5e_priv *priv) void mlx5e_activate_priv_channels(struct mlx5e_priv *priv) { - int num_txqs = priv->channels.num * priv->channels.params.num_tc; - int num_rxqs = priv->channels.num * priv->profile->rq_groups; - struct net_device *netdev = priv->netdev; - - mlx5e_netdev_set_tcs(netdev); - netif_set_real_num_tx_queues(netdev, num_txqs); - netif_set_real_num_rx_queues(netdev, num_rxqs); - mlx5e_build_txq_maps(priv); mlx5e_activate_channels(&priv->channels); mlx5e_xdp_tx_enable(priv); @@ -2930,42 +2943,52 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv) mlx5e_deactivate_channels(&priv->channels); } -static void mlx5e_switch_priv_channels(struct mlx5e_priv *priv, - struct mlx5e_channels *new_chs, - mlx5e_fp_hw_modify hw_modify) +static int mlx5e_switch_priv_channels(struct mlx5e_priv *priv, + struct mlx5e_channels *new_chs, + mlx5e_fp_preactivate preactivate, + void *context) { struct net_device *netdev = priv->netdev; - int new_num_txqs; + struct mlx5e_channels old_chs; int carrier_ok; - - new_num_txqs = new_chs->num * new_chs->params.num_tc; + int err = 0; carrier_ok = netif_carrier_ok(netdev); netif_carrier_off(netdev); - if (new_num_txqs < netdev->real_num_tx_queues) - netif_set_real_num_tx_queues(netdev, new_num_txqs); - mlx5e_deactivate_priv_channels(priv); - mlx5e_close_channels(&priv->channels); + old_chs = priv->channels; priv->channels = *new_chs; - /* New channels are ready to roll, modify HW settings if needed */ - if (hw_modify) - hw_modify(priv); + /* New channels are ready to roll, call the preactivate hook if needed + * to modify HW settings or update kernel parameters. + */ + if (preactivate) { + err = preactivate(priv, context); + if (err) { + priv->channels = old_chs; + goto out; + } + } + mlx5e_close_channels(&old_chs); priv->profile->update_rx(priv); + +out: mlx5e_activate_priv_channels(priv); /* return carrier back if needed */ if (carrier_ok) netif_carrier_on(netdev); + + return err; } int mlx5e_safe_switch_channels(struct mlx5e_priv *priv, struct mlx5e_channels *new_chs, - mlx5e_fp_hw_modify hw_modify) + mlx5e_fp_preactivate preactivate, + void *context) { int err; @@ -2973,8 +2996,16 @@ int mlx5e_safe_switch_channels(struct mlx5e_priv *priv, if (err) return err; - mlx5e_switch_priv_channels(priv, new_chs, hw_modify); + err = mlx5e_switch_priv_channels(priv, new_chs, preactivate, context); + if (err) + goto err_close; + return 0; + +err_close: + mlx5e_close_channels(new_chs); + + return err; } int mlx5e_safe_reopen_channels(struct mlx5e_priv *priv) @@ -2982,7 +3013,7 @@ int mlx5e_safe_reopen_channels(struct mlx5e_priv *priv) struct mlx5e_channels new_channels = {}; new_channels.params = priv->channels.params; - return mlx5e_safe_switch_channels(priv, &new_channels, NULL); + return mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); } void mlx5e_timestamp_init(struct mlx5e_priv *priv) @@ -3431,7 +3462,8 @@ static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv, goto out; } - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, + mlx5e_num_channels_changed_ctx, NULL); if (err) goto out; @@ -3644,7 +3676,8 @@ static int set_feature_lro(struct net_device *netdev, bool enable) goto out; } - err = mlx5e_safe_switch_channels(priv, &new_channels, mlx5e_modify_tirs_lro); + err = mlx5e_safe_switch_channels(priv, &new_channels, + mlx5e_modify_tirs_lro_ctx, NULL); out: mutex_unlock(&priv->state_lock); return err; @@ -3863,7 +3896,7 @@ static bool mlx5e_xsk_validate_mtu(struct net_device *netdev, } int mlx5e_change_mtu(struct net_device *netdev, int new_mtu, - change_hw_mtu_cb set_mtu_cb) + mlx5e_fp_preactivate preactivate) { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_channels new_channels = {}; @@ -3912,13 +3945,13 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu, if (!reset) { params->sw_mtu = new_mtu; - if (set_mtu_cb) - set_mtu_cb(priv); + if (preactivate) + preactivate(priv, NULL); netdev->mtu = params->sw_mtu; goto out; } - err = mlx5e_safe_switch_channels(priv, &new_channels, set_mtu_cb); + err = mlx5e_safe_switch_channels(priv, &new_channels, preactivate, NULL); if (err) goto out; @@ -3931,7 +3964,7 @@ out: static int mlx5e_change_nic_mtu(struct net_device *netdev, int new_mtu) { - return mlx5e_change_mtu(netdev, new_mtu, mlx5e_set_dev_port_mtu); + return mlx5e_change_mtu(netdev, new_mtu, mlx5e_set_dev_port_mtu_ctx); } int mlx5e_hwstamp_set(struct mlx5e_priv *priv, struct ifreq *ifr) @@ -4392,7 +4425,7 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog) mlx5e_set_rq_type(priv->mdev, &new_channels.params); old_prog = priv->channels.params.xdp_prog; - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); if (err) goto unlock; } else { @@ -4770,9 +4803,8 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, mlx5e_build_rq_params(mdev, params); /* HW LRO */ - - /* TODO: && MLX5_CAP_ETH(mdev, lro_cap) */ - if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) { + if (MLX5_CAP_ETH(mdev, lro_cap) && + params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) { /* No XSK params: checking the availability of striding RQ in general. */ if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL)) params->lro_en = !slow_pci_heuristic(mdev); @@ -5213,6 +5245,9 @@ int mlx5e_netdev_init(struct net_device *netdev, priv->max_nch = netdev->num_rx_queues / max_t(u8, profile->rq_groups, 1); priv->max_opened_tc = 1; + if (!alloc_cpumask_var(&priv->scratchpad.cpumask, GFP_KERNEL)) + return -ENOMEM; + mutex_init(&priv->state_lock); INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work); INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work); @@ -5221,7 +5256,7 @@ int mlx5e_netdev_init(struct net_device *netdev, priv->wq = create_singlethread_workqueue("mlx5e"); if (!priv->wq) - return -ENOMEM; + goto err_free_cpumask; /* netdev init */ netif_carrier_off(netdev); @@ -5231,11 +5266,17 @@ int mlx5e_netdev_init(struct net_device *netdev, #endif return 0; + +err_free_cpumask: + free_cpumask_var(priv->scratchpad.cpumask); + + return -ENOMEM; } void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv) { destroy_workqueue(priv->wq); + free_cpumask_var(priv->scratchpad.cpumask); } struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev, @@ -5270,6 +5311,7 @@ err_free_netdev: int mlx5e_attach_netdev(struct mlx5e_priv *priv) { + const bool take_rtnl = priv->netdev->reg_state == NETREG_REGISTERED; const struct mlx5e_profile *profile; int max_nch; int err; @@ -5281,10 +5323,25 @@ int mlx5e_attach_netdev(struct mlx5e_priv *priv) max_nch = mlx5e_get_max_num_channels(priv->mdev); if (priv->channels.params.num_channels > max_nch) { mlx5_core_warn(priv->mdev, "MLX5E: Reducing number of channels to %d\n", max_nch); + /* Reducing the number of channels - RXFH has to be reset, and + * mlx5e_num_channels_changed below will build the RQT. + */ + priv->netdev->priv_flags &= ~IFF_RXFH_CONFIGURED; priv->channels.params.num_channels = max_nch; - mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt, - MLX5E_INDIR_RQT_SIZE, max_nch); } + /* 1. Set the real number of queues in the kernel the first time. + * 2. Set our default XPS cpumask. + * 3. Build the RQT. + * + * rtnl_lock is required by netif_set_real_num_*_queues in case the + * netdev has been registered by this point (if this function was called + * in the reload or resume flow). + */ + if (take_rtnl) + rtnl_lock(); + mlx5e_num_channels_changed(priv); + if (take_rtnl) + rtnl_unlock(); err = profile->init_tx(priv); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 6ed307d7f191..5df8f50b76e7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1396,7 +1396,7 @@ static int mlx5e_rep_change_mtu(struct net_device *netdev, int new_mtu) static int mlx5e_uplink_rep_change_mtu(struct net_device *netdev, int new_mtu) { - return mlx5e_change_mtu(netdev, new_mtu, mlx5e_set_dev_port_mtu); + return mlx5e_change_mtu(netdev, new_mtu, mlx5e_set_dev_port_mtu_ctx); } static int mlx5e_uplink_rep_set_mac(struct net_device *netdev, void *addr) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 1c3ab69cbd96..065c74a2d0c5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -158,7 +158,8 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq, mlx5e_read_mini_arr_slot(wq, cqd, cqcc); mlx5e_decompress_cqe_no_hash(rq, wq, cqcc); - rq->handle_rx_cqe(rq, &cqd->title); + INDIRECT_CALL_2(rq->handle_rx_cqe, mlx5e_handle_rx_cqe_mpwrq, + mlx5e_handle_rx_cqe, rq, &cqd->title); } mlx5e_cqes_update_owner(wq, cqcc - wq->cc); wq->cc = cqcc; @@ -178,7 +179,8 @@ static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq, mlx5e_read_title_slot(rq, wq, cc); mlx5e_read_mini_arr_slot(wq, cqd, cc + 1); mlx5e_decompress_cqe(rq, wq, cc); - rq->handle_rx_cqe(rq, &cqd->title); + INDIRECT_CALL_2(rq->handle_rx_cqe, mlx5e_handle_rx_cqe_mpwrq, + mlx5e_handle_rx_cqe, rq, &cqd->title); cqd->mini_arr_idx++; return mlx5e_decompress_cqes_cont(rq, wq, 1, budget_rem) - 1; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index ee60383adc5b..fd6b2a1898c5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -72,8 +72,8 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, { int txq_ix = netdev_pick_tx(dev, skb, NULL); struct mlx5e_priv *priv = netdev_priv(dev); - u16 num_channels; int up = 0; + int ch_ix; if (!netdev_get_num_tc(dev)) return txq_ix; @@ -86,14 +86,13 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, if (skb_vlan_tag_present(skb)) up = skb_vlan_tag_get_prio(skb); - /* txq_ix can be larger than num_channels since - * dev->num_real_tx_queues = num_channels * num_tc + /* Normalize any picked txq_ix to [0, num_channels), + * So we can return a txq_ix that matches the channel and + * packet UP. */ - num_channels = priv->channels.params.num_channels; - if (txq_ix >= num_channels) - txq_ix = priv->txq2sq[txq_ix]->ch_ix; + ch_ix = priv->txq2sq[txq_ix]->ch_ix; - return priv->channel_tc2realtxq[txq_ix][up]; + return priv->channel_tc2realtxq[ch_ix][up]; } static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c index 257a7c9f7a14..267f4535c36b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c @@ -31,6 +31,7 @@ */ #include <linux/irq.h> +#include <linux/indirect_call_wrapper.h> #include "en.h" #include "en/xdp.h" #include "en/xsk/rx.h" @@ -99,7 +100,10 @@ static bool mlx5e_napi_xsk_post(struct mlx5e_xdpsq *xsksq, struct mlx5e_rq *xskr busy_xsk |= mlx5e_xsk_tx(xsksq, MLX5E_TX_XSK_POLL_BUDGET); mlx5e_xsk_update_tx_wakeup(xsksq); - xsk_rx_alloc_err = xskrq->post_wqes(xskrq); + xsk_rx_alloc_err = INDIRECT_CALL_2(xskrq->post_wqes, + mlx5e_post_rx_mpwqes, + mlx5e_post_rx_wqes, + xskrq); busy_xsk |= mlx5e_xsk_update_rx_wakeup(xskrq, xsk_rx_alloc_err); return busy_xsk; @@ -142,7 +146,10 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget) mlx5e_poll_ico_cq(&c->icosq.cq); - busy |= rq->post_wqes(rq); + busy |= INDIRECT_CALL_2(rq->post_wqes, + mlx5e_post_rx_mpwqes, + mlx5e_post_rx_wqes, + rq); if (xsk_open) { mlx5e_poll_ico_cq(&c->xskicosq.cq); busy |= mlx5e_poll_xdpsq_cq(&xsksq->cq); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 909a7f284614..90e3d0233101 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -613,6 +613,44 @@ static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) fwhandle, 0); } +#define MLX5_FSM_REACTIVATE_TOUT 5000 /* msecs */ +static int mlx5_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, u8 *status) +{ + unsigned long exp_time = jiffies + msecs_to_jiffies(MLX5_FSM_REACTIVATE_TOUT); + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + u32 out[MLX5_ST_SZ_DW(mirc_reg)]; + u32 in[MLX5_ST_SZ_DW(mirc_reg)]; + int err; + + if (!MLX5_CAP_MCAM_REG2(dev, mirc)) + return -EOPNOTSUPP; + + memset(in, 0, sizeof(in)); + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_MIRC, 0, 1); + if (err) + return err; + + do { + memset(out, 0, sizeof(out)); + err = mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_MIRC, 0, 0); + if (err) + return err; + + *status = MLX5_GET(mirc_reg, out, status_code); + if (*status != MLXFW_FSM_REACTIVATE_STATUS_BUSY) + return 0; + + msleep(20); + } while (time_before(jiffies, exp_time)); + + return 0; +} + static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = { .component_query = mlx5_component_query, .fsm_lock = mlx5_fsm_lock, @@ -620,6 +658,7 @@ static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = { .fsm_block_download = mlx5_fsm_block_download, .fsm_component_verify = mlx5_fsm_component_verify, .fsm_activate = mlx5_fsm_activate, + .fsm_reactivate = mlx5_fsm_reactivate, .fsm_query_state = mlx5_fsm_query_state, .fsm_cancel = mlx5_fsm_cancel, .fsm_release = mlx5_fsm_release @@ -634,6 +673,7 @@ int mlx5_firmware_flash(struct mlx5_core_dev *dev, .ops = &mlx5_mlxfw_dev_ops, .psid = dev->board_id, .psid_size = strlen(dev->board_id), + .devlink = priv_to_devlink(dev), }, .mlx5_core_dev = dev }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 56078b23f1a0..673aaa815f57 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -483,7 +483,7 @@ static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu) new_channels.params = *params; new_channels.params.sw_mtu = new_mtu; - err = mlx5e_safe_switch_channels(priv, &new_channels, NULL); + err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL); if (err) goto out; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c index e065c2f68f5a..6cbccba56f70 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c @@ -21,7 +21,7 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev) struct mlx5_dm *dm; if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM)) - return 0; + return NULL; dm = kzalloc(sizeof(*dm), GFP_KERNEL); if (!dm) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index f554cfddcf4e..204a26bf0a5f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -70,6 +70,7 @@ #include "diag/fw_tracer.h" #include "ecpf.h" #include "lib/hv_vhca.h" +#include "diag/rsc_dump.h" MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver"); @@ -880,6 +881,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev) dev->tracer = mlx5_fw_tracer_create(dev); dev->hv_vhca = mlx5_hv_vhca_create(dev); + dev->rsc_dump = mlx5_rsc_dump_create(dev); return 0; @@ -909,6 +911,7 @@ err_devcom: static void mlx5_cleanup_once(struct mlx5_core_dev *dev) { + mlx5_rsc_dump_destroy(dev); mlx5_hv_vhca_destroy(dev->hv_vhca); mlx5_fw_tracer_destroy(dev->tracer); mlx5_dm_cleanup(dev); @@ -1079,6 +1082,12 @@ static int mlx5_load(struct mlx5_core_dev *dev) mlx5_hv_vhca_init(dev->hv_vhca); + err = mlx5_rsc_dump_init(dev); + if (err) { + mlx5_core_err(dev, "Failed to init Resource dump\n"); + goto err_rsc_dump; + } + err = mlx5_fpga_device_start(dev); if (err) { mlx5_core_err(dev, "fpga device start failed %d\n", err); @@ -1134,6 +1143,8 @@ err_tls_start: err_ipsec_start: mlx5_fpga_device_stop(dev); err_fpga_start: + mlx5_rsc_dump_cleanup(dev); +err_rsc_dump: mlx5_hv_vhca_cleanup(dev->hv_vhca); mlx5_fw_tracer_cleanup(dev->tracer); err_fw_tracer: @@ -1155,6 +1166,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev) mlx5_accel_ipsec_cleanup(dev); mlx5_accel_tls_cleanup(dev); mlx5_fpga_device_stop(dev); + mlx5_rsc_dump_cleanup(dev); mlx5_hv_vhca_cleanup(dev->hv_vhca); mlx5_fw_tracer_cleanup(dev->tracer); mlx5_eq_table_destroy(dev); diff --git a/drivers/net/ethernet/mellanox/mlxfw/Kconfig b/drivers/net/ethernet/mellanox/mlxfw/Kconfig index 0367f835a846..5b604501f33e 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxfw/Kconfig @@ -12,3 +12,4 @@ config MLXFW To compile this driver as a module, choose M here: the module will be called mlxfw. select XZ_DEC + select NET_DEVLINK diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h index c50e74ab02c4..7654841a05c2 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h @@ -6,6 +6,30 @@ #include <linux/firmware.h> #include <linux/netlink.h> +#include <linux/device.h> +#include <net/devlink.h> + +struct mlxfw_dev { + const struct mlxfw_dev_ops *ops; + const char *psid; + u16 psid_size; + struct devlink *devlink; +}; + +static inline +struct device *mlxfw_dev_dev(struct mlxfw_dev *mlxfw_dev) +{ + return mlxfw_dev->devlink->dev; +} + +#define MLXFW_PRFX "mlxfw: " + +#define mlxfw_info(mlxfw_dev, fmt, ...) \ + dev_info(mlxfw_dev_dev(mlxfw_dev), MLXFW_PRFX fmt, ## __VA_ARGS__) +#define mlxfw_err(mlxfw_dev, fmt, ...) \ + dev_err(mlxfw_dev_dev(mlxfw_dev), MLXFW_PRFX fmt, ## __VA_ARGS__) +#define mlxfw_dbg(mlxfw_dev, fmt, ...) \ + dev_dbg(mlxfw_dev_dev(mlxfw_dev), MLXFW_PRFX fmt, ## __VA_ARGS__) enum mlxfw_fsm_state { MLXFW_FSM_STATE_IDLE, @@ -31,7 +55,19 @@ enum mlxfw_fsm_state_err { MLXFW_FSM_STATE_ERR_MAX, }; -struct mlxfw_dev; +enum mlxfw_fsm_reactivate_status { + MLXFW_FSM_REACTIVATE_STATUS_OK, + MLXFW_FSM_REACTIVATE_STATUS_BUSY, + MLXFW_FSM_REACTIVATE_STATUS_PROHIBITED_FW_VER_ERR, + MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_COPY_FAILED, + MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_ERASE_FAILED, + MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_RESTORE_FAILED, + MLXFW_FSM_REACTIVATE_STATUS_CANDIDATE_FW_DEACTIVATION_FAILED, + MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED, + MLXFW_FSM_REACTIVATE_STATUS_ERR_DEVICE_RESET_REQUIRED, + MLXFW_FSM_REACTIVATE_STATUS_ERR_FW_PROGRAMMING_NEEDED, + MLXFW_FSM_REACTIVATE_STATUS_MAX, +}; struct mlxfw_dev_ops { int (*component_query)(struct mlxfw_dev *mlxfw_dev, u16 component_index, @@ -51,6 +87,8 @@ struct mlxfw_dev_ops { int (*fsm_activate)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); + int (*fsm_reactivate)(struct mlxfw_dev *mlxfw_dev, u8 *status); + int (*fsm_query_state)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, enum mlxfw_fsm_state *fsm_state, enum mlxfw_fsm_state_err *fsm_state_err); @@ -58,16 +96,6 @@ struct mlxfw_dev_ops { void (*fsm_cancel)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); void (*fsm_release)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); - - void (*status_notify)(struct mlxfw_dev *mlxfw_dev, - const char *msg, const char *comp_name, - u32 done_bytes, u32 total_bytes); -}; - -struct mlxfw_dev { - const struct mlxfw_dev_ops *ops; - const char *psid; - u16 psid_size; }; #if IS_REACHABLE(CONFIG_MLXFW) diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c index 29e95d0a6ad1..046a0cb82ed8 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c @@ -16,38 +16,70 @@ (MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS) #define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20)) -static const char * const mlxfw_fsm_state_err_str[] = { - [MLXFW_FSM_STATE_ERR_ERROR] = - "general error", - [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] = - "component hash mismatch", - [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] = - "component not applicable", - [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] = - "unknown key", - [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] = - "authentication failed", - [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] = - "component was not signed", - [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] = - "key not applicable", - [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] = - "bad format", - [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] = - "pending reset", - [MLXFW_FSM_STATE_ERR_MAX] = - "unknown error" +static const int mlxfw_fsm_state_errno[] = { + [MLXFW_FSM_STATE_ERR_ERROR] = -EIO, + [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] = -EBADMSG, + [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] = -ENOENT, + [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] = -ENOKEY, + [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] = -EACCES, + [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] = -EKEYREVOKED, + [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] = -EKEYREJECTED, + [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] = -ENOEXEC, + [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] = -EBUSY, + [MLXFW_FSM_STATE_ERR_MAX] = -EINVAL }; -static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev, - const char *msg, const char *comp_name, - u32 done_bytes, u32 total_bytes) +#define MLXFW_ERR_PRFX "Firmware flash failed: " +#define MLXFW_ERR_MSG(fwdev, extack, msg, err) do { \ + mlxfw_err(fwdev, "%s, err (%d)\n", MLXFW_ERR_PRFX msg, err); \ + NL_SET_ERR_MSG_MOD(extack, MLXFW_ERR_PRFX msg); \ +} while (0) + +static int mlxfw_fsm_state_err(struct mlxfw_dev *mlxfw_dev, + struct netlink_ext_ack *extack, + enum mlxfw_fsm_state_err err) { - if (!mlxfw_dev->ops->status_notify) - return; - mlxfw_dev->ops->status_notify(mlxfw_dev, msg, comp_name, - done_bytes, total_bytes); -} + enum mlxfw_fsm_state_err fsm_state_err; + + fsm_state_err = min_t(enum mlxfw_fsm_state_err, err, + MLXFW_FSM_STATE_ERR_MAX); + + switch (fsm_state_err) { + case MLXFW_FSM_STATE_ERR_ERROR: + MLXFW_ERR_MSG(mlxfw_dev, extack, "general error", err); + break; + case MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR: + MLXFW_ERR_MSG(mlxfw_dev, extack, "component hash mismatch", err); + break; + case MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE: + MLXFW_ERR_MSG(mlxfw_dev, extack, "component not applicable", err); + break; + case MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY: + MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown key", err); + break; + case MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED: + MLXFW_ERR_MSG(mlxfw_dev, extack, "authentication failed", err); + break; + case MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED: + MLXFW_ERR_MSG(mlxfw_dev, extack, "component was not signed", err); + break; + case MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE: + MLXFW_ERR_MSG(mlxfw_dev, extack, "key not applicable", err); + break; + case MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT: + MLXFW_ERR_MSG(mlxfw_dev, extack, "bad format", err); + break; + case MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET: + MLXFW_ERR_MSG(mlxfw_dev, extack, "pending reset", err); + break; + case MLXFW_FSM_STATE_ERR_OK: /* fall through */ + case MLXFW_FSM_STATE_ERR_MAX: + MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown error", err); + break; + }; + + return mlxfw_fsm_state_errno[fsm_state_err]; +}; static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, enum mlxfw_fsm_state fsm_state, @@ -62,21 +94,18 @@ static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, retry: err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle, &curr_fsm_state, &fsm_state_err); - if (err) + if (err) { + MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM state query failed", err); return err; - - if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) { - fsm_state_err = min_t(enum mlxfw_fsm_state_err, - fsm_state_err, MLXFW_FSM_STATE_ERR_MAX); - pr_err("Firmware flash failed: %s\n", - mlxfw_fsm_state_err_str[fsm_state_err]); - NL_SET_ERR_MSG_MOD(extack, "Firmware flash failed"); - return -EINVAL; } + + if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) + return mlxfw_fsm_state_err(mlxfw_dev, extack, fsm_state_err); + if (curr_fsm_state != fsm_state) { if (--times == 0) { - pr_err("Timeout reached on FSM state change"); - NL_SET_ERR_MSG_MOD(extack, "Timeout reached on FSM state change"); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Timeout reached on FSM state change", -ETIMEDOUT); return -ETIMEDOUT; } msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS); @@ -85,6 +114,92 @@ retry: return 0; } +static int +mlxfw_fsm_reactivate_err(struct mlxfw_dev *mlxfw_dev, + struct netlink_ext_ack *extack, u8 err) +{ + enum mlxfw_fsm_reactivate_status status; + +#define MXFW_REACT_PRFX "Reactivate FSM: " +#define MLXFW_REACT_ERR(msg, err) \ + MLXFW_ERR_MSG(mlxfw_dev, extack, MXFW_REACT_PRFX msg, err) + + status = min_t(enum mlxfw_fsm_reactivate_status, err, + MLXFW_FSM_REACTIVATE_STATUS_MAX); + + switch (status) { + case MLXFW_FSM_REACTIVATE_STATUS_BUSY: + MLXFW_REACT_ERR("busy", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_PROHIBITED_FW_VER_ERR: + MLXFW_REACT_ERR("prohibited fw ver", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_COPY_FAILED: + MLXFW_REACT_ERR("first page copy failed", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_ERASE_FAILED: + MLXFW_REACT_ERR("first page erase failed", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_RESTORE_FAILED: + MLXFW_REACT_ERR("first page restore failed", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_CANDIDATE_FW_DEACTIVATION_FAILED: + MLXFW_REACT_ERR("candidate fw deactivation failed", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_ERR_DEVICE_RESET_REQUIRED: + MLXFW_REACT_ERR("device reset required", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_ERR_FW_PROGRAMMING_NEEDED: + MLXFW_REACT_ERR("fw programming needed", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED: + MLXFW_REACT_ERR("fw already activated", err); + break; + case MLXFW_FSM_REACTIVATE_STATUS_OK: /* fall through */ + case MLXFW_FSM_REACTIVATE_STATUS_MAX: + MLXFW_REACT_ERR("unexpected error", err); + break; + }; + return -EREMOTEIO; +}; + +static int mlxfw_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, + struct netlink_ext_ack *extack, + bool *supported) +{ + u8 status; + int err; + + if (!mlxfw_dev->ops->fsm_reactivate) + return 0; + + err = mlxfw_dev->ops->fsm_reactivate(mlxfw_dev, &status); + if (err == -EOPNOTSUPP) { + *supported = false; + return 0; + } + + if (err) { + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Could not reactivate firmware flash", err); + return err; + } + + if (status == MLXFW_FSM_REACTIVATE_STATUS_OK || + status == MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED) + return 0; + + return mlxfw_fsm_reactivate_err(mlxfw_dev, extack, status); +} + +static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev, + const char *msg, const char *comp_name, + u32 done_bytes, u32 total_bytes) +{ + devlink_flash_update_status_notify(mlxfw_dev->devlink, msg, comp_name, + done_bytes, total_bytes); +} + #define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1)) #define MLXFW_ALIGN_UP(x, align_bits) \ MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits)) @@ -92,6 +207,7 @@ retry: static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, struct mlxfw_mfa2_component *comp, + bool reactivate_supp, struct netlink_ext_ack *extack) { u16 comp_max_write_size; @@ -108,34 +224,43 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev, err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index, &comp_max_size, &comp_align_bits, &comp_max_write_size); - if (err) + if (err) { + MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM component query failed", err); return err; + } comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE); if (comp->data_size > comp_max_size) { - pr_err("Component %d is of size %d which is bigger than limit %d\n", - comp->index, comp->data_size, comp_max_size); - NL_SET_ERR_MSG_MOD(extack, "Component is bigger than limit"); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Component size is bigger than limit", -EINVAL); return -EINVAL; } comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size, comp_align_bits); - pr_debug("Component update\n"); + mlxfw_dbg(mlxfw_dev, "Component update\n"); mlxfw_status_notify(mlxfw_dev, "Updating component", comp_name, 0, 0); err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle, comp->index, comp->data_size); - if (err) + if (err) { + if (!reactivate_supp) + MLXFW_ERR_MSG(mlxfw_dev, extack, + "FSM component update failed, FW reactivate is not supported", + err); + else + MLXFW_ERR_MSG(mlxfw_dev, extack, + "FSM component update failed", err); return err; + } err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_DOWNLOAD, extack); if (err) goto err_out; - pr_debug("Component download\n"); + mlxfw_dbg(mlxfw_dev, "Component download\n"); mlxfw_status_notify(mlxfw_dev, "Downloading component", comp_name, 0, comp->data_size); for (offset = 0; @@ -147,19 +272,25 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev, err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle, block_ptr, block_size, offset); - if (err) + if (err) { + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Component download failed", err); goto err_out; + } mlxfw_status_notify(mlxfw_dev, "Downloading component", comp_name, offset + block_size, comp->data_size); } - pr_debug("Component verify\n"); + mlxfw_dbg(mlxfw_dev, "Component verify\n"); mlxfw_status_notify(mlxfw_dev, "Verifying component", comp_name, 0, 0); err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle, comp->index); - if (err) + if (err) { + MLXFW_ERR_MSG(mlxfw_dev, extack, + "FSM component verify failed", err); goto err_out; + } err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED, extack); @@ -174,6 +305,7 @@ err_out: static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, struct mlxfw_mfa2_file *mfa2_file, + bool reactivate_supp, struct netlink_ext_ack *extack) { u32 component_count; @@ -184,8 +316,8 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, mlxfw_dev->psid_size, &component_count); if (err) { - pr_err("Could not find device PSID in MFA2 file\n"); - NL_SET_ERR_MSG_MOD(extack, "Could not find device PSID in MFA2 file"); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Could not find device PSID in MFA2 file", err); return err; } @@ -194,11 +326,17 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid, mlxfw_dev->psid_size, i); - if (IS_ERR(comp)) - return PTR_ERR(comp); + if (IS_ERR(comp)) { + err = PTR_ERR(comp); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Failed to get MFA2 component", err); + return err; + } - pr_info("Flashing component type %d\n", comp->index); - err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp, extack); + mlxfw_info(mlxfw_dev, "Flashing component type %d\n", + comp->index); + err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp, + reactivate_supp, extack); mlxfw_mfa2_file_component_put(comp); if (err) return err; @@ -211,26 +349,32 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, struct netlink_ext_ack *extack) { struct mlxfw_mfa2_file *mfa2_file; + bool reactivate_supp = true; u32 fwhandle; int err; if (!mlxfw_mfa2_check(firmware)) { - pr_err("Firmware file is not MFA2\n"); - NL_SET_ERR_MSG_MOD(extack, "Firmware file is not MFA2"); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Firmware file is not MFA2", -EINVAL); return -EINVAL; } mfa2_file = mlxfw_mfa2_file_init(firmware); - if (IS_ERR(mfa2_file)) - return PTR_ERR(mfa2_file); + if (IS_ERR(mfa2_file)) { + err = PTR_ERR(mfa2_file); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Failed to initialize MFA2 firmware file", err); + return err; + } - pr_info("Initialize firmware flash process\n"); + mlxfw_info(mlxfw_dev, "Initialize firmware flash process\n"); + devlink_flash_update_begin_notify(mlxfw_dev->devlink); mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process", NULL, 0, 0); err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle); if (err) { - pr_err("Could not lock the firmware FSM\n"); - NL_SET_ERR_MSG_MOD(extack, "Could not lock the firmware FSM"); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Could not lock the firmware FSM", err); goto err_fsm_lock; } @@ -239,16 +383,26 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, if (err) goto err_state_wait_idle_to_locked; - err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file, extack); + err = mlxfw_fsm_reactivate(mlxfw_dev, extack, &reactivate_supp); + if (err) + goto err_fsm_reactivate; + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, + MLXFW_FSM_STATE_LOCKED, extack); + if (err) + goto err_state_wait_reactivate_to_locked; + + err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file, + reactivate_supp, extack); if (err) goto err_flash_components; - pr_debug("Activate image\n"); + mlxfw_dbg(mlxfw_dev, "Activate image\n"); mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0); err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle); if (err) { - pr_err("Could not activate the downloaded image\n"); - NL_SET_ERR_MSG_MOD(extack, "Could not activate the downloaded image"); + MLXFW_ERR_MSG(mlxfw_dev, extack, + "Could not activate the downloaded image", err); goto err_fsm_activate; } @@ -257,21 +411,25 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, if (err) goto err_state_wait_activate_to_locked; - pr_debug("Handle release\n"); + mlxfw_dbg(mlxfw_dev, "Handle release\n"); mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle); - pr_info("Firmware flash done.\n"); + mlxfw_info(mlxfw_dev, "Firmware flash done\n"); mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0); mlxfw_mfa2_file_fini(mfa2_file); + devlink_flash_update_end_notify(mlxfw_dev->devlink); return 0; err_state_wait_activate_to_locked: err_fsm_activate: err_flash_components: +err_state_wait_reactivate_to_locked: +err_fsm_reactivate: err_state_wait_idle_to_locked: mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle); err_fsm_lock: mlxfw_mfa2_file_fini(mfa2_file); + devlink_flash_update_end_notify(mlxfw_dev->devlink); return err; } EXPORT_SYMBOL(mlxfw_firmware_flash); diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index e9f791c43f20..1078f88cff18 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -82,7 +82,7 @@ struct mlxsw_core { struct mlxsw_core_port *ports; unsigned int max_ports; bool fw_flash_in_progress; - unsigned long driver_priv[0]; + unsigned long driver_priv[]; /* driver_priv has to be always the last item */ }; @@ -142,6 +142,7 @@ struct mlxsw_rx_listener_item { struct list_head list; struct mlxsw_rx_listener rxl; void *priv; + bool enabled; }; struct mlxsw_event_listener_item { @@ -1457,14 +1458,12 @@ static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a, static struct mlxsw_rx_listener_item * __find_rx_listener_item(struct mlxsw_core *mlxsw_core, - const struct mlxsw_rx_listener *rxl, - void *priv) + const struct mlxsw_rx_listener *rxl) { struct mlxsw_rx_listener_item *rxl_item; list_for_each_entry(rxl_item, &mlxsw_core->rx_listener_list, list) { - if (__is_rx_listener_equal(&rxl_item->rxl, rxl) && - rxl_item->priv == priv) + if (__is_rx_listener_equal(&rxl_item->rxl, rxl)) return rxl_item; } return NULL; @@ -1472,11 +1471,11 @@ __find_rx_listener_item(struct mlxsw_core *mlxsw_core, int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, const struct mlxsw_rx_listener *rxl, - void *priv) + void *priv, bool enabled) { struct mlxsw_rx_listener_item *rxl_item; - rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv); + rxl_item = __find_rx_listener_item(mlxsw_core, rxl); if (rxl_item) return -EEXIST; rxl_item = kmalloc(sizeof(*rxl_item), GFP_KERNEL); @@ -1484,6 +1483,7 @@ int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, return -ENOMEM; rxl_item->rxl = *rxl; rxl_item->priv = priv; + rxl_item->enabled = enabled; list_add_rcu(&rxl_item->list, &mlxsw_core->rx_listener_list); return 0; @@ -1491,12 +1491,11 @@ int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, EXPORT_SYMBOL(mlxsw_core_rx_listener_register); void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, - const struct mlxsw_rx_listener *rxl, - void *priv) + const struct mlxsw_rx_listener *rxl) { struct mlxsw_rx_listener_item *rxl_item; - rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv); + rxl_item = __find_rx_listener_item(mlxsw_core, rxl); if (!rxl_item) return; list_del_rcu(&rxl_item->list); @@ -1505,6 +1504,19 @@ void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_core_rx_listener_unregister); +static void +mlxsw_core_rx_listener_state_set(struct mlxsw_core *mlxsw_core, + const struct mlxsw_rx_listener *rxl, + bool enabled) +{ + struct mlxsw_rx_listener_item *rxl_item; + + rxl_item = __find_rx_listener_item(mlxsw_core, rxl); + if (WARN_ON(!rxl_item)) + return; + rxl_item->enabled = enabled; +} + static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port, void *priv) { @@ -1534,14 +1546,12 @@ static bool __is_event_listener_equal(const struct mlxsw_event_listener *el_a, static struct mlxsw_event_listener_item * __find_event_listener_item(struct mlxsw_core *mlxsw_core, - const struct mlxsw_event_listener *el, - void *priv) + const struct mlxsw_event_listener *el) { struct mlxsw_event_listener_item *el_item; list_for_each_entry(el_item, &mlxsw_core->event_listener_list, list) { - if (__is_event_listener_equal(&el_item->el, el) && - el_item->priv == priv) + if (__is_event_listener_equal(&el_item->el, el)) return el_item; } return NULL; @@ -1559,7 +1569,7 @@ int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core, .trap_id = el->trap_id, }; - el_item = __find_event_listener_item(mlxsw_core, el, priv); + el_item = __find_event_listener_item(mlxsw_core, el); if (el_item) return -EEXIST; el_item = kmalloc(sizeof(*el_item), GFP_KERNEL); @@ -1568,7 +1578,7 @@ int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core, el_item->el = *el; el_item->priv = priv; - err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item); + err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item, true); if (err) goto err_rx_listener_register; @@ -1586,8 +1596,7 @@ err_rx_listener_register: EXPORT_SYMBOL(mlxsw_core_event_listener_register); void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, - const struct mlxsw_event_listener *el, - void *priv) + const struct mlxsw_event_listener *el) { struct mlxsw_event_listener_item *el_item; const struct mlxsw_rx_listener rxl = { @@ -1596,10 +1605,10 @@ void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, .trap_id = el->trap_id, }; - el_item = __find_event_listener_item(mlxsw_core, el, priv); + el_item = __find_event_listener_item(mlxsw_core, el); if (!el_item) return; - mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl, el_item); + mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl); list_del(&el_item->list); kfree(el_item); } @@ -1607,16 +1616,18 @@ EXPORT_SYMBOL(mlxsw_core_event_listener_unregister); static int mlxsw_core_listener_register(struct mlxsw_core *mlxsw_core, const struct mlxsw_listener *listener, - void *priv) + void *priv, bool enabled) { - if (listener->is_event) + if (listener->is_event) { + WARN_ON(!enabled); return mlxsw_core_event_listener_register(mlxsw_core, - &listener->u.event_listener, + &listener->event_listener, priv); - else + } else { return mlxsw_core_rx_listener_register(mlxsw_core, - &listener->u.rx_listener, - priv); + &listener->rx_listener, + priv, enabled); + } } static void mlxsw_core_listener_unregister(struct mlxsw_core *mlxsw_core, @@ -1625,26 +1636,31 @@ static void mlxsw_core_listener_unregister(struct mlxsw_core *mlxsw_core, { if (listener->is_event) mlxsw_core_event_listener_unregister(mlxsw_core, - &listener->u.event_listener, - priv); + &listener->event_listener); else mlxsw_core_rx_listener_unregister(mlxsw_core, - &listener->u.rx_listener, - priv); + &listener->rx_listener); } int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core, const struct mlxsw_listener *listener, void *priv) { + enum mlxsw_reg_htgt_trap_group trap_group; + enum mlxsw_reg_hpkt_action action; char hpkt_pl[MLXSW_REG_HPKT_LEN]; int err; - err = mlxsw_core_listener_register(mlxsw_core, listener, priv); + err = mlxsw_core_listener_register(mlxsw_core, listener, priv, + listener->enabled_on_register); if (err) return err; - mlxsw_reg_hpkt_pack(hpkt_pl, listener->action, listener->trap_id, - listener->trap_group, listener->is_ctrl); + action = listener->enabled_on_register ? listener->en_action : + listener->dis_action; + trap_group = listener->enabled_on_register ? listener->en_trap_group : + listener->dis_trap_group; + mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id, + trap_group, listener->is_ctrl); err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); if (err) goto err_trap_set; @@ -1664,8 +1680,8 @@ void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core, char hpkt_pl[MLXSW_REG_HPKT_LEN]; if (!listener->is_event) { - mlxsw_reg_hpkt_pack(hpkt_pl, listener->unreg_action, - listener->trap_id, listener->trap_group, + mlxsw_reg_hpkt_pack(hpkt_pl, listener->dis_action, + listener->trap_id, listener->dis_trap_group, listener->is_ctrl); mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); } @@ -1674,17 +1690,33 @@ void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_core_trap_unregister); -int mlxsw_core_trap_action_set(struct mlxsw_core *mlxsw_core, - const struct mlxsw_listener *listener, - enum mlxsw_reg_hpkt_action action) +int mlxsw_core_trap_state_set(struct mlxsw_core *mlxsw_core, + const struct mlxsw_listener *listener, + bool enabled) { + enum mlxsw_reg_htgt_trap_group trap_group; + enum mlxsw_reg_hpkt_action action; char hpkt_pl[MLXSW_REG_HPKT_LEN]; + int err; + + /* Not supported for event listener */ + if (WARN_ON(listener->is_event)) + return -EINVAL; + action = enabled ? listener->en_action : listener->dis_action; + trap_group = enabled ? listener->en_trap_group : + listener->dis_trap_group; mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id, - listener->trap_group, listener->is_ctrl); - return mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); + trap_group, listener->is_ctrl); + err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); + if (err) + return err; + + mlxsw_core_rx_listener_state_set(mlxsw_core, &listener->rx_listener, + enabled); + return 0; } -EXPORT_SYMBOL(mlxsw_core_trap_action_set); +EXPORT_SYMBOL(mlxsw_core_trap_state_set); static u64 mlxsw_core_tid_get(struct mlxsw_core *mlxsw_core) { @@ -1942,7 +1974,8 @@ void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, if ((rxl->local_port == MLXSW_PORT_DONT_CARE || rxl->local_port == local_port) && rxl->trap_id == rx_info->trap_id) { - found = true; + if (rxl_item->enabled) + found = true; break; } } @@ -2168,13 +2201,22 @@ int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module) /* Here we need to get the module width according to the module type. */ switch (module_type) { + case MLXSW_REG_PMTM_MODULE_TYPE_C2C8X: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_OSFP: + return 8; + case MLXSW_REG_PMTM_MODULE_TYPE_C2C4X: /* fall through */ case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X: /* fall through */ - case MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP: + case MLXSW_REG_PMTM_MODULE_TYPE_QSFP: return 4; - case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X: + case MLXSW_REG_PMTM_MODULE_TYPE_C2C2X: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_DSFP: return 2; - case MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP: /* fall through */ - case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X: + case MLXSW_REG_PMTM_MODULE_TYPE_C2C1X: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_SFP: return 1; default: return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 543476a2e503..46226823c7a6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -62,7 +62,6 @@ struct mlxsw_rx_listener { void (*func)(struct sk_buff *skb, u8 local_port, void *priv); u8 local_port; u16 trap_id; - enum mlxsw_reg_hpkt_action action; }; struct mlxsw_event_listener { @@ -76,58 +75,71 @@ struct mlxsw_listener { union { struct mlxsw_rx_listener rx_listener; struct mlxsw_event_listener event_listener; - } u; - enum mlxsw_reg_hpkt_action action; - enum mlxsw_reg_hpkt_action unreg_action; - u8 trap_group; - bool is_ctrl; /* should go via control buffer or not */ - bool is_event; + }; + enum mlxsw_reg_hpkt_action en_action; /* Action when enabled */ + enum mlxsw_reg_hpkt_action dis_action; /* Action when disabled */ + u8 en_trap_group; /* Trap group when enabled */ + u8 dis_trap_group; /* Trap group when disabled */ + u8 is_ctrl:1, /* should go via control buffer or not */ + is_event:1, + enabled_on_register:1; /* Trap should be enabled when listener + * is registered. + */ }; -#define MLXSW_RXL(_func, _trap_id, _action, _is_ctrl, _trap_group, \ - _unreg_action) \ - { \ - .trap_id = MLXSW_TRAP_ID_##_trap_id, \ - .u.rx_listener = \ - { \ - .func = _func, \ - .local_port = MLXSW_PORT_DONT_CARE, \ - .trap_id = MLXSW_TRAP_ID_##_trap_id, \ - }, \ - .action = MLXSW_REG_HPKT_ACTION_##_action, \ - .unreg_action = MLXSW_REG_HPKT_ACTION_##_unreg_action, \ - .trap_group = MLXSW_REG_HTGT_TRAP_GROUP_##_trap_group, \ - .is_ctrl = _is_ctrl, \ - .is_event = false, \ +#define __MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \ + _dis_action, _enabled_on_register, _dis_trap_group) \ + { \ + .trap_id = MLXSW_TRAP_ID_##_trap_id, \ + .rx_listener = \ + { \ + .func = _func, \ + .local_port = MLXSW_PORT_DONT_CARE, \ + .trap_id = MLXSW_TRAP_ID_##_trap_id, \ + }, \ + .en_action = MLXSW_REG_HPKT_ACTION_##_en_action, \ + .dis_action = MLXSW_REG_HPKT_ACTION_##_dis_action, \ + .en_trap_group = MLXSW_REG_HTGT_TRAP_GROUP_##_en_trap_group, \ + .dis_trap_group = MLXSW_REG_HTGT_TRAP_GROUP_##_dis_trap_group, \ + .is_ctrl = _is_ctrl, \ + .enabled_on_register = _enabled_on_register, \ } -#define MLXSW_EVENTL(_func, _trap_id, _trap_group) \ - { \ - .trap_id = MLXSW_TRAP_ID_##_trap_id, \ - .u.event_listener = \ - { \ - .func = _func, \ - .trap_id = MLXSW_TRAP_ID_##_trap_id, \ - }, \ - .action = MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, \ - .trap_group = MLXSW_REG_HTGT_TRAP_GROUP_##_trap_group, \ - .is_ctrl = false, \ - .is_event = true, \ +#define MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _trap_group, \ + _dis_action) \ + __MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _trap_group, \ + _dis_action, true, _trap_group) + +#define MLXSW_RXL_DIS(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \ + _dis_action, _dis_trap_group) \ + __MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \ + _dis_action, false, _dis_trap_group) + +#define MLXSW_EVENTL(_func, _trap_id, _trap_group) \ + { \ + .trap_id = MLXSW_TRAP_ID_##_trap_id, \ + .event_listener = \ + { \ + .func = _func, \ + .trap_id = MLXSW_TRAP_ID_##_trap_id, \ + }, \ + .en_action = MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, \ + .en_trap_group = MLXSW_REG_HTGT_TRAP_GROUP_##_trap_group, \ + .is_event = true, \ + .enabled_on_register = true, \ } int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, const struct mlxsw_rx_listener *rxl, - void *priv); + void *priv, bool enabled); void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, - const struct mlxsw_rx_listener *rxl, - void *priv); + const struct mlxsw_rx_listener *rxl); int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core, const struct mlxsw_event_listener *el, void *priv); void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, - const struct mlxsw_event_listener *el, - void *priv); + const struct mlxsw_event_listener *el); int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core, const struct mlxsw_listener *listener, @@ -135,9 +147,9 @@ int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core, void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core, const struct mlxsw_listener *listener, void *priv); -int mlxsw_core_trap_action_set(struct mlxsw_core *mlxsw_core, - const struct mlxsw_listener *listener, - enum mlxsw_reg_hpkt_action action); +int mlxsw_core_trap_state_set(struct mlxsw_core *mlxsw_core, + const struct mlxsw_listener *listener, + bool enabled); typedef void mlxsw_reg_trans_cb_t(struct mlxsw_core *mlxsw_core, char *payload, size_t payload_len, unsigned long cb_priv); @@ -461,7 +473,10 @@ enum mlxsw_devlink_param_id { }; struct mlxsw_skb_cb { - struct mlxsw_tx_info tx_info; + union { + struct mlxsw_tx_info tx_info; + u32 cookie_index; /* Only used during receive */ + }; }; static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index c51b2adfc1e1..1f2e6db743e1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@ -7,6 +7,9 @@ #include <linux/errno.h> #include <linux/rhashtable.h> #include <linux/list.h> +#include <linux/idr.h> +#include <linux/refcount.h> +#include <net/flow_offload.h> #include "item.h" #include "trap.h" @@ -63,6 +66,8 @@ struct mlxsw_afa { void *ops_priv; struct rhashtable set_ht; struct rhashtable fwd_entry_ht; + struct rhashtable cookie_ht; + struct idr cookie_idr; }; #define MLXSW_AFA_SET_LEN 0xA8 @@ -121,6 +126,55 @@ static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = { .automatic_shrinking = true, }; +struct mlxsw_afa_cookie { + struct rhash_head ht_node; + refcount_t ref_count; + struct rcu_head rcu; + u32 cookie_index; + struct flow_action_cookie fa_cookie; +}; + +static u32 mlxsw_afa_cookie_hash(const struct flow_action_cookie *fa_cookie, + u32 seed) +{ + return jhash2((u32 *) fa_cookie->cookie, + fa_cookie->cookie_len / sizeof(u32), seed); +} + +static u32 mlxsw_afa_cookie_key_hashfn(const void *data, u32 len, u32 seed) +{ + const struct flow_action_cookie *fa_cookie = data; + + return mlxsw_afa_cookie_hash(fa_cookie, seed); +} + +static u32 mlxsw_afa_cookie_obj_hashfn(const void *data, u32 len, u32 seed) +{ + const struct mlxsw_afa_cookie *cookie = data; + + return mlxsw_afa_cookie_hash(&cookie->fa_cookie, seed); +} + +static int mlxsw_afa_cookie_obj_cmpfn(struct rhashtable_compare_arg *arg, + const void *obj) +{ + const struct flow_action_cookie *fa_cookie = arg->key; + const struct mlxsw_afa_cookie *cookie = obj; + + if (cookie->fa_cookie.cookie_len == fa_cookie->cookie_len) + return memcmp(cookie->fa_cookie.cookie, fa_cookie->cookie, + fa_cookie->cookie_len); + return 1; +} + +static const struct rhashtable_params mlxsw_afa_cookie_ht_params = { + .head_offset = offsetof(struct mlxsw_afa_cookie, ht_node), + .hashfn = mlxsw_afa_cookie_key_hashfn, + .obj_hashfn = mlxsw_afa_cookie_obj_hashfn, + .obj_cmpfn = mlxsw_afa_cookie_obj_cmpfn, + .automatic_shrinking = true, +}; + struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set, const struct mlxsw_afa_ops *ops, void *ops_priv) @@ -138,11 +192,18 @@ struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set, &mlxsw_afa_fwd_entry_ht_params); if (err) goto err_fwd_entry_rhashtable_init; + err = rhashtable_init(&mlxsw_afa->cookie_ht, + &mlxsw_afa_cookie_ht_params); + if (err) + goto err_cookie_rhashtable_init; + idr_init(&mlxsw_afa->cookie_idr); mlxsw_afa->max_acts_per_set = max_acts_per_set; mlxsw_afa->ops = ops; mlxsw_afa->ops_priv = ops_priv; return mlxsw_afa; +err_cookie_rhashtable_init: + rhashtable_destroy(&mlxsw_afa->fwd_entry_ht); err_fwd_entry_rhashtable_init: rhashtable_destroy(&mlxsw_afa->set_ht); err_set_rhashtable_init: @@ -153,6 +214,9 @@ EXPORT_SYMBOL(mlxsw_afa_create); void mlxsw_afa_destroy(struct mlxsw_afa *mlxsw_afa) { + WARN_ON(!idr_is_empty(&mlxsw_afa->cookie_idr)); + idr_destroy(&mlxsw_afa->cookie_idr); + rhashtable_destroy(&mlxsw_afa->cookie_ht); rhashtable_destroy(&mlxsw_afa->fwd_entry_ht); rhashtable_destroy(&mlxsw_afa->set_ht); kfree(mlxsw_afa); @@ -627,6 +691,151 @@ err_counter_index_get: return ERR_PTR(err); } +/* 20 bits is a maximum that hardware can handle in trap with userdef action + * and carry along with the trapped packet. + */ +#define MLXSW_AFA_COOKIE_INDEX_BITS 20 +#define MLXSW_AFA_COOKIE_INDEX_MAX ((1 << MLXSW_AFA_COOKIE_INDEX_BITS) - 1) + +static struct mlxsw_afa_cookie * +mlxsw_afa_cookie_create(struct mlxsw_afa *mlxsw_afa, + const struct flow_action_cookie *fa_cookie) +{ + struct mlxsw_afa_cookie *cookie; + u32 cookie_index; + int err; + + cookie = kzalloc(sizeof(*cookie) + fa_cookie->cookie_len, GFP_KERNEL); + if (!cookie) + return ERR_PTR(-ENOMEM); + refcount_set(&cookie->ref_count, 1); + memcpy(&cookie->fa_cookie, fa_cookie, + sizeof(*fa_cookie) + fa_cookie->cookie_len); + + err = rhashtable_insert_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, + mlxsw_afa_cookie_ht_params); + if (err) + goto err_rhashtable_insert; + + /* Start cookie indexes with 1. Leave the 0 index unused. Packets + * that come from the HW which are not dropped by drop-with-cookie + * action are going to pass cookie_index 0 to lookup. + */ + cookie_index = 1; + err = idr_alloc_u32(&mlxsw_afa->cookie_idr, cookie, &cookie_index, + MLXSW_AFA_COOKIE_INDEX_MAX, GFP_KERNEL); + if (err) + goto err_idr_alloc; + cookie->cookie_index = cookie_index; + return cookie; + +err_idr_alloc: + rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, + mlxsw_afa_cookie_ht_params); +err_rhashtable_insert: + kfree(cookie); + return ERR_PTR(err); +} + +static void mlxsw_afa_cookie_destroy(struct mlxsw_afa *mlxsw_afa, + struct mlxsw_afa_cookie *cookie) +{ + idr_remove(&mlxsw_afa->cookie_idr, cookie->cookie_index); + rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node, + mlxsw_afa_cookie_ht_params); + kfree_rcu(cookie, rcu); +} + +static struct mlxsw_afa_cookie * +mlxsw_afa_cookie_get(struct mlxsw_afa *mlxsw_afa, + const struct flow_action_cookie *fa_cookie) +{ + struct mlxsw_afa_cookie *cookie; + + cookie = rhashtable_lookup_fast(&mlxsw_afa->cookie_ht, fa_cookie, + mlxsw_afa_cookie_ht_params); + if (cookie) { + refcount_inc(&cookie->ref_count); + return cookie; + } + return mlxsw_afa_cookie_create(mlxsw_afa, fa_cookie); +} + +static void mlxsw_afa_cookie_put(struct mlxsw_afa *mlxsw_afa, + struct mlxsw_afa_cookie *cookie) +{ + if (!refcount_dec_and_test(&cookie->ref_count)) + return; + mlxsw_afa_cookie_destroy(mlxsw_afa, cookie); +} + +/* RCU read lock must be held */ +const struct flow_action_cookie * +mlxsw_afa_cookie_lookup(struct mlxsw_afa *mlxsw_afa, u32 cookie_index) +{ + struct mlxsw_afa_cookie *cookie; + + /* 0 index means no cookie */ + if (!cookie_index) + return NULL; + cookie = idr_find(&mlxsw_afa->cookie_idr, cookie_index); + if (!cookie) + return NULL; + return &cookie->fa_cookie; +} +EXPORT_SYMBOL(mlxsw_afa_cookie_lookup); + +struct mlxsw_afa_cookie_ref { + struct mlxsw_afa_resource resource; + struct mlxsw_afa_cookie *cookie; +}; + +static void +mlxsw_afa_cookie_ref_destroy(struct mlxsw_afa_block *block, + struct mlxsw_afa_cookie_ref *cookie_ref) +{ + mlxsw_afa_resource_del(&cookie_ref->resource); + mlxsw_afa_cookie_put(block->afa, cookie_ref->cookie); + kfree(cookie_ref); +} + +static void +mlxsw_afa_cookie_ref_destructor(struct mlxsw_afa_block *block, + struct mlxsw_afa_resource *resource) +{ + struct mlxsw_afa_cookie_ref *cookie_ref; + + cookie_ref = container_of(resource, struct mlxsw_afa_cookie_ref, + resource); + mlxsw_afa_cookie_ref_destroy(block, cookie_ref); +} + +static struct mlxsw_afa_cookie_ref * +mlxsw_afa_cookie_ref_create(struct mlxsw_afa_block *block, + const struct flow_action_cookie *fa_cookie) +{ + struct mlxsw_afa_cookie_ref *cookie_ref; + struct mlxsw_afa_cookie *cookie; + int err; + + cookie_ref = kzalloc(sizeof(*cookie_ref), GFP_KERNEL); + if (!cookie_ref) + return ERR_PTR(-ENOMEM); + cookie = mlxsw_afa_cookie_get(block->afa, fa_cookie); + if (IS_ERR(cookie)) { + err = PTR_ERR(cookie); + goto err_cookie_get; + } + cookie_ref->cookie = cookie; + cookie_ref->resource.destructor = mlxsw_afa_cookie_ref_destructor; + mlxsw_afa_resource_add(block, &cookie_ref->resource); + return cookie_ref; + +err_cookie_get: + kfree(cookie_ref); + return ERR_PTR(err); +} + #define MLXSW_AFA_ONE_ACTION_LEN 32 #define MLXSW_AFA_PAYLOAD_OFFSET 4 @@ -747,97 +956,170 @@ int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block, } EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify); -/* Trap / Discard Action - * --------------------- - * The Trap / Discard action enables trapping / mirroring packets to the CPU +/* Trap Action / Trap With Userdef Action + * -------------------------------------- + * The Trap action enables trapping / mirroring packets to the CPU * as well as discarding packets. * The ACL Trap / Discard separates the forward/discard control from CPU * trap control. In addition, the Trap / Discard action enables activating * SPAN (port mirroring). + * + * The Trap with userdef action action has the same functionality as + * the Trap action with addition of user defined value that can be set + * and used by higher layer applications. */ -#define MLXSW_AFA_TRAPDISC_CODE 0x03 -#define MLXSW_AFA_TRAPDISC_SIZE 1 +#define MLXSW_AFA_TRAP_CODE 0x03 +#define MLXSW_AFA_TRAP_SIZE 1 + +#define MLXSW_AFA_TRAPWU_CODE 0x04 +#define MLXSW_AFA_TRAPWU_SIZE 2 -enum mlxsw_afa_trapdisc_trap_action { - MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP = 0, - MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP = 2, +enum mlxsw_afa_trap_trap_action { + MLXSW_AFA_TRAP_TRAP_ACTION_NOP = 0, + MLXSW_AFA_TRAP_TRAP_ACTION_TRAP = 2, }; -/* afa_trapdisc_trap_action +/* afa_trap_trap_action * Trap Action. */ -MLXSW_ITEM32(afa, trapdisc, trap_action, 0x00, 24, 4); +MLXSW_ITEM32(afa, trap, trap_action, 0x00, 24, 4); -enum mlxsw_afa_trapdisc_forward_action { - MLXSW_AFA_TRAPDISC_FORWARD_ACTION_FORWARD = 1, - MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD = 3, +enum mlxsw_afa_trap_forward_action { + MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD = 1, + MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD = 3, }; -/* afa_trapdisc_forward_action +/* afa_trap_forward_action * Forward Action. */ -MLXSW_ITEM32(afa, trapdisc, forward_action, 0x00, 0, 4); +MLXSW_ITEM32(afa, trap, forward_action, 0x00, 0, 4); -/* afa_trapdisc_trap_id +/* afa_trap_trap_id * Trap ID to configure. */ -MLXSW_ITEM32(afa, trapdisc, trap_id, 0x04, 0, 9); +MLXSW_ITEM32(afa, trap, trap_id, 0x04, 0, 9); -/* afa_trapdisc_mirror_agent +/* afa_trap_mirror_agent * Mirror agent. */ -MLXSW_ITEM32(afa, trapdisc, mirror_agent, 0x08, 29, 3); +MLXSW_ITEM32(afa, trap, mirror_agent, 0x08, 29, 3); -/* afa_trapdisc_mirror_enable +/* afa_trap_mirror_enable * Mirror enable. */ -MLXSW_ITEM32(afa, trapdisc, mirror_enable, 0x08, 24, 1); +MLXSW_ITEM32(afa, trap, mirror_enable, 0x08, 24, 1); + +/* user_def_val + * Value for the SW usage. Can be used to pass information of which + * rule has caused a trap. This may be overwritten by later traps. + * This field does a set on the packet's user_def_val only if this + * is the first trap_id or if the trap_id has replaced the previous + * packet's trap_id. + */ +MLXSW_ITEM32(afa, trap, user_def_val, 0x0C, 0, 20); static inline void -mlxsw_afa_trapdisc_pack(char *payload, - enum mlxsw_afa_trapdisc_trap_action trap_action, - enum mlxsw_afa_trapdisc_forward_action forward_action, - u16 trap_id) +mlxsw_afa_trap_pack(char *payload, + enum mlxsw_afa_trap_trap_action trap_action, + enum mlxsw_afa_trap_forward_action forward_action, + u16 trap_id) { - mlxsw_afa_trapdisc_trap_action_set(payload, trap_action); - mlxsw_afa_trapdisc_forward_action_set(payload, forward_action); - mlxsw_afa_trapdisc_trap_id_set(payload, trap_id); + mlxsw_afa_trap_trap_action_set(payload, trap_action); + mlxsw_afa_trap_forward_action_set(payload, forward_action); + mlxsw_afa_trap_trap_id_set(payload, trap_id); } static inline void -mlxsw_afa_trapdisc_mirror_pack(char *payload, bool mirror_enable, - u8 mirror_agent) +mlxsw_afa_trapwu_pack(char *payload, + enum mlxsw_afa_trap_trap_action trap_action, + enum mlxsw_afa_trap_forward_action forward_action, + u16 trap_id, u32 user_def_val) { - mlxsw_afa_trapdisc_mirror_enable_set(payload, mirror_enable); - mlxsw_afa_trapdisc_mirror_agent_set(payload, mirror_agent); + mlxsw_afa_trap_pack(payload, trap_action, forward_action, trap_id); + mlxsw_afa_trap_user_def_val_set(payload, user_def_val); } -int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block) +static inline void +mlxsw_afa_trap_mirror_pack(char *payload, bool mirror_enable, + u8 mirror_agent) { - char *act = mlxsw_afa_block_append_action(block, - MLXSW_AFA_TRAPDISC_CODE, - MLXSW_AFA_TRAPDISC_SIZE); + mlxsw_afa_trap_mirror_enable_set(payload, mirror_enable); + mlxsw_afa_trap_mirror_agent_set(payload, mirror_agent); +} + +static int mlxsw_afa_block_append_drop_plain(struct mlxsw_afa_block *block, + bool ingress) +{ + char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_TRAP_CODE, + MLXSW_AFA_TRAP_SIZE); if (IS_ERR(act)) return PTR_ERR(act); - mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP, - MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD, 0); + mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, + MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, + ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL : + MLXSW_TRAP_ID_DISCARD_EGRESS_ACL); return 0; } + +static int +mlxsw_afa_block_append_drop_with_cookie(struct mlxsw_afa_block *block, + bool ingress, + const struct flow_action_cookie *fa_cookie, + struct netlink_ext_ack *extack) +{ + struct mlxsw_afa_cookie_ref *cookie_ref; + u32 cookie_index; + char *act; + int err; + + cookie_ref = mlxsw_afa_cookie_ref_create(block, fa_cookie); + if (IS_ERR(cookie_ref)) { + NL_SET_ERR_MSG_MOD(extack, "Cannot create cookie for drop action"); + return PTR_ERR(cookie_ref); + } + cookie_index = cookie_ref->cookie->cookie_index; + + act = mlxsw_afa_block_append_action(block, MLXSW_AFA_TRAPWU_CODE, + MLXSW_AFA_TRAPWU_SIZE); + if (IS_ERR(act)) { + NL_SET_ERR_MSG_MOD(extack, "Cannot append drop with cookie action"); + err = PTR_ERR(act); + goto err_append_action; + } + mlxsw_afa_trapwu_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, + MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, + ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL : + MLXSW_TRAP_ID_DISCARD_EGRESS_ACL, + cookie_index); + return 0; + +err_append_action: + mlxsw_afa_cookie_ref_destroy(block, cookie_ref); + return err; +} + +int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block, bool ingress, + const struct flow_action_cookie *fa_cookie, + struct netlink_ext_ack *extack) +{ + return fa_cookie ? + mlxsw_afa_block_append_drop_with_cookie(block, ingress, + fa_cookie, extack) : + mlxsw_afa_block_append_drop_plain(block, ingress); +} EXPORT_SYMBOL(mlxsw_afa_block_append_drop); int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id) { - char *act = mlxsw_afa_block_append_action(block, - MLXSW_AFA_TRAPDISC_CODE, - MLXSW_AFA_TRAPDISC_SIZE); + char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_TRAP_CODE, + MLXSW_AFA_TRAP_SIZE); if (IS_ERR(act)) return PTR_ERR(act); - mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP, - MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD, - trap_id); + mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, + MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, trap_id); return 0; } EXPORT_SYMBOL(mlxsw_afa_block_append_trap); @@ -845,15 +1127,13 @@ EXPORT_SYMBOL(mlxsw_afa_block_append_trap); int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, u16 trap_id) { - char *act = mlxsw_afa_block_append_action(block, - MLXSW_AFA_TRAPDISC_CODE, - MLXSW_AFA_TRAPDISC_SIZE); + char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_TRAP_CODE, + MLXSW_AFA_TRAP_SIZE); if (IS_ERR(act)) return PTR_ERR(act); - mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP, - MLXSW_AFA_TRAPDISC_FORWARD_ACTION_FORWARD, - trap_id); + mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP, + MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, trap_id); return 0; } EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward); @@ -920,13 +1200,13 @@ mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block *block, u8 mirror_agent) { char *act = mlxsw_afa_block_append_action(block, - MLXSW_AFA_TRAPDISC_CODE, - MLXSW_AFA_TRAPDISC_SIZE); + MLXSW_AFA_TRAP_CODE, + MLXSW_AFA_TRAP_SIZE); if (IS_ERR(act)) return PTR_ERR(act); - mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP, - MLXSW_AFA_TRAPDISC_FORWARD_ACTION_FORWARD, 0); - mlxsw_afa_trapdisc_mirror_pack(act, true, mirror_agent); + mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_NOP, + MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, 0); + mlxsw_afa_trap_mirror_pack(act, true, mirror_agent); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h index 0e3a59dda12e..5f4c1e505136 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h @@ -6,6 +6,7 @@ #include <linux/types.h> #include <linux/netdevice.h> +#include <net/flow_offload.h> struct mlxsw_afa; struct mlxsw_afa_block; @@ -42,7 +43,11 @@ int mlxsw_afa_block_activity_get(struct mlxsw_afa_block *block, bool *activity); int mlxsw_afa_block_continue(struct mlxsw_afa_block *block); int mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id); int mlxsw_afa_block_terminate(struct mlxsw_afa_block *block); -int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block); +const struct flow_action_cookie * +mlxsw_afa_cookie_lookup(struct mlxsw_afa *mlxsw_afa, u32 cookie_index); +int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block, bool ingress, + const struct flow_action_cookie *fa_cookie, + struct netlink_ext_ack *extack); int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id); int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, u16 trap_id); diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c index feb4672a5ac0..bd2207f60722 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c @@ -72,7 +72,7 @@ struct mlxsw_afk_key_info { * is index inside "blocks" */ struct mlxsw_afk_element_usage elusage; - const struct mlxsw_afk_block *blocks[0]; + const struct mlxsw_afk_block *blocks[]; }; static bool diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 914c33e46fb4..67ee0da75af2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -575,6 +575,15 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe); + if (rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_INGRESS_ACL || + rx_info.trap_id == MLXSW_TRAP_ID_DISCARD_EGRESS_ACL) { + u32 cookie_index = 0; + + if (mlxsw_pci->max_cqe_ver >= MLXSW_PCI_CQE_V2) + cookie_index = mlxsw_pci_cqe2_user_def_val_orig_pkt_len_get(cqe); + mlxsw_skb_cb(skb)->cookie_index = cookie_index; + } + byte_count = mlxsw_pci_cqe_byte_count_get(cqe); if (mlxsw_pci_cqe_crc_get(cqe_v, cqe)) byte_count -= ETH_FCS_LEN; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 43fa8c85b5d9..32c7cabfb261 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -25,8 +25,6 @@ #define MLXSW_PCI_CIR_CTRL_STATUS_SHIFT 24 #define MLXSW_PCI_CIR_TIMEOUT_MSECS 1000 -#define MLXSW_PCI_SW_RESET 0xF0010 -#define MLXSW_PCI_SW_RESET_RST_BIT BIT(0) #define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 900000 #define MLXSW_PCI_SW_RESET_WAIT_MSECS 200 #define MLXSW_PCI_FW_READY 0xA1844 @@ -210,6 +208,11 @@ MLXSW_ITEM32(pci, cqe0, dqn, 0x0C, 1, 5); MLXSW_ITEM32(pci, cqe12, dqn, 0x0C, 1, 6); mlxsw_pci_cqe_item_helpers(dqn, 0, 12, 12); +/* pci_cqe_user_def_val_orig_pkt_len + * When trap_id is an ACL: User defined value from policy engine action. + */ +MLXSW_ITEM32(pci, cqe2, user_def_val_orig_pkt_len, 0x14, 0, 20); + /* pci_cqe_owner * Ownership bit. */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index dd6685156396..1bc65e597de0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -621,7 +621,7 @@ static inline void mlxsw_reg_sfn_pack(char *payload) { MLXSW_REG_ZERO(sfn, payload); mlxsw_reg_sfn_swid_set(payload, 0); - mlxsw_reg_sfn_end_set(payload, 1); + mlxsw_reg_sfn_end_set(payload, 0); mlxsw_reg_sfn_num_rec_set(payload, MLXSW_REG_SFN_REC_MAX_COUNT); } @@ -5440,15 +5440,29 @@ enum mlxsw_reg_pmtm_module_type { /* Backplane with 4 lanes */ MLXSW_REG_PMTM_MODULE_TYPE_BP_4X, /* QSFP */ - MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP, + MLXSW_REG_PMTM_MODULE_TYPE_QSFP, /* SFP */ - MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP, + MLXSW_REG_PMTM_MODULE_TYPE_SFP, /* Backplane with single lane */ MLXSW_REG_PMTM_MODULE_TYPE_BP_1X = 4, /* Backplane with two lane */ MLXSW_REG_PMTM_MODULE_TYPE_BP_2X = 8, - /* Chip2Chip */ - MLXSW_REG_PMTM_MODULE_TYPE_C2C = 10, + /* Chip2Chip4x */ + MLXSW_REG_PMTM_MODULE_TYPE_C2C4X = 10, + /* Chip2Chip2x */ + MLXSW_REG_PMTM_MODULE_TYPE_C2C2X, + /* Chip2Chip1x */ + MLXSW_REG_PMTM_MODULE_TYPE_C2C1X, + /* QSFP-DD */ + MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD = 14, + /* OSFP */ + MLXSW_REG_PMTM_MODULE_TYPE_OSFP, + /* SFP-DD */ + MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD, + /* DSFP */ + MLXSW_REG_PMTM_MODULE_TYPE_DSFP, + /* Chip2Chip8x */ + MLXSW_REG_PMTM_MODULE_TYPE_C2C8X, }; /* reg_pmtm_module_type @@ -5526,9 +5540,11 @@ enum mlxsw_reg_htgt_trap_group { enum mlxsw_reg_htgt_discard_trap_group { MLXSW_REG_HTGT_DISCARD_TRAP_GROUP_BASE = MLXSW_REG_HTGT_TRAP_GROUP_MAX, + MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS, MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS, MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS, + MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS, }; /* reg_htgt_trap_group diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 7358b5bc7eb6..673fa2fd995c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -347,19 +347,6 @@ static void mlxsw_sp_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); } -static void mlxsw_sp_status_notify(struct mlxfw_dev *mlxfw_dev, - const char *msg, const char *comp_name, - u32 done_bytes, u32 total_bytes) -{ - struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = - container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; - - devlink_flash_update_status_notify(priv_to_devlink(mlxsw_sp->core), - msg, comp_name, - done_bytes, total_bytes); -} - static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = { .component_query = mlxsw_sp_component_query, .fsm_lock = mlxsw_sp_fsm_lock, @@ -370,7 +357,6 @@ static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = { .fsm_query_state = mlxsw_sp_fsm_query_state, .fsm_cancel = mlxsw_sp_fsm_cancel, .fsm_release = mlxsw_sp_fsm_release, - .status_notify = mlxsw_sp_status_notify, }; static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp, @@ -382,16 +368,15 @@ static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp, .ops = &mlxsw_sp_mlxfw_dev_ops, .psid = mlxsw_sp->bus_info->psid, .psid_size = strlen(mlxsw_sp->bus_info->psid), + .devlink = priv_to_devlink(mlxsw_sp->core), }, .mlxsw_sp = mlxsw_sp }; int err; mlxsw_core_fw_flash_start(mlxsw_sp->core); - devlink_flash_update_begin_notify(priv_to_devlink(mlxsw_sp->core)); err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware, extack); - devlink_flash_update_end_notify(priv_to_devlink(mlxsw_sp->core)); mlxsw_core_fw_flash_end(mlxsw_sp->core); return err; @@ -2243,6 +2228,15 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_3635_stats[] = { #define MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN \ ARRAY_SIZE(mlxsw_sp_port_hw_rfc_3635_stats) +static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_ext_stats[] = { + { + .str = "ecn_marked", + .getter = mlxsw_reg_ppcnt_ecn_marked_get, + }, +}; + +#define MLXSW_SP_PORT_HW_EXT_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_ext_stats) + static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_discard_stats[] = { { .str = "discard_ingress_general", @@ -2352,6 +2346,7 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = { MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN + \ MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \ MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN + \ + MLXSW_SP_PORT_HW_EXT_STATS_LEN + \ MLXSW_SP_PORT_HW_DISCARD_STATS_LEN + \ (MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \ IEEE_8021QAZ_MAX_TCS) + \ @@ -2413,6 +2408,12 @@ static void mlxsw_sp_port_get_strings(struct net_device *dev, p += ETH_GSTRING_LEN; } + for (i = 0; i < MLXSW_SP_PORT_HW_EXT_STATS_LEN; i++) { + memcpy(p, mlxsw_sp_port_hw_ext_stats[i].str, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; i++) { memcpy(p, mlxsw_sp_port_hw_discard_stats[i].str, ETH_GSTRING_LEN); @@ -2474,6 +2475,10 @@ mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats, *p_hw_stats = mlxsw_sp_port_hw_rfc_3635_stats; *p_len = MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; break; + case MLXSW_REG_PPCNT_EXT_CNT: + *p_hw_stats = mlxsw_sp_port_hw_ext_stats; + *p_len = MLXSW_SP_PORT_HW_EXT_STATS_LEN; + break; case MLXSW_REG_PPCNT_DISCARD_CNT: *p_hw_stats = mlxsw_sp_port_hw_discard_stats; *p_len = MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; @@ -2543,6 +2548,11 @@ static void mlxsw_sp_port_get_stats(struct net_device *dev, data, data_index); data_index += MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; + /* Extended Counters */ + __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_EXT_CNT, 0, + data, data_index); + data_index += MLXSW_SP_PORT_HW_EXT_STATS_LEN; + /* Discard Counters */ __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_DISCARD_CNT, 0, data, data_index); @@ -2788,27 +2798,6 @@ static u32 mlxsw_sp1_to_ptys_speed(struct mlxsw_sp *mlxsw_sp, u8 width, return ptys_proto; } -static u32 -mlxsw_sp1_to_ptys_upper_speed(struct mlxsw_sp *mlxsw_sp, u32 upper_speed) -{ - u32 ptys_proto = 0; - int i; - - for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) { - if (mlxsw_sp1_port_link_mode[i].speed <= upper_speed) - ptys_proto |= mlxsw_sp1_port_link_mode[i].mask; - } - return ptys_proto; -} - -static int -mlxsw_sp1_port_speed_base(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u32 *base_speed) -{ - *base_speed = MLXSW_SP_PORT_BASE_SPEED_25G; - return 0; -} - static void mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload, u8 local_port, u32 proto_admin, bool autoneg) @@ -2833,8 +2822,6 @@ mlxsw_sp1_port_type_speed_ops = { .from_ptys_speed_duplex = mlxsw_sp1_from_ptys_speed_duplex, .to_ptys_advert_link = mlxsw_sp1_to_ptys_advert_link, .to_ptys_speed = mlxsw_sp1_to_ptys_speed, - .to_ptys_upper_speed = mlxsw_sp1_to_ptys_upper_speed, - .port_speed_base = mlxsw_sp1_port_speed_base, .reg_ptys_eth_pack = mlxsw_sp1_reg_ptys_eth_pack, .reg_ptys_eth_unpack = mlxsw_sp1_reg_ptys_eth_unpack, }; @@ -3235,51 +3222,6 @@ static u32 mlxsw_sp2_to_ptys_speed(struct mlxsw_sp *mlxsw_sp, return ptys_proto; } -static u32 -mlxsw_sp2_to_ptys_upper_speed(struct mlxsw_sp *mlxsw_sp, u32 upper_speed) -{ - u32 ptys_proto = 0; - int i; - - for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) { - if (mlxsw_sp2_port_link_mode[i].speed <= upper_speed) - ptys_proto |= mlxsw_sp2_port_link_mode[i].mask; - } - return ptys_proto; -} - -static int -mlxsw_sp2_port_speed_base(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u32 *base_speed) -{ - char ptys_pl[MLXSW_REG_PTYS_LEN]; - u32 eth_proto_cap; - int err; - - /* In Spectrum-2, the speed of 1x can change from port to port, so query - * it from firmware. - */ - mlxsw_reg_ptys_ext_eth_pack(ptys_pl, local_port, 0, false); - err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); - if (err) - return err; - mlxsw_reg_ptys_ext_eth_unpack(ptys_pl, ð_proto_cap, NULL, NULL); - - if (eth_proto_cap & - MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR) { - *base_speed = MLXSW_SP_PORT_BASE_SPEED_50G; - return 0; - } - - if (eth_proto_cap & - MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR) { - *base_speed = MLXSW_SP_PORT_BASE_SPEED_25G; - return 0; - } - - return -EIO; -} - static void mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload, u8 local_port, u32 proto_admin, @@ -3305,8 +3247,6 @@ mlxsw_sp2_port_type_speed_ops = { .from_ptys_speed_duplex = mlxsw_sp2_from_ptys_speed_duplex, .to_ptys_advert_link = mlxsw_sp2_to_ptys_advert_link, .to_ptys_speed = mlxsw_sp2_to_ptys_speed, - .to_ptys_upper_speed = mlxsw_sp2_to_ptys_upper_speed, - .port_speed_base = mlxsw_sp2_port_speed_base, .reg_ptys_eth_pack = mlxsw_sp2_reg_ptys_eth_pack, .reg_ptys_eth_unpack = mlxsw_sp2_reg_ptys_eth_unpack, }; @@ -3520,24 +3460,24 @@ static int mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u32 eth_proto_cap, eth_proto_admin, eth_proto_oper; const struct mlxsw_sp_port_type_speed_ops *ops; char ptys_pl[MLXSW_REG_PTYS_LEN]; - u32 eth_proto_admin; - u32 upper_speed; - u32 base_speed; int err; ops = mlxsw_sp->port_type_speed_ops; - err = ops->port_speed_base(mlxsw_sp, mlxsw_sp_port->local_port, - &base_speed); + /* Set advertised speeds to supported speeds. */ + ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, + 0, false); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); if (err) return err; - upper_speed = base_speed * mlxsw_sp_port->mapping.width; - eth_proto_admin = ops->to_ptys_upper_speed(mlxsw_sp, upper_speed); + ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, ð_proto_cap, + ð_proto_admin, ð_proto_oper); ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, - eth_proto_admin, mlxsw_sp_port->link.autoneg); + eth_proto_cap, mlxsw_sp_port->link.autoneg); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); } @@ -4935,16 +4875,35 @@ static const struct mlxsw_sp_span_ops mlxsw_sp1_span_ops = { }; #define MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR 38 +#define MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR 50 + +static u32 __mlxsw_sp_span_buffsize_get(int mtu, u32 speed, u32 buffer_factor) +{ + return 3 * mtu + buffer_factor * speed / 1000; +} static u32 mlxsw_sp2_span_buffsize_get(int mtu, u32 speed) { - return 3 * mtu + MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR * speed / 1000; + int factor = MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR; + + return __mlxsw_sp_span_buffsize_get(mtu, speed, factor); } static const struct mlxsw_sp_span_ops mlxsw_sp2_span_ops = { .buffsize_get = mlxsw_sp2_span_buffsize_get, }; +static u32 mlxsw_sp3_span_buffsize_get(int mtu, u32 speed) +{ + int factor = MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR; + + return __mlxsw_sp_span_buffsize_get(mtu, speed, factor); +} + +static const struct mlxsw_sp_span_ops mlxsw_sp3_span_ops = { + .buffsize_get = mlxsw_sp3_span_buffsize_get, +}; + u32 mlxsw_sp_span_buffsize_get(struct mlxsw_sp *mlxsw_sp, int mtu, u32 speed) { u32 buffsize = mlxsw_sp->span_ops->buffsize_get(speed, mtu); @@ -5223,7 +5182,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals; mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; - mlxsw_sp->span_ops = &mlxsw_sp2_span_ops; + mlxsw_sp->span_ops = &mlxsw_sp3_span_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3; return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); @@ -6316,7 +6275,7 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, return -EINVAL; } if (netif_is_macvlan(upper_dev) && - !mlxsw_sp_rif_find_by_dev(mlxsw_sp, lower_dev)) { + !mlxsw_sp_rif_exists(mlxsw_sp, lower_dev)) { NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); return -EOPNOTSUPP; } @@ -6472,7 +6431,7 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, return -EINVAL; } if (netif_is_macvlan(upper_dev) && - !mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan_dev)) { + !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) { NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); return -EOPNOTSUPP; } @@ -6549,7 +6508,7 @@ static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev, if (!info->linking) break; if (netif_is_macvlan(upper_dev) && - !mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan_dev)) { + !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) { NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); return -EOPNOTSUPP; } @@ -6609,7 +6568,7 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev, if (!info->linking) break; if (netif_is_macvlan(upper_dev) && - !mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev)) { + !mlxsw_sp_rif_exists(mlxsw_sp, br_dev)) { NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index a0f1f9dceec5..9708156e7871 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -19,6 +19,7 @@ #include <net/pkt_cls.h> #include <net/red.h> #include <net/vxlan.h> +#include <net/flow_offload.h> #include "port.h" #include "core.h" @@ -32,9 +33,6 @@ #define MLXSW_SP_MID_MAX 7000 -#define MLXSW_SP_PORT_BASE_SPEED_25G 25000 /* Mb/s */ -#define MLXSW_SP_PORT_BASE_SPEED_50G 50000 /* Mb/s */ - #define MLXSW_SP_KVD_LINEAR_SIZE 98304 /* entries */ #define MLXSW_SP_KVD_GRANULARITY 128 @@ -168,12 +166,8 @@ struct mlxsw_sp { struct notifier_block netdevice_nb; struct mlxsw_sp_ptp_clock *clock; struct mlxsw_sp_ptp_state *ptp_state; - struct mlxsw_sp_counter_pool *counter_pool; - struct { - struct mlxsw_sp_span_entry *entries; - int entries_count; - } span; + struct mlxsw_sp_span *span; const struct mlxsw_fw_rev *req_rev; const char *fw_filename; const struct mlxsw_sp_kvdl_ops *kvdl_ops; @@ -313,9 +307,6 @@ struct mlxsw_sp_port_type_speed_ops { u32 (*to_ptys_advert_link)(struct mlxsw_sp *mlxsw_sp, u8 width, const struct ethtool_link_ksettings *cmd); u32 (*to_ptys_speed)(struct mlxsw_sp *mlxsw_sp, u8 width, u32 speed); - u32 (*to_ptys_upper_speed)(struct mlxsw_sp *mlxsw_sp, u32 upper_speed); - int (*port_speed_base)(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u32 *base_speed); void (*reg_ptys_eth_pack)(struct mlxsw_sp *mlxsw_sp, char *payload, u8 local_port, u32 proto_admin, bool autoneg); void (*reg_ptys_eth_unpack)(struct mlxsw_sp *mlxsw_sp, char *payload, @@ -468,10 +459,6 @@ int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp, struct netlink_ext_ack *extack); void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp, const struct net_device *vxlan_dev); -struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, - const struct net_device *br_dev, - u16 vid, - struct netlink_ext_ack *extack); extern struct notifier_block mlxsw_sp_switchdev_notifier; /* spectrum.c */ @@ -556,7 +543,7 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, struct netdev_notifier_changeupper_info *info); bool mlxsw_sp_netdev_is_ipip_ol(const struct mlxsw_sp *mlxsw_sp, const struct net_device *dev); -bool mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp *mlxsw_sp, +bool mlxsw_sp_netdev_is_ipip_ul(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev); int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp, struct net_device *l3_dev, @@ -571,10 +558,10 @@ void mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, struct net_device *dev); -struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, - const struct net_device *dev); +bool mlxsw_sp_rif_exists(struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev); +u16 mlxsw_sp_rif_vid(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev); u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp); -struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif); int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, enum mlxsw_sp_l3proto ul_proto, const union mlxsw_sp_l3addr *ul_sip, @@ -653,6 +640,7 @@ struct mlxsw_sp_acl_rule_info { struct mlxsw_afk_element_values values; struct mlxsw_afa_block *act_block; u8 action_created:1, + ingress_bind_blocker:1, egress_bind_blocker:1; unsigned int counter_index; }; @@ -672,16 +660,20 @@ struct mlxsw_sp_acl_block { struct mlxsw_sp *mlxsw_sp; unsigned int rule_count; unsigned int disable_count; + unsigned int ingress_blocker_rule_count; unsigned int egress_blocker_rule_count; + unsigned int ingress_binding_count; + unsigned int egress_binding_count; struct net *net; }; struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl); struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block); -unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block); +unsigned int +mlxsw_sp_acl_block_rule_count(const struct mlxsw_sp_acl_block *block); void mlxsw_sp_acl_block_disable_inc(struct mlxsw_sp_acl_block *block); void mlxsw_sp_acl_block_disable_dec(struct mlxsw_sp_acl_block *block); -bool mlxsw_sp_acl_block_disabled(struct mlxsw_sp_acl_block *block); +bool mlxsw_sp_acl_block_disabled(const struct mlxsw_sp_acl_block *block); struct mlxsw_sp_acl_block *mlxsw_sp_acl_block_create(struct mlxsw_sp *mlxsw_sp, struct net *net); void mlxsw_sp_acl_block_destroy(struct mlxsw_sp_acl_block *block); @@ -694,7 +686,9 @@ int mlxsw_sp_acl_block_unbind(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_block *block, struct mlxsw_sp_port *mlxsw_sp_port, bool ingress); -bool mlxsw_sp_acl_block_is_egress_bound(struct mlxsw_sp_acl_block *block); +bool mlxsw_sp_acl_block_is_egress_bound(const struct mlxsw_sp_acl_block *block); +bool mlxsw_sp_acl_block_is_ingress_bound(const struct mlxsw_sp_acl_block *block); +bool mlxsw_sp_acl_block_is_mixed_bound(const struct mlxsw_sp_acl_block *block); struct mlxsw_sp_acl_ruleset * mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_block *block, u32 chain_index, @@ -726,7 +720,10 @@ int mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei, u16 group_id); int mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei); -int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei); +int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei, + bool ingress, + const struct flow_action_cookie *fa_cookie, + struct netlink_ext_ack *extack); int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, @@ -777,6 +774,12 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp); +static inline const struct flow_action_cookie * +mlxsw_sp_acl_act_cookie_lookup(struct mlxsw_sp *mlxsw_sp, u32 cookie_index) +{ + return mlxsw_afa_cookie_lookup(mlxsw_sp->afa, cookie_index); +} + int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp); u32 mlxsw_sp_acl_region_rehash_intrvl_get(struct mlxsw_sp *mlxsw_sp); @@ -974,9 +977,6 @@ void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, enum mlxsw_sp_l3proto proto, union mlxsw_sp_l3addr *addr); -u32 mlxsw_sp_nve_decap_tunnel_index_get(const struct mlxsw_sp *mlxsw_sp); -bool mlxsw_sp_nve_ipv4_route_is_decap(const struct mlxsw_sp *mlxsw_sp, - u32 tb_id, __be32 addr); int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, struct mlxsw_sp_nve_params *params, struct netlink_ext_ack *extack); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum1_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum1_kvdl.c index 09ee0a807747..a9fff8adc75e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum1_kvdl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum1_kvdl.c @@ -60,7 +60,7 @@ static const struct mlxsw_sp1_kvdl_part_info mlxsw_sp1_kvdl_parts_info[] = { struct mlxsw_sp1_kvdl_part { struct mlxsw_sp1_kvdl_part_info info; - unsigned long usage[0]; /* Entries */ + unsigned long usage[]; /* Entries */ }; struct mlxsw_sp1_kvdl { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c index 8d14770766b4..3a73d654017f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c @@ -45,7 +45,7 @@ struct mlxsw_sp2_kvdl_part { unsigned int usage_bit_count; unsigned int indexes_per_usage_bit; unsigned int last_allocated_bit; - unsigned long usage[0]; /* Usage bits */ + unsigned long usage[]; /* Usage bits */ }; struct mlxsw_sp2_kvdl { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 3d3cca596116..36b264798f04 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -58,7 +58,7 @@ struct mlxsw_sp_acl_ruleset { struct mlxsw_sp_acl_ruleset_ht_key ht_key; struct rhashtable rule_ht; unsigned int ref_count; - unsigned long priv[0]; + unsigned long priv[]; /* priv has to be always the last item */ }; @@ -71,7 +71,7 @@ struct mlxsw_sp_acl_rule { u64 last_used; u64 last_packets; u64 last_bytes; - unsigned long priv[0]; + unsigned long priv[]; /* priv has to be always the last item */ }; @@ -99,7 +99,8 @@ struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block) return block->mlxsw_sp; } -unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block) +unsigned int +mlxsw_sp_acl_block_rule_count(const struct mlxsw_sp_acl_block *block) { return block ? block->rule_count : 0; } @@ -116,20 +117,24 @@ void mlxsw_sp_acl_block_disable_dec(struct mlxsw_sp_acl_block *block) block->disable_count--; } -bool mlxsw_sp_acl_block_disabled(struct mlxsw_sp_acl_block *block) +bool mlxsw_sp_acl_block_disabled(const struct mlxsw_sp_acl_block *block) { return block->disable_count; } -bool mlxsw_sp_acl_block_is_egress_bound(struct mlxsw_sp_acl_block *block) +bool mlxsw_sp_acl_block_is_egress_bound(const struct mlxsw_sp_acl_block *block) { - struct mlxsw_sp_acl_block_binding *binding; + return block->egress_binding_count; +} - list_for_each_entry(binding, &block->binding_list, list) { - if (!binding->ingress) - return true; - } - return false; +bool mlxsw_sp_acl_block_is_ingress_bound(const struct mlxsw_sp_acl_block *block) +{ + return block->ingress_binding_count; +} + +bool mlxsw_sp_acl_block_is_mixed_bound(const struct mlxsw_sp_acl_block *block) +{ + return block->ingress_binding_count && block->egress_binding_count; } static bool @@ -163,7 +168,8 @@ mlxsw_sp_acl_ruleset_unbind(struct mlxsw_sp *mlxsw_sp, binding->mlxsw_sp_port, binding->ingress); } -static bool mlxsw_sp_acl_ruleset_block_bound(struct mlxsw_sp_acl_block *block) +static bool +mlxsw_sp_acl_ruleset_block_bound(const struct mlxsw_sp_acl_block *block) { return block->ruleset_zero; } @@ -250,6 +256,11 @@ int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp, if (WARN_ON(mlxsw_sp_acl_block_lookup(block, mlxsw_sp_port, ingress))) return -EEXIST; + if (ingress && block->ingress_blocker_rule_count) { + NL_SET_ERR_MSG_MOD(extack, "Block cannot be bound to ingress because it contains unsupported rules"); + return -EOPNOTSUPP; + } + if (!ingress && block->egress_blocker_rule_count) { NL_SET_ERR_MSG_MOD(extack, "Block cannot be bound to egress because it contains unsupported rules"); return -EOPNOTSUPP; @@ -267,6 +278,10 @@ int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp, goto err_ruleset_bind; } + if (ingress) + block->ingress_binding_count++; + else + block->egress_binding_count++; list_add(&binding->list, &block->binding_list); return 0; @@ -288,6 +303,11 @@ int mlxsw_sp_acl_block_unbind(struct mlxsw_sp *mlxsw_sp, list_del(&binding->list); + if (ingress) + block->ingress_binding_count--; + else + block->egress_binding_count--; + if (mlxsw_sp_acl_ruleset_block_bound(block)) mlxsw_sp_acl_ruleset_unbind(mlxsw_sp, block, binding); @@ -515,9 +535,13 @@ int mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei) return mlxsw_afa_block_terminate(rulei->act_block); } -int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei) +int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei, + bool ingress, + const struct flow_action_cookie *fa_cookie, + struct netlink_ext_ack *extack) { - return mlxsw_afa_block_append_drop(rulei->act_block); + return mlxsw_afa_block_append_drop(rulei->act_block, ingress, + fa_cookie, extack); } int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei) @@ -707,6 +731,7 @@ int mlxsw_sp_acl_rule_add(struct mlxsw_sp *mlxsw_sp, list_add_tail(&rule->list, &mlxsw_sp->acl->rules); mutex_unlock(&mlxsw_sp->acl->rules_lock); block->rule_count++; + block->ingress_blocker_rule_count += rule->rulei->ingress_bind_blocker; block->egress_blocker_rule_count += rule->rulei->egress_bind_blocker; return 0; @@ -726,6 +751,7 @@ void mlxsw_sp_acl_rule_del(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_block *block = ruleset->ht_key.block; block->egress_blocker_rule_count -= rule->rulei->egress_bind_blocker; + block->ingress_blocker_rule_count -= rule->rulei->ingress_bind_blocker; ruleset->ht_key.block->rule_count--; mutex_lock(&mlxsw_sp->acl->rules_lock); list_del(&rule->list); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c index 3a2de13fcb68..dbd3bebf11ec 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c @@ -13,7 +13,7 @@ struct mlxsw_sp_acl_bf { struct mutex lock; /* Protects Bloom Filter updates. */ unsigned int bank_size; - refcount_t refcnt[0]; + refcount_t refcnt[]; }; /* Bloom filter uses a crc-16 hash over chunks of data which contain 4 key diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index e993159e8e4c..430da69003d8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -224,7 +224,7 @@ struct mlxsw_sp_acl_tcam_vchunk; struct mlxsw_sp_acl_tcam_chunk { struct mlxsw_sp_acl_tcam_vchunk *vchunk; struct mlxsw_sp_acl_tcam_region *region; - unsigned long priv[0]; + unsigned long priv[]; /* priv has to be always the last item */ }; @@ -243,7 +243,7 @@ struct mlxsw_sp_acl_tcam_vchunk { struct mlxsw_sp_acl_tcam_entry { struct mlxsw_sp_acl_tcam_ventry *ventry; struct mlxsw_sp_acl_tcam_chunk *chunk; - unsigned long priv[0]; + unsigned long priv[]; /* priv has to be always the last item */ }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h index 5965913565a5..96437992b102 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h @@ -20,7 +20,7 @@ struct mlxsw_sp_acl_tcam { struct mutex lock; /* guards vregion list */ struct list_head vregion_list; u32 vregion_rehash_intrvl; /* ms */ - unsigned long priv[0]; + unsigned long priv[]; /* priv has to be always the last item */ }; @@ -86,7 +86,7 @@ struct mlxsw_sp_acl_tcam_region { char tcam_region_info[MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN]; struct mlxsw_afk_key_info *key_info; struct mlxsw_sp *mlxsw_sp; - unsigned long priv[0]; + unsigned long priv[]; /* priv has to be always the last item */ }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c index 83c2e1e5f216..6a02ef9ec00e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c @@ -3,6 +3,7 @@ #include <linux/kernel.h> #include <linux/bitops.h> +#include <linux/spinlock.h> #include "spectrum_cnt.h" @@ -18,6 +19,7 @@ struct mlxsw_sp_counter_sub_pool { struct mlxsw_sp_counter_pool { unsigned int pool_size; unsigned long *usage; /* Usage bitmap */ + spinlock_t counter_pool_lock; /* Protects counter pool allocations */ struct mlxsw_sp_counter_sub_pool *sub_pools; }; @@ -87,6 +89,7 @@ int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp) pool = kzalloc(sizeof(*pool), GFP_KERNEL); if (!pool) return -ENOMEM; + spin_lock_init(&pool->counter_pool_lock); pool->pool_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, COUNTER_POOL_SIZE); map_size = BITS_TO_LONGS(pool->pool_size) * sizeof(unsigned long); @@ -139,25 +142,35 @@ int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_counter_sub_pool *sub_pool; unsigned int entry_index; unsigned int stop_index; - int i; + int i, err; sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id]; stop_index = sub_pool->base_index + sub_pool->size; entry_index = sub_pool->base_index; + spin_lock(&pool->counter_pool_lock); entry_index = find_next_zero_bit(pool->usage, stop_index, entry_index); - if (entry_index == stop_index) - return -ENOBUFS; + if (entry_index == stop_index) { + err = -ENOBUFS; + goto err_alloc; + } /* The sub-pools can contain non-integer number of entries * so we must check for overflow */ - if (entry_index + sub_pool->entry_size > stop_index) - return -ENOBUFS; + if (entry_index + sub_pool->entry_size > stop_index) { + err = -ENOBUFS; + goto err_alloc; + } for (i = 0; i < sub_pool->entry_size; i++) __set_bit(entry_index + i, pool->usage); + spin_unlock(&pool->counter_pool_lock); *p_counter_index = entry_index; return 0; + +err_alloc: + spin_unlock(&pool->counter_pool_lock); + return err; } void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp, @@ -171,6 +184,8 @@ void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp, if (WARN_ON(counter_index >= pool->pool_size)) return; sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id]; + spin_lock(&pool->counter_pool_lock); for (i = 0; i < sub_pool->entry_size; i++) __clear_bit(counter_index + i, pool->usage); + spin_unlock(&pool->counter_pool_lock); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c index 2dc0978428e6..daf029931b5f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c @@ -2,6 +2,7 @@ /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ #include <linux/kernel.h> +#include <linux/mutex.h> #include <net/devlink.h> #include "spectrum.h" @@ -210,7 +211,7 @@ mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled, return err; rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); i = 0; start_again: err = devlink_dpipe_entry_ctx_prepare(dump_ctx); @@ -241,14 +242,14 @@ start_again: devlink_dpipe_entry_ctx_close(dump_ctx); if (i != rif_count) goto start_again; - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); devlink_dpipe_entry_clear(&entry); return 0; err_entry_append: err_entry_get: err_ctx_prepare: - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); devlink_dpipe_entry_clear(&entry); return err; } @@ -258,7 +259,7 @@ static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable) struct mlxsw_sp *mlxsw_sp = priv; int i; - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); @@ -271,7 +272,7 @@ static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable) mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); } - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return 0; } @@ -546,7 +547,7 @@ mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp, int i, j; int err; - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); i = 0; rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); start_again: @@ -602,12 +603,12 @@ out: if (i != rif_count) goto start_again; - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return 0; err_ctx_prepare: err_entry_append: - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return err; } @@ -662,7 +663,7 @@ mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp, { int i; - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); struct mlxsw_sp_neigh_entry *neigh_entry; @@ -684,7 +685,7 @@ mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp, enable); } } - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); } static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable) @@ -701,7 +702,7 @@ mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type) u64 size = 0; int i; - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); struct mlxsw_sp_neigh_entry *neigh_entry; @@ -721,7 +722,7 @@ mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type) size++; } } - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return size; } @@ -1093,7 +1094,7 @@ mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp, int j; int err; - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); start_again: err = devlink_dpipe_entry_ctx_prepare(dump_ctx); @@ -1130,13 +1131,13 @@ skip: devlink_dpipe_entry_ctx_close(dump_ctx); if (nh_count != nh_count_max) goto start_again; - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return 0; err_ctx_prepare: err_entry_append: - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return err; } @@ -1206,9 +1207,9 @@ mlxsw_sp_dpipe_table_adj_size_get(void *priv) struct mlxsw_sp *mlxsw_sp = priv; u64 size; - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return size; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 8df3cb21baa6..65486a90b526 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -8,6 +8,7 @@ #include <linux/netdevice.h> #include <linux/rhashtable.h> #include <linux/rtnetlink.h> +#include <linux/refcount.h> #include "spectrum.h" #include "reg.h" @@ -24,7 +25,7 @@ struct mlxsw_sp_fid_core { struct mlxsw_sp_fid { struct list_head list; struct mlxsw_sp_rif *rif; - unsigned int ref_count; + refcount_t ref_count; u16 fid_index; struct mlxsw_sp_fid_family *fid_family; struct rhash_head ht_node; @@ -149,7 +150,7 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index, mlxsw_sp_fid_ht_params); if (fid) - fid->ref_count++; + refcount_inc(&fid->ref_count); return fid; } @@ -183,7 +184,7 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp, fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni, mlxsw_sp_fid_vni_ht_params); if (fid) - fid->ref_count++; + refcount_inc(&fid->ref_count); return fid; } @@ -1030,7 +1031,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, list_for_each_entry(fid, &fid_family->fids_list, list) { if (!fid->fid_family->ops->compare(fid, arg)) continue; - fid->ref_count++; + refcount_inc(&fid->ref_count); return fid; } @@ -1075,7 +1076,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, goto err_rhashtable_insert; list_add(&fid->list, &fid_family->fids_list); - fid->ref_count++; + refcount_set(&fid->ref_count, 1); return fid; err_rhashtable_insert: @@ -1093,7 +1094,7 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) struct mlxsw_sp_fid_family *fid_family = fid->fid_family; struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; - if (--fid->ref_count != 0) + if (!refcount_dec_and_test(&fid->ref_count)) return; list_del(&fid->list); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index b607919c8ad0..0011a71114e3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -41,12 +41,30 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, return err; } break; - case FLOW_ACTION_DROP: - err = mlxsw_sp_acl_rulei_act_drop(rulei); + case FLOW_ACTION_DROP: { + bool ingress; + + if (mlxsw_sp_acl_block_is_mixed_bound(block)) { + NL_SET_ERR_MSG_MOD(extack, "Drop action is not supported when block is bound to ingress and egress"); + return -EOPNOTSUPP; + } + ingress = mlxsw_sp_acl_block_is_ingress_bound(block); + err = mlxsw_sp_acl_rulei_act_drop(rulei, ingress, + act->cookie, extack); if (err) { NL_SET_ERR_MSG_MOD(extack, "Cannot append drop action"); return err; } + + /* Forbid block with this rulei to be bound + * to ingress/egress in future. Ingress rule is + * a blocker for egress and vice versa. + */ + if (ingress) + rulei->egress_bind_blocker = 1; + else + rulei->ingress_bind_blocker = 1; + } break; case FLOW_ACTION_TRAP: err = mlxsw_sp_acl_rulei_act_trap(rulei); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c index 1e4cdee7bcd7..20d72f1c0cee 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c @@ -2,13 +2,15 @@ /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ #include <linux/kernel.h> +#include <linux/mutex.h> #include <linux/slab.h> #include "spectrum.h" struct mlxsw_sp_kvdl { const struct mlxsw_sp_kvdl_ops *kvdl_ops; - unsigned long priv[0]; + struct mutex kvdl_lock; /* Protects kvdl allocations */ + unsigned long priv[]; /* priv has to be always the last item */ }; @@ -22,6 +24,7 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp) GFP_KERNEL); if (!kvdl) return -ENOMEM; + mutex_init(&kvdl->kvdl_lock); kvdl->kvdl_ops = kvdl_ops; mlxsw_sp->kvdl = kvdl; @@ -31,6 +34,7 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp) return 0; err_init: + mutex_destroy(&kvdl->kvdl_lock); kfree(kvdl); return err; } @@ -40,6 +44,7 @@ void mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp) struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl; kvdl->kvdl_ops->fini(mlxsw_sp, kvdl->priv); + mutex_destroy(&kvdl->kvdl_lock); kfree(kvdl); } @@ -48,9 +53,14 @@ int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, u32 *p_entry_index) { struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl; + int err; + + mutex_lock(&kvdl->kvdl_lock); + err = kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type, + entry_count, p_entry_index); + mutex_unlock(&kvdl->kvdl_lock); - return kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type, - entry_count, p_entry_index); + return err; } void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, @@ -59,8 +69,10 @@ void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl; + mutex_lock(&kvdl->kvdl_lock); kvdl->kvdl_ops->free(mlxsw_sp, kvdl->priv, type, entry_count, entry_index); + mutex_unlock(&kvdl->kvdl_lock); } int mlxsw_sp_kvdl_alloc_count_query(struct mlxsw_sp *mlxsw_sp, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c index 54275624718b..085d9676e34b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ +#include <linux/mutex.h> #include <linux/rhashtable.h> #include <net/ipv6.h> @@ -12,6 +13,7 @@ struct mlxsw_sp_mr { void *catchall_route_priv; struct delayed_work stats_update_dw; struct list_head table_list; + struct mutex table_list_lock; /* Protects table_list */ #define MLXSW_SP_MR_ROUTES_COUNTER_UPDATE_INTERVAL 5000 /* ms */ unsigned long priv[0]; /* priv has to be always the last item */ @@ -66,9 +68,10 @@ struct mlxsw_sp_mr_table { u32 vr_id; struct mlxsw_sp_mr_vif vifs[MAXVIFS]; struct list_head route_list; + struct mutex route_list_lock; /* Protects route_list */ struct rhashtable route_ht; const struct mlxsw_sp_mr_table_ops *ops; - char catchall_route_priv[0]; + char catchall_route_priv[]; /* catchall_route_priv has to be always the last item */ }; @@ -370,11 +373,13 @@ static void mlxsw_sp_mr_mfc_offload_update(struct mlxsw_sp_mr_route *mr_route) static void __mlxsw_sp_mr_route_del(struct mlxsw_sp_mr_table *mr_table, struct mlxsw_sp_mr_route *mr_route) { + WARN_ON_ONCE(!mutex_is_locked(&mr_table->route_list_lock)); + mlxsw_sp_mr_mfc_offload_set(mr_route, false); - mlxsw_sp_mr_route_erase(mr_table, mr_route); rhashtable_remove_fast(&mr_table->route_ht, &mr_route->ht_node, mlxsw_sp_mr_route_ht_params); list_del(&mr_route->node); + mlxsw_sp_mr_route_erase(mr_table, mr_route); mlxsw_sp_mr_route_destroy(mr_table, mr_route); } @@ -415,19 +420,21 @@ int mlxsw_sp_mr_route_add(struct mlxsw_sp_mr_table *mr_table, goto err_duplicate_route; } + /* Write the route to the hardware */ + err = mlxsw_sp_mr_route_write(mr_table, mr_route, replace); + if (err) + goto err_mr_route_write; + /* Put it in the table data-structures */ + mutex_lock(&mr_table->route_list_lock); list_add_tail(&mr_route->node, &mr_table->route_list); + mutex_unlock(&mr_table->route_list_lock); err = rhashtable_insert_fast(&mr_table->route_ht, &mr_route->ht_node, mlxsw_sp_mr_route_ht_params); if (err) goto err_rhashtable_insert; - /* Write the route to the hardware */ - err = mlxsw_sp_mr_route_write(mr_table, mr_route, replace); - if (err) - goto err_mr_route_write; - /* Destroy the original route */ if (replace) { rhashtable_remove_fast(&mr_table->route_ht, @@ -440,11 +447,12 @@ int mlxsw_sp_mr_route_add(struct mlxsw_sp_mr_table *mr_table, mlxsw_sp_mr_mfc_offload_update(mr_route); return 0; -err_mr_route_write: - rhashtable_remove_fast(&mr_table->route_ht, &mr_route->ht_node, - mlxsw_sp_mr_route_ht_params); err_rhashtable_insert: + mutex_lock(&mr_table->route_list_lock); list_del(&mr_route->node); + mutex_unlock(&mr_table->route_list_lock); + mlxsw_sp_mr_route_erase(mr_table, mr_route); +err_mr_route_write: err_no_orig_route: err_duplicate_route: mlxsw_sp_mr_route_destroy(mr_table, mr_route); @@ -460,8 +468,11 @@ void mlxsw_sp_mr_route_del(struct mlxsw_sp_mr_table *mr_table, mr_table->ops->key_create(mr_table, &key, mfc); mr_route = rhashtable_lookup_fast(&mr_table->route_ht, &key, mlxsw_sp_mr_route_ht_params); - if (mr_route) + if (mr_route) { + mutex_lock(&mr_table->route_list_lock); __mlxsw_sp_mr_route_del(mr_table, mr_route); + mutex_unlock(&mr_table->route_list_lock); + } } /* Should be called after the VIF struct is updated */ @@ -910,6 +921,7 @@ struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp, mr_table->proto = proto; mr_table->ops = &mlxsw_sp_mr_table_ops_arr[proto]; INIT_LIST_HEAD(&mr_table->route_list); + mutex_init(&mr_table->route_list_lock); err = rhashtable_init(&mr_table->route_ht, &mlxsw_sp_mr_route_ht_params); @@ -927,12 +939,15 @@ struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp, &catchall_route_params); if (err) goto err_ops_route_create; + mutex_lock(&mr->table_list_lock); list_add_tail(&mr_table->node, &mr->table_list); + mutex_unlock(&mr->table_list_lock); return mr_table; err_ops_route_create: rhashtable_destroy(&mr_table->route_ht); err_route_rhashtable_init: + mutex_destroy(&mr_table->route_list_lock); kfree(mr_table); return ERR_PTR(err); } @@ -943,10 +958,13 @@ void mlxsw_sp_mr_table_destroy(struct mlxsw_sp_mr_table *mr_table) struct mlxsw_sp_mr *mr = mlxsw_sp->mr; WARN_ON(!mlxsw_sp_mr_table_empty(mr_table)); + mutex_lock(&mr->table_list_lock); list_del(&mr_table->node); + mutex_unlock(&mr->table_list_lock); mr->mr_ops->route_destroy(mlxsw_sp, mr->priv, &mr_table->catchall_route_priv); rhashtable_destroy(&mr_table->route_ht); + mutex_destroy(&mr_table->route_list_lock); kfree(mr_table); } @@ -955,8 +973,10 @@ void mlxsw_sp_mr_table_flush(struct mlxsw_sp_mr_table *mr_table) struct mlxsw_sp_mr_route *mr_route, *tmp; int i; + mutex_lock(&mr_table->route_list_lock); list_for_each_entry_safe(mr_route, tmp, &mr_table->route_list, node) __mlxsw_sp_mr_route_del(mr_table, mr_route); + mutex_unlock(&mr_table->route_list_lock); for (i = 0; i < MAXVIFS; i++) { mr_table->vifs[i].dev = NULL; @@ -1000,12 +1020,15 @@ static void mlxsw_sp_mr_stats_update(struct work_struct *work) struct mlxsw_sp_mr_route *mr_route; unsigned long interval; - rtnl_lock(); - list_for_each_entry(mr_table, &mr->table_list, node) + mutex_lock(&mr->table_list_lock); + list_for_each_entry(mr_table, &mr->table_list, node) { + mutex_lock(&mr_table->route_list_lock); list_for_each_entry(mr_route, &mr_table->route_list, node) mlxsw_sp_mr_route_stats_update(mr_table->mlxsw_sp, mr_route); - rtnl_unlock(); + mutex_unlock(&mr_table->route_list_lock); + } + mutex_unlock(&mr->table_list_lock); interval = msecs_to_jiffies(MLXSW_SP_MR_ROUTES_COUNTER_UPDATE_INTERVAL); mlxsw_core_schedule_dw(&mr->stats_update_dw, interval); @@ -1024,6 +1047,7 @@ int mlxsw_sp_mr_init(struct mlxsw_sp *mlxsw_sp, mr->mr_ops = mr_ops; mlxsw_sp->mr = mr; INIT_LIST_HEAD(&mr->table_list); + mutex_init(&mr->table_list_lock); err = mr_ops->init(mlxsw_sp, mr->priv); if (err) @@ -1035,6 +1059,7 @@ int mlxsw_sp_mr_init(struct mlxsw_sp *mlxsw_sp, mlxsw_core_schedule_dw(&mr->stats_update_dw, interval); return 0; err: + mutex_destroy(&mr->table_list_lock); kfree(mr); return err; } @@ -1045,5 +1070,6 @@ void mlxsw_sp_mr_fini(struct mlxsw_sp *mlxsw_sp) cancel_delayed_work_sync(&mr->stats_update_dw); mr->mr_ops->fini(mlxsw_sp, mr->priv); + mutex_destroy(&mr->table_list_lock); kfree(mr); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index 2153bcc4b585..54d3e7dcd303 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -67,7 +67,7 @@ struct mlxsw_sp_nve_mc_record { struct mlxsw_sp_nve_mc_list *mc_list; const struct mlxsw_sp_nve_mc_record_ops *ops; u32 kvdl_index; - struct mlxsw_sp_nve_mc_entry entries[0]; + struct mlxsw_sp_nve_mc_entry entries[]; }; struct mlxsw_sp_nve_mc_list { @@ -713,27 +713,6 @@ static void mlxsw_sp_nve_flood_ip_flush(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list); } -u32 mlxsw_sp_nve_decap_tunnel_index_get(const struct mlxsw_sp *mlxsw_sp) -{ - WARN_ON(mlxsw_sp->nve->num_nve_tunnels == 0); - - return mlxsw_sp->nve->tunnel_index; -} - -bool mlxsw_sp_nve_ipv4_route_is_decap(const struct mlxsw_sp *mlxsw_sp, - u32 tb_id, __be32 addr) -{ - struct mlxsw_sp_nve *nve = mlxsw_sp->nve; - struct mlxsw_sp_nve_config *config = &nve->config; - - if (nve->num_nve_tunnels && - config->ul_proto == MLXSW_SP_L3_PROTO_IPV4 && - config->ul_sip.addr4 == addr && config->ul_tb_id == tb_id) - return true; - - return false; -} - static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nve_config *config) { @@ -744,6 +723,8 @@ static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp, if (nve->num_nve_tunnels++ != 0) return 0; + nve->config = *config; + err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, &nve->tunnel_index); if (err) @@ -760,6 +741,7 @@ err_ops_init: mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, nve->tunnel_index); err_kvdl_alloc: + memset(&nve->config, 0, sizeof(nve->config)); nve->num_nve_tunnels--; return err; } @@ -840,8 +822,6 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, goto err_fid_vni_set; } - nve->config = config; - err = ops->fdb_replay(params->dev, params->vni, extack); if (err) goto err_fdb_replay; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c index 02526c53d4f5..13a054c0ce0f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c @@ -347,7 +347,6 @@ mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_qdisc->prio_bitmap, &stats_base->tx_packets, &stats_base->tx_bytes); - red_base->prob_mark = xstats->ecn; red_base->prob_drop = xstats->wred_drop[tclass_num]; red_base->pdrop = mlxsw_sp_xstats_tail_drop(xstats, tclass_num); @@ -453,22 +452,19 @@ mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port, u8 tclass_num = mlxsw_sp_qdisc->tclass_num; struct mlxsw_sp_port_xstats *xstats; struct red_stats *res = xstats_ptr; - int early_drops, marks, pdrops; + int early_drops, pdrops; xstats = &mlxsw_sp_port->periodic_hw_stats.xstats; early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop; - marks = xstats->ecn - xstats_base->prob_mark; pdrops = mlxsw_sp_xstats_tail_drop(xstats, tclass_num) - xstats_base->pdrop; res->pdrop += pdrops; res->prob_drop += early_drops; - res->prob_mark += marks; xstats_base->pdrop += pdrops; xstats_base->prob_drop += early_drops; - xstats_base->prob_mark += marks; return 0; } @@ -486,8 +482,7 @@ mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port, stats_base = &mlxsw_sp_qdisc->stats_base; mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, stats_ptr); - overlimits = xstats->wred_drop[tclass_num] + xstats->ecn - - stats_base->overlimits; + overlimits = xstats->wred_drop[tclass_num] - stats_base->overlimits; stats_ptr->qstats->overlimits += overlimits; stats_base->overlimits += overlimits; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 4a77b511ead2..b527387ccf80 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -17,6 +17,7 @@ #include <linux/refcount.h> #include <linux/jhash.h> #include <linux/net_namespace.h> +#include <linux/mutex.h> #include <net/netevent.h> #include <net/neighbour.h> #include <net/arp.h> @@ -48,39 +49,6 @@ struct mlxsw_sp_vr; struct mlxsw_sp_lpm_tree; struct mlxsw_sp_rif_ops; -struct mlxsw_sp_router { - struct mlxsw_sp *mlxsw_sp; - struct mlxsw_sp_rif **rifs; - struct mlxsw_sp_vr *vrs; - struct rhashtable neigh_ht; - struct rhashtable nexthop_group_ht; - struct rhashtable nexthop_ht; - struct list_head nexthop_list; - struct { - /* One tree for each protocol: IPv4 and IPv6 */ - struct mlxsw_sp_lpm_tree *proto_trees[2]; - struct mlxsw_sp_lpm_tree *trees; - unsigned int tree_count; - } lpm; - struct { - struct delayed_work dw; - unsigned long interval; /* ms */ - } neighs_update; - struct delayed_work nexthop_probe_dw; -#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ - struct list_head nexthop_neighs_list; - struct list_head ipip_list; - bool aborted; - struct notifier_block fib_nb; - struct notifier_block netevent_nb; - struct notifier_block inetaddr_nb; - struct notifier_block inet6addr_nb; - const struct mlxsw_sp_rif_ops **rif_ops_arr; - const struct mlxsw_sp_ipip_ops **ipip_ops_arr; - u32 adj_discard_index; - bool adj_discard_index_valid; -}; - struct mlxsw_sp_rif { struct list_head nexthop_list; struct list_head neigh_list; @@ -145,6 +113,9 @@ struct mlxsw_sp_rif_ops { void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac); }; +static struct mlxsw_sp_rif * +mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev); static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree); static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp, @@ -760,13 +731,18 @@ int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id, u16 *vr_id) { struct mlxsw_sp_vr *vr; + int err = 0; + mutex_lock(&mlxsw_sp->router->lock); vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id); - if (!vr) - return -ESRCH; + if (!vr) { + err = -ESRCH; + goto out; + } *vr_id = vr->id; - - return 0; +out: + mutex_unlock(&mlxsw_sp->router->lock); + return err; } static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr, @@ -988,17 +964,23 @@ __mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev) struct ip_tunnel *tun = netdev_priv(ol_dev); struct net *net = dev_net(ol_dev); - return __dev_get_by_index(net, tun->parms.link); + return dev_get_by_index_rcu(net, tun->parms.link); } u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev) { - struct net_device *d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); + struct net_device *d; + u32 tb_id; + rcu_read_lock(); + d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); if (d) - return l3mdev_fib_table(d) ? : RT_TABLE_MAIN; + tb_id = l3mdev_fib_table(d) ? : RT_TABLE_MAIN; else - return RT_TABLE_MAIN; + tb_id = RT_TABLE_MAIN; + rcu_read_unlock(); + + return tb_id; } static struct mlxsw_sp_rif * @@ -1355,8 +1337,12 @@ mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp *mlxsw_sp, ipip_list_node); list_for_each_entry_continue(ipip_entry, &mlxsw_sp->router->ipip_list, ipip_list_node) { - struct net_device *ipip_ul_dev = - __mlxsw_sp_ipip_netdev_ul_dev_get(ipip_entry->ol_dev); + struct net_device *ol_dev = ipip_entry->ol_dev; + struct net_device *ipip_ul_dev; + + rcu_read_lock(); + ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); + rcu_read_unlock(); if (ipip_ul_dev == ul_dev) return ipip_entry; @@ -1365,10 +1351,16 @@ mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp *mlxsw_sp, return NULL; } -bool mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp *mlxsw_sp, +bool mlxsw_sp_netdev_is_ipip_ul(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev) { - return mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL); + bool is_ipip_ul; + + mutex_lock(&mlxsw_sp->router->lock); + is_ipip_ul = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL); + mutex_unlock(&mlxsw_sp->router->lock); + + return is_ipip_ul; } static bool mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp *mlxsw_sp, @@ -1722,9 +1714,12 @@ static void mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(struct mlxsw_sp *mlxsw_sp, list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list, ipip_list_node) { - struct net_device *ipip_ul_dev = - __mlxsw_sp_ipip_netdev_ul_dev_get(ipip_entry->ol_dev); + struct net_device *ol_dev = ipip_entry->ol_dev; + struct net_device *ipip_ul_dev; + rcu_read_lock(); + ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); + rcu_read_unlock(); if (ipip_ul_dev == ul_dev) mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); } @@ -1737,35 +1732,41 @@ int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp, { struct netdev_notifier_changeupper_info *chup; struct netlink_ext_ack *extack; + int err = 0; + mutex_lock(&mlxsw_sp->router->lock); switch (event) { case NETDEV_REGISTER: - return mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev); + err = mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev); + break; case NETDEV_UNREGISTER: mlxsw_sp_netdevice_ipip_ol_unreg_event(mlxsw_sp, ol_dev); - return 0; + break; case NETDEV_UP: mlxsw_sp_netdevice_ipip_ol_up_event(mlxsw_sp, ol_dev); - return 0; + break; case NETDEV_DOWN: mlxsw_sp_netdevice_ipip_ol_down_event(mlxsw_sp, ol_dev); - return 0; + break; case NETDEV_CHANGEUPPER: chup = container_of(info, typeof(*chup), info); extack = info->extack; if (netif_is_l3_master(chup->upper_dev)) - return mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp, - ol_dev, - extack); - return 0; + err = mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp, + ol_dev, + extack); + break; case NETDEV_CHANGE: extack = info->extack; - return mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp, - ol_dev, extack); + err = mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp, + ol_dev, extack); + break; case NETDEV_CHANGEMTU: - return mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev); + err = mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev); + break; } - return 0; + mutex_unlock(&mlxsw_sp->router->lock); + return err; } static int @@ -1809,8 +1810,9 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, struct netdev_notifier_info *info) { struct mlxsw_sp_ipip_entry *ipip_entry = NULL; - int err; + int err = 0; + mutex_lock(&mlxsw_sp->router->lock); while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, ul_dev, ipip_entry))) { @@ -1823,7 +1825,7 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, if (err) { mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp, ul_dev); - return err; + break; } if (demote_this) { @@ -1840,8 +1842,9 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, ipip_entry = prev; } } + mutex_unlock(&mlxsw_sp->router->lock); - return 0; + return err; } int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, @@ -1850,8 +1853,22 @@ int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, u32 tunnel_index) { enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; + struct mlxsw_sp_router *router = mlxsw_sp->router; struct mlxsw_sp_fib_entry *fib_entry; - int err; + int err = 0; + + mutex_lock(&mlxsw_sp->router->lock); + + if (WARN_ON_ONCE(router->nve_decap_config.valid)) { + err = -EINVAL; + goto out; + } + + router->nve_decap_config.ul_tb_id = ul_tb_id; + router->nve_decap_config.tunnel_index = tunnel_index; + router->nve_decap_config.ul_proto = ul_proto; + router->nve_decap_config.ul_sip = *ul_sip; + router->nve_decap_config.valid = true; /* It is valid to create a tunnel with a local IP and only later * assign this IP address to a local interface @@ -1860,7 +1877,7 @@ int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, ul_proto, ul_sip, type); if (!fib_entry) - return 0; + goto out; fib_entry->decap.tunnel_index = tunnel_index; fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; @@ -1869,11 +1886,13 @@ int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, if (err) goto err_fib_entry_update; - return 0; + goto out; err_fib_entry_update: fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); +out: + mutex_unlock(&mlxsw_sp->router->lock); return err; } @@ -1882,16 +1901,40 @@ void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, const union mlxsw_sp_l3addr *ul_sip) { enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; + struct mlxsw_sp_router *router = mlxsw_sp->router; struct mlxsw_sp_fib_entry *fib_entry; + mutex_lock(&mlxsw_sp->router->lock); + + if (WARN_ON_ONCE(!router->nve_decap_config.valid)) + goto out; + + router->nve_decap_config.valid = false; + fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id, ul_proto, ul_sip, type); if (!fib_entry) - return; + goto out; fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); +out: + mutex_unlock(&mlxsw_sp->router->lock); +} + +static bool mlxsw_sp_router_nve_is_decap(struct mlxsw_sp *mlxsw_sp, + u32 ul_tb_id, + enum mlxsw_sp_l3proto ul_proto, + const union mlxsw_sp_l3addr *ul_sip) +{ + struct mlxsw_sp_router *router = mlxsw_sp->router; + + return router->nve_decap_config.valid && + router->nve_decap_config.ul_tb_id == ul_tb_id && + router->nve_decap_config.ul_proto == ul_proto && + !memcmp(&router->nve_decap_config.ul_sip, ul_sip, + sizeof(*ul_sip)); } struct mlxsw_sp_neigh_key { @@ -2264,10 +2307,8 @@ __mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp, int i, num_rec; int err; - /* Make sure the neighbour's netdev isn't removed in the - * process. - */ - rtnl_lock(); + /* Ensure the RIF we read from the device does not change mid-dump. */ + mutex_lock(&mlxsw_sp->router->lock); do { mlxsw_reg_rauhtd_pack(rauhtd_pl, type); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd), @@ -2281,7 +2322,7 @@ __mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl, i); } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl)); - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); return err; } @@ -2312,15 +2353,14 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_neigh_entry *neigh_entry; - /* Take RTNL mutex here to prevent lists from changes */ - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list, nexthop_neighs_list_node) /* If this neigh have nexthops, make the kernel think this neigh * is active regardless of the traffic. */ neigh_event_send(neigh_entry->key.n, NULL); - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); } static void @@ -2360,15 +2400,13 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work) * the nexthop wouldn't get offloaded until the neighbor is resolved * but it wouldn't get resolved ever in case traffic is flowing in HW * using different nexthop. - * - * Take RTNL mutex here to prevent lists from changes. */ - rtnl_lock(); + mutex_lock(&router->lock); list_for_each_entry(neigh_entry, &router->nexthop_neighs_list, nexthop_neighs_list_node) if (!neigh_entry->connected) neigh_event_send(neigh_entry->key.n, NULL); - rtnl_unlock(); + mutex_unlock(&router->lock); mlxsw_core_schedule_dw(&router->nexthop_probe_dw, MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL); @@ -2506,7 +2544,7 @@ static void mlxsw_sp_router_neigh_event_work(struct work_struct *work) dead = n->dead; read_unlock_bh(&n->lock); - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); mlxsw_sp_span_respin(mlxsw_sp); entry_connected = nud_state & NUD_VALID && !dead; @@ -2528,7 +2566,7 @@ static void mlxsw_sp_router_neigh_event_work(struct work_struct *work) mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry); out: - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); neigh_release(n); kfree(net_work); } @@ -3711,9 +3749,15 @@ static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp *mlxsw_sp, static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev) { - struct net_device *ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); + struct net_device *ul_dev; + bool is_up; + + rcu_read_lock(); + ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev); + is_up = ul_dev ? (ul_dev->flags & IFF_UP) : true; + rcu_read_unlock(); - return ul_dev ? (ul_dev->flags & IFF_UP) : true; + return is_up; } static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp, @@ -3840,10 +3884,14 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp, if (!dev) return 0; - in_dev = __in_dev_get_rtnl(dev); + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); if (in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) && - fib_nh->fib_nh_flags & RTNH_F_LINKDOWN) + fib_nh->fib_nh_flags & RTNH_F_LINKDOWN) { + rcu_read_unlock(); return 0; + } + rcu_read_unlock(); err = mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh); if (err) @@ -4473,6 +4521,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp, { struct net_device *dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev; union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) }; + struct mlxsw_sp_router *router = mlxsw_sp->router; u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id); struct mlxsw_sp_ipip_entry *ipip_entry; struct fib_info *fi = fen_info->fi; @@ -4487,12 +4536,13 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp, fib_entry, ipip_entry); } - if (mlxsw_sp_nve_ipv4_route_is_decap(mlxsw_sp, tb_id, - dip.addr4)) { - u32 t_index; + if (mlxsw_sp_router_nve_is_decap(mlxsw_sp, tb_id, + MLXSW_SP_L3_PROTO_IPV4, + &dip)) { + u32 tunnel_index; - t_index = mlxsw_sp_nve_decap_tunnel_index_get(mlxsw_sp); - fib_entry->decap.tunnel_index = t_index; + tunnel_index = router->nve_decap_config.tunnel_index; + fib_entry->decap.tunnel_index = tunnel_index; fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; return 0; } @@ -5923,8 +5973,7 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; int err; - /* Protect internal structures from changes */ - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); mlxsw_sp_span_respin(mlxsw_sp); switch (fib_work->event) { @@ -5946,7 +5995,7 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) fib_info_put(fib_work->fnh_info.fib_nh->nh_parent); break; } - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); kfree(fib_work); } @@ -5957,7 +6006,7 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; int err; - rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); mlxsw_sp_span_respin(mlxsw_sp); switch (fib_work->event) { @@ -5984,7 +6033,7 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); break; } - rtnl_unlock(); + mutex_unlock(&mlxsw_sp->router->lock); kfree(fib_work); } @@ -5997,6 +6046,7 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work) int err; rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); switch (fib_work->event) { case FIB_EVENT_ENTRY_REPLACE: /* fall through */ case FIB_EVENT_ENTRY_ADD: @@ -6025,6 +6075,7 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work) dev_put(fib_work->ven_info.dev); break; } + mutex_unlock(&mlxsw_sp->router->lock); rtnl_unlock(); kfree(fib_work); } @@ -6233,7 +6284,7 @@ err_fib_event: return NOTIFY_BAD; } -struct mlxsw_sp_rif * +static struct mlxsw_sp_rif * mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, const struct net_device *dev) { @@ -6247,6 +6298,41 @@ mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, return NULL; } +bool mlxsw_sp_rif_exists(struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev) +{ + struct mlxsw_sp_rif *rif; + + mutex_lock(&mlxsw_sp->router->lock); + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); + mutex_unlock(&mlxsw_sp->router->lock); + + return rif; +} + +u16 mlxsw_sp_rif_vid(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev) +{ + struct mlxsw_sp_rif *rif; + u16 vid = 0; + + mutex_lock(&mlxsw_sp->router->lock); + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); + if (!rif) + goto out; + + /* We only return the VID for VLAN RIFs. Otherwise we return an + * invalid value (0). + */ + if (rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN) + goto out; + + vid = mlxsw_sp_fid_8021q_vid(rif->fid); + +out: + mutex_unlock(&mlxsw_sp->router->lock); + return vid; +} + static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif) { char ritr_pl[MLXSW_REG_RITR_LEN]; @@ -6281,7 +6367,8 @@ mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev, case NETDEV_UP: return rif == NULL; case NETDEV_DOWN: - idev = __in_dev_get_rtnl(dev); + rcu_read_lock(); + idev = __in_dev_get_rcu(dev); if (idev && idev->ifa_list) addr_list_empty = false; @@ -6289,6 +6376,7 @@ mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev, if (addr_list_empty && inet6_dev && !list_empty(&inet6_dev->addr_list)) addr_list_empty = false; + rcu_read_unlock(); /* macvlans do not have a RIF, but rather piggy back on the * RIF of their lower device. @@ -6411,11 +6499,6 @@ const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) return rif->dev; } -struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif) -{ - return rif->fid; -} - static struct mlxsw_sp_rif * mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_rif_params *params, @@ -6528,10 +6611,13 @@ void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_rif *rif; + mutex_lock(&mlxsw_sp->router->lock); rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!rif) - return; + goto out; mlxsw_sp_rif_destroy(rif); +out: + mutex_unlock(&mlxsw_sp->router->lock); } static void @@ -6631,8 +6717,8 @@ err_fid_port_vid_map: return err; } -void -mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +static void +__mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; @@ -6650,6 +6736,16 @@ mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) mlxsw_sp_rif_subport_put(rif); } +void +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port_vlan->mlxsw_sp_port->mlxsw_sp; + + mutex_lock(&mlxsw_sp->router->lock); + __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); + mutex_unlock(&mlxsw_sp->router->lock); +} + static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, struct net_device *port_dev, unsigned long event, u16 vid, @@ -6667,7 +6763,7 @@ static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, l3_dev, extack); case NETDEV_DOWN: - mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); + __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); break; } @@ -6848,8 +6944,8 @@ err_rif_vrrp_add: return err; } -void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, - const struct net_device *macvlan_dev) +static void __mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, + const struct net_device *macvlan_dev) { struct macvlan_dev *vlan = netdev_priv(macvlan_dev); struct mlxsw_sp_rif *rif; @@ -6866,6 +6962,14 @@ void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fid_index(rif->fid), false); } +void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, + const struct net_device *macvlan_dev) +{ + mutex_lock(&mlxsw_sp->router->lock); + __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev); + mutex_unlock(&mlxsw_sp->router->lock); +} + static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp, struct net_device *macvlan_dev, unsigned long event, @@ -6875,7 +6979,7 @@ static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp, case NETDEV_UP: return mlxsw_sp_rif_macvlan_add(mlxsw_sp, macvlan_dev, extack); case NETDEV_DOWN: - mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev); + __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev); break; } @@ -6945,15 +7049,17 @@ static int mlxsw_sp_inetaddr_event(struct notifier_block *nb, /* NETDEV_UP event is handled by mlxsw_sp_inetaddr_valid_event */ if (event == NETDEV_UP) - goto out; + return NOTIFY_DONE; router = container_of(nb, struct mlxsw_sp_router, inetaddr_nb); + mutex_lock(&router->lock); rif = mlxsw_sp_rif_find_by_dev(router->mlxsw_sp, dev); if (!mlxsw_sp_rif_should_config(rif, dev, event)) goto out; err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, NULL); out: + mutex_unlock(&router->lock); return notifier_from_errno(err); } @@ -6968,8 +7074,9 @@ int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused, mlxsw_sp = mlxsw_sp_lower_get(dev); if (!mlxsw_sp) - goto out; + return NOTIFY_DONE; + mutex_lock(&mlxsw_sp->router->lock); rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!mlxsw_sp_rif_should_config(rif, dev, event)) goto out; @@ -6981,6 +7088,7 @@ int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused, err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, ivi->extack); out: + mutex_unlock(&mlxsw_sp->router->lock); return notifier_from_errno(err); } @@ -7001,6 +7109,7 @@ static void mlxsw_sp_inet6addr_event_work(struct work_struct *work) struct mlxsw_sp_rif *rif; rtnl_lock(); + mutex_lock(&mlxsw_sp->router->lock); rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!mlxsw_sp_rif_should_config(rif, dev, event)) @@ -7008,6 +7117,7 @@ static void mlxsw_sp_inet6addr_event_work(struct work_struct *work) __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, NULL); out: + mutex_unlock(&mlxsw_sp->router->lock); rtnl_unlock(); dev_put(dev); kfree(inet6addr_work); @@ -7052,8 +7162,9 @@ int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused, mlxsw_sp = mlxsw_sp_lower_get(dev); if (!mlxsw_sp) - goto out; + return NOTIFY_DONE; + mutex_lock(&mlxsw_sp->router->lock); rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!mlxsw_sp_rif_should_config(rif, dev, event)) goto out; @@ -7065,6 +7176,7 @@ int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused, err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, i6vi->extack); out: + mutex_unlock(&mlxsw_sp->router->lock); return notifier_from_errno(err); } @@ -7151,24 +7263,30 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev, { struct mlxsw_sp *mlxsw_sp; struct mlxsw_sp_rif *rif; + int err = 0; mlxsw_sp = mlxsw_sp_lower_get(dev); if (!mlxsw_sp) return 0; + mutex_lock(&mlxsw_sp->router->lock); rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!rif) - return 0; + goto out; switch (event) { case NETDEV_CHANGEMTU: /* fall through */ case NETDEV_CHANGEADDR: - return mlxsw_sp_router_port_change_event(mlxsw_sp, rif); + err = mlxsw_sp_router_port_change_event(mlxsw_sp, rif); + break; case NETDEV_PRE_CHANGEADDR: - return mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr); + err = mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr); + break; } - return 0; +out: + mutex_unlock(&mlxsw_sp->router->lock); + return err; } static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp, @@ -7211,9 +7329,10 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, if (!mlxsw_sp || netif_is_macvlan(l3_dev)) return 0; + mutex_lock(&mlxsw_sp->router->lock); switch (event) { case NETDEV_PRECHANGEUPPER: - return 0; + break; case NETDEV_CHANGEUPPER: if (info->linking) { struct netlink_ext_ack *extack; @@ -7225,6 +7344,7 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, } break; } + mutex_unlock(&mlxsw_sp->router->lock); return err; } @@ -7428,7 +7548,7 @@ mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif, } } - return mlxsw_sp_bridge_fid_get(rif->mlxsw_sp, br_dev, vid, extack); + return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid); } static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) @@ -7519,7 +7639,7 @@ static struct mlxsw_sp_fid * mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { - return mlxsw_sp_bridge_fid_get(rif->mlxsw_sp, rif->dev, 0, extack); + return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex); } static void mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) @@ -7733,28 +7853,32 @@ int mlxsw_sp_router_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, u16 *ul_rif_index) { struct mlxsw_sp_rif *ul_rif; + int err = 0; - ASSERT_RTNL(); - + mutex_lock(&mlxsw_sp->router->lock); ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL); - if (IS_ERR(ul_rif)) - return PTR_ERR(ul_rif); + if (IS_ERR(ul_rif)) { + err = PTR_ERR(ul_rif); + goto out; + } *ul_rif_index = ul_rif->rif_index; - - return 0; +out: + mutex_unlock(&mlxsw_sp->router->lock); + return err; } void mlxsw_sp_router_ul_rif_put(struct mlxsw_sp *mlxsw_sp, u16 ul_rif_index) { struct mlxsw_sp_rif *ul_rif; - ASSERT_RTNL(); - + mutex_lock(&mlxsw_sp->router->lock); ul_rif = mlxsw_sp->router->rifs[ul_rif_index]; if (WARN_ON(!ul_rif)) - return; + goto out; mlxsw_sp_ul_rif_put(ul_rif); +out: + mutex_unlock(&mlxsw_sp->router->lock); } static int @@ -8004,6 +8128,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL); if (!router) return -ENOMEM; + mutex_init(&router->lock); mlxsw_sp->router = router; router->mlxsw_sp = mlxsw_sp; @@ -8107,6 +8232,7 @@ err_router_init: err_register_inet6addr_notifier: unregister_inetaddr_notifier(&router->inetaddr_nb); err_register_inetaddr_notifier: + mutex_destroy(&mlxsw_sp->router->lock); kfree(mlxsw_sp->router); return err; } @@ -8127,5 +8253,6 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) __mlxsw_sp_router_fini(mlxsw_sp); unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb); unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb); + mutex_destroy(&mlxsw_sp->router->lock); kfree(mlxsw_sp->router); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index c9b94f435cdd..8418dc3ae967 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -7,6 +7,49 @@ #include "spectrum.h" #include "reg.h" +struct mlxsw_sp_router_nve_decap { + u32 ul_tb_id; + u32 tunnel_index; + enum mlxsw_sp_l3proto ul_proto; + union mlxsw_sp_l3addr ul_sip; + u8 valid:1; +}; + +struct mlxsw_sp_router { + struct mlxsw_sp *mlxsw_sp; + struct mlxsw_sp_rif **rifs; + struct mlxsw_sp_vr *vrs; + struct rhashtable neigh_ht; + struct rhashtable nexthop_group_ht; + struct rhashtable nexthop_ht; + struct list_head nexthop_list; + struct { + /* One tree for each protocol: IPv4 and IPv6 */ + struct mlxsw_sp_lpm_tree *proto_trees[2]; + struct mlxsw_sp_lpm_tree *trees; + unsigned int tree_count; + } lpm; + struct { + struct delayed_work dw; + unsigned long interval; /* ms */ + } neighs_update; + struct delayed_work nexthop_probe_dw; +#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ + struct list_head nexthop_neighs_list; + struct list_head ipip_list; + bool aborted; + struct notifier_block fib_nb; + struct notifier_block netevent_nb; + struct notifier_block inetaddr_nb; + struct notifier_block inet6addr_nb; + const struct mlxsw_sp_rif_ops **rif_ops_arr; + const struct mlxsw_sp_ipip_ops **ipip_ops_arr; + u32 adj_discard_index; + bool adj_discard_index_valid; + struct mlxsw_sp_router_nve_decap nve_decap_config; + struct mutex lock; /* Protects shared router resources */ +}; + struct mlxsw_sp_rif_ipip_lb; struct mlxsw_sp_rif_ipip_lb_config { enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 0cdd7954a085..9fb2e9d93929 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@ -3,6 +3,8 @@ #include <linux/if_bridge.h> #include <linux/list.h> +#include <linux/rtnetlink.h> +#include <linux/workqueue.h> #include <net/arp.h> #include <net/gre.h> #include <net/lag.h> @@ -14,38 +16,43 @@ #include "spectrum_span.h" #include "spectrum_switchdev.h" +struct mlxsw_sp_span { + struct work_struct work; + struct mlxsw_sp *mlxsw_sp; + atomic_t active_entries_count; + int entries_count; + struct mlxsw_sp_span_entry entries[0]; +}; + +static void mlxsw_sp_span_respin_work(struct work_struct *work); + static u64 mlxsw_sp_span_occ_get(void *priv) { const struct mlxsw_sp *mlxsw_sp = priv; - u64 occ = 0; - int i; - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - if (mlxsw_sp->span.entries[i].ref_count) - occ++; - } - - return occ; + return atomic_read(&mlxsw_sp->span->active_entries_count); } int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) { struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); - int i; + struct mlxsw_sp_span *span; + int i, entries_count; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN)) return -EIO; - mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, - MAX_SPAN); - mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count, - sizeof(struct mlxsw_sp_span_entry), - GFP_KERNEL); - if (!mlxsw_sp->span.entries) + entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_SPAN); + span = kzalloc(struct_size(span, entries, entries_count), GFP_KERNEL); + if (!span) return -ENOMEM; + span->entries_count = entries_count; + atomic_set(&span->active_entries_count, 0); + span->mlxsw_sp = mlxsw_sp; + mlxsw_sp->span = span; - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; INIT_LIST_HEAD(&curr->bound_ports_list); curr->id = i; @@ -53,6 +60,7 @@ int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) devlink_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_SPAN, mlxsw_sp_span_occ_get, mlxsw_sp); + INIT_WORK(&span->work, mlxsw_sp_span_respin_work); return 0; } @@ -62,14 +70,15 @@ void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; + cancel_work_sync(&mlxsw_sp->span->work); devlink_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_SPAN); - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; WARN_ON_ONCE(!list_empty(&curr->bound_ports_list)); } - kfree(mlxsw_sp->span.entries); + kfree(mlxsw_sp->span); } static int @@ -645,15 +654,16 @@ mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp, int i; /* find a free entry to use */ - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - if (!mlxsw_sp->span.entries[i].ref_count) { - span_entry = &mlxsw_sp->span.entries[i]; + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { + if (!mlxsw_sp->span->entries[i].ref_count) { + span_entry = &mlxsw_sp->span->entries[i]; break; } } if (!span_entry) return NULL; + atomic_inc(&mlxsw_sp->span->active_entries_count); span_entry->ops = ops; span_entry->ref_count = 1; span_entry->to_dev = to_dev; @@ -662,9 +672,11 @@ mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp, return span_entry; } -static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry *span_entry) +static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_span_entry *span_entry) { mlxsw_sp_span_entry_deconfigure(span_entry); + atomic_dec(&mlxsw_sp->span->active_entries_count); } struct mlxsw_sp_span_entry * @@ -673,8 +685,8 @@ mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp, { int i; - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; if (curr->ref_count && curr->to_dev == to_dev) return curr; @@ -694,8 +706,8 @@ mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp *mlxsw_sp, int span_id) { int i; - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; if (curr->ref_count && curr->id == span_id) return curr; @@ -726,7 +738,7 @@ static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, { WARN_ON(!span_entry->ref_count); if (--span_entry->ref_count == 0) - mlxsw_sp_span_entry_destroy(span_entry); + mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry); return 0; } @@ -736,8 +748,8 @@ static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port) struct mlxsw_sp_span_inspected_port *p; int i; - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; list_for_each_entry(p, &curr->bound_ports_list, list) if (p->local_port == port->local_port && @@ -842,9 +854,9 @@ mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port, * so if a binding is requested, check for conflicts. */ if (bind) - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { struct mlxsw_sp_span_entry *curr = - &mlxsw_sp->span.entries[i]; + &mlxsw_sp->span->entries[i]; if (mlxsw_sp_span_entry_bound_port_find(curr, type, port, bind)) @@ -988,14 +1000,18 @@ void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, int span_id, mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind); } -void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp) +static void mlxsw_sp_span_respin_work(struct work_struct *work) { - int i; - int err; + struct mlxsw_sp_span *span; + struct mlxsw_sp *mlxsw_sp; + int i, err; - ASSERT_RTNL(); - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; + span = container_of(work, struct mlxsw_sp_span, work); + mlxsw_sp = span->mlxsw_sp; + + rtnl_lock(); + for (i = 0; i < mlxsw_sp->span->entries_count; i++) { + struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; struct mlxsw_sp_span_parms sparms = {NULL}; if (!curr->ref_count) @@ -1010,4 +1026,12 @@ void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_span_entry_configure(mlxsw_sp, curr, sparms); } } + rtnl_unlock(); +} + +void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp) +{ + if (atomic_read(&mlxsw_sp->span->active_entries_count) == 0) + return; + mlxsw_core_schedule_work(&mlxsw_sp->span->work); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index a3af171c6358..a26162b08b7d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -153,16 +153,64 @@ static void mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp); } +static int mlxsw_sp_bridge_device_vxlan_init(struct mlxsw_sp_bridge *bridge, + struct net_device *br_dev, + struct netlink_ext_ack *extack) +{ + struct net_device *dev, *stop_dev; + struct list_head *iter; + int err; + + netdev_for_each_lower_dev(br_dev, dev, iter) { + if (netif_is_vxlan(dev) && netif_running(dev)) { + err = mlxsw_sp_bridge_vxlan_join(bridge->mlxsw_sp, + br_dev, dev, 0, + extack); + if (err) { + stop_dev = dev; + goto err_vxlan_join; + } + } + } + + return 0; + +err_vxlan_join: + netdev_for_each_lower_dev(br_dev, dev, iter) { + if (netif_is_vxlan(dev) && netif_running(dev)) { + if (stop_dev == dev) + break; + mlxsw_sp_bridge_vxlan_leave(bridge->mlxsw_sp, dev); + } + } + return err; +} + +static void mlxsw_sp_bridge_device_vxlan_fini(struct mlxsw_sp_bridge *bridge, + struct net_device *br_dev) +{ + struct net_device *dev; + struct list_head *iter; + + netdev_for_each_lower_dev(br_dev, dev, iter) { + if (netif_is_vxlan(dev) && netif_running(dev)) + mlxsw_sp_bridge_vxlan_leave(bridge->mlxsw_sp, dev); + } +} + static struct mlxsw_sp_bridge_device * mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, - struct net_device *br_dev) + struct net_device *br_dev, + struct netlink_ext_ack *extack) { struct device *dev = bridge->mlxsw_sp->bus_info->dev; struct mlxsw_sp_bridge_device *bridge_device; bool vlan_enabled = br_vlan_enabled(br_dev); + int err; if (vlan_enabled && bridge->vlan_enabled_exists) { dev_err(dev, "Only one VLAN-aware bridge is supported\n"); + NL_SET_ERR_MSG_MOD(extack, "Only one VLAN-aware bridge is supported"); return ERR_PTR(-EINVAL); } @@ -184,13 +232,29 @@ mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, INIT_LIST_HEAD(&bridge_device->mids_list); list_add(&bridge_device->list, &bridge->bridges_list); + /* It is possible we already have VXLAN devices enslaved to the bridge. + * In which case, we need to replay their configuration as if they were + * just now enslaved to the bridge. + */ + err = mlxsw_sp_bridge_device_vxlan_init(bridge, br_dev, extack); + if (err) + goto err_vxlan_init; + return bridge_device; + +err_vxlan_init: + list_del(&bridge_device->list); + if (bridge_device->vlan_enabled) + bridge->vlan_enabled_exists = false; + kfree(bridge_device); + return ERR_PTR(err); } static void mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, struct mlxsw_sp_bridge_device *bridge_device) { + mlxsw_sp_bridge_device_vxlan_fini(bridge, bridge_device->dev); mlxsw_sp_bridge_device_rifs_destroy(bridge->mlxsw_sp, bridge_device->dev); list_del(&bridge_device->list); @@ -203,7 +267,8 @@ mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, static struct mlxsw_sp_bridge_device * mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge *bridge, - struct net_device *br_dev) + struct net_device *br_dev, + struct netlink_ext_ack *extack) { struct mlxsw_sp_bridge_device *bridge_device; @@ -211,7 +276,7 @@ mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge *bridge, if (bridge_device) return bridge_device; - return mlxsw_sp_bridge_device_create(bridge, br_dev); + return mlxsw_sp_bridge_device_create(bridge, br_dev, extack); } static void @@ -292,7 +357,8 @@ mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port) static struct mlxsw_sp_bridge_port * mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge, - struct net_device *brport_dev) + struct net_device *brport_dev, + struct netlink_ext_ack *extack) { struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev); struct mlxsw_sp_bridge_device *bridge_device; @@ -305,7 +371,7 @@ mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge, return bridge_port; } - bridge_device = mlxsw_sp_bridge_device_get(bridge, br_dev); + bridge_device = mlxsw_sp_bridge_device_get(bridge, br_dev, extack); if (IS_ERR(bridge_device)) return ERR_CAST(bridge_device); @@ -1000,7 +1066,7 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list); mlxsw_sp_bridge_port_get(mlxsw_sp_port->mlxsw_sp->bridge, - bridge_port->dev); + bridge_port->dev, extack); mlxsw_sp_port_vlan->bridge_port = bridge_port; return 0; @@ -1107,16 +1173,12 @@ mlxsw_sp_br_ban_rif_pvid_change(struct mlxsw_sp *mlxsw_sp, const struct net_device *br_dev, const struct switchdev_obj_port_vlan *vlan) { - struct mlxsw_sp_rif *rif; - struct mlxsw_sp_fid *fid; u16 pvid; u16 vid; - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev); - if (!rif) + pvid = mlxsw_sp_rif_vid(mlxsw_sp, br_dev); + if (!pvid) return 0; - fid = mlxsw_sp_rif_fid(rif); - pvid = mlxsw_sp_fid_8021q_vid(fid); for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { if (vlan->flags & BRIDGE_VLAN_INFO_PVID) { @@ -1712,36 +1774,6 @@ mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port, } } -struct mlxsw_sp_span_respin_work { - struct work_struct work; - struct mlxsw_sp *mlxsw_sp; -}; - -static void mlxsw_sp_span_respin_work(struct work_struct *work) -{ - struct mlxsw_sp_span_respin_work *respin_work = - container_of(work, struct mlxsw_sp_span_respin_work, work); - - rtnl_lock(); - mlxsw_sp_span_respin(respin_work->mlxsw_sp); - rtnl_unlock(); - kfree(respin_work); -} - -static void mlxsw_sp_span_respin_schedule(struct mlxsw_sp *mlxsw_sp) -{ - struct mlxsw_sp_span_respin_work *respin_work; - - respin_work = kzalloc(sizeof(*respin_work), GFP_ATOMIC); - if (!respin_work) - return; - - INIT_WORK(&respin_work->work, mlxsw_sp_span_respin_work); - respin_work->mlxsw_sp = mlxsw_sp; - - mlxsw_core_schedule_work(&respin_work->work); -} - static int mlxsw_sp_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj, struct switchdev_trans *trans, @@ -1763,7 +1795,7 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, * call for later, so that the respin logic sees the * updated bridge state. */ - mlxsw_sp_span_respin_schedule(mlxsw_sp_port->mlxsw_sp); + mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp); } break; case SWITCHDEV_OBJ_ID_PORT_MDB: @@ -1916,7 +1948,7 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev, break; } - mlxsw_sp_span_respin_schedule(mlxsw_sp_port->mlxsw_sp); + mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp); return err; } @@ -1990,12 +2022,11 @@ mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, return err; } - /* If no other port is member in the VLAN, then the FID does not exist. - * NVE will be enabled on the FID once a port joins the VLAN - */ - fid = mlxsw_sp_fid_8021q_lookup(mlxsw_sp, vid); - if (!fid) - return 0; + fid = mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); + if (IS_ERR(fid)) { + NL_SET_ERR_MSG_MOD(extack, "Failed to create 802.1Q FID"); + return PTR_ERR(fid); + } if (mlxsw_sp_fid_vni_is_set(fid)) { NL_SET_ERR_MSG_MOD(extack, "VNI is already set on FID"); @@ -2007,11 +2038,6 @@ mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, if (err) goto err_nve_fid_enable; - /* The tunnel port does not hold a reference on the FID. Only - * local ports and the router port - */ - mlxsw_sp_fid_put(fid); - return 0; err_nve_fid_enable: @@ -2048,38 +2074,8 @@ mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device, u16 vid, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); - struct net_device *vxlan_dev; - struct mlxsw_sp_fid *fid; - int err; - - fid = mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); - if (IS_ERR(fid)) - return fid; - - if (mlxsw_sp_fid_vni_is_set(fid)) - return fid; - - /* Find the VxLAN device that has the specified VLAN configured as - * PVID and egress untagged. There can be at most one such device - */ - vxlan_dev = mlxsw_sp_bridge_8021q_vxlan_dev_find(bridge_device->dev, - vid); - if (!vxlan_dev) - return fid; - - if (!netif_running(vxlan_dev)) - return fid; - - err = mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, vid, - extack); - if (err) - goto err_vxlan_join; - - return fid; -err_vxlan_join: - mlxsw_sp_fid_put(fid); - return ERR_PTR(err); + return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); } static struct mlxsw_sp_fid * @@ -2184,9 +2180,9 @@ mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, struct mlxsw_sp_fid *fid; int err; - fid = mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex); - if (!fid) { - NL_SET_ERR_MSG_MOD(extack, "Did not find a corresponding FID"); + fid = mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); + if (IS_ERR(fid)) { + NL_SET_ERR_MSG_MOD(extack, "Failed to create 802.1D FID"); return -EINVAL; } @@ -2200,11 +2196,6 @@ mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, if (err) goto err_nve_fid_enable; - /* The tunnel port does not hold a reference on the FID. Only - * local ports and the router port - */ - mlxsw_sp_fid_put(fid); - return 0; err_nve_fid_enable: @@ -2218,34 +2209,8 @@ mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device, u16 vid, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); - struct net_device *vxlan_dev; - struct mlxsw_sp_fid *fid; - int err; - fid = mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); - if (IS_ERR(fid)) - return fid; - - if (mlxsw_sp_fid_vni_is_set(fid)) - return fid; - - vxlan_dev = mlxsw_sp_bridge_vxlan_dev_find(bridge_device->dev); - if (!vxlan_dev) - return fid; - - if (!netif_running(vxlan_dev)) - return fid; - - err = mlxsw_sp_bridge_8021d_vxlan_join(bridge_device, vxlan_dev, 0, - extack); - if (err) - goto err_vxlan_join; - - return fid; - -err_vxlan_join: - mlxsw_sp_fid_put(fid); - return ERR_PTR(err); + return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); } static struct mlxsw_sp_fid * @@ -2287,7 +2252,8 @@ int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_bridge_port *bridge_port; int err; - bridge_port = mlxsw_sp_bridge_port_get(mlxsw_sp->bridge, brport_dev); + bridge_port = mlxsw_sp_bridge_port_get(mlxsw_sp->bridge, brport_dev, + extack); if (IS_ERR(bridge_port)) return PTR_ERR(bridge_port); bridge_device = bridge_port->bridge_device; @@ -2351,21 +2317,11 @@ void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp, return; mlxsw_sp_nve_fid_disable(mlxsw_sp, fid); + /* Drop both the reference we just took during lookup and the reference + * the VXLAN device took. + */ + mlxsw_sp_fid_put(fid); mlxsw_sp_fid_put(fid); -} - -struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, - const struct net_device *br_dev, - u16 vid, - struct netlink_ext_ack *extack) -{ - struct mlxsw_sp_bridge_device *bridge_device; - - bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); - if (WARN_ON(!bridge_device)) - return ERR_PTR(-EINVAL); - - return bridge_device->ops->fid_get(bridge_device, vid, extack); } static void @@ -2718,19 +2674,24 @@ static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp, } } -static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp) +static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp, + bool no_delay) { struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; + unsigned int interval = no_delay ? 0 : bridge->fdb_notify.interval; mlxsw_core_schedule_dw(&bridge->fdb_notify.dw, - msecs_to_jiffies(bridge->fdb_notify.interval)); + msecs_to_jiffies(interval)); } +#define MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION 10 + static void mlxsw_sp_fdb_notify_work(struct work_struct *work) { struct mlxsw_sp_bridge *bridge; struct mlxsw_sp *mlxsw_sp; char *sfn_pl; + int queries; u8 num_rec; int i; int err; @@ -2743,20 +2704,26 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work) mlxsw_sp = bridge->mlxsw_sp; rtnl_lock(); - mlxsw_reg_sfn_pack(sfn_pl); - err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); - if (err) { - dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n"); - goto out; + queries = MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION; + while (queries > 0) { + mlxsw_reg_sfn_pack(sfn_pl); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); + if (err) { + dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n"); + goto out; + } + num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl); + for (i = 0; i < num_rec; i++) + mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i); + if (num_rec != MLXSW_REG_SFN_REC_MAX_COUNT) + goto out; + queries--; } - num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl); - for (i = 0; i < num_rec; i++) - mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i); out: rtnl_unlock(); kfree(sfn_pl); - mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); + mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, !queries); } struct mlxsw_sp_switchdev_event_work { @@ -3502,7 +3469,7 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work); bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; - mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); + mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, false); return 0; err_register_switchdev_blocking_notifier: diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c index 60205aa3f6a5..9c300d625e04 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c @@ -25,16 +25,121 @@ enum { #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT +static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, + u8 local_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_pcpu_stats *pcpu_stats; + + if (unlikely(!mlxsw_sp_port)) { + dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", + local_port); + kfree_skb(skb); + return -EINVAL; + } + + skb->dev = mlxsw_sp_port->dev; + + pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); + u64_stats_update_begin(&pcpu_stats->syncp); + pcpu_stats->rx_packets++; + pcpu_stats->rx_bytes += skb->len; + u64_stats_update_end(&pcpu_stats->syncp); + + skb->protocol = eth_type_trans(skb, skb->dev); + + return 0; +} + static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, - void *priv); + void *trap_ctx) +{ + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + int err; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); + if (err) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); + consume_skb(skb); +} + +static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + u32 cookie_index = mlxsw_skb_cb(skb)->cookie_index; + const struct flow_action_cookie *fa_cookie; + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + int err; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); + if (err) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + rcu_read_lock(); + fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie); + rcu_read_unlock(); + consume_skb(skb); +} + static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, - void *trap_ctx); + void *trap_ctx) +{ + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + int err; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); + if (err) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); + skb_pull(skb, ETH_HLEN); + skb->offload_fwd_mark = 1; + netif_receive_skb(skb); +} #define MLXSW_SP_TRAP_DROP(_id, _group_id) \ DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ MLXSW_SP_TRAP_METADATA) +#define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata) \ + DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ + DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ + MLXSW_SP_TRAP_METADATA | (_metadata)) + #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id) \ DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id, \ DEVLINK_MLXSW_TRAP_NAME_##_id, \ @@ -47,14 +152,20 @@ static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, MLXSW_SP_TRAP_METADATA) #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \ - MLXSW_RXL(mlxsw_sp_rx_drop_listener, DISCARD_##_id, SET_FW_DEFAULT, \ - false, SP_##_group_id, DISCARD) + MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id, \ + TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id, \ + SET_FW_DEFAULT, SP_##_group_id) + +#define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id) \ + MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id, \ + TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id, \ + SET_FW_DEFAULT, SP_##_dis_group_id) #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \ MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \ - _action, false, SP_##_group_id, DISCARD) + _action, false, SP_##_group_id, SET_FW_DEFAULT) -static struct devlink_trap mlxsw_sp_traps_arr[] = { +static const struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), @@ -83,9 +194,13 @@ static struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS), MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS), MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS), + MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, + DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), + MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, + DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), }; -static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { +static const struct mlxsw_listener mlxsw_sp_listeners_arr[] = { MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS), @@ -124,13 +239,15 @@ static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS, TRAP_EXCEPTION_TO_CPU), MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS), + MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, DUMMY), + MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, DUMMY), }; /* Mapping between hardware trap and devlink trap. Multiple hardware traps can * be mapped to the same devlink trap. Order is according to * 'mlxsw_sp_listeners_arr'. */ -static u16 mlxsw_sp_listener_devlink_map[] = { +static const u16 mlxsw_sp_listener_devlink_map[] = { DEVLINK_TRAP_GENERIC_ID_SMAC_MC, DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH, DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER, @@ -164,83 +281,53 @@ static u16 mlxsw_sp_listener_devlink_map[] = { DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, DEVLINK_TRAP_GENERIC_ID_OVERLAY_SMAC_MC, + DEVLINK_TRAP_GENERIC_ID_INGRESS_FLOW_ACTION_DROP, + DEVLINK_TRAP_GENERIC_ID_EGRESS_FLOW_ACTION_DROP, }; -static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, - u8 local_port, - struct mlxsw_sp_port *mlxsw_sp_port) -{ - struct mlxsw_sp_port_pcpu_stats *pcpu_stats; - - if (unlikely(!mlxsw_sp_port)) { - dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", - local_port); - kfree_skb(skb); - return -EINVAL; - } - - skb->dev = mlxsw_sp_port->dev; - - pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); - u64_stats_update_begin(&pcpu_stats->syncp); - pcpu_stats->rx_packets++; - pcpu_stats->rx_bytes += skb->len; - u64_stats_update_end(&pcpu_stats->syncp); - - skb->protocol = eth_type_trans(skb, skb->dev); - - return 0; -} +#define MLXSW_SP_DISCARD_POLICER_ID (MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1) +#define MLXSW_SP_THIN_POLICER_ID (MLXSW_SP_DISCARD_POLICER_ID + 1) -static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, - void *trap_ctx) +static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp) { - struct devlink_port *in_devlink_port; - struct mlxsw_sp_port *mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp; - struct devlink *devlink; - - mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; + char qpcr_pl[MLXSW_REG_QPCR_LEN]; + int err; - if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port)) - return; + mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_DISCARD_POLICER_ID, + MLXSW_REG_QPCR_IR_UNITS_M, false, 10 * 1024, 7); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); + if (err) + return err; - devlink = priv_to_devlink(mlxsw_sp->core); - in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, - local_port); - skb_push(skb, ETH_HLEN); - devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port); - consume_skb(skb); + /* The purpose of "thin" policer is to drop as many packets + * as possible. The dummy group is using it. + */ + mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_THIN_POLICER_ID, + MLXSW_REG_QPCR_IR_UNITS_M, false, 1, 4); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); } -static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, - void *trap_ctx) +static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp) { - struct devlink_port *in_devlink_port; - struct mlxsw_sp_port *mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp; - struct devlink *devlink; - - mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; - - if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port)) - return; + char htgt_pl[MLXSW_REG_HTGT_LEN]; - devlink = priv_to_devlink(mlxsw_sp->core); - in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, - local_port); - skb_push(skb, ETH_HLEN); - devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port); - skb_pull(skb, ETH_HLEN); - skb->offload_fwd_mark = 1; - netif_receive_skb(skb); + mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, + MLXSW_SP_THIN_POLICER_ID, 0, 1); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); } int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) { struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + int err; + + err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); + if (err) + return err; + + err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp); + if (err) + return err; if (WARN_ON(ARRAY_SIZE(mlxsw_sp_listener_devlink_map) != ARRAY_SIZE(mlxsw_sp_listeners_arr))) @@ -265,7 +352,7 @@ int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, int i; for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { - struct mlxsw_listener *listener; + const struct mlxsw_listener *listener; int err; if (mlxsw_sp_listener_devlink_map[i] != trap->id) @@ -286,7 +373,7 @@ void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, int i; for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { - struct mlxsw_listener *listener; + const struct mlxsw_listener *listener; if (mlxsw_sp_listener_devlink_map[i] != trap->id) continue; @@ -303,27 +390,24 @@ int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, int i; for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { - enum mlxsw_reg_hpkt_action hw_action; - struct mlxsw_listener *listener; + const struct mlxsw_listener *listener; + bool enabled; int err; if (mlxsw_sp_listener_devlink_map[i] != trap->id) continue; listener = &mlxsw_sp_listeners_arr[i]; - switch (action) { case DEVLINK_TRAP_ACTION_DROP: - hw_action = MLXSW_REG_HPKT_ACTION_SET_FW_DEFAULT; + enabled = false; break; case DEVLINK_TRAP_ACTION_TRAP: - hw_action = MLXSW_REG_HPKT_ACTION_TRAP_EXCEPTION_TO_CPU; + enabled = true; break; default: return -EINVAL; } - - err = mlxsw_core_trap_action_set(mlxsw_core, listener, - hw_action); + err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled); if (err) return err; } @@ -331,41 +415,8 @@ int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, return 0; } -#define MLXSW_SP_DISCARD_POLICER_ID (MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1) - -static int -mlxsw_sp_trap_group_policer_init(struct mlxsw_sp *mlxsw_sp, - const struct devlink_trap_group *group) -{ - enum mlxsw_reg_qpcr_ir_units ir_units; - char qpcr_pl[MLXSW_REG_QPCR_LEN]; - u16 policer_id; - u8 burst_size; - bool is_bytes; - u32 rate; - - switch (group->id) { - case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS: /* fall through */ - case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS: /* fall through */ - case DEVLINK_TRAP_GROUP_GENERIC_ID_TUNNEL_DROPS: - policer_id = MLXSW_SP_DISCARD_POLICER_ID; - ir_units = MLXSW_REG_QPCR_IR_UNITS_M; - is_bytes = false; - rate = 10 * 1024; /* 10Kpps */ - burst_size = 7; - break; - default: - return -EINVAL; - } - - mlxsw_reg_qpcr_pack(qpcr_pl, policer_id, ir_units, is_bytes, rate, - burst_size); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); -} - -static int -__mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp, - const struct devlink_trap_group *group) +int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, + const struct devlink_trap_group *group) { char htgt_pl[MLXSW_REG_HTGT_LEN]; u8 priority, tc, group_id; @@ -390,27 +441,16 @@ __mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp, priority = 0; tc = 1; break; + case DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_DROPS: + group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS; + policer_id = MLXSW_SP_DISCARD_POLICER_ID; + priority = 0; + tc = 1; + break; default: return -EINVAL; } mlxsw_reg_htgt_pack(htgt_pl, group_id, policer_id, priority, tc); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); -} - -int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, - const struct devlink_trap_group *group) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); - int err; - - err = mlxsw_sp_trap_group_policer_init(mlxsw_sp, group); - if (err) - return err; - - err = __mlxsw_sp_trap_group_init(mlxsw_sp, group); - if (err) - return err; - - return 0; + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index 12e1fa998d42..eaa521b7561b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -102,6 +102,8 @@ enum { MLXSW_TRAP_ID_ACL1 = 0x1C1, /* Multicast trap used for routes with trap-and-forward action */ MLXSW_TRAP_ID_ACL2 = 0x1C2, + MLXSW_TRAP_ID_DISCARD_INGRESS_ACL = 0x1C3, + MLXSW_TRAP_ID_DISCARD_EGRESS_ACL = 0x1C4, MLXSW_TRAP_ID_MAX = 0x1FF }; diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index d1444ba36e10..4fe6aedca22f 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -5694,7 +5694,7 @@ static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv, * from the bridge. */ if ((hw->features & STP_SUPPORT) && !promiscuous && - (dev->priv_flags & IFF_BRIDGE_PORT)) { + netif_is_bridge_port(dev)) { struct ksz_switch *sw = hw->ksz_switch; int port = priv->port.first_port; diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c index 51fa82b429a3..bfa0c0d39600 100644 --- a/drivers/net/ethernet/natsemi/jazzsonic.c +++ b/drivers/net/ethernet/natsemi/jazzsonic.c @@ -147,39 +147,12 @@ static int sonic_probe1(struct net_device *dev) dev->dev_addr[i*2+1] = val >> 8; } - err = -ENOMEM; - - /* Initialize the device structure. */ - lp->dma_bitmode = SONIC_BITMODE32; - /* Allocate the entire chunk of memory for the descriptors. - Note that this cannot cross a 64K boundary. */ - lp->descriptors = dma_alloc_coherent(lp->device, - SIZEOF_SONIC_DESC * - SONIC_BUS_SCALE(lp->dma_bitmode), - &lp->descriptors_laddr, - GFP_KERNEL); - if (lp->descriptors == NULL) + err = sonic_alloc_descriptors(dev); + if (err) goto out; - /* Now set up the pointers to point to the appropriate places */ - lp->cda = lp->descriptors; - lp->tda = lp->cda + (SIZEOF_SONIC_CDA - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - - lp->cda_laddr = lp->descriptors_laddr; - lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->netdev_ops = &sonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c index 0937fc2a928e..1b5559aacb38 100644 --- a/drivers/net/ethernet/natsemi/macsonic.c +++ b/drivers/net/ethernet/natsemi/macsonic.c @@ -114,17 +114,6 @@ static inline void bit_reverse_addr(unsigned char addr[6]) addr[i] = bitrev8(addr[i]); } -static irqreturn_t macsonic_interrupt(int irq, void *dev_id) -{ - irqreturn_t result; - unsigned long flags; - - local_irq_save(flags); - result = sonic_interrupt(irq, dev_id); - local_irq_restore(flags); - return result; -} - static int macsonic_open(struct net_device* dev) { int retval; @@ -135,12 +124,12 @@ static int macsonic_open(struct net_device* dev) dev->name, dev->irq); goto err; } - /* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes - * in at priority level 3. However, we sometimes get the level 2 inter- - * rupt as well, which must prevent re-entrance of the sonic handler. + /* Under the A/UX interrupt scheme, the onboard SONIC interrupt gets + * moved from level 2 to level 3. Unfortunately we still get some + * level 2 interrupts so register the handler for both. */ if (dev->irq == IRQ_AUTO_3) { - retval = request_irq(IRQ_NUBUS_9, macsonic_interrupt, 0, + retval = request_irq(IRQ_NUBUS_9, sonic_interrupt, 0, "sonic", dev); if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", @@ -186,33 +175,10 @@ static const struct net_device_ops macsonic_netdev_ops = { static int macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); + int err = sonic_alloc_descriptors(dev); - /* Allocate the entire chunk of memory for the descriptors. - Note that this cannot cross a 64K boundary. */ - lp->descriptors = dma_alloc_coherent(lp->device, - SIZEOF_SONIC_DESC * - SONIC_BUS_SCALE(lp->dma_bitmode), - &lp->descriptors_laddr, - GFP_KERNEL); - if (lp->descriptors == NULL) - return -ENOMEM; - - /* Now set up the pointers to point to the appropriate places */ - lp->cda = lp->descriptors; - lp->tda = lp->cda + (SIZEOF_SONIC_CDA - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - - lp->cda_laddr = lp->descriptors_laddr; - lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); + if (err) + return err; dev->netdev_ops = &macsonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 31be3ba66877..dd3605aa5f23 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -50,6 +50,42 @@ static void sonic_msg_init(struct net_device *dev) netif_dbg(lp, drv, dev, "%s", version); } +static int sonic_alloc_descriptors(struct net_device *dev) +{ + struct sonic_local *lp = netdev_priv(dev); + + /* Allocate a chunk of memory for the descriptors. Note that this + * must not cross a 64K boundary. It is smaller than one page which + * means that page alignment is a sufficient condition. + */ + lp->descriptors = + dma_alloc_coherent(lp->device, + SIZEOF_SONIC_DESC * + SONIC_BUS_SCALE(lp->dma_bitmode), + &lp->descriptors_laddr, GFP_KERNEL); + + if (!lp->descriptors) + return -ENOMEM; + + lp->cda = lp->descriptors; + lp->tda = lp->cda + SIZEOF_SONIC_CDA * + SONIC_BUS_SCALE(lp->dma_bitmode); + lp->rda = lp->tda + SIZEOF_SONIC_TD * SONIC_NUM_TDS * + SONIC_BUS_SCALE(lp->dma_bitmode); + lp->rra = lp->rda + SIZEOF_SONIC_RD * SONIC_NUM_RDS * + SONIC_BUS_SCALE(lp->dma_bitmode); + + lp->cda_laddr = lp->descriptors_laddr; + lp->tda_laddr = lp->cda_laddr + SIZEOF_SONIC_CDA * + SONIC_BUS_SCALE(lp->dma_bitmode); + lp->rda_laddr = lp->tda_laddr + SIZEOF_SONIC_TD * SONIC_NUM_TDS * + SONIC_BUS_SCALE(lp->dma_bitmode); + lp->rra_laddr = lp->rda_laddr + SIZEOF_SONIC_RD * SONIC_NUM_RDS * + SONIC_BUS_SCALE(lp->dma_bitmode); + + return 0; +} + /* * Open/initialize the SONIC controller. * @@ -264,7 +300,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); - entry = lp->next_tx; + entry = (lp->eol_tx + 1) & SONIC_TDS_MASK; sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */ @@ -275,27 +311,26 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) sonic_tda_put(dev, entry, SONIC_TD_LINK, sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL); - wmb(); + sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK, ~SONIC_EOL & + sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK)); + + netif_dbg(lp, tx_queued, dev, "%s: issuing Tx command\n", __func__); + + SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); + lp->tx_len[entry] = length; lp->tx_laddr[entry] = laddr; lp->tx_skb[entry] = skb; - wmb(); - sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK, - sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK) & ~SONIC_EOL); lp->eol_tx = entry; - lp->next_tx = (entry + 1) & SONIC_TDS_MASK; - if (lp->tx_skb[lp->next_tx] != NULL) { + entry = (entry + 1) & SONIC_TDS_MASK; + if (lp->tx_skb[entry]) { /* The ring is full, the ISR has yet to process the next TD. */ netif_dbg(lp, tx_queued, dev, "%s: stopping queue\n", __func__); netif_stop_queue(dev); /* after this packet, wait for ISR to free up some TDAs */ - } else netif_start_queue(dev); - - netif_dbg(lp, tx_queued, dev, "%s: issuing Tx command\n", __func__); - - SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); + } spin_unlock_irqrestore(&lp->lock, flags); @@ -594,11 +629,6 @@ static void sonic_rx(struct net_device *dev) if (rbe) SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); - /* - * If any worth-while packets have been received, netif_rx() - * has done a mark_bh(NET_BH) for us and will work on them - * when we get to the bottom-half routine. - */ } @@ -780,7 +810,7 @@ static int sonic_init(struct net_device *dev) SONIC_WRITE(SONIC_UTDA, lp->tda_laddr >> 16); SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff); - lp->cur_tx = lp->next_tx = 0; + lp->cur_tx = 0; lp->eol_tx = SONIC_NUM_TDS - 1; /* diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h index e0e4cba6f6f6..3cbb62c860c8 100644 --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -321,7 +321,6 @@ struct sonic_local { unsigned int cur_tx; /* first unacked transmit packet */ unsigned int eol_rx; unsigned int eol_tx; /* last unacked transmit packet */ - unsigned int next_tx; /* next free TD */ int msg_enable; struct device *device; /* generic device */ struct net_device_stats stats; @@ -342,6 +341,7 @@ static void sonic_multicast_list(struct net_device *dev); static int sonic_init(struct net_device *dev); static void sonic_tx_timeout(struct net_device *dev, unsigned int txqueue); static void sonic_msg_init(struct net_device *dev); +static int sonic_alloc_descriptors(struct net_device *dev); /* Internal inlines for reading/writing DMA buffers. Note that bus size and endianness matter here, whereas they don't for registers, diff --git a/drivers/net/ethernet/natsemi/xtsonic.c b/drivers/net/ethernet/natsemi/xtsonic.c index e1b886e87a76..dda9ec7d9cee 100644 --- a/drivers/net/ethernet/natsemi/xtsonic.c +++ b/drivers/net/ethernet/natsemi/xtsonic.c @@ -167,47 +167,11 @@ static int __init sonic_probe1(struct net_device *dev) dev->dev_addr[i*2+1] = val >> 8; } - /* Initialize the device structure. */ - lp->dma_bitmode = SONIC_BITMODE32; - /* - * Allocate local private descriptor areas in uncached space. - * The entire structure must be located within the same 64kb segment. - * A simple way to ensure this is to allocate twice the - * size of the structure -- given that the structure is - * much less than 64 kB, at least one of the halves of - * the allocated area will be contained entirely in 64 kB. - * We also allocate extra space for a pointer to allow freeing - * this structure later on (in xtsonic_cleanup_module()). - */ - lp->descriptors = dma_alloc_coherent(lp->device, - SIZEOF_SONIC_DESC * - SONIC_BUS_SCALE(lp->dma_bitmode), - &lp->descriptors_laddr, - GFP_KERNEL); - if (lp->descriptors == NULL) { - err = -ENOMEM; + err = sonic_alloc_descriptors(dev); + if (err) goto out; - } - - lp->cda = lp->descriptors; - lp->tda = lp->cda + (SIZEOF_SONIC_CDA - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - - /* get the virtual dma address */ - - lp->cda_laddr = lp->descriptors_laddr; - lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); - lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->netdev_ops = &xtsonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h index a83a0ad5e27d..4268a7e0f344 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h @@ -104,14 +104,14 @@ struct cmsg_req_map_op { __be32 tid; __be32 count; __be32 flags; - u8 data[0]; + u8 data[]; }; struct cmsg_reply_map_op { struct cmsg_reply_map_simple reply_hdr; __be32 count; __be32 resv; - u8 data[0]; + u8 data[]; }; struct cmsg_bpf_event { @@ -120,6 +120,6 @@ struct cmsg_bpf_event { __be64 map_ptr; __be32 data_size; __be32 pkt_size; - u8 data[0]; + u8 data[]; }; #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 9b50d76bbc09..bf516285510f 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -587,7 +587,7 @@ struct nfp_flower_cmsg_mac_repr { u8 info; u8 nbi_port; u8 phys_port; - } ports[0]; + } ports[]; }; #define NFP_FLOWER_CMSG_MAC_REPR_NBI GENMASK(1, 0) @@ -619,7 +619,7 @@ struct nfp_flower_cmsg_merge_hint { struct { __be32 host_ctx; __be64 host_cookie; - } __packed flow[0]; + } __packed flow[]; }; enum nfp_flower_cmsg_port_type { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 5d5812fd9317..fa6b13a05941 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -42,7 +42,7 @@ struct nfp_shared_buf; */ struct nfp_dumpspec { u32 size; - u8 data[0]; + u8 data[]; }; /** diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c index 769ceef09756..a614df095b08 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c @@ -36,7 +36,7 @@ enum nfp_dumpspec_type { struct nfp_dump_tl { __be32 type; __be32 length; /* chunk length to follow, aligned to 8 bytes */ - char data[0]; + char data[]; }; /* NFP CPP parameters */ @@ -62,7 +62,7 @@ struct nfp_dumpspec_csr { struct nfp_dumpspec_rtsym { struct nfp_dump_tl tl; - char rtsym[0]; + char rtsym[]; }; /* header for register dumpable */ @@ -79,7 +79,7 @@ struct nfp_dump_rtsym { struct nfp_dump_common_cpp cpp; __be32 error; /* error code encountered while reading */ u8 padded_name_length; /* pad so data starts at 8 byte boundary */ - char rtsym[0]; + char rtsym[]; /* after padded_name_length, there is dump_length data */ }; @@ -92,7 +92,7 @@ struct nfp_dump_error { struct nfp_dump_tl tl; __be32 error; char padding[4]; - char spec[0]; + char spec[]; }; /* to track state through debug size calculation TLV traversal */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h index e0f13dfe1f39..48a74accbbd3 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -18,7 +18,7 @@ struct nfp_port; */ struct nfp_reprs { unsigned int num_reprs; - struct net_device __rcu *reprs[0]; + struct net_device __rcu *reprs[]; }; /** diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 1531c1870020..f5360bae6f75 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -183,7 +183,7 @@ struct nfp_eth_table { bool is_split; unsigned int fec_modes_supported; - } ports[0]; + } ports[]; }; struct nfp_eth_table *nfp_eth_read_ports(struct nfp_cpp *cpp); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index e452f4242ba0..020acc300d7e 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -632,10 +632,7 @@ static int ionic_tx_tcp_pseudo_csum(struct sk_buff *skb) ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } else if (skb->protocol == cpu_to_be16(ETH_P_IPV6)) { - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); } return 0; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h index 3dce769d83a1..86153660d245 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h @@ -1316,7 +1316,7 @@ struct netxen_minidump_template_hdr { u32 driver_info_word4; u32 saved_state_array[NX_DUMP_STATE_ARRAY_LEN]; u32 capture_size_array[NX_DUMP_CAP_SIZE_ARRAY_LEN]; - u32 rsvd[0]; + u32 rsvd[]; }; /* Common Entry Header: Common to All Entry Types */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 374a4d4371f9..134611aa2c9a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -418,7 +418,7 @@ struct qlcnic_83xx_dump_template_hdr { u32 saved_state[16]; u32 cap_sizes[8]; u32 ocm_wnd_reg[16]; - u32 rsvd[0]; + u32 rsvd[]; }; struct qlcnic_82xx_dump_template_hdr { @@ -436,7 +436,7 @@ struct qlcnic_82xx_dump_template_hdr { u32 cap_sizes[8]; u32 rsvd[7]; u32 capabilities; - u32 rsvd1[0]; + u32 rsvd1[]; }; #define QLC_PEX_DMA_READ_SIZE (PAGE_SIZE * 16) @@ -740,7 +740,7 @@ struct qlcnic_hostrq_rx_ctx { The following is packed: - N hostrq_rds_rings - N hostrq_sds_rings */ - char data[0]; + char data[]; } __packed; struct qlcnic_cardrsp_rds_ring{ @@ -769,7 +769,7 @@ struct qlcnic_cardrsp_rx_ctx { The following is packed: - N cardrsp_rds_rings - N cardrs_sds_rings */ - char data[0]; + char data[]; } __packed; #define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \ diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c index bebe38d74d66..251d4ac4af02 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c @@ -1288,11 +1288,8 @@ static int emac_tso_csum(struct emac_adapter *adpt, memset(tpd, 0, sizeof(*tpd)); memset(&extra_tpd, 0, sizeof(extra_tpd)); - ipv6_hdr(skb)->payload_len = 0; - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); + TPD_PKT_LEN_SET(&extra_tpd, skb->len); TPD_LSO_SET(&extra_tpd, 1); TPD_LSOV_SET(&extra_tpd, 1); diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index a2168a14794c..f081007a245b 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -212,7 +212,6 @@ enum rtl_registers { /* Unlimited maximum PCI burst. */ #define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT) - RxMissed = 0x4c, Cfg9346 = 0x50, Config0 = 0x51, Config1 = 0x52, @@ -576,6 +575,7 @@ struct rtl8169_tc_offsets { __le64 tx_errors; __le32 tx_multi_collision; __le16 tx_aborted; + __le16 rx_missed; }; enum rtl_flag { @@ -689,6 +689,12 @@ static void rtl_unlock_config_regs(struct rtl8169_private *tp) RTL_W8(tp, Cfg9346, Cfg9346_Unlock); } +static void rtl_pci_commit(struct rtl8169_private *tp) +{ + /* Read an arbitrary register to commit a preceding PCI write */ + RTL_R8(tp, ChipCmd); +} + static bool rtl_is_8125(struct rtl8169_private *tp) { return tp->mac_version >= RTL_GIGA_MAC_VER_60; @@ -1302,10 +1308,6 @@ static void rtl_irq_disable(struct rtl8169_private *tp) tp->irq_enabled = 0; } -#define RTL_EVENT_NAPI_RX (RxOK | RxErr) -#define RTL_EVENT_NAPI_TX (TxOK | TxErr) -#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX) - static void rtl_irq_enable(struct rtl8169_private *tp) { tp->irq_enabled = 1; @@ -1319,18 +1321,13 @@ static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) { rtl_irq_disable(tp); rtl_ack_events(tp, 0xffffffff); - /* PCI commit */ - RTL_R8(tp, ChipCmd); + rtl_pci_commit(tp); } static void rtl_link_chg_patch(struct rtl8169_private *tp) { - struct net_device *dev = tp->dev; struct phy_device *phydev = tp->phydev; - if (!netif_running(dev)) - return; - if (tp->mac_version == RTL_GIGA_MAC_VER_34 || tp->mac_version == RTL_GIGA_MAC_VER_38) { if (phydev->speed == SPEED_1000) { @@ -1536,7 +1533,7 @@ static int rtl8169_set_features(struct net_device *dev, } RTL_W16(tp, CPlusCmd, tp->cp_cmd); - RTL_R16(tp, CPlusCmd); + rtl_pci_commit(tp); rtl_unlock_work(tp); @@ -1622,7 +1619,7 @@ static bool rtl8169_do_counters(struct rtl8169_private *tp, u32 counter_cmd) u32 cmd; RTL_W32(tp, CounterAddrHigh, (u64)paddr >> 32); - RTL_R32(tp, CounterAddrHigh); + rtl_pci_commit(tp); cmd = (u64)paddr & DMA_BIT_MASK(32); RTL_W32(tp, CounterAddrLow, cmd); RTL_W32(tp, CounterAddrLow, cmd | counter_cmd); @@ -1689,6 +1686,7 @@ static bool rtl8169_init_counter_offsets(struct rtl8169_private *tp) tp->tc_offset.tx_errors = counters->tx_errors; tp->tc_offset.tx_multi_collision = counters->tx_multi_collision; tp->tc_offset.tx_aborted = counters->tx_aborted; + tp->tc_offset.rx_missed = counters->rx_missed; tp->tc_offset.inited = true; return ret; @@ -1946,7 +1944,7 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) tp->cp_cmd = (tp->cp_cmd & ~INTT_MASK) | cp01; RTL_W16(tp, CPlusCmd, tp->cp_cmd); - RTL_R16(tp, CPlusCmd); + rtl_pci_commit(tp); rtl_unlock_work(tp); @@ -2044,7 +2042,7 @@ static void rtl_enable_eee(struct rtl8169_private *tp) phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv); } -static void rtl8169_get_mac_version(struct rtl8169_private *tp) +static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) { /* * The driver currently handles the 8168Bf and the 8168Be identically @@ -2060,7 +2058,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp) static const struct rtl_mac_info { u16 mask; u16 val; - u16 mac_version; + enum mac_version ver; } mac_info[] = { /* 8125 family. */ { 0x7cf, 0x608, RTL_GIGA_MAC_VER_60 }, @@ -2147,22 +2145,22 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp) { 0x000, 0x000, RTL_GIGA_MAC_NONE } }; const struct rtl_mac_info *p = mac_info; - u16 reg = RTL_R32(tp, TxConfig) >> 20; + enum mac_version ver; - while ((reg & p->mask) != p->val) + while ((xid & p->mask) != p->val) p++; - tp->mac_version = p->mac_version; - - if (tp->mac_version == RTL_GIGA_MAC_NONE) { - dev_err(tp_to_dev(tp), "unknown chip XID %03x\n", reg & 0xfcf); - } else if (!tp->supports_gmii) { - if (tp->mac_version == RTL_GIGA_MAC_VER_42) - tp->mac_version = RTL_GIGA_MAC_VER_43; - else if (tp->mac_version == RTL_GIGA_MAC_VER_45) - tp->mac_version = RTL_GIGA_MAC_VER_47; - else if (tp->mac_version == RTL_GIGA_MAC_VER_46) - tp->mac_version = RTL_GIGA_MAC_VER_48; + ver = p->ver; + + if (ver != RTL_GIGA_MAC_NONE && !gmii) { + if (ver == RTL_GIGA_MAC_VER_42) + ver = RTL_GIGA_MAC_VER_43; + else if (ver == RTL_GIGA_MAC_VER_45) + ver = RTL_GIGA_MAC_VER_47; + else if (ver == RTL_GIGA_MAC_VER_46) + ver = RTL_GIGA_MAC_VER_48; } + + return ver; } static void rtl_release_firmware(struct rtl8169_private *tp) @@ -2264,10 +2262,10 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) rtl_unlock_config_regs(tp); RTL_W32(tp, MAC4, addr[4] | addr[5] << 8); - RTL_R32(tp, MAC4); + rtl_pci_commit(tp); RTL_W32(tp, MAC0, addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); - RTL_R32(tp, MAC0); + rtl_pci_commit(tp); if (tp->mac_version == RTL_GIGA_MAC_VER_34) rtl_rar_exgmac_set(tp, addr); @@ -2471,66 +2469,52 @@ static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); } -static void rtl_hw_jumbo_enable(struct rtl8169_private *tp) +static void rtl_jumbo_config(struct rtl8169_private *tp) { - rtl_unlock_config_regs(tp); - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_12: - case RTL_GIGA_MAC_VER_17: - pcie_set_readrq(tp->pci_dev, 512); - r8168b_1_hw_jumbo_enable(tp); - break; - case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: - pcie_set_readrq(tp->pci_dev, 512); - r8168c_hw_jumbo_enable(tp); - break; - case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28: - r8168dp_hw_jumbo_enable(tp); - break; - case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: - pcie_set_readrq(tp->pci_dev, 512); - r8168e_hw_jumbo_enable(tp); - break; - default: - break; - } - rtl_lock_config_regs(tp); -} + bool jumbo = tp->dev->mtu > ETH_DATA_LEN; -static void rtl_hw_jumbo_disable(struct rtl8169_private *tp) -{ rtl_unlock_config_regs(tp); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: - r8168b_1_hw_jumbo_disable(tp); + if (jumbo) { + pcie_set_readrq(tp->pci_dev, 512); + r8168b_1_hw_jumbo_enable(tp); + } else { + r8168b_1_hw_jumbo_disable(tp); + } break; case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: - r8168c_hw_jumbo_disable(tp); + if (jumbo) { + pcie_set_readrq(tp->pci_dev, 512); + r8168c_hw_jumbo_enable(tp); + } else { + r8168c_hw_jumbo_disable(tp); + } break; case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28: - r8168dp_hw_jumbo_disable(tp); + if (jumbo) + r8168dp_hw_jumbo_enable(tp); + else + r8168dp_hw_jumbo_disable(tp); break; case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: - r8168e_hw_jumbo_disable(tp); + if (jumbo) { + pcie_set_readrq(tp->pci_dev, 512); + r8168e_hw_jumbo_enable(tp); + } else { + r8168e_hw_jumbo_disable(tp); + } break; default: break; } rtl_lock_config_regs(tp); - if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii) + if (!jumbo && pci_is_pcie(tp->pci_dev) && tp->supports_gmii) pcie_set_readrq(tp->pci_dev, 4096); } -static void rtl_jumbo_config(struct rtl8169_private *tp, int mtu) -{ - if (mtu > ETH_DATA_LEN) - rtl_hw_jumbo_enable(tp); - else - rtl_hw_jumbo_disable(tp); -} - DECLARE_RTL_COND(rtl_chipcmd_cond) { return RTL_R8(tp, ChipCmd) & CmdReset; @@ -3838,9 +3822,6 @@ static void rtl_hw_start_8168(struct rtl8169_private *tp) static void rtl_hw_start_8169(struct rtl8169_private *tp) { - if (tp->mac_version == RTL_GIGA_MAC_VER_05) - pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); - RTL_W8(tp, EarlyTxThres, NoEarlyTx); tp->cp_cmd |= PCIMulRW; @@ -3853,8 +3834,6 @@ static void rtl_hw_start_8169(struct rtl8169_private *tp) rtl8169_set_magic_reg(tp, tp->mac_version); - RTL_W32(tp, RxMissed, 0); - /* disable interrupt coalescing */ RTL_W16(tp, IntrMitigate, 0x0000); } @@ -3877,10 +3856,11 @@ static void rtl_hw_start(struct rtl8169_private *tp) rtl_set_rx_tx_desc_registers(tp); rtl_lock_config_regs(tp); - rtl_jumbo_config(tp, tp->dev->mtu); + rtl_jumbo_config(tp); /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ - RTL_R16(tp, CPlusCmd); + rtl_pci_commit(tp); + RTL_W8(tp, ChipCmd, CmdTxEnb | CmdRxEnb); rtl_init_rxcfg(tp); rtl_set_tx_config_registers(tp); @@ -3892,10 +3872,9 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) { struct rtl8169_private *tp = netdev_priv(dev); - rtl_jumbo_config(tp, new_mtu); - dev->mtu = new_mtu; netdev_update_features(dev); + rtl_jumbo_config(tp); return 0; } @@ -4108,12 +4087,10 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, tp->tx_skb[entry].len = len; } - if (cur_frag) { - tp->tx_skb[entry].skb = skb; - txd->opts1 |= cpu_to_le32(LastFrag); - } + tp->tx_skb[entry].skb = skb; + txd->opts1 |= cpu_to_le32(LastFrag); - return cur_frag; + return 0; err_out: rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag); @@ -4125,29 +4102,6 @@ static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp, struct sk_buff *skb) return skb->len < ETH_ZLEN && tp->mac_version == RTL_GIGA_MAC_VER_34; } -/* msdn_giant_send_check() - * According to the document of microsoft, the TCP Pseudo Header excludes the - * packet length for IPv6 TCP large packets. - */ -static int msdn_giant_send_check(struct sk_buff *skb) -{ - const struct ipv6hdr *ipv6h; - struct tcphdr *th; - int ret; - - ret = skb_cow_head(skb, 0); - if (ret) - return ret; - - ipv6h = ipv6_hdr(skb); - th = tcp_hdr(skb); - - th->check = 0; - th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); - - return ret; -} - static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts) { u32 mss = skb_shinfo(skb)->gso_size; @@ -4180,9 +4134,10 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp, break; case htons(ETH_P_IPV6): - if (msdn_giant_send_check(skb)) + if (skb_cow_head(skb, 0)) return false; + tcp_v6_gso_csum_prep(skb); opts[0] |= TD1_GTSENV6; break; @@ -4260,6 +4215,7 @@ static void rtl8169_doorbell(struct rtl8169_private *tp) static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) { + unsigned int frags = skb_shinfo(skb)->nr_frags; struct rtl8169_private *tp = netdev_priv(dev); unsigned int entry = tp->cur_tx % NUM_TX_DESC; struct TxDesc *txd = tp->TxDescArray + entry; @@ -4268,9 +4224,8 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, u32 opts[2], len; bool stop_queue; bool door_bell; - int frags; - if (unlikely(!rtl_tx_slots_avail(tp, skb_shinfo(skb)->nr_frags))) { + if (unlikely(!rtl_tx_slots_avail(tp, frags))) { netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n"); goto err_stop_0; } @@ -4299,14 +4254,13 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->tx_skb[entry].len = len; txd->addr = cpu_to_le64(mapping); - frags = rtl8169_xmit_frags(tp, skb, opts); - if (frags < 0) - goto err_dma_1; - else if (frags) - opts[0] |= FirstFrag; - else { + if (!frags) { opts[0] |= FirstFrag | LastFrag; tp->tx_skb[entry].skb = skb; + } else { + if (rtl8169_xmit_frags(tp, skb, opts)) + goto err_dma_1; + opts[0] |= FirstFrag; } txd->opts2 = cpu_to_le32(opts[1]); @@ -4697,17 +4651,6 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) return work_done; } -static void rtl8169_rx_missed(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - - if (tp->mac_version > RTL_GIGA_MAC_VER_06) - return; - - dev->stats.rx_missed_errors += RTL_R32(tp, RxMissed) & 0xffffff; - RTL_W32(tp, RxMissed, 0); -} - static void r8169_phylink_handler(struct net_device *ndev) { struct rtl8169_private *tp = netdev_priv(ndev); @@ -4757,12 +4700,6 @@ static void rtl8169_down(struct net_device *dev) netif_stop_queue(dev); rtl8169_hw_reset(tp); - /* - * At this point device interrupts can not be enabled in any function, - * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task) - * and napi is disabled (rtl8169_poll). - */ - rtl8169_rx_missed(dev); /* Give a racing hard_start_xmit a few cycles to complete. */ synchronize_rcu(); @@ -4907,9 +4844,6 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) pm_runtime_get_noresume(&pdev->dev); - if (netif_running(dev) && pm_runtime_active(&pdev->dev)) - rtl8169_rx_missed(dev); - do { start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp); stats->rx_packets = tp->rx_stats.packets; @@ -4928,7 +4862,6 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) stats->rx_errors = dev->stats.rx_errors; stats->rx_crc_errors = dev->stats.rx_crc_errors; stats->rx_fifo_errors = dev->stats.rx_fifo_errors; - stats->rx_missed_errors = dev->stats.rx_missed_errors; stats->multicast = dev->stats.multicast; /* @@ -4948,6 +4881,8 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) le32_to_cpu(tp->tc_offset.tx_multi_collision); stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) - le16_to_cpu(tp->tc_offset.tx_aborted); + stats->rx_missed_errors = le16_to_cpu(counters->rx_missed) - + le16_to_cpu(tp->tc_offset.rx_missed); pm_runtime_put_noidle(&pdev->dev); } @@ -5033,7 +4968,6 @@ static int rtl8169_runtime_suspend(struct device *device) rtl8169_net_suspend(dev); /* Update counters before going runtime suspend */ - rtl8169_rx_missed(dev); rtl8169_update_counters(tp); return 0; @@ -5098,8 +5032,7 @@ static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp) pci_clear_master(tp->pci_dev); RTL_W8(tp, ChipCmd, CmdRxEnb); - /* PCI commit */ - RTL_R8(tp, ChipCmd); + rtl_pci_commit(tp); break; default: break; @@ -5173,7 +5106,7 @@ static const struct net_device_ops rtl_netdev_ops = { static void rtl_set_irq_mask(struct rtl8169_private *tp) { - tp->irq_mask = RTL_EVENT_NAPI | LinkChg; + tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg; if (tp->mac_version <= RTL_GIGA_MAC_VER_06) tp->irq_mask |= SYSErr | RxOverflow | RxFIFOOver; @@ -5442,9 +5375,10 @@ done: static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct rtl8169_private *tp; + int jumbo_max, region, rc; + enum mac_version chipset; struct net_device *dev; - int chipset, region; - int jumbo_max, rc; + u16 xid; /* Some tools for creating an initramfs don't consider softdeps, then * r8169.ko may be in initramfs, but realtek.ko not. Then the generic @@ -5511,10 +5445,16 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->mmio_addr = pcim_iomap_table(pdev)[region]; + xid = (RTL_R32(tp, TxConfig) >> 20) & 0xfcf; + /* Identify chip attached to board */ - rtl8169_get_mac_version(tp); - if (tp->mac_version == RTL_GIGA_MAC_NONE) + chipset = rtl8169_get_mac_version(xid, tp->supports_gmii); + if (chipset == RTL_GIGA_MAC_NONE) { + dev_err(&pdev->dev, "unknown chip XID %03x\n", xid); return -ENODEV; + } + + tp->mac_version = chipset; tp->cp_cmd = RTL_R16(tp, CPlusCmd); @@ -5532,8 +5472,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - chipset = tp->mac_version; - rc = rtl_alloc_irq(tp); if (rc < 0) { dev_err(&pdev->dev, "Can't allocate interrupt\n"); @@ -5551,9 +5489,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &tp->napi, rtl8169_poll, NAPI_POLL_WEIGHT); - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | - NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_CTAG_RX; dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; @@ -5575,7 +5510,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rtl_chip_supports_csum_v2(tp)) { dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; - dev->features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; dev->gso_max_size = RTL_GSO_MAX_SIZE_V2; dev->gso_max_segs = RTL_GSO_MAX_SEGS_V2; } else { @@ -5590,9 +5524,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->mac_version == RTL_GIGA_MAC_VER_22) { dev->vlan_features &= ~(NETIF_F_ALL_TSO | NETIF_F_SG); dev->hw_features &= ~(NETIF_F_ALL_TSO | NETIF_F_SG); - dev->features &= ~(NETIF_F_ALL_TSO | NETIF_F_SG); } + dev->features |= dev->hw_features; + dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; @@ -5624,8 +5559,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_mdio_unregister; netif_info(tp, probe, dev, "%s, %pM, XID %03x, IRQ %d\n", - rtl_chip_infos[chipset].name, dev->dev_addr, - (RTL_R32(tp, TxConfig) >> 20) & 0xfcf, + rtl_chip_infos[chipset].name, dev->dev_addr, xid, pci_irq_vector(pdev, 0)); if (jumbo_max) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 58ca126518a2..8ed73f44405d 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -142,69 +142,6 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { [FWALCR1] = 0x00b4, }; -static const u16 sh_eth_offset_fast_rz[SH_ETH_MAX_REGISTER_OFFSET] = { - SH_ETH_OFFSET_DEFAULTS, - - [EDSR] = 0x0000, - [EDMR] = 0x0400, - [EDTRR] = 0x0408, - [EDRRR] = 0x0410, - [EESR] = 0x0428, - [EESIPR] = 0x0430, - [TDLAR] = 0x0010, - [TDFAR] = 0x0014, - [TDFXR] = 0x0018, - [TDFFR] = 0x001c, - [RDLAR] = 0x0030, - [RDFAR] = 0x0034, - [RDFXR] = 0x0038, - [RDFFR] = 0x003c, - [TRSCER] = 0x0438, - [RMFCR] = 0x0440, - [TFTR] = 0x0448, - [FDR] = 0x0450, - [RMCR] = 0x0458, - [RPADIR] = 0x0460, - [FCFTR] = 0x0468, - [CSMR] = 0x04E4, - - [ECMR] = 0x0500, - [RFLR] = 0x0508, - [ECSR] = 0x0510, - [ECSIPR] = 0x0518, - [PIR] = 0x0520, - [APR] = 0x0554, - [MPR] = 0x0558, - [PFTCR] = 0x055c, - [PFRCR] = 0x0560, - [TPAUSER] = 0x0564, - [MAHR] = 0x05c0, - [MALR] = 0x05c8, - [CEFCR] = 0x0740, - [FRECR] = 0x0748, - [TSFRCR] = 0x0750, - [TLFRCR] = 0x0758, - [RFCR] = 0x0760, - [MAFCR] = 0x0778, - - [ARSTR] = 0x0000, - [TSU_CTRST] = 0x0004, - [TSU_FWSLC] = 0x0038, - [TSU_VTAG0] = 0x0058, - [TSU_ADSBSY] = 0x0060, - [TSU_TEN] = 0x0064, - [TSU_POST1] = 0x0070, - [TSU_POST2] = 0x0074, - [TSU_POST3] = 0x0078, - [TSU_POST4] = 0x007c, - [TSU_ADRH0] = 0x0100, - - [TXNLCR0] = 0x0080, - [TXALCR0] = 0x0084, - [RXNLCR0] = 0x0088, - [RXALCR0] = 0x008C, -}; - static const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = { SH_ETH_OFFSET_DEFAULTS, @@ -569,6 +506,9 @@ static void sh_eth_set_rate_gether(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); + if (WARN_ON(!mdp->cd->gecmr)) + return; + switch (mdp->speed) { case 10: /* 10BASE */ sh_eth_write(ndev, GECMR_10, GECMR); @@ -590,7 +530,7 @@ static struct sh_eth_cpu_data r7s72100_data = { .chip_reset = sh_eth_chip_reset, .set_duplex = sh_eth_set_duplex, - .register_type = SH_ETH_REG_FAST_RZ, + .register_type = SH_ETH_REG_GIGABIT, .edtrr_trns = EDTRR_TRNS_GETHER, .ecsr_value = ECSR_ICD, @@ -663,6 +603,7 @@ static struct sh_eth_cpu_data r8a7740_data = { .apr = 1, .mpr = 1, .tpauser = 1, + .gecmr = 1, .bculr = 1, .hw_swap = 1, .rpadir = 1, @@ -788,6 +729,7 @@ static struct sh_eth_cpu_data r8a77980_data = { .apr = 1, .mpr = 1, .tpauser = 1, + .gecmr = 1, .bculr = 1, .hw_swap = 1, .nbst = 1, @@ -957,6 +899,9 @@ static void sh_eth_set_rate_giga(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); + if (WARN_ON(!mdp->cd->gecmr)) + return; + switch (mdp->speed) { case 10: /* 10BASE */ sh_eth_write(ndev, 0x00000000, GECMR); @@ -1002,6 +947,7 @@ static struct sh_eth_cpu_data sh7757_data_giga = { .apr = 1, .mpr = 1, .tpauser = 1, + .gecmr = 1, .bculr = 1, .hw_swap = 1, .rpadir = 1, @@ -1042,6 +988,7 @@ static struct sh_eth_cpu_data sh7734_data = { .apr = 1, .mpr = 1, .tpauser = 1, + .gecmr = 1, .bculr = 1, .hw_swap = 1, .no_trimd = 1, @@ -1083,6 +1030,7 @@ static struct sh_eth_cpu_data sh7763_data = { .apr = 1, .mpr = 1, .tpauser = 1, + .gecmr = 1, .bculr = 1, .hw_swap = 1, .no_trimd = 1, @@ -2140,11 +2088,13 @@ static size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf) add_reg(EESR); add_reg(EESIPR); add_reg(TDLAR); - add_reg(TDFAR); + if (!cd->no_xdfar) + add_reg(TDFAR); add_reg(TDFXR); add_reg(TDFFR); add_reg(RDLAR); - add_reg(RDFAR); + if (!cd->no_xdfar) + add_reg(RDFAR); add_reg(RDFXR); add_reg(RDFFR); add_reg(TRSCER); @@ -2179,21 +2129,26 @@ static size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf) if (cd->tpauser) add_reg(TPAUSER); add_reg(TPAUSECR); - add_reg(GECMR); + if (cd->gecmr) + add_reg(GECMR); if (cd->bculr) add_reg(BCULR); add_reg(MAHR); add_reg(MALR); - add_reg(TROCR); - add_reg(CDCR); - add_reg(LCCR); - add_reg(CNDCR); + if (!cd->no_tx_cntrs) { + add_reg(TROCR); + add_reg(CDCR); + add_reg(LCCR); + add_reg(CNDCR); + } add_reg(CEFCR); add_reg(FRECR); add_reg(TSFRCR); add_reg(TLFRCR); - add_reg(CERCR); - add_reg(CEECR); + if (cd->cexcr) { + add_reg(CERCR); + add_reg(CEECR); + } add_reg(MAFCR); if (cd->rtrate) add_reg(RTRATE); @@ -3121,9 +3076,6 @@ static const u16 *sh_eth_get_register_offset(int register_type) case SH_ETH_REG_GIGABIT: reg_offset = sh_eth_offset_gigabit; break; - case SH_ETH_REG_FAST_RZ: - reg_offset = sh_eth_offset_fast_rz; - break; case SH_ETH_REG_FAST_RCAR: reg_offset = sh_eth_offset_fast_rcar; break; diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 850726301e1c..c1b3751b12c4 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -145,7 +145,6 @@ enum { enum { SH_ETH_REG_GIGABIT, - SH_ETH_REG_FAST_RZ, SH_ETH_REG_FAST_RCAR, SH_ETH_REG_FAST_SH4, SH_ETH_REG_FAST_SH3_SH2 @@ -490,6 +489,7 @@ struct sh_eth_cpu_data { unsigned apr:1; /* EtherC has APR */ unsigned mpr:1; /* EtherC has MPR */ unsigned tpauser:1; /* EtherC has TPAUSER */ + unsigned gecmr:1; /* EtherC has GECMR */ unsigned bculr:1; /* EtherC has BCULR */ unsigned tsu:1; /* EtherC has TSU */ unsigned hw_swap:1; /* E-DMAC has DE bit in EDMR */ diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 4481f21a1f43..256807c28ff7 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -113,7 +113,6 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); * *************************************************************************/ -static const struct efx_channel_type efx_default_channel_type; static void efx_remove_port(struct efx_nic *efx); static int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog); static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp); diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index f1bdb04efbe4..da54afaa3c44 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -150,24 +150,6 @@ static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx, int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, u16 rxq_index, u32 flow_id); bool __efx_filter_rfs_expire(struct efx_channel *channel, unsigned int quota); -static inline void efx_filter_rfs_expire(struct work_struct *data) -{ - struct delayed_work *dwork = to_delayed_work(data); - struct efx_channel *channel; - unsigned int time, quota; - - channel = container_of(dwork, struct efx_channel, filter_work); - time = jiffies - channel->rfs_last_expiry; - quota = channel->rfs_filter_count * time / (30 * HZ); - if (quota > 20 && __efx_filter_rfs_expire(channel, min(channel->rfs_filter_count, quota))) - channel->rfs_last_expiry += time; - /* Ensure we do more work eventually even if NAPI poll is not happening */ - schedule_delayed_work(dwork, 30 * HZ); -} -#define efx_filter_rfs_enabled() 1 -#else -static inline void efx_filter_rfs_expire(struct work_struct *data) {} -#define efx_filter_rfs_enabled() 0 #endif /* RSS contexts */ diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index aeb5e8aa2f2a..d2d738314c50 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -485,6 +485,23 @@ void efx_remove_eventq(struct efx_channel *channel) * *************************************************************************/ +#ifdef CONFIG_RFS_ACCEL +static void efx_filter_rfs_expire(struct work_struct *data) +{ + struct delayed_work *dwork = to_delayed_work(data); + struct efx_channel *channel; + unsigned int time, quota; + + channel = container_of(dwork, struct efx_channel, filter_work); + time = jiffies - channel->rfs_last_expiry; + quota = channel->rfs_filter_count * time / (30 * HZ); + if (quota >= 20 && __efx_filter_rfs_expire(channel, min(channel->rfs_filter_count, quota))) + channel->rfs_last_expiry += time; + /* Ensure we do more work eventually even if NAPI poll is not happening */ + schedule_delayed_work(dwork, 30 * HZ); +} +#endif + /* Allocate and initialise a channel structure. */ struct efx_channel * efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) @@ -1166,6 +1183,9 @@ static int efx_poll(struct napi_struct *napi, int budget) struct efx_channel *channel = container_of(napi, struct efx_channel, napi_str); struct efx_nic *efx = channel->efx; +#ifdef CONFIG_RFS_ACCEL + unsigned int time; +#endif int spent; netif_vdbg(efx, intr, efx->net_dev, @@ -1185,7 +1205,10 @@ static int efx_poll(struct napi_struct *napi, int budget) #ifdef CONFIG_RFS_ACCEL /* Perhaps expire some ARFS filters */ - mod_delayed_work(system_wq, &channel->filter_work, 0); + time = jiffies - channel->rfs_last_expiry; + /* Would our quota be >= 20? */ + if (channel->rfs_filter_count * time >= 600 * HZ) + mod_delayed_work(system_wq, &channel->filter_work, 0); #endif /* There is no race here; although napi_disable() will diff --git a/drivers/net/ethernet/sfc/falcon/net_driver.h b/drivers/net/ethernet/sfc/falcon/net_driver.h index a49ea2e719b6..a529ff395ead 100644 --- a/drivers/net/ethernet/sfc/falcon/net_driver.h +++ b/drivers/net/ethernet/sfc/falcon/net_driver.h @@ -288,7 +288,7 @@ struct ef4_rx_buffer { struct ef4_rx_page_state { dma_addr_t dma_addr; - unsigned int __pad[0] ____cacheline_aligned; + unsigned int __pad[] ____cacheline_aligned; }; /** diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 9f9886f222c8..392bd5b7017e 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -336,7 +336,7 @@ struct efx_rx_buffer { struct efx_rx_page_state { dma_addr_t dma_addr; - unsigned int __pad[0] ____cacheline_aligned; + unsigned int __pad[] ____cacheline_aligned; }; /** diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 04d7f41d7ed9..696a77c20cb7 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -287,9 +287,8 @@ static int efx_tx_tso_fallback(struct efx_tx_queue *tx_queue, return PTR_ERR(segments); dev_consume_skb_any(skb); - skb = segments; - skb_list_walk_safe(skb, skb, next) { + skb_list_walk_safe(segments, skb, next) { skb_mark_not_on_list(skb); efx_enqueue_skb(tx_queue, skb); } diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index e8224b543dfc..58b9b7ce7195 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -896,9 +896,9 @@ static u32 netsec_run_xdp(struct netsec_priv *priv, struct bpf_prog *prog, case XDP_TX: ret = netsec_xdp_xmit_back(priv, xdp); if (ret != NETSEC_XDP_TX) - __page_pool_put_page(dring->page_pool, - virt_to_head_page(xdp->data), - len, true); + page_pool_put_page(dring->page_pool, + virt_to_head_page(xdp->data), len, + true); break; case XDP_REDIRECT: err = xdp_do_redirect(priv->ndev, xdp, prog); @@ -906,9 +906,9 @@ static u32 netsec_run_xdp(struct netsec_priv *priv, struct bpf_prog *prog, ret = NETSEC_XDP_REDIR; } else { ret = NETSEC_XDP_CONSUMED; - __page_pool_put_page(dring->page_pool, - virt_to_head_page(xdp->data), - len, true); + page_pool_put_page(dring->page_pool, + virt_to_head_page(xdp->data), len, + true); } break; default: @@ -919,9 +919,8 @@ static u32 netsec_run_xdp(struct netsec_priv *priv, struct bpf_prog *prog, /* fall through -- handle aborts by dropping packet */ case XDP_DROP: ret = NETSEC_XDP_CONSUMED; - __page_pool_put_page(dring->page_pool, - virt_to_head_page(xdp->data), - len, true); + page_pool_put_page(dring->page_pool, + virt_to_head_page(xdp->data), len, true); break; } @@ -1020,8 +1019,8 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget) * cache state. Since we paid the allocation cost if * building an skb fails try to put the page into cache */ - __page_pool_put_page(dring->page_pool, page, - pkt_len, true); + page_pool_put_page(dring->page_pool, page, pkt_len, + true); netif_err(priv, drv, priv->ndev, "rx failed to build skb\n"); break; @@ -1148,11 +1147,7 @@ static netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb, ~tcp_v4_check(0, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, 0); } else { - ipv6_hdr(skb)->payload_len = 0; - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); } tx_ctrl.tcp_seg_offload_flag = true; @@ -1199,7 +1194,7 @@ static void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id) if (id == NETSEC_RING_RX) { struct page *page = virt_to_page(desc->addr); - page_pool_put_page(dring->page_pool, page, false); + page_pool_put_full_page(dring->page_pool, page, false); } else if (id == NETSEC_RING_TX) { dma_unmap_single(priv->dev, desc->dma_addr, desc->len, DMA_TO_DEVICE); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 9b7be996d07b..b2dc99289687 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -304,7 +304,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, /* Get ETH_CLK clocks */ dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck"); if (IS_ERR(dwmac->clk_eth_ck)) { - dev_warn(dev, "No phy clock provided...\n"); + dev_info(dev, "No phy clock provided...\n"); dwmac->clk_eth_ck = NULL; } @@ -324,7 +324,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, /* Get IRQ information early to have an ability to ask for deferred * probe if needed before we went too far with resource allocation. */ - dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev, + dwmac->irq_pwr_wakeup = platform_get_irq_byname_optional(pdev, "stm32_pwr_wakeup"); if (dwmac->irq_pwr_wakeup == -EPROBE_DEFER) return -EPROBE_DEFER; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7da18c9afa01..cb7a5bad4cfe 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -950,8 +950,10 @@ static void stmmac_mac_link_down(struct phylink_config *config, } static void stmmac_mac_link_up(struct phylink_config *config, + struct phy_device *phy, unsigned int mode, phy_interface_t interface, - struct phy_device *phy) + int speed, int duplex, + bool tx_pause, bool rx_pause) { struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); @@ -1251,11 +1253,11 @@ static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (buf->page) - page_pool_put_page(rx_q->page_pool, buf->page, false); + page_pool_put_full_page(rx_q->page_pool, buf->page, false); buf->page = NULL; if (buf->sec_page) - page_pool_put_page(rx_q->page_pool, buf->sec_page, false); + page_pool_put_full_page(rx_q->page_pool, buf->sec_page, false); buf->sec_page = NULL; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index fe2c9fa6a71c..7acbac73c29c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -579,28 +579,23 @@ static int __maybe_unused stmmac_pci_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); /* synthetic ID, no official vendor */ -#define PCI_VENDOR_ID_STMMAC 0x700 - -#define STMMAC_QUARK_ID 0x0937 -#define STMMAC_DEVICE_ID 0x1108 -#define STMMAC_EHL_RGMII1G_ID 0x4b30 -#define STMMAC_EHL_SGMII1G_ID 0x4b31 -#define STMMAC_TGL_SGMII1G_ID 0xa0ac -#define STMMAC_GMAC5_ID 0x7102 - -#define STMMAC_DEVICE(vendor_id, dev_id, info) { \ - PCI_VDEVICE(vendor_id, dev_id), \ - .driver_data = (kernel_ulong_t)&info \ - } +#define PCI_VENDOR_ID_STMMAC 0x0700 + +#define PCI_DEVICE_ID_STMMAC_STMMAC 0x1108 +#define PCI_DEVICE_ID_INTEL_QUARK_ID 0x0937 +#define PCI_DEVICE_ID_INTEL_EHL_RGMII1G_ID 0x4b30 +#define PCI_DEVICE_ID_INTEL_EHL_SGMII1G_ID 0x4b31 +#define PCI_DEVICE_ID_INTEL_TGL_SGMII1G_ID 0xa0ac +#define PCI_DEVICE_ID_SYNOPSYS_GMAC5_ID 0x7102 static const struct pci_device_id stmmac_id_table[] = { - STMMAC_DEVICE(STMMAC, STMMAC_DEVICE_ID, stmmac_pci_info), - STMMAC_DEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC, stmmac_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_QUARK_ID, quark_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_EHL_RGMII1G_ID, ehl_rgmii1g_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_EHL_SGMII1G_ID, ehl_sgmii1g_pci_info), - STMMAC_DEVICE(INTEL, STMMAC_TGL_SGMII1G_ID, tgl_sgmii1g_pci_info), - STMMAC_DEVICE(SYNOPSYS, STMMAC_GMAC5_ID, snps_gmac5_pci_info), + { PCI_DEVICE_DATA(STMMAC, STMMAC, &stmmac_pci_info) }, + { PCI_DEVICE_DATA(STMICRO, MAC, &stmmac_pci_info) }, + { PCI_DEVICE_DATA(INTEL, QUARK_ID, &quark_pci_info) }, + { PCI_DEVICE_DATA(INTEL, EHL_RGMII1G_ID, &ehl_rgmii1g_pci_info) }, + { PCI_DEVICE_DATA(INTEL, EHL_SGMII1G_ID, &ehl_sgmii1g_pci_info) }, + { PCI_DEVICE_DATA(INTEL, TGL_SGMII1G_ID, &tgl_sgmii1g_pci_info) }, + { PCI_DEVICE_DATA(SYNOPSYS, GMAC5_ID, &snps_gmac5_pci_info) }, {} }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index d10ac54bf385..165958c9f069 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -588,7 +588,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) if (IS_ERR(plat->clk_ptp_ref)) { plat->clk_ptp_rate = clk_get_rate(plat->stmmac_clk); plat->clk_ptp_ref = NULL; - dev_warn(&pdev->dev, "PTP uses main clock\n"); + dev_info(&pdev->dev, "PTP uses main clock\n"); } else { plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref); dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate); diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h index 805903dbddcc..68f324ed4eaf 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h @@ -308,7 +308,7 @@ struct gelic_port { struct gelic_card *card; struct net_device *netdev; enum gelic_port_type type; - long priv[0]; /* long for alignment */ + long priv[]; /* long for alignment */ }; static inline struct gelic_card *port_to_card(struct gelic_port *p) diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h index 4041d946b649..1f203d1ae8db 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h @@ -158,7 +158,7 @@ struct gelic_eurus_scan_info { __be32 reserved2; __be32 reserved3; __be32 reserved4; - u8 elements[0]; /* ie */ + u8 elements[]; /* ie */ } __packed; /* the hypervisor returns bbs up to 16 */ diff --git a/drivers/net/ethernet/toshiba/spider_net.h b/drivers/net/ethernet/toshiba/spider_net.h index c0c68cbc898c..05b1a0736835 100644 --- a/drivers/net/ethernet/toshiba/spider_net.h +++ b/drivers/net/ethernet/toshiba/spider_net.h @@ -470,7 +470,7 @@ struct spider_net_card { struct spider_net_extra_stats spider_stats; /* Must be last item in struct */ - struct spider_net_descr darray[0]; + struct spider_net_descr darray[]; }; #endif diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index 3fd43d30b20d..b50c3ec3495b 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -367,7 +367,7 @@ struct TxFD { struct RxFD { struct FDesc fd; - struct BDesc bd[0]; /* variable length */ + struct BDesc bd[]; /* variable length */ }; struct FrFD { diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 20746b801959..c2f4c5ca2e80 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1441,6 +1441,22 @@ static void axienet_mac_an_restart(struct phylink_config *config) static void axienet_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { + /* nothing meaningful to do */ +} + +static void axienet_mac_link_down(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ + /* nothing meaningful to do */ +} + +static void axienet_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ struct net_device *ndev = to_net_dev(config->dev); struct axienet_local *lp = netdev_priv(ndev); u32 emmc_reg, fcc_reg; @@ -1448,7 +1464,7 @@ static void axienet_mac_config(struct phylink_config *config, unsigned int mode, emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET); emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK; - switch (state->speed) { + switch (speed) { case SPEED_1000: emmc_reg |= XAE_EMMC_LINKSPD_1000; break; @@ -1467,32 +1483,17 @@ static void axienet_mac_config(struct phylink_config *config, unsigned int mode, axienet_iow(lp, XAE_EMMC_OFFSET, emmc_reg); fcc_reg = axienet_ior(lp, XAE_FCC_OFFSET); - if (state->pause & MLO_PAUSE_TX) + if (tx_pause) fcc_reg |= XAE_FCC_FCTX_MASK; else fcc_reg &= ~XAE_FCC_FCTX_MASK; - if (state->pause & MLO_PAUSE_RX) + if (rx_pause) fcc_reg |= XAE_FCC_FCRX_MASK; else fcc_reg &= ~XAE_FCC_FCRX_MASK; axienet_iow(lp, XAE_FCC_OFFSET, fcc_reg); } -static void axienet_mac_link_down(struct phylink_config *config, - unsigned int mode, - phy_interface_t interface) -{ - /* nothing meaningful to do */ -} - -static void axienet_mac_link_up(struct phylink_config *config, - unsigned int mode, - phy_interface_t interface, - struct phy_device *phy) -{ - /* nothing meaningful to do */ -} - static const struct phylink_mac_ops axienet_phylink_ops = { .validate = axienet_validate, .mac_pcs_get_state = axienet_mac_pcs_get_state, |