diff options
Diffstat (limited to 'drivers/net/ethernet/pensando')
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic.h | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c | 113 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_dev.c | 58 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_dev.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_if.h | 99 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_lif.c | 249 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_lif.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_main.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_stats.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 23 |
10 files changed, 558 insertions, 20 deletions
diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h index 98e102af7756..bb106a32f416 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic.h +++ b/drivers/net/ethernet/pensando/ionic/ionic.h @@ -12,19 +12,27 @@ struct ionic_lif; #define IONIC_DRV_NAME "ionic" #define IONIC_DRV_DESCRIPTION "Pensando Ethernet NIC Driver" -#define IONIC_DRV_VERSION "0.18.0-k" +#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 IONIC_SUBDEV_ID_NAPLES_25 0x4000 -#define IONIC_SUBDEV_ID_NAPLES_100_4 0x4001 -#define IONIC_SUBDEV_ID_NAPLES_100_8 0x4002 - #define DEVCMD_TIMEOUT 10 +struct ionic_vf { + u16 index; + u8 macaddr[6]; + __le32 maxrate; + __le16 vlanid; + u8 spoofchk; + u8 trusted; + u8 linkstate; + dma_addr_t stats_pa; + struct ionic_lif_stats stats; +}; + struct ionic { struct pci_dev *pdev; struct device *dev; @@ -46,6 +54,9 @@ struct ionic { DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX); struct work_struct nb_work; struct notifier_block nb; + struct rw_semaphore vf_op_lock; /* lock for VF operations */ + struct ionic_vf *vfs; + int num_vfs; struct timer_list watchdog_timer; int watchdog_period; }; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c index 9a9ab8cb2cb3..448d7b23b2f7 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c @@ -104,10 +104,112 @@ void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page) iounmap(page); } +static void ionic_vf_dealloc_locked(struct ionic *ionic) +{ + struct ionic_vf *v; + dma_addr_t dma = 0; + int i; + + if (!ionic->vfs) + return; + + for (i = ionic->num_vfs - 1; i >= 0; i--) { + v = &ionic->vfs[i]; + + if (v->stats_pa) { + (void)ionic_set_vf_config(ionic, i, + IONIC_VF_ATTR_STATSADDR, + (u8 *)&dma); + dma_unmap_single(ionic->dev, v->stats_pa, + sizeof(v->stats), DMA_FROM_DEVICE); + v->stats_pa = 0; + } + } + + kfree(ionic->vfs); + ionic->vfs = NULL; + ionic->num_vfs = 0; +} + +static void ionic_vf_dealloc(struct ionic *ionic) +{ + down_write(&ionic->vf_op_lock); + ionic_vf_dealloc_locked(ionic); + up_write(&ionic->vf_op_lock); +} + +static int ionic_vf_alloc(struct ionic *ionic, int num_vfs) +{ + struct ionic_vf *v; + int err = 0; + int i; + + down_write(&ionic->vf_op_lock); + + ionic->vfs = kcalloc(num_vfs, sizeof(struct ionic_vf), GFP_KERNEL); + if (!ionic->vfs) { + err = -ENOMEM; + goto out; + } + + for (i = 0; i < num_vfs; i++) { + v = &ionic->vfs[i]; + v->stats_pa = dma_map_single(ionic->dev, &v->stats, + sizeof(v->stats), DMA_FROM_DEVICE); + if (dma_mapping_error(ionic->dev, v->stats_pa)) { + v->stats_pa = 0; + err = -ENODEV; + goto out; + } + + /* ignore failures from older FW, we just won't get stats */ + (void)ionic_set_vf_config(ionic, i, IONIC_VF_ATTR_STATSADDR, + (u8 *)&v->stats_pa); + ionic->num_vfs++; + } + +out: + if (err) + ionic_vf_dealloc_locked(ionic); + up_write(&ionic->vf_op_lock); + return err; +} + +static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + struct ionic *ionic = pci_get_drvdata(pdev); + struct device *dev = ionic->dev; + int ret = 0; + + if (num_vfs > 0) { + ret = pci_enable_sriov(pdev, num_vfs); + if (ret) { + dev_err(dev, "Cannot enable SRIOV: %d\n", ret); + goto out; + } + + ret = ionic_vf_alloc(ionic, num_vfs); + if (ret) { + dev_err(dev, "Cannot alloc VFs: %d\n", ret); + pci_disable_sriov(pdev); + goto out; + } + + ret = num_vfs; + } else { + pci_disable_sriov(pdev); + ionic_vf_dealloc(ionic); + } + +out: + return ret; +} + static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct device *dev = &pdev->dev; struct ionic *ionic; + int num_vfs; int err; ionic = ionic_devlink_alloc(dev); @@ -206,6 +308,15 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_lifs; } + init_rwsem(&ionic->vf_op_lock); + num_vfs = pci_num_vf(pdev); + if (num_vfs) { + dev_info(dev, "%d VFs found already enabled\n", num_vfs); + err = ionic_vf_alloc(ionic, num_vfs); + if (err) + dev_err(dev, "Cannot enable existing VFs: %d\n", err); + } + err = ionic_lifs_register(ionic); if (err) { dev_err(dev, "Cannot register LIFs: %d, aborting\n", err); @@ -223,6 +334,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_out_deregister_lifs: ionic_lifs_unregister(ionic); err_out_deinit_lifs: + ionic_vf_dealloc(ionic); ionic_lifs_deinit(ionic); err_out_free_lifs: ionic_lifs_free(ionic); @@ -279,6 +391,7 @@ static struct pci_driver ionic_driver = { .id_table = ionic_id_table, .probe = ionic_probe, .remove = ionic_remove, + .sriov_configure = ionic_sriov_configure, }; int ionic_bus_register_driver(void) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 5f9d2ec70446..87f82f36812f 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -286,6 +286,64 @@ void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type) ionic_dev_cmd_go(idev, &cmd); } +/* VF commands */ +int ionic_set_vf_config(struct ionic *ionic, int vf, u8 attr, u8 *data) +{ + union ionic_dev_cmd cmd = { + .vf_setattr.opcode = IONIC_CMD_VF_SETATTR, + .vf_setattr.attr = attr, + .vf_setattr.vf_index = vf, + }; + int err; + + switch (attr) { + case IONIC_VF_ATTR_SPOOFCHK: + cmd.vf_setattr.spoofchk = *data; + dev_dbg(ionic->dev, "%s: vf %d spoof %d\n", + __func__, vf, *data); + break; + case IONIC_VF_ATTR_TRUST: + cmd.vf_setattr.trust = *data; + dev_dbg(ionic->dev, "%s: vf %d trust %d\n", + __func__, vf, *data); + break; + case IONIC_VF_ATTR_LINKSTATE: + cmd.vf_setattr.linkstate = *data; + dev_dbg(ionic->dev, "%s: vf %d linkstate %d\n", + __func__, vf, *data); + break; + case IONIC_VF_ATTR_MAC: + ether_addr_copy(cmd.vf_setattr.macaddr, data); + dev_dbg(ionic->dev, "%s: vf %d macaddr %pM\n", + __func__, vf, data); + break; + case IONIC_VF_ATTR_VLAN: + cmd.vf_setattr.vlanid = cpu_to_le16(*(u16 *)data); + dev_dbg(ionic->dev, "%s: vf %d vlan %d\n", + __func__, vf, *(u16 *)data); + break; + case IONIC_VF_ATTR_RATE: + cmd.vf_setattr.maxrate = cpu_to_le32(*(u32 *)data); + dev_dbg(ionic->dev, "%s: vf %d maxrate %d\n", + __func__, vf, *(u32 *)data); + break; + case IONIC_VF_ATTR_STATSADDR: + cmd.vf_setattr.stats_pa = cpu_to_le64(*(u64 *)data); + dev_dbg(ionic->dev, "%s: vf %d stats_pa 0x%08llx\n", + __func__, vf, *(u64 *)data); + break; + default: + return -EINVAL; + } + + mutex_lock(&ionic->dev_cmd_lock); + ionic_dev_cmd_go(&ionic->idev, &cmd); + err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); + mutex_unlock(&ionic->dev_cmd_lock); + + return err; +} + /* LIF commands */ void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver) { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 4665c5dc5324..7838e342c4fd 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -113,6 +113,12 @@ static_assert(sizeof(struct ionic_rxq_desc) == 16); static_assert(sizeof(struct ionic_rxq_sg_desc) == 128); static_assert(sizeof(struct ionic_rxq_comp) == 16); +/* SR/IOV */ +static_assert(sizeof(struct ionic_vf_setattr_cmd) == 64); +static_assert(sizeof(struct ionic_vf_setattr_comp) == 16); +static_assert(sizeof(struct ionic_vf_getattr_cmd) == 64); +static_assert(sizeof(struct ionic_vf_getattr_comp) == 16); + struct ionic_devinfo { u8 asic_type; u8 asic_rev; @@ -275,6 +281,7 @@ void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable); void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type); void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type); +int ionic_set_vf_config(struct ionic *ionic, int vf, u8 attr, u8 *data); void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver); void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index, dma_addr_t addr); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h index 39317cdfa6cf..ce07c2931a72 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_if.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h @@ -51,6 +51,10 @@ enum ionic_cmd_opcode { IONIC_CMD_RDMA_CREATE_CQ = 52, IONIC_CMD_RDMA_CREATE_ADMINQ = 53, + /* SR/IOV commands */ + IONIC_CMD_VF_GETATTR = 60, + IONIC_CMD_VF_SETATTR = 61, + /* QoS commands */ IONIC_CMD_QOS_CLASS_IDENTIFY = 240, IONIC_CMD_QOS_CLASS_INIT = 241, @@ -862,7 +866,7 @@ struct ionic_rxq_comp { #define IONIC_RXQ_COMP_CSUM_F_VLAN 0x40 #define IONIC_RXQ_COMP_CSUM_F_CALC 0x80 u8 pkt_type_color; -#define IONIC_RXQ_COMP_PKT_TYPE_MASK 0x0f +#define IONIC_RXQ_COMP_PKT_TYPE_MASK 0x7f }; enum ionic_pkt_type { @@ -1639,6 +1643,93 @@ enum ionic_qos_sched_type { IONIC_QOS_SCHED_TYPE_DWRR = 1, /* Deficit weighted round-robin */ }; +enum ionic_vf_attr { + IONIC_VF_ATTR_SPOOFCHK = 1, + IONIC_VF_ATTR_TRUST = 2, + IONIC_VF_ATTR_MAC = 3, + IONIC_VF_ATTR_LINKSTATE = 4, + IONIC_VF_ATTR_VLAN = 5, + IONIC_VF_ATTR_RATE = 6, + IONIC_VF_ATTR_STATSADDR = 7, +}; + +/** + * VF link status + */ +enum ionic_vf_link_status { + IONIC_VF_LINK_STATUS_AUTO = 0, /* link state of the uplink */ + IONIC_VF_LINK_STATUS_UP = 1, /* link is always up */ + IONIC_VF_LINK_STATUS_DOWN = 2, /* link is always down */ +}; + +/** + * struct ionic_vf_setattr_cmd - Set VF attributes on the NIC + * @opcode: Opcode + * @index: VF index + * @attr: Attribute type (enum ionic_vf_attr) + * macaddr mac address + * vlanid vlan ID + * maxrate max Tx rate in Mbps + * spoofchk enable address spoof checking + * trust enable VF trust + * linkstate set link up or down + * stats_pa set DMA address for VF stats + */ +struct ionic_vf_setattr_cmd { + u8 opcode; + u8 attr; + __le16 vf_index; + union { + u8 macaddr[6]; + __le16 vlanid; + __le32 maxrate; + u8 spoofchk; + u8 trust; + u8 linkstate; + __le64 stats_pa; + u8 pad[60]; + }; +}; + +struct ionic_vf_setattr_comp { + u8 status; + u8 attr; + __le16 vf_index; + __le16 comp_index; + u8 rsvd[9]; + u8 color; +}; + +/** + * struct ionic_vf_getattr_cmd - Get VF attributes from the NIC + * @opcode: Opcode + * @index: VF index + * @attr: Attribute type (enum ionic_vf_attr) + */ +struct ionic_vf_getattr_cmd { + u8 opcode; + u8 attr; + __le16 vf_index; + u8 rsvd[60]; +}; + +struct ionic_vf_getattr_comp { + u8 status; + u8 attr; + __le16 vf_index; + union { + u8 macaddr[6]; + __le16 vlanid; + __le32 maxrate; + u8 spoofchk; + u8 trust; + u8 linkstate; + __le64 stats_pa; + u8 pad[11]; + }; + u8 color; +}; + /** * union ionic_qos_config - Qos configuration structure * @flags: Configuration flags @@ -2289,6 +2380,9 @@ union ionic_dev_cmd { struct ionic_port_getattr_cmd port_getattr; struct ionic_port_setattr_cmd port_setattr; + struct ionic_vf_setattr_cmd vf_setattr; + struct ionic_vf_getattr_cmd vf_getattr; + struct ionic_lif_identify_cmd lif_identify; struct ionic_lif_init_cmd lif_init; struct ionic_lif_reset_cmd lif_reset; @@ -2318,6 +2412,9 @@ union ionic_dev_cmd_comp { struct ionic_port_getattr_comp port_getattr; struct ionic_port_setattr_comp port_setattr; + struct ionic_vf_setattr_comp vf_setattr; + struct ionic_vf_getattr_comp vf_getattr; + struct ionic_lif_identify_comp lif_identify; struct ionic_lif_init_comp lif_init; ionic_lif_reset_comp lif_reset; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index ef8258713369..191271f6260d 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1285,7 +1285,7 @@ static void ionic_tx_timeout_work(struct work_struct *ws) rtnl_unlock(); } -static void ionic_tx_timeout(struct net_device *netdev) +static void ionic_tx_timeout(struct net_device *netdev, unsigned int txqueue) { struct ionic_lif *lif = netdev_priv(netdev); @@ -1619,6 +1619,227 @@ int ionic_stop(struct net_device *netdev) return err; } +static int ionic_get_vf_config(struct net_device *netdev, + int vf, struct ifla_vf_info *ivf) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + int ret = 0; + + down_read(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + ivf->vf = vf; + ivf->vlan = ionic->vfs[vf].vlanid; + ivf->qos = 0; + ivf->spoofchk = ionic->vfs[vf].spoofchk; + ivf->linkstate = ionic->vfs[vf].linkstate; + ivf->max_tx_rate = ionic->vfs[vf].maxrate; + ivf->trusted = ionic->vfs[vf].trusted; + ether_addr_copy(ivf->mac, ionic->vfs[vf].macaddr); + } + + up_read(&ionic->vf_op_lock); + return ret; +} + +static int ionic_get_vf_stats(struct net_device *netdev, int vf, + struct ifla_vf_stats *vf_stats) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + struct ionic_lif_stats *vs; + int ret = 0; + + down_read(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + memset(vf_stats, 0, sizeof(*vf_stats)); + vs = &ionic->vfs[vf].stats; + + vf_stats->rx_packets = le64_to_cpu(vs->rx_ucast_packets); + vf_stats->tx_packets = le64_to_cpu(vs->tx_ucast_packets); + vf_stats->rx_bytes = le64_to_cpu(vs->rx_ucast_bytes); + vf_stats->tx_bytes = le64_to_cpu(vs->tx_ucast_bytes); + vf_stats->broadcast = le64_to_cpu(vs->rx_bcast_packets); + vf_stats->multicast = le64_to_cpu(vs->rx_mcast_packets); + vf_stats->rx_dropped = le64_to_cpu(vs->rx_ucast_drop_packets) + + le64_to_cpu(vs->rx_mcast_drop_packets) + + le64_to_cpu(vs->rx_bcast_drop_packets); + vf_stats->tx_dropped = le64_to_cpu(vs->tx_ucast_drop_packets) + + le64_to_cpu(vs->tx_mcast_drop_packets) + + le64_to_cpu(vs->tx_bcast_drop_packets); + } + + up_read(&ionic->vf_op_lock); + return ret; +} + +static int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + int ret; + + if (!(is_zero_ether_addr(mac) || is_valid_ether_addr(mac))) + return -EINVAL; + + down_read(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + ret = ionic_set_vf_config(ionic, vf, IONIC_VF_ATTR_MAC, mac); + if (!ret) + ether_addr_copy(ionic->vfs[vf].macaddr, mac); + } + + up_read(&ionic->vf_op_lock); + return ret; +} + +static int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, + u8 qos, __be16 proto) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + int ret; + + /* until someday when we support qos */ + if (qos) + return -EINVAL; + + if (vlan > 4095) + return -EINVAL; + + if (proto != htons(ETH_P_8021Q)) + return -EPROTONOSUPPORT; + + down_read(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + ret = ionic_set_vf_config(ionic, vf, + IONIC_VF_ATTR_VLAN, (u8 *)&vlan); + if (!ret) + ionic->vfs[vf].vlanid = vlan; + } + + up_read(&ionic->vf_op_lock); + return ret; +} + +static int ionic_set_vf_rate(struct net_device *netdev, int vf, + int tx_min, int tx_max) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + int ret; + + /* setting the min just seems silly */ + if (tx_min) + return -EINVAL; + + down_write(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + ret = ionic_set_vf_config(ionic, vf, + IONIC_VF_ATTR_RATE, (u8 *)&tx_max); + if (!ret) + lif->ionic->vfs[vf].maxrate = tx_max; + } + + up_write(&ionic->vf_op_lock); + return ret; +} + +static int ionic_set_vf_spoofchk(struct net_device *netdev, int vf, bool set) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + u8 data = set; /* convert to u8 for config */ + int ret; + + down_write(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + ret = ionic_set_vf_config(ionic, vf, + IONIC_VF_ATTR_SPOOFCHK, &data); + if (!ret) + ionic->vfs[vf].spoofchk = data; + } + + up_write(&ionic->vf_op_lock); + return ret; +} + +static int ionic_set_vf_trust(struct net_device *netdev, int vf, bool set) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + u8 data = set; /* convert to u8 for config */ + int ret; + + down_write(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + ret = ionic_set_vf_config(ionic, vf, + IONIC_VF_ATTR_TRUST, &data); + if (!ret) + ionic->vfs[vf].trusted = data; + } + + up_write(&ionic->vf_op_lock); + return ret; +} + +static int ionic_set_vf_link_state(struct net_device *netdev, int vf, int set) +{ + struct ionic_lif *lif = netdev_priv(netdev); + struct ionic *ionic = lif->ionic; + u8 data; + int ret; + + switch (set) { + case IFLA_VF_LINK_STATE_ENABLE: + data = IONIC_VF_LINK_STATUS_UP; + break; + case IFLA_VF_LINK_STATE_DISABLE: + data = IONIC_VF_LINK_STATUS_DOWN; + break; + case IFLA_VF_LINK_STATE_AUTO: + data = IONIC_VF_LINK_STATUS_AUTO; + break; + default: + return -EINVAL; + } + + down_write(&ionic->vf_op_lock); + + if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { + ret = -EINVAL; + } else { + ret = ionic_set_vf_config(ionic, vf, + IONIC_VF_ATTR_LINKSTATE, &data); + if (!ret) + ionic->vfs[vf].linkstate = set; + } + + up_write(&ionic->vf_op_lock); + return ret; +} + static const struct net_device_ops ionic_netdev_ops = { .ndo_open = ionic_open, .ndo_stop = ionic_stop, @@ -1632,6 +1853,14 @@ static const struct net_device_ops ionic_netdev_ops = { .ndo_change_mtu = ionic_change_mtu, .ndo_vlan_rx_add_vid = ionic_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ionic_vlan_rx_kill_vid, + .ndo_set_vf_vlan = ionic_set_vf_vlan, + .ndo_set_vf_trust = ionic_set_vf_trust, + .ndo_set_vf_mac = ionic_set_vf_mac, + .ndo_set_vf_rate = ionic_set_vf_rate, + .ndo_set_vf_spoofchk = ionic_set_vf_spoofchk, + .ndo_get_vf_config = ionic_get_vf_config, + .ndo_set_vf_link_state = ionic_set_vf_link_state, + .ndo_get_vf_stats = ionic_get_vf_stats, }; int ionic_reset_queues(struct ionic_lif *lif) @@ -1965,18 +2194,22 @@ static int ionic_station_set(struct ionic_lif *lif) if (err) return err; + 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) - return err; - - if (!is_zero_ether_addr(netdev->dev_addr)) { - netdev_dbg(lif->netdev, "deleting station MAC addr %pM\n", - netdev->dev_addr); - ionic_lif_addr(lif, netdev->dev_addr, false); + if (err) { + netdev_warn(lif->netdev, "ignoring bad MAC addr from NIC %pM\n", + addr.sa_data); + 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); netdev_dbg(lif->netdev, "adding station MAC addr %pM\n", netdev->dev_addr); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index a55fd1f8c31b..9c5a7dd45f9d 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -37,6 +37,7 @@ struct ionic_rx_stats { u64 csum_complete; u64 csum_error; u64 buffers_posted; + u64 dropped; }; #define IONIC_QCQ_F_INITED BIT(0) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index 3590ea7fd88a..a8e3fb73b465 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -165,6 +165,10 @@ static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode) return "IONIC_CMD_FW_DOWNLOAD"; case IONIC_CMD_FW_CONTROL: return "IONIC_CMD_FW_CONTROL"; + case IONIC_CMD_VF_GETATTR: + return "IONIC_CMD_VF_GETATTR"; + case IONIC_CMD_VF_SETATTR: + return "IONIC_CMD_VF_SETATTR"; default: return "DEVCMD_UNKNOWN"; } @@ -326,9 +330,9 @@ int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) unsigned long max_wait; unsigned long duration; int opcode; + int hb = 0; int done; int err; - int hb; WARN_ON(in_interrupt()); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c index 03916b6d47f2..a1e9796a660a 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c @@ -39,6 +39,7 @@ static const struct ionic_stat_desc ionic_rx_stats_desc[] = { IONIC_RX_STAT_DESC(csum_none), IONIC_RX_STAT_DESC(csum_complete), IONIC_RX_STAT_DESC(csum_error), + IONIC_RX_STAT_DESC(dropped), }; static const struct ionic_stat_desc ionic_txq_stats_desc[] = { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 97e79949b359..e452f4242ba0 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -152,12 +152,16 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i stats = q_to_rx_stats(q); netdev = q->lif->netdev; - if (comp->status) + if (comp->status) { + stats->dropped++; return; + } /* no packet processing while resetting */ - if (unlikely(test_bit(IONIC_LIF_QUEUE_RESET, q->lif->state))) + if (unlikely(test_bit(IONIC_LIF_QUEUE_RESET, q->lif->state))) { + stats->dropped++; return; + } stats->pkts++; stats->bytes += le16_to_cpu(comp->len); @@ -167,8 +171,10 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i else skb = ionic_rx_frags(q, desc_info, cq_info); - if (unlikely(!skb)) + if (unlikely(!skb)) { + stats->dropped++; return; + } skb_record_rx_queue(skb, q->index); @@ -337,6 +343,8 @@ void ionic_rx_fill(struct ionic_queue *q) struct ionic_rxq_sg_desc *sg_desc; struct ionic_rxq_sg_elem *sg_elem; struct ionic_rxq_desc *desc; + unsigned int remain_len; + unsigned int seg_len; unsigned int nfrags; bool ring_doorbell; unsigned int i, j; @@ -346,6 +354,7 @@ void ionic_rx_fill(struct ionic_queue *q) nfrags = round_up(len, PAGE_SIZE) / PAGE_SIZE; for (i = ionic_q_space_avail(q); i; i--) { + remain_len = len; desc_info = q->head; desc = desc_info->desc; sg_desc = desc_info->sg_desc; @@ -369,7 +378,9 @@ void ionic_rx_fill(struct ionic_queue *q) return; } desc->addr = cpu_to_le64(page_info->dma_addr); - desc->len = cpu_to_le16(PAGE_SIZE); + seg_len = min_t(unsigned int, PAGE_SIZE, len); + desc->len = cpu_to_le16(seg_len); + remain_len -= seg_len; page_info++; /* fill sg descriptors - pages[1..n] */ @@ -385,7 +396,9 @@ void ionic_rx_fill(struct ionic_queue *q) return; } sg_elem->addr = cpu_to_le64(page_info->dma_addr); - sg_elem->len = cpu_to_le16(PAGE_SIZE); + seg_len = min_t(unsigned int, PAGE_SIZE, remain_len); + sg_elem->len = cpu_to_le16(seg_len); + remain_len -= seg_len; page_info++; } |