diff options
Diffstat (limited to 'drivers/net/ethernet/pensando')
17 files changed, 587 insertions, 313 deletions
diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h index bb106a32f416..23ccc0da2341 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic.h +++ b/drivers/net/ethernet/pensando/ionic/ionic.h @@ -12,12 +12,12 @@ struct ionic_lif; #define IONIC_DRV_NAME "ionic" #define IONIC_DRV_DESCRIPTION "Pensando Ethernet NIC Driver" -#define IONIC_DRV_VERSION "0.20.0-k" #define PCI_VENDOR_ID_PENSANDO 0x1dd8 #define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_PF 0x1002 #define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF 0x1003 +#define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_MGMT 0x1004 #define DEVCMD_TIMEOUT 10 @@ -42,6 +42,7 @@ struct ionic { struct dentry *dentry; struct ionic_dev_bar bars[IONIC_BARS_MAX]; unsigned int num_bars; + bool is_mgmt_nic; struct ionic_identity ident; struct list_head lifs; struct ionic_lif *master_lif; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c index 448d7b23b2f7..60fc191a35e5 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c @@ -15,6 +15,7 @@ static const struct pci_device_id ionic_id_table[] = { { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_PF) }, { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF) }, + { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_MGMT) }, { 0, } /* end of table */ }; MODULE_DEVICE_TABLE(pci, ionic_id_table); @@ -37,6 +38,9 @@ int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs) void ionic_bus_free_irq_vectors(struct ionic *ionic) { + if (!ionic->nintrs) + return; + pci_free_irq_vectors(ionic->pdev); } @@ -221,6 +225,9 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, ionic); mutex_init(&ionic->dev_cmd_lock); + ionic->is_mgmt_nic = + ent->device == PCI_DEVICE_ID_PENSANDO_IONIC_ETH_MGMT; + /* Query system for DMA addressing limitation for the device. */ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN)); if (err) { @@ -245,6 +252,8 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } pci_set_master(pdev); + if (!ionic->is_mgmt_nic) + pcie_print_link_status(pdev); err = ionic_map_bars(ionic); if (err) @@ -346,6 +355,11 @@ err_out_reset: ionic_reset(ionic); err_out_teardown: ionic_dev_teardown(ionic); + /* Don't fail the probe for these errors, keep + * the hw interface around for inspection + */ + return 0; + err_out_unmap_bars: ionic_unmap_bars(ionic); pci_release_regions(pdev); @@ -369,11 +383,14 @@ static void ionic_remove(struct pci_dev *pdev) if (!ionic) return; - ionic_devlink_unregister(ionic); - ionic_lifs_unregister(ionic); - ionic_lifs_deinit(ionic); - ionic_lifs_free(ionic); - ionic_bus_free_irq_vectors(ionic); + if (ionic->master_lif) { + ionic_devlink_unregister(ionic); + ionic_lifs_unregister(ionic); + ionic_lifs_deinit(ionic); + ionic_lifs_free(ionic); + ionic_bus_free_irq_vectors(ionic); + } + ionic_port_reset(ionic); ionic_reset(ionic); ionic_dev_teardown(ionic); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c index bc03cecf80cc..11621ccc1faf 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c @@ -170,8 +170,7 @@ void ionic_debugfs_add_qcq(struct ionic_lif *lif, struct ionic_qcq *qcq) debugfs_create_x64("base_pa", 0400, cq_dentry, &cq->base_pa); debugfs_create_u32("num_descs", 0400, cq_dentry, &cq->num_descs); debugfs_create_u32("desc_size", 0400, cq_dentry, &cq->desc_size); - debugfs_create_u8("done_color", 0400, cq_dentry, - (u8 *)&cq->done_color); + debugfs_create_bool("done_color", 0400, cq_dentry, &cq->done_color); debugfs_create_file("tail", 0400, cq_dentry, cq, &cq_tail_fops); @@ -228,7 +227,13 @@ DEFINE_SHOW_ATTRIBUTE(netdev); void ionic_debugfs_add_lif(struct ionic_lif *lif) { - lif->dentry = debugfs_create_dir(lif->name, lif->ionic->dentry); + struct dentry *lif_dentry; + + lif_dentry = debugfs_create_dir(lif->name, lif->ionic->dentry); + if (IS_ERR_OR_NULL(lif_dentry)) + return; + lif->dentry = lif_dentry; + debugfs_create_file("netdev", 0400, lif->dentry, lif->netdev, &netdev_fops); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 87f82f36812f..f4ae40ae1e53 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -14,11 +14,15 @@ static void ionic_watchdog_cb(struct timer_list *t) { struct ionic *ionic = from_timer(ionic, t, watchdog_timer); + int hb; mod_timer(&ionic->watchdog_timer, round_jiffies(jiffies + ionic->watchdog_period)); - ionic_heartbeat_check(ionic); + hb = ionic_heartbeat_check(ionic); + + if (hb >= 0 && ionic->master_lif) + ionic_link_status_check_request(ionic->master_lif); } void ionic_init_devinfo(struct ionic *ionic) @@ -82,6 +86,7 @@ int ionic_dev_setup(struct ionic *ionic) return -EFAULT; } + idev->last_fw_status = 0xff; timer_setup(&ionic->watchdog_timer, ionic_watchdog_cb, 0); ionic->watchdog_period = IONIC_WATCHDOG_SECS * HZ; mod_timer(&ionic->watchdog_timer, @@ -103,7 +108,7 @@ int ionic_heartbeat_check(struct ionic *ionic) { struct ionic_dev *idev = &ionic->idev; unsigned long hb_time; - u32 fw_status; + u8 fw_status; u32 hb; /* wait a little more than one second before testing again */ @@ -111,9 +116,47 @@ int ionic_heartbeat_check(struct ionic *ionic) if (time_before(hb_time, (idev->last_hb_time + ionic->watchdog_period))) return 0; - /* firmware is useful only if fw_status is non-zero */ - fw_status = ioread32(&idev->dev_info_regs->fw_status); - if (!fw_status) + /* firmware is useful only if the running bit is set and + * fw_status != 0xff (bad PCI read) + */ + fw_status = ioread8(&idev->dev_info_regs->fw_status); + if (fw_status != 0xff) + fw_status &= IONIC_FW_STS_F_RUNNING; /* use only the run bit */ + + /* is this a transition? */ + if (fw_status != idev->last_fw_status && + idev->last_fw_status != 0xff) { + struct ionic_lif *lif = ionic->master_lif; + bool trigger = false; + + if (!fw_status || fw_status == 0xff) { + dev_info(ionic->dev, "FW stopped %u\n", fw_status); + if (lif && !test_bit(IONIC_LIF_F_FW_RESET, lif->state)) + trigger = true; + } else { + dev_info(ionic->dev, "FW running %u\n", fw_status); + if (lif && test_bit(IONIC_LIF_F_FW_RESET, lif->state)) + trigger = true; + } + + if (trigger) { + struct ionic_deferred_work *work; + + work = kzalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + dev_err(ionic->dev, "%s OOM\n", __func__); + } else { + work->type = IONIC_DW_TYPE_LIF_RESET; + if (fw_status & IONIC_FW_STS_F_RUNNING && + fw_status != 0xff) + work->fw_status = 1; + ionic_lif_deferred_enqueue(&lif->deferred, work); + } + } + } + idev->last_fw_status = fw_status; + + if (!fw_status || fw_status == 0xff) return -ENXIO; /* early FW has no heartbeat, else FW will return non-zero */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 7838e342c4fd..587398b01997 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -132,6 +132,7 @@ struct ionic_dev { unsigned long last_hb_time; u32 last_hb; + u8 last_fw_status; u64 __iomem *db_pages; dma_addr_t phy_db_pages; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c index 6fb27dcc5787..273c889faaad 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c @@ -77,6 +77,10 @@ int ionic_devlink_register(struct ionic *ionic) return err; } + /* don't register the mgmt_nic as a port */ + if (ionic->is_mgmt_nic) + return 0; + devlink_port_attrs_set(&ionic->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL, 0, false, 0, NULL, 0); err = devlink_port_register(dl, &ionic->dl_port, 0); @@ -93,6 +97,7 @@ void ionic_devlink_unregister(struct ionic *ionic) { struct devlink *dl = priv_to_devlink(ionic); - devlink_port_unregister(&ionic->dl_port); + if (ionic->dl_port.registered) + devlink_port_unregister(&ionic->dl_port); devlink_unregister(dl); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index f778fff034f5..6996229facfd 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -3,6 +3,7 @@ #include <linux/module.h> #include <linux/netdevice.h> +#include <linux/sfp.h> #include "ionic.h" #include "ionic_bus.h" @@ -86,7 +87,6 @@ static void ionic_get_drvinfo(struct net_device *netdev, struct ionic *ionic = lif->ionic; strlcpy(drvinfo->driver, IONIC_DRV_NAME, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, IONIC_DRV_VERSION, sizeof(drvinfo->version)); strlcpy(drvinfo->fw_version, ionic->idev.dev_info.fw_version, sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, ionic_bus_info(ionic), @@ -412,28 +412,6 @@ static int ionic_set_coalesce(struct net_device *netdev, unsigned int i; u32 coal; - if (coalesce->rx_max_coalesced_frames || - coalesce->rx_coalesce_usecs_irq || - coalesce->rx_max_coalesced_frames_irq || - coalesce->tx_max_coalesced_frames || - coalesce->tx_coalesce_usecs_irq || - coalesce->tx_max_coalesced_frames_irq || - coalesce->stats_block_coalesce_usecs || - coalesce->use_adaptive_rx_coalesce || - coalesce->use_adaptive_tx_coalesce || - coalesce->pkt_rate_low || - coalesce->rx_coalesce_usecs_low || - coalesce->rx_max_coalesced_frames_low || - coalesce->tx_coalesce_usecs_low || - coalesce->tx_max_coalesced_frames_low || - coalesce->pkt_rate_high || - coalesce->rx_coalesce_usecs_high || - coalesce->rx_max_coalesced_frames_high || - coalesce->tx_coalesce_usecs_high || - coalesce->tx_max_coalesced_frames_high || - coalesce->rate_sample_interval) - return -EINVAL; - ident = &lif->ionic->ident; if (ident->dev.intr_coal_div == 0) { netdev_warn(netdev, "bad HW value in dev.intr_coal_div = %d\n", @@ -462,7 +440,7 @@ static int ionic_set_coalesce(struct net_device *netdev, if (coal != lif->rx_coalesce_hw) { lif->rx_coalesce_hw = coal; - if (test_bit(IONIC_LIF_UP, lif->state)) { + if (test_bit(IONIC_LIF_F_UP, lif->state)) { for (i = 0; i < lif->nxqs; i++) { qcq = lif->rxqcqs[i].qcq; ionic_intr_coal_init(lif->ionic->idev.intr_ctrl, @@ -509,11 +487,11 @@ static int ionic_set_ringparam(struct net_device *netdev, ring->rx_pending == lif->nrxq_descs) return 0; - err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET); + err = ionic_wait_for_bit(lif, IONIC_LIF_F_QUEUE_RESET); if (err) return err; - running = test_bit(IONIC_LIF_UP, lif->state); + running = test_bit(IONIC_LIF_F_UP, lif->state); if (running) ionic_stop(netdev); @@ -522,7 +500,7 @@ static int ionic_set_ringparam(struct net_device *netdev, if (running) ionic_open(netdev); - clear_bit(IONIC_LIF_QUEUE_RESET, lif->state); + clear_bit(IONIC_LIF_F_QUEUE_RESET, lif->state); return 0; } @@ -553,11 +531,11 @@ static int ionic_set_channels(struct net_device *netdev, if (ch->combined_count == lif->nxqs) return 0; - err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET); + err = ionic_wait_for_bit(lif, IONIC_LIF_F_QUEUE_RESET); if (err) return err; - running = test_bit(IONIC_LIF_UP, lif->state); + running = test_bit(IONIC_LIF_F_UP, lif->state); if (running) ionic_stop(netdev); @@ -565,7 +543,7 @@ static int ionic_set_channels(struct net_device *netdev, if (running) ionic_open(netdev); - clear_bit(IONIC_LIF_QUEUE_RESET, lif->state); + clear_bit(IONIC_LIF_F_QUEUE_RESET, lif->state); return 0; } @@ -575,7 +553,7 @@ static u32 ionic_get_priv_flags(struct net_device *netdev) struct ionic_lif *lif = netdev_priv(netdev); u32 priv_flags = 0; - if (test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) + if (test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state)) priv_flags |= PRIV_F_SW_DBG_STATS; return priv_flags; @@ -584,14 +562,10 @@ static u32 ionic_get_priv_flags(struct net_device *netdev) static int ionic_set_priv_flags(struct net_device *netdev, u32 priv_flags) { struct ionic_lif *lif = netdev_priv(netdev); - u32 flags = lif->flags; - clear_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state); + clear_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state); if (priv_flags & PRIV_F_SW_DBG_STATS) - set_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state); - - if (flags != lif->flags) - lif->flags = flags; + set_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state); return 0; } @@ -704,23 +678,27 @@ static int ionic_get_module_info(struct net_device *netdev, struct ionic_lif *lif = netdev_priv(netdev); struct ionic_dev *idev = &lif->ionic->idev; struct ionic_xcvr_status *xcvr; + struct sfp_eeprom_base *sfp; xcvr = &idev->port_info->status.xcvr; + sfp = (struct sfp_eeprom_base *) xcvr->sprom; /* report the module data type and length */ - switch (xcvr->sprom[0]) { - case 0x03: /* SFP */ + switch (sfp->phys_id) { + case SFF8024_ID_SFP: modinfo->type = ETH_MODULE_SFF_8079; modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; break; - case 0x0D: /* QSFP */ - case 0x11: /* QSFP28 */ + case SFF8024_ID_QSFP_8436_8636: + case SFF8024_ID_QSFP28_8636: modinfo->type = ETH_MODULE_SFF_8436; modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; break; default: netdev_info(netdev, "unknown xcvr type 0x%02x\n", xcvr->sprom[0]); + modinfo->type = 0; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; break; } @@ -784,6 +762,7 @@ static int ionic_nway_reset(struct net_device *netdev) } static const struct ethtool_ops ionic_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS, .get_drvinfo = ionic_get_drvinfo, .get_regs_len = ionic_get_regs_len, .get_regs = ionic_get_regs, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h index ce07c2931a72..ceeb7629e7a0 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_if.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h @@ -1,11 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB OR BSD-2-Clause */ +/* SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) OR BSD-2-Clause */ /* Copyright (c) 2017-2019 Pensando Systems, Inc. All rights reserved. */ #ifndef _IONIC_IF_H_ #define _IONIC_IF_H_ -#pragma pack(push, 1) - #define IONIC_DEV_INFO_SIGNATURE 0x44455649 /* 'DEVI' */ #define IONIC_DEV_INFO_VERSION 1 #define IONIC_IFNAMSIZ 16 @@ -366,7 +364,7 @@ union ionic_lif_config { u8 rsvd2[2]; __le64 features; __le32 queue_count[IONIC_QTYPE_MAX]; - }; + } __packed; __le32 words[64]; }; @@ -417,7 +415,7 @@ union ionic_lif_identity { __le32 max_frame_size; u8 rsvd2[106]; union ionic_lif_config config; - } eth; + } __packed eth; struct { u8 version; @@ -439,8 +437,8 @@ union ionic_lif_identity { struct ionic_lif_logical_qtype rq_qtype; struct ionic_lif_logical_qtype cq_qtype; struct ionic_lif_logical_qtype eq_qtype; - } rdma; - }; + } __packed rdma; + } __packed; __le32 words[512]; }; @@ -526,7 +524,7 @@ struct ionic_q_init_cmd { __le64 sg_ring_base; __le32 eq_index; u8 rsvd2[16]; -}; +} __packed; /** * struct ionic_q_init_comp - Queue init command completion @@ -1095,7 +1093,7 @@ struct ionic_port_status { u8 status; u8 rsvd[51]; struct ionic_xcvr_status xcvr; -}; +} __packed; /** * struct ionic_port_identify_cmd - Port identify command @@ -1251,7 +1249,7 @@ struct ionic_port_getattr_comp { u8 pause_type; u8 loopback_mode; u8 rsvd2[11]; - }; + } __packed; u8 color; }; @@ -1319,7 +1317,7 @@ struct ionic_dev_setattr_cmd { char name[IONIC_IFNAMSIZ]; __le64 features; u8 rsvd2[60]; - }; + } __packed; }; /** @@ -1334,7 +1332,7 @@ struct ionic_dev_setattr_comp { union { __le64 features; u8 rsvd2[11]; - }; + } __packed; u8 color; }; @@ -1361,7 +1359,7 @@ struct ionic_dev_getattr_comp { union { __le64 features; u8 rsvd2[11]; - }; + } __packed; u8 color; }; @@ -1426,7 +1424,7 @@ struct ionic_lif_setattr_cmd { } rss; u8 stats_ctl; u8 rsvd[60]; - }; + } __packed; }; /** @@ -1444,7 +1442,7 @@ struct ionic_lif_setattr_comp { union { __le64 features; u8 rsvd2[11]; - }; + } __packed; u8 color; }; @@ -1483,7 +1481,7 @@ struct ionic_lif_getattr_comp { u8 mac[6]; __le64 features; u8 rsvd2[11]; - }; + } __packed; u8 color; }; @@ -1688,7 +1686,7 @@ struct ionic_vf_setattr_cmd { u8 linkstate; __le64 stats_pa; u8 pad[60]; - }; + } __packed; }; struct ionic_vf_setattr_comp { @@ -1726,7 +1724,7 @@ struct ionic_vf_getattr_comp { u8 linkstate; __le64 stats_pa; u8 pad[11]; - }; + } __packed; u8 color; }; @@ -2445,6 +2443,7 @@ union ionic_dev_info_regs { u8 version; u8 asic_type; u8 asic_rev; +#define IONIC_FW_STS_F_RUNNING 0x1 u8 fw_status; u32 fw_heartbeat; char fw_version[IONIC_DEVINFO_FWVERS_BUFLEN]; @@ -2471,7 +2470,7 @@ union ionic_dev_cmd_regs { union ionic_dev_cmd_comp comp; u8 rsvd[48]; u32 data[478]; - }; + } __packed; u32 words[512]; }; @@ -2484,7 +2483,7 @@ union ionic_dev_regs { struct { union ionic_dev_info_regs info; union ionic_dev_cmd_regs devcmd; - }; + } __packed; __le32 words[1024]; }; @@ -2574,6 +2573,4 @@ struct ionic_identity { union ionic_qos_identity qos; }; -#pragma pack(pop) - #endif /* _IONIC_IF_H_ */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 191271f6260d..f8a9c1bcffc9 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -21,6 +21,12 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode); static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr); static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr); static void ionic_link_status_check(struct ionic_lif *lif); +static void ionic_lif_handle_fw_down(struct ionic_lif *lif); +static void ionic_lif_handle_fw_up(struct ionic_lif *lif); +static void ionic_lif_set_netdev_info(struct ionic_lif *lif); + +static int ionic_start_queues(struct ionic_lif *lif); +static void ionic_stop_queues(struct ionic_lif *lif); static void ionic_lif_deferred_work(struct work_struct *work) { @@ -50,6 +56,12 @@ static void ionic_lif_deferred_work(struct work_struct *work) case IONIC_DW_TYPE_LINK_STATUS: ionic_link_status_check(lif); break; + case IONIC_DW_TYPE_LIF_RESET: + if (w->fw_status) + ionic_lif_handle_fw_up(lif); + else + ionic_lif_handle_fw_down(lif); + break; default: break; } @@ -58,8 +70,8 @@ static void ionic_lif_deferred_work(struct work_struct *work) } } -static void ionic_lif_deferred_enqueue(struct ionic_deferred *def, - struct ionic_deferred_work *work) +void ionic_lif_deferred_enqueue(struct ionic_deferred *def, + struct ionic_deferred_work *work) { spin_lock_bh(&def->lock); list_add_tail(&work->list, &def->list); @@ -73,40 +85,47 @@ static void ionic_link_status_check(struct ionic_lif *lif) u16 link_status; bool link_up; + if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state)) + return; + + if (lif->ionic->is_mgmt_nic) + return; + link_status = le16_to_cpu(lif->info->status.link_status); link_up = link_status == IONIC_PORT_OPER_STATUS_UP; - /* filter out the no-change cases */ - if (link_up == netif_carrier_ok(netdev)) - goto link_out; - if (link_up) { - netdev_info(netdev, "Link up - %d Gbps\n", - le32_to_cpu(lif->info->status.link_speed) / 1000); + if (!netif_carrier_ok(netdev)) { + u32 link_speed; - if (test_bit(IONIC_LIF_UP, lif->state)) { - netif_tx_wake_all_queues(lif->netdev); + ionic_port_identify(lif->ionic); + link_speed = le32_to_cpu(lif->info->status.link_speed); + netdev_info(netdev, "Link up - %d Gbps\n", + link_speed / 1000); netif_carrier_on(netdev); } + + if (netif_running(lif->netdev)) + ionic_start_queues(lif); } else { - netdev_info(netdev, "Link down\n"); + if (netif_carrier_ok(netdev)) { + netdev_info(netdev, "Link down\n"); + netif_carrier_off(netdev); + } - /* carrier off first to avoid watchdog timeout */ - netif_carrier_off(netdev); - if (test_bit(IONIC_LIF_UP, lif->state)) - netif_tx_stop_all_queues(netdev); + if (netif_running(lif->netdev)) + ionic_stop_queues(lif); } -link_out: - clear_bit(IONIC_LIF_LINK_CHECK_REQUESTED, lif->state); + clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state); } -static void ionic_link_status_check_request(struct ionic_lif *lif) +void ionic_link_status_check_request(struct ionic_lif *lif) { struct ionic_deferred_work *work; /* we only need one request outstanding at a time */ - if (test_and_set_bit(IONIC_LIF_LINK_CHECK_REQUESTED, lif->state)) + if (test_and_set_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state)) return; if (in_interrupt()) { @@ -244,38 +263,19 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq) return ionic_adminq_post_wait(lif, &ctx); } -static void ionic_lif_quiesce(struct ionic_lif *lif) -{ - struct ionic_admin_ctx ctx = { - .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work), - .cmd.lif_setattr = { - .opcode = IONIC_CMD_LIF_SETATTR, - .attr = IONIC_LIF_ATTR_STATE, - .index = lif->index, - .state = IONIC_LIF_DISABLE - }, - }; - - ionic_adminq_post_wait(lif, &ctx); -} - static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq) { struct ionic_dev *idev = &lif->ionic->idev; - struct device *dev = lif->ionic->dev; if (!qcq) return; - ionic_debugfs_del_qcq(qcq); - if (!(qcq->flags & IONIC_QCQ_F_INITED)) return; if (qcq->flags & IONIC_QCQ_F_INTR) { ionic_intr_mask(idev->intr_ctrl, qcq->intr.index, IONIC_INTR_MASK_SET); - devm_free_irq(dev, qcq->intr.vector, &qcq->napi); netif_napi_del(&qcq->napi); } @@ -289,12 +289,18 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq) if (!qcq) return; + ionic_debugfs_del_qcq(qcq); + dma_free_coherent(dev, qcq->total_size, qcq->base, qcq->base_pa); qcq->base = NULL; qcq->base_pa = 0; - if (qcq->flags & IONIC_QCQ_F_INTR) + if (qcq->flags & IONIC_QCQ_F_INTR) { + irq_set_affinity_hint(qcq->intr.vector, NULL); + devm_free_irq(dev, qcq->intr.vector, &qcq->napi); + qcq->intr.vector = 0; ionic_intr_free(lif, qcq->intr.index); + } devm_kfree(dev, qcq->cq.info); qcq->cq.info = NULL; @@ -318,19 +324,21 @@ static void ionic_qcqs_free(struct ionic_lif *lif) lif->adminqcq = NULL; } - for (i = 0; i < lif->nxqs; i++) - if (lif->rxqcqs[i].stats) - devm_kfree(dev, lif->rxqcqs[i].stats); - - devm_kfree(dev, lif->rxqcqs); - lif->rxqcqs = NULL; - - for (i = 0; i < lif->nxqs; i++) - if (lif->txqcqs[i].stats) - devm_kfree(dev, lif->txqcqs[i].stats); + if (lif->rxqcqs) { + for (i = 0; i < lif->nxqs; i++) + if (lif->rxqcqs[i].stats) + devm_kfree(dev, lif->rxqcqs[i].stats); + devm_kfree(dev, lif->rxqcqs); + lif->rxqcqs = NULL; + } - devm_kfree(dev, lif->txqcqs); - lif->txqcqs = NULL; + if (lif->txqcqs) { + for (i = 0; i < lif->nxqs; i++) + if (lif->txqcqs[i].stats) + devm_kfree(dev, lif->txqcqs[i].stats); + devm_kfree(dev, lif->txqcqs); + lif->txqcqs = NULL; + } } static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq, @@ -424,8 +432,15 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, ionic_intr_mask_assert(idev->intr_ctrl, new->intr.index, IONIC_INTR_MASK_SET); - new->intr.cpu = new->intr.index % num_online_cpus(); - if (cpu_online(new->intr.cpu)) + err = ionic_request_irq(lif, new); + if (err) { + netdev_warn(lif->netdev, "irq request failed %d\n", err); + goto err_out_free_intr; + } + + new->intr.cpu = cpumask_local_spread(new->intr.index, + dev_to_node(dev)); + if (new->intr.cpu != -1) cpumask_set_cpu(new->intr.cpu, &new->intr.affinity_mask); } else { @@ -437,13 +452,13 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, if (!new->cq.info) { netdev_err(lif->netdev, "Cannot allocate completion queue info\n"); err = -ENOMEM; - goto err_out_free_intr; + goto err_out_free_irq; } err = ionic_cq_init(lif, &new->cq, &new->intr, num_descs, cq_desc_size); if (err) { netdev_err(lif->netdev, "Cannot initialize completion queue\n"); - goto err_out_free_intr; + goto err_out_free_irq; } new->base = dma_alloc_coherent(dev, total_size, &new->base_pa, @@ -451,7 +466,7 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, if (!new->base) { netdev_err(lif->netdev, "Cannot allocate queue DMA memory\n"); err = -ENOMEM; - goto err_out_free_intr; + goto err_out_free_irq; } new->total_size = total_size; @@ -477,8 +492,12 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, return 0; +err_out_free_irq: + if (flags & IONIC_QCQ_F_INTR) + devm_free_irq(dev, new->intr.vector, &new->napi); err_out_free_intr: - ionic_intr_free(lif, new->intr.index); + if (flags & IONIC_QCQ_F_INTR) + ionic_intr_free(lif, new->intr.index); err_out: dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err); return err; @@ -500,6 +519,7 @@ static int ionic_qcqs_alloc(struct ionic_lif *lif) 0, lif->kern_pid, &lif->adminqcq); if (err) return err; + ionic_debugfs_add_qcq(lif, lif->adminqcq); if (lif->ionic->nnqs_per_lif) { flags = IONIC_QCQ_F_NOTIFYQ; @@ -510,6 +530,7 @@ static int ionic_qcqs_alloc(struct ionic_lif *lif) 0, lif->kern_pid, &lif->notifyqcq); if (err) goto err_out_free_adminqcq; + ionic_debugfs_add_qcq(lif, lif->notifyqcq); /* Let the notifyq ride on the adminq interrupt */ ionic_link_qcq_interrupts(lif->adminqcq, lif->notifyqcq); @@ -594,6 +615,10 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) dev_dbg(dev, "txq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base); dev_dbg(dev, "txq_init.ring_size %d\n", ctx.cmd.q_init.ring_size); + q->tail = q->info; + q->head = q->tail; + cq->tail = cq->info; + err = ionic_adminq_post_wait(lif, &ctx); if (err) return err; @@ -607,8 +632,6 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) qcq->flags |= IONIC_QCQ_F_INITED; - ionic_debugfs_add_qcq(lif, qcq); - return 0; } @@ -641,6 +664,10 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) dev_dbg(dev, "rxq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base); dev_dbg(dev, "rxq_init.ring_size %d\n", ctx.cmd.q_init.ring_size); + q->tail = q->info; + q->head = q->tail; + cq->tail = cq->info; + err = ionic_adminq_post_wait(lif, &ctx); if (err) return err; @@ -655,16 +682,8 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi, NAPI_POLL_WEIGHT); - err = ionic_request_irq(lif, qcq); - if (err) { - netif_napi_del(&qcq->napi); - return err; - } - qcq->flags |= IONIC_QCQ_F_INITED; - ionic_debugfs_add_qcq(lif, qcq); - return 0; } @@ -672,6 +691,7 @@ static bool ionic_notifyq_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) { union ionic_notifyq_comp *comp = cq_info->cq_desc; + struct ionic_deferred_work *work; struct net_device *netdev; struct ionic_queue *q; struct ionic_lif *lif; @@ -697,11 +717,13 @@ static bool ionic_notifyq_service(struct ionic_cq *cq, ionic_link_status_check_request(lif); break; case IONIC_EVENT_RESET: - netdev_info(netdev, "Notifyq IONIC_EVENT_RESET eid=%lld\n", - eid); - netdev_info(netdev, " reset_code=%d state=%d\n", - comp->reset.reset_code, - comp->reset.state); + work = kzalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + netdev_err(lif->netdev, "%s OOM\n", __func__); + } else { + work->type = IONIC_DW_TYPE_LIF_RESET; + ionic_lif_deferred_enqueue(&lif->deferred, work); + } break; default: netdev_warn(netdev, "Notifyq unknown event ecode=%d eid=%lld\n", @@ -831,7 +853,7 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr) memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN); err = ionic_adminq_post_wait(lif, &ctx); - if (err) + if (err && err != -EEXIST) return err; return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx); @@ -861,7 +883,7 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr) spin_unlock_bh(&lif->rx_filters.lock); err = ionic_adminq_post_wait(lif, &ctx); - if (err) + if (err && err != -EEXIST) return err; netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n", addr, @@ -948,18 +970,18 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode) int i; #define REMAIN(__x) (sizeof(buf) - (__x)) - i = snprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:", - lif->rx_mode, rx_mode); + i = scnprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:", + lif->rx_mode, rx_mode); if (rx_mode & IONIC_RX_MODE_F_UNICAST) - i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST"); + i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST"); if (rx_mode & IONIC_RX_MODE_F_MULTICAST) - i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST"); + i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST"); if (rx_mode & IONIC_RX_MODE_F_BROADCAST) - i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST"); + i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST"); if (rx_mode & IONIC_RX_MODE_F_PROMISC) - i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC"); + i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC"); if (rx_mode & IONIC_RX_MODE_F_ALLMULTI) - i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI"); + i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI"); netdev_dbg(lif->netdev, "lif%d %s\n", lif->index, buf); err = ionic_adminq_post_wait(lif, &ctx); @@ -1093,6 +1115,7 @@ static int ionic_set_nic_features(struct ionic_lif *lif, u64 vlan_flags = IONIC_ETH_HW_VLAN_TX_TAG | IONIC_ETH_HW_VLAN_RX_STRIP | IONIC_ETH_HW_VLAN_RX_FILTER; + u64 old_hw_features; int err; ctx.cmd.lif_setattr.features = ionic_netdev_features_to_nic(features); @@ -1100,9 +1123,13 @@ static int ionic_set_nic_features(struct ionic_lif *lif, if (err) return err; + old_hw_features = lif->hw_features; lif->hw_features = le64_to_cpu(ctx.cmd.lif_setattr.features & ctx.comp.lif_setattr.features); + if ((old_hw_features ^ lif->hw_features) & IONIC_ETH_HW_RX_HASH) + ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL); + if ((vlan_flags & features) && !(vlan_flags & le64_to_cpu(ctx.comp.lif_setattr.features))) dev_info_once(lif->ionic->dev, "NIC is not supporting vlan offload, likely in SmartNIC mode\n"); @@ -1149,6 +1176,10 @@ static int ionic_init_nic_features(struct ionic_lif *lif) netdev_features_t features; int err; + /* no netdev features on the management device */ + if (lif->ionic->is_mgmt_nic) + return 0; + /* set up what we expect to support by default */ features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | @@ -1205,7 +1236,8 @@ static int ionic_init_nic_features(struct ionic_lif *lif) netdev->hw_features |= netdev->hw_enc_features; netdev->features |= netdev->hw_features; - netdev->priv_flags |= IFF_UNICAST_FLT; + netdev->priv_flags |= IFF_UNICAST_FLT | + IFF_LIVE_ADDR_CHANGE; return 0; } @@ -1356,13 +1388,15 @@ int ionic_lif_rss_config(struct ionic_lif *lif, const u16 types, .cmd.lif_setattr = { .opcode = IONIC_CMD_LIF_SETATTR, .attr = IONIC_LIF_ATTR_RSS, - .rss.types = cpu_to_le16(types), .rss.addr = cpu_to_le64(lif->rss_ind_tbl_pa), }, }; unsigned int i, tbl_sz; - lif->rss_types = types; + if (lif->hw_features & IONIC_ETH_HW_RX_HASH) { + lif->rss_types = types; + ctx.cmd.lif_setattr.rss.types = cpu_to_le16(types); + } if (key) memcpy(lif->rss_hash_key, key, IONIC_RSS_HASH_KEY_SIZE); @@ -1413,10 +1447,22 @@ static void ionic_lif_rss_deinit(struct ionic_lif *lif) static void ionic_txrx_disable(struct ionic_lif *lif) { unsigned int i; + int err; - for (i = 0; i < lif->nxqs; i++) { - ionic_qcq_disable(lif->txqcqs[i].qcq); - ionic_qcq_disable(lif->rxqcqs[i].qcq); + if (lif->txqcqs) { + for (i = 0; i < lif->nxqs; i++) { + err = ionic_qcq_disable(lif->txqcqs[i].qcq); + if (err == -ETIMEDOUT) + break; + } + } + + if (lif->rxqcqs) { + for (i = 0; i < lif->nxqs; i++) { + err = ionic_qcq_disable(lif->rxqcqs[i].qcq); + if (err == -ETIMEDOUT) + break; + } } } @@ -1424,26 +1470,40 @@ static void ionic_txrx_deinit(struct ionic_lif *lif) { unsigned int i; - for (i = 0; i < lif->nxqs; i++) { - ionic_lif_qcq_deinit(lif, lif->txqcqs[i].qcq); - ionic_tx_flush(&lif->txqcqs[i].qcq->cq); + if (lif->txqcqs) { + for (i = 0; i < lif->nxqs; i++) { + ionic_lif_qcq_deinit(lif, lif->txqcqs[i].qcq); + ionic_tx_flush(&lif->txqcqs[i].qcq->cq); + ionic_tx_empty(&lif->txqcqs[i].qcq->q); + } + } - ionic_lif_qcq_deinit(lif, lif->rxqcqs[i].qcq); - ionic_rx_flush(&lif->rxqcqs[i].qcq->cq); - ionic_rx_empty(&lif->rxqcqs[i].qcq->q); + if (lif->rxqcqs) { + for (i = 0; i < lif->nxqs; i++) { + ionic_lif_qcq_deinit(lif, lif->rxqcqs[i].qcq); + ionic_rx_flush(&lif->rxqcqs[i].qcq->cq); + ionic_rx_empty(&lif->rxqcqs[i].qcq->q); + } } + lif->rx_mode = 0; } static void ionic_txrx_free(struct ionic_lif *lif) { unsigned int i; - for (i = 0; i < lif->nxqs; i++) { - ionic_qcq_free(lif, lif->txqcqs[i].qcq); - lif->txqcqs[i].qcq = NULL; + if (lif->txqcqs) { + for (i = 0; i < lif->nxqs; i++) { + ionic_qcq_free(lif, lif->txqcqs[i].qcq); + lif->txqcqs[i].qcq = NULL; + } + } - ionic_qcq_free(lif, lif->rxqcqs[i].qcq); - lif->rxqcqs[i].qcq = NULL; + if (lif->rxqcqs) { + for (i = 0; i < lif->nxqs; i++) { + ionic_qcq_free(lif, lif->rxqcqs[i].qcq); + lif->rxqcqs[i].qcq = NULL; + } } } @@ -1465,6 +1525,7 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) goto err_out; lif->txqcqs[i].qcq->stats = lif->txqcqs[i].stats; + ionic_debugfs_add_qcq(lif, lif->txqcqs[i].qcq); } flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG | IONIC_QCQ_F_INTR; @@ -1485,6 +1546,7 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) lif->rx_coalesce_hw); ionic_link_qcq_interrupts(lif->rxqcqs[i].qcq, lif->txqcqs[i].qcq); + ionic_debugfs_add_qcq(lif, lif->rxqcqs[i].qcq); } return 0; @@ -1533,14 +1595,15 @@ static int ionic_txrx_enable(struct ionic_lif *lif) int i, err; for (i = 0; i < lif->nxqs; i++) { - err = ionic_qcq_enable(lif->txqcqs[i].qcq); + ionic_rx_fill(&lif->rxqcqs[i].qcq->q); + err = ionic_qcq_enable(lif->rxqcqs[i].qcq); if (err) goto err_out; - ionic_rx_fill(&lif->rxqcqs[i].qcq->q); - err = ionic_qcq_enable(lif->rxqcqs[i].qcq); + err = ionic_qcq_enable(lif->txqcqs[i].qcq); if (err) { - ionic_qcq_disable(lif->txqcqs[i].qcq); + if (err != -ETIMEDOUT) + ionic_qcq_disable(lif->rxqcqs[i].qcq); goto err_out; } } @@ -1549,74 +1612,84 @@ static int ionic_txrx_enable(struct ionic_lif *lif) err_out: while (i--) { - ionic_qcq_disable(lif->rxqcqs[i].qcq); - ionic_qcq_disable(lif->txqcqs[i].qcq); + err = ionic_qcq_disable(lif->txqcqs[i].qcq); + if (err == -ETIMEDOUT) + break; + err = ionic_qcq_disable(lif->rxqcqs[i].qcq); + if (err == -ETIMEDOUT) + break; } return err; } +static int ionic_start_queues(struct ionic_lif *lif) +{ + int err; + + if (test_and_set_bit(IONIC_LIF_F_UP, lif->state)) + return 0; + + err = ionic_txrx_enable(lif); + if (err) { + clear_bit(IONIC_LIF_F_UP, lif->state); + return err; + } + netif_tx_wake_all_queues(lif->netdev); + + return 0; +} + int ionic_open(struct net_device *netdev) { struct ionic_lif *lif = netdev_priv(netdev); int err; - netif_carrier_off(netdev); - err = ionic_txrx_alloc(lif); if (err) return err; err = ionic_txrx_init(lif); if (err) - goto err_txrx_free; - - err = ionic_txrx_enable(lif); - if (err) - goto err_txrx_deinit; - - netif_set_real_num_tx_queues(netdev, lif->nxqs); - netif_set_real_num_rx_queues(netdev, lif->nxqs); - - set_bit(IONIC_LIF_UP, lif->state); + goto err_out; - ionic_link_status_check_request(lif); - if (netif_carrier_ok(netdev)) - netif_tx_wake_all_queues(netdev); + /* don't start the queues until we have link */ + if (netif_carrier_ok(netdev)) { + err = ionic_start_queues(lif); + if (err) + goto err_txrx_deinit; + } return 0; err_txrx_deinit: ionic_txrx_deinit(lif); -err_txrx_free: +err_out: ionic_txrx_free(lif); return err; } +static void ionic_stop_queues(struct ionic_lif *lif) +{ + if (!test_and_clear_bit(IONIC_LIF_F_UP, lif->state)) + return; + + ionic_txrx_disable(lif); + netif_tx_disable(lif->netdev); +} + int ionic_stop(struct net_device *netdev) { struct ionic_lif *lif = netdev_priv(netdev); - int err = 0; - if (!test_bit(IONIC_LIF_UP, lif->state)) { - dev_dbg(lif->ionic->dev, "%s: %s state=DOWN\n", - __func__, lif->name); + if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) return 0; - } - dev_dbg(lif->ionic->dev, "%s: %s state=UP\n", __func__, lif->name); - clear_bit(IONIC_LIF_UP, lif->state); - /* carrier off before disabling queues to avoid watchdog timeout */ - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - netif_tx_disable(netdev); - - ionic_txrx_disable(lif); - ionic_lif_quiesce(lif); + ionic_stop_queues(lif); ionic_txrx_deinit(lif); ionic_txrx_free(lif); - return err; + return 0; } static int ionic_get_vf_config(struct net_device *netdev, @@ -1688,7 +1761,7 @@ static int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) if (!(is_zero_ether_addr(mac) || is_valid_ether_addr(mac))) return -EINVAL; - down_read(&ionic->vf_op_lock); + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { ret = -EINVAL; @@ -1698,7 +1771,7 @@ static int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) ether_addr_copy(ionic->vfs[vf].macaddr, mac); } - up_read(&ionic->vf_op_lock); + up_write(&ionic->vf_op_lock); return ret; } @@ -1719,7 +1792,7 @@ static int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, if (proto != htons(ETH_P_8021Q)) return -EPROTONOSUPPORT; - down_read(&ionic->vf_op_lock); + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { ret = -EINVAL; @@ -1730,7 +1803,7 @@ static int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, ionic->vfs[vf].vlanid = vlan; } - up_read(&ionic->vf_op_lock); + up_write(&ionic->vf_op_lock); return ret; } @@ -1871,7 +1944,7 @@ int ionic_reset_queues(struct ionic_lif *lif) /* Put off the next watchdog timeout */ netif_trans_update(lif->netdev); - err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET); + err = ionic_wait_for_bit(lif, IONIC_LIF_F_QUEUE_RESET); if (err) return err; @@ -1881,7 +1954,7 @@ int ionic_reset_queues(struct ionic_lif *lif) if (!err && running) ionic_open(lif->netdev); - clear_bit(IONIC_LIF_QUEUE_RESET, lif->state); + clear_bit(IONIC_LIF_F_QUEUE_RESET, lif->state); return err; } @@ -1910,6 +1983,8 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index ionic_ethtool_set_ops(netdev); netdev->watchdog_timeo = 2 * HZ; + netif_carrier_off(netdev); + netdev->min_mtu = IONIC_MIN_MTU; netdev->max_mtu = IONIC_MAX_MTU; @@ -1944,6 +2019,8 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index goto err_out_free_netdev; } + ionic_debugfs_add_lif(lif); + /* allocate queues */ err = ionic_qcqs_alloc(lif); if (err) @@ -2003,6 +2080,85 @@ static void ionic_lif_reset(struct ionic_lif *lif) mutex_unlock(&lif->ionic->dev_cmd_lock); } +static void ionic_lif_handle_fw_down(struct ionic_lif *lif) +{ + struct ionic *ionic = lif->ionic; + + if (test_and_set_bit(IONIC_LIF_F_FW_RESET, lif->state)) + return; + + dev_info(ionic->dev, "FW Down: Stopping LIFs\n"); + + netif_device_detach(lif->netdev); + + if (test_bit(IONIC_LIF_F_UP, lif->state)) { + dev_info(ionic->dev, "Surprise FW stop, stopping queues\n"); + ionic_stop_queues(lif); + } + + if (netif_running(lif->netdev)) { + ionic_txrx_deinit(lif); + ionic_txrx_free(lif); + } + ionic_lifs_deinit(ionic); + ionic_reset(ionic); + ionic_qcqs_free(lif); + + dev_info(ionic->dev, "FW Down: LIFs stopped\n"); +} + +static void ionic_lif_handle_fw_up(struct ionic_lif *lif) +{ + struct ionic *ionic = lif->ionic; + int err; + + if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) + return; + + dev_info(ionic->dev, "FW Up: restarting LIFs\n"); + + ionic_init_devinfo(ionic); + ionic_port_init(ionic); + err = ionic_qcqs_alloc(lif); + if (err) + goto err_out; + + err = ionic_lifs_init(ionic); + if (err) + goto err_qcqs_free; + + if (lif->registered) + ionic_lif_set_netdev_info(lif); + + ionic_rx_filter_replay(lif); + + if (netif_running(lif->netdev)) { + err = ionic_txrx_alloc(lif); + if (err) + goto err_lifs_deinit; + + err = ionic_txrx_init(lif); + if (err) + goto err_txrx_free; + } + + clear_bit(IONIC_LIF_F_FW_RESET, lif->state); + ionic_link_status_check_request(lif); + netif_device_attach(lif->netdev); + dev_info(ionic->dev, "FW Up: LIFs restarted\n"); + + return; + +err_txrx_free: + ionic_txrx_free(lif); +err_lifs_deinit: + ionic_lifs_deinit(ionic); +err_qcqs_free: + ionic_qcqs_free(lif); +err_out: + dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err); +} + static void ionic_lif_free(struct ionic_lif *lif) { struct device *dev = lif->ionic->dev; @@ -2015,7 +2171,8 @@ static void ionic_lif_free(struct ionic_lif *lif) /* free queues */ ionic_qcqs_free(lif); - ionic_lif_reset(lif); + if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) + ionic_lif_reset(lif); /* free lif info */ dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa); @@ -2048,13 +2205,17 @@ void ionic_lifs_free(struct ionic *ionic) static void ionic_lif_deinit(struct ionic_lif *lif) { - if (!test_bit(IONIC_LIF_INITED, lif->state)) + if (!test_and_clear_bit(IONIC_LIF_F_INITED, lif->state)) return; - clear_bit(IONIC_LIF_INITED, lif->state); + if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) { + cancel_work_sync(&lif->deferred.work); + cancel_work_sync(&lif->tx_timeout_work); + ionic_rx_filters_deinit(lif); + } - ionic_rx_filters_deinit(lif); - ionic_lif_rss_deinit(lif); + if (lif->netdev->features & NETIF_F_RXHASH) + ionic_lif_rss_deinit(lif); napi_disable(&lif->adminqcq->napi); ionic_lif_qcq_deinit(lif, lif->notifyqcq); @@ -2107,13 +2268,6 @@ static int ionic_lif_adminq_init(struct ionic_lif *lif) netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi, NAPI_POLL_WEIGHT); - err = ionic_request_irq(lif, qcq); - if (err) { - netdev_warn(lif->netdev, "adminq irq request failed %d\n", err); - netif_napi_del(&qcq->napi); - return err; - } - napi_enable(&qcq->napi); if (qcq->flags & IONIC_QCQ_F_INTR) @@ -2122,8 +2276,6 @@ static int ionic_lif_adminq_init(struct ionic_lif *lif) qcq->flags |= IONIC_QCQ_F_INITED; - ionic_debugfs_add_qcq(lif, qcq); - return 0; } @@ -2159,6 +2311,7 @@ static int ionic_lif_notifyq_init(struct ionic_lif *lif) if (err) return err; + lif->last_eid = 0; q->hw_type = ctx.comp.q_init.hw_type; q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index); q->dbval = IONIC_DBELL_QID(q->hw_index); @@ -2171,8 +2324,6 @@ static int ionic_lif_notifyq_init(struct ionic_lif *lif) qcq->flags |= IONIC_QCQ_F_INITED; - ionic_debugfs_add_qcq(lif, qcq); - return 0; } @@ -2193,24 +2344,34 @@ static int ionic_station_set(struct ionic_lif *lif) err = ionic_adminq_post_wait(lif, &ctx); if (err) return err; - + netdev_dbg(lif->netdev, "found initial MAC addr %pM\n", + ctx.comp.lif_getattr.mac); if (is_zero_ether_addr(ctx.comp.lif_getattr.mac)) return 0; - memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len); - addr.sa_family = AF_INET; - err = eth_prepare_mac_addr_change(netdev, &addr); - if (err) { - netdev_warn(lif->netdev, "ignoring bad MAC addr from NIC %pM\n", - addr.sa_data); - return 0; - } + if (!is_zero_ether_addr(netdev->dev_addr)) { + /* If the netdev mac is non-zero and doesn't match the default + * device address, it was set by something earlier and we're + * likely here again after a fw-upgrade reset. We need to be + * sure the netdev mac is in our filter list. + */ + if (!ether_addr_equal(ctx.comp.lif_getattr.mac, + netdev->dev_addr)) + ionic_lif_addr(lif, netdev->dev_addr, true); + } else { + /* Update the netdev mac with the device's mac */ + memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len); + addr.sa_family = AF_INET; + err = eth_prepare_mac_addr_change(netdev, &addr); + if (err) { + netdev_warn(lif->netdev, "ignoring bad MAC addr from NIC %pM - err %d\n", + addr.sa_data, err); + return 0; + } - netdev_dbg(lif->netdev, "deleting station MAC addr %pM\n", - netdev->dev_addr); - ionic_lif_addr(lif, netdev->dev_addr, false); + eth_commit_mac_addr_change(netdev, &addr); + } - eth_commit_mac_addr_change(netdev, &addr); netdev_dbg(lif->netdev, "adding station MAC addr %pM\n", netdev->dev_addr); ionic_lif_addr(lif, netdev->dev_addr, true); @@ -2226,8 +2387,6 @@ static int ionic_lif_init(struct ionic_lif *lif) int dbpage_num; int err; - ionic_debugfs_add_lif(lif); - mutex_lock(&lif->ionic->dev_cmd_lock); ionic_dev_cmd_lif_init(idev, lif->index, lif->info_pa); err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT); @@ -2277,9 +2436,11 @@ static int ionic_lif_init(struct ionic_lif *lif) if (err) goto err_out_notifyq_deinit; - err = ionic_rx_filters_init(lif); - if (err) - goto err_out_notifyq_deinit; + if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) { + err = ionic_rx_filters_init(lif); + if (err) + goto err_out_notifyq_deinit; + } err = ionic_station_set(lif); if (err) @@ -2287,7 +2448,7 @@ static int ionic_lif_init(struct ionic_lif *lif) lif->rx_copybreak = IONIC_RX_COPYBREAK_DEFAULT; - set_bit(IONIC_LIF_INITED, lif->state); + set_bit(IONIC_LIF_F_INITED, lif->state); INIT_WORK(&lif->tx_timeout_work, ionic_tx_timeout_work); @@ -2375,6 +2536,12 @@ int ionic_lifs_register(struct ionic *ionic) { int err; + /* the netdev is not registered on the management device, it is + * only used as a vehicle for napi operations on the adminq + */ + if (ionic->is_mgmt_nic) + return 0; + INIT_WORK(&ionic->nb_work, ionic_lif_notify_work); ionic->nb.notifier_call = ionic_lif_notify; @@ -2389,8 +2556,6 @@ int ionic_lifs_register(struct ionic *ionic) dev_err(ionic->dev, "Cannot register net device, aborting\n"); return err; } - - ionic_link_status_check_request(ionic->master_lif); ionic->master_lif->registered = true; return 0; @@ -2408,9 +2573,8 @@ void ionic_lifs_unregister(struct ionic *ionic) * current model, so don't bother searching the * ionic->lif for candidates to unregister */ - cancel_work_sync(&ionic->master_lif->deferred.work); - cancel_work_sync(&ionic->master_lif->tx_timeout_work); - if (ionic->master_lif->netdev->reg_state == NETREG_REGISTERED) + if (ionic->master_lif && + ionic->master_lif->netdev->reg_state == NETREG_REGISTERED) unregister_netdev(ionic->master_lif->netdev); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 9c5a7dd45f9d..5d4ffda5c05f 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -98,6 +98,7 @@ struct ionic_deferred_work { union { unsigned int rx_mode; u8 addr[ETH_ALEN]; + u8 fw_status; }; }; @@ -121,14 +122,15 @@ struct ionic_lif_sw_stats { }; enum ionic_lif_state_flags { - IONIC_LIF_INITED, - IONIC_LIF_SW_DEBUG_STATS, - IONIC_LIF_UP, - IONIC_LIF_LINK_CHECK_REQUESTED, - IONIC_LIF_QUEUE_RESET, + IONIC_LIF_F_INITED, + IONIC_LIF_F_SW_DEBUG_STATS, + IONIC_LIF_F_UP, + IONIC_LIF_F_LINK_CHECK_REQUESTED, + IONIC_LIF_F_QUEUE_RESET, + IONIC_LIF_F_FW_RESET, /* leave this as last */ - IONIC_LIF_STATE_SIZE + IONIC_LIF_F_STATE_SIZE }; #define IONIC_LIF_NAME_MAX_SZ 32 @@ -136,7 +138,7 @@ struct ionic_lif { char name[IONIC_LIF_NAME_MAX_SZ]; struct list_head list; struct net_device *netdev; - DECLARE_BITMAP(state, IONIC_LIF_STATE_SIZE); + DECLARE_BITMAP(state, IONIC_LIF_F_STATE_SIZE); struct ionic *ionic; bool registered; unsigned int index; @@ -179,7 +181,6 @@ struct ionic_lif { u32 rx_coalesce_usecs; /* what the user asked for */ u32 rx_coalesce_hw; /* what the hw is using */ - u32 flags; struct work_struct tx_timeout_work; }; @@ -225,6 +226,9 @@ static inline u32 ionic_coal_hw_to_usec(struct ionic *ionic, u32 units) return (units * div) / mult; } +void ionic_link_status_check_request(struct ionic_lif *lif); +void ionic_lif_deferred_enqueue(struct ionic_deferred *def, + struct ionic_deferred_work *work); int ionic_lifs_alloc(struct ionic *ionic); void ionic_lifs_free(struct ionic *ionic); void ionic_lifs_deinit(struct ionic *ionic); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index a8e3fb73b465..3344bc1f7671 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/utsname.h> +#include <linux/vermagic.h> #include "ionic.h" #include "ionic_bus.h" @@ -15,7 +16,6 @@ MODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION); MODULE_AUTHOR("Pensando Systems, Inc"); MODULE_LICENSE("GPL"); -MODULE_VERSION(IONIC_DRV_VERSION); static const char *ionic_error_to_str(enum ionic_status_code code) { @@ -58,6 +58,8 @@ static const char *ionic_error_to_str(enum ionic_status_code code) return "IONIC_RC_BAD_ADDR"; case IONIC_RC_DEV_CMD: return "IONIC_RC_DEV_CMD"; + case IONIC_RC_ENOSUPP: + return "IONIC_RC_ENOSUPP"; case IONIC_RC_ERROR: return "IONIC_RC_ERROR"; case IONIC_RC_ERDMA: @@ -76,6 +78,7 @@ static int ionic_error_to_errno(enum ionic_status_code code) case IONIC_RC_EQTYPE: case IONIC_RC_EQID: case IONIC_RC_EINVAL: + case IONIC_RC_ENOSUPP: return -EINVAL; case IONIC_RC_EPERM: return -EPERM; @@ -240,11 +243,16 @@ static void ionic_adminq_cb(struct ionic_queue *q, static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) { - struct ionic_queue *adminq = &lif->adminqcq->q; + struct ionic_queue *adminq; int err = 0; WARN_ON(in_interrupt()); + if (!lif->adminqcq) + return -EIO; + + adminq = &lif->adminqcq->q; + spin_lock(&lif->adminq_lock); if (!ionic_q_has_space(adminq, 1)) { err = -ENOSPC; @@ -278,9 +286,11 @@ int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) err = ionic_adminq_post(lif, ctx); if (err) { - name = ionic_opcode_to_str(ctx->cmd.cmd.opcode); - netdev_err(netdev, "Posting of %s (%d) failed: %d\n", - name, ctx->cmd.cmd.opcode, err); + if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) { + name = ionic_opcode_to_str(ctx->cmd.cmd.opcode); + netdev_err(netdev, "Posting of %s (%d) failed: %d\n", + name, ctx->cmd.cmd.opcode, err); + } return err; } @@ -357,7 +367,10 @@ try_again: done, duration / HZ, duration); if (!done && hb) { - ionic_dev_cmd_clean(ionic); + /* It is possible (but unlikely) that FW was busy and missed a + * heartbeat check but is still alive and will process this + * request, so don't clean the dev_cmd in this case. + */ dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n", ionic_opcode_to_str(opcode), opcode); return -ENXIO; @@ -414,7 +427,7 @@ int ionic_identify(struct ionic *ionic) memset(ident, 0, sizeof(*ident)); ident->drv.os_type = cpu_to_le32(IONIC_OS_TYPE_LINUX); - strncpy(ident->drv.driver_ver_str, IONIC_DRV_VERSION, + strncpy(ident->drv.driver_ver_str, UTS_RELEASE, sizeof(ident->drv.driver_ver_str) - 1); mutex_lock(&ionic->dev_cmd_lock); @@ -496,16 +509,16 @@ int ionic_port_init(struct ionic *ionic) size_t sz; int err; - if (idev->port_info) - return 0; - - idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE); - idev->port_info = dma_alloc_coherent(ionic->dev, idev->port_info_sz, - &idev->port_info_pa, - GFP_KERNEL); if (!idev->port_info) { - dev_err(ionic->dev, "Failed to allocate port info, aborting\n"); - return -ENOMEM; + idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE); + idev->port_info = dma_alloc_coherent(ionic->dev, + idev->port_info_sz, + &idev->port_info_pa, + GFP_KERNEL); + if (!idev->port_info) { + dev_err(ionic->dev, "Failed to allocate port info\n"); + return -ENOMEM; + } } sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data)); @@ -558,8 +571,6 @@ int ionic_port_reset(struct ionic *ionic) static int __init ionic_init_module(void) { - pr_info("%s %s, ver %s\n", - IONIC_DRV_NAME, IONIC_DRV_DESCRIPTION, IONIC_DRV_VERSION); ionic_debugfs_create(); return ionic_bus_register_driver(); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_regs.h b/drivers/net/ethernet/pensando/ionic/ionic_regs.h index 03ee5a36472b..2e174f45c030 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_regs.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_regs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB OR BSD-2-Clause */ +/* SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) OR BSD-2-Clause */ /* Copyright (c) 2018-2019 Pensando Systems, Inc. All rights reserved. */ #ifndef IONIC_REGS_H diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c index 7a093f148ee5..80eeb7696e01 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c @@ -2,6 +2,7 @@ /* Copyright(c) 2017 - 2019 Pensando Systems, Inc */ #include <linux/netdevice.h> +#include <linux/dynamic_debug.h> #include <linux/etherdevice.h> #include "ionic.h" @@ -17,17 +18,49 @@ void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f) devm_kfree(dev, f); } -int ionic_rx_filter_del(struct ionic_lif *lif, struct ionic_rx_filter *f) +void ionic_rx_filter_replay(struct ionic_lif *lif) { - struct ionic_admin_ctx ctx = { - .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work), - .cmd.rx_filter_del = { - .opcode = IONIC_CMD_RX_FILTER_DEL, - .filter_id = cpu_to_le32(f->filter_id), - }, - }; - - return ionic_adminq_post_wait(lif, &ctx); + struct ionic_rx_filter_add_cmd *ac; + struct ionic_admin_ctx ctx; + struct ionic_rx_filter *f; + struct hlist_head *head; + struct hlist_node *tmp; + unsigned int i; + int err; + + ac = &ctx.cmd.rx_filter_add; + + for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { + head = &lif->rx_filters.by_id[i]; + hlist_for_each_entry_safe(f, tmp, head, by_id) { + ctx.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work); + memcpy(ac, &f->cmd, sizeof(f->cmd)); + dev_dbg(&lif->netdev->dev, "replay filter command:\n"); + dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1, + &ctx.cmd, sizeof(ctx.cmd), true); + + err = ionic_adminq_post_wait(lif, &ctx); + if (err) { + switch (le16_to_cpu(ac->match)) { + case IONIC_RX_FILTER_MATCH_VLAN: + netdev_info(lif->netdev, "Replay failed - %d: vlan %d\n", + err, + le16_to_cpu(ac->vlan.vlan)); + break; + case IONIC_RX_FILTER_MATCH_MAC: + netdev_info(lif->netdev, "Replay failed - %d: mac %pM\n", + err, ac->mac.addr); + break; + case IONIC_RX_FILTER_MATCH_MAC_VLAN: + netdev_info(lif->netdev, "Replay failed - %d: vlan %d mac %pM\n", + err, + le16_to_cpu(ac->vlan.vlan), + ac->mac.addr); + break; + } + } + } + } } int ionic_rx_filters_init(struct ionic_lif *lif) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h index b6aec9c19918..cf8f4c0a961c 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h @@ -24,7 +24,7 @@ struct ionic_rx_filters { }; void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f); -int ionic_rx_filter_del(struct ionic_lif *lif, struct ionic_rx_filter *f); +void ionic_rx_filter_replay(struct ionic_lif *lif); int ionic_rx_filters_init(struct ionic_lif *lif); void ionic_rx_filters_deinit(struct ionic_lif *lif); int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c index a1e9796a660a..8f2a8fb029f1 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c @@ -118,8 +118,8 @@ static u64 ionic_sw_stats_get_count(struct ionic_lif *lif) /* rx stats */ total += MAX_Q(lif) * IONIC_NUM_RX_STATS; - if (test_bit(IONIC_LIF_UP, lif->state) && - test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_F_UP, lif->state) && + test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state)) { /* tx debug stats */ total += MAX_Q(lif) * (IONIC_NUM_DBG_CQ_STATS + IONIC_NUM_TX_Q_STATS + @@ -151,8 +151,8 @@ static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf) *buf += ETH_GSTRING_LEN; } - if (test_bit(IONIC_LIF_UP, lif->state) && - test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_F_UP, lif->state) && + test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state)) { for (i = 0; i < IONIC_NUM_TX_Q_STATS; i++) { snprintf(*buf, ETH_GSTRING_LEN, "txq_%d_%s", @@ -190,8 +190,8 @@ static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf) *buf += ETH_GSTRING_LEN; } - if (test_bit(IONIC_LIF_UP, lif->state) && - test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_F_UP, lif->state) && + test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state)) { for (i = 0; i < IONIC_NUM_DBG_CQ_STATS; i++) { snprintf(*buf, ETH_GSTRING_LEN, "rxq_%d_cq_%s", @@ -247,8 +247,8 @@ static void ionic_sw_stats_get_values(struct ionic_lif *lif, u64 **buf) (*buf)++; } - if (test_bit(IONIC_LIF_UP, lif->state) && - test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_F_UP, lif->state) && + test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state)) { txqcq = lif_to_txqcq(lif, q_num); for (i = 0; i < IONIC_NUM_TX_Q_STATS; i++) { **buf = IONIC_READ_STAT64(&txqcq->q, @@ -281,8 +281,8 @@ static void ionic_sw_stats_get_values(struct ionic_lif *lif, u64 **buf) (*buf)++; } - if (test_bit(IONIC_LIF_UP, lif->state) && - test_bit(IONIC_LIF_SW_DEBUG_STATS, lif->state)) { + if (test_bit(IONIC_LIF_F_UP, lif->state) && + test_bit(IONIC_LIF_F_SW_DEBUG_STATS, lif->state)) { rxqcq = lif_to_rxqcq(lif, q_num); for (i = 0; i < IONIC_NUM_DBG_CQ_STATS; i++) { **buf = IONIC_READ_STAT64(&rxqcq->cq, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index e452f4242ba0..d233b6e77b1e 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -158,7 +158,7 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i } /* no packet processing while resetting */ - if (unlikely(test_bit(IONIC_LIF_QUEUE_RESET, q->lif->state))) { + if (unlikely(test_bit(IONIC_LIF_F_QUEUE_RESET, q->lif->state))) { stats->dropped++; return; } @@ -593,6 +593,22 @@ void ionic_tx_flush(struct ionic_cq *cq) work_done, 0); } +void ionic_tx_empty(struct ionic_queue *q) +{ + struct ionic_desc_info *desc_info; + int done = 0; + + /* walk the not completed tx entries, if any */ + while (q->head != q->tail) { + desc_info = q->tail; + q->tail = desc_info->next; + ionic_tx_clean(q, desc_info, NULL, desc_info->cb_arg); + desc_info->cb = NULL; + desc_info->cb_arg = NULL; + done++; + } +} + static int ionic_tx_tcp_inner_pseudo_csum(struct sk_buff *skb) { int err; @@ -632,10 +648,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; @@ -1026,7 +1039,7 @@ netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev) int ndescs; int err; - if (unlikely(!test_bit(IONIC_LIF_UP, lif->state))) { + if (unlikely(!test_bit(IONIC_LIF_F_UP, lif->state))) { dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.h b/drivers/net/ethernet/pensando/ionic/ionic_txrx.h index 53775c62c85a..71973e3c35a6 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.h @@ -9,6 +9,7 @@ void ionic_tx_flush(struct ionic_cq *cq); void ionic_rx_fill(struct ionic_queue *q); void ionic_rx_empty(struct ionic_queue *q); +void ionic_tx_empty(struct ionic_queue *q); int ionic_rx_napi(struct napi_struct *napi, int budget); netdev_tx_t ionic_start_xmit(struct sk_buff *skb, struct net_device *netdev); |