diff options
Diffstat (limited to 'drivers/net/ethernet/pensando/ionic/ionic_lif.c')
-rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_lif.c | 211 |
1 files changed, 179 insertions, 32 deletions
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 4b8a76098ca3..7321a92f8395 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -17,6 +17,16 @@ #include "ionic_ethtool.h" #include "ionic_debugfs.h" +/* queuetype support level */ +static const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = { + [IONIC_QTYPE_ADMINQ] = 0, /* 0 = Base version with CQ support */ + [IONIC_QTYPE_NOTIFYQ] = 0, /* 0 = Base version */ + [IONIC_QTYPE_RXQ] = 0, /* 0 = Base version with CQ+SG support */ + [IONIC_QTYPE_TXQ] = 1, /* 0 = Base version with CQ+SG support + * 1 = ... with Tx SG version 1 + */ +}; + 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); @@ -27,6 +37,7 @@ 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_queue_identify(struct ionic_lif *lif); static void ionic_lif_deferred_work(struct work_struct *work) { @@ -186,10 +197,10 @@ static int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr) return 0; } -static void ionic_intr_free(struct ionic_lif *lif, int index) +static void ionic_intr_free(struct ionic *ionic, int index) { - if (index != INTR_INDEX_NOT_ASSIGNED && index < lif->ionic->nintrs) - clear_bit(index, lif->ionic->intrs); + if (index != IONIC_INTR_INDEX_NOT_ASSIGNED && index < ionic->nintrs) + clear_bit(index, ionic->intrs); } static int ionic_qcq_enable(struct ionic_qcq *qcq) @@ -299,7 +310,7 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq) 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); + ionic_intr_free(lif->ionic, qcq->intr.index); } devm_kfree(dev, qcq->cq.info); @@ -345,7 +356,7 @@ static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq, struct ionic_qcq *n_qcq) { if (WARN_ON(n_qcq->flags & IONIC_QCQ_F_INTR)) { - ionic_intr_free(n_qcq->cq.lif, n_qcq->intr.index); + ionic_intr_free(n_qcq->cq.lif->ionic, n_qcq->intr.index); n_qcq->flags &= ~IONIC_QCQ_F_INTR; } @@ -444,7 +455,7 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, cpumask_set_cpu(new->intr.cpu, &new->intr.affinity_mask); } else { - new->intr.index = INTR_INDEX_NOT_ASSIGNED; + new->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED; } new->cq.info = devm_kzalloc(dev, sizeof(*new->cq.info) * num_descs, @@ -497,7 +508,7 @@ err_out_free_irq: devm_free_irq(dev, new->intr.vector, &new->napi); err_out_free_intr: if (flags & IONIC_QCQ_F_INTR) - ionic_intr_free(lif, new->intr.index); + ionic_intr_free(lif->ionic, new->intr.index); err_out: dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err); return err; @@ -597,6 +608,7 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) .opcode = IONIC_CMD_Q_INIT, .lif_index = cpu_to_le16(lif->index), .type = q->type, + .ver = lif->qtype_info[q->type].version, .index = cpu_to_le32(q->index), .flags = cpu_to_le16(IONIC_QINIT_F_IRQ | IONIC_QINIT_F_SG), @@ -614,6 +626,8 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) dev_dbg(dev, "txq_init.index %d\n", ctx.cmd.q_init.index); 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); + dev_dbg(dev, "txq_init.flags 0x%x\n", ctx.cmd.q_init.flags); + dev_dbg(dev, "txq_init.ver %d\n", ctx.cmd.q_init.ver); q->tail = q->info; q->head = q->tail; @@ -646,6 +660,7 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) .opcode = IONIC_CMD_Q_INIT, .lif_index = cpu_to_le16(lif->index), .type = q->type, + .ver = lif->qtype_info[q->type].version, .index = cpu_to_le32(q->index), .flags = cpu_to_le16(IONIC_QINIT_F_IRQ | IONIC_QINIT_F_SG), @@ -663,6 +678,8 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) dev_dbg(dev, "rxq_init.index %d\n", ctx.cmd.q_init.index); 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); + dev_dbg(dev, "rxq_init.flags 0x%x\n", ctx.cmd.q_init.flags); + dev_dbg(dev, "rxq_init.ver %d\n", ctx.cmd.q_init.ver); q->tail = q->info; q->head = q->tail; @@ -726,7 +743,7 @@ static bool ionic_notifyq_service(struct ionic_cq *cq, } break; default: - netdev_warn(netdev, "Notifyq unknown event ecode=%d eid=%lld\n", + netdev_warn(netdev, "Notifyq event ecode=%d eid=%lld\n", comp->event.ecode, eid); break; } @@ -775,8 +792,8 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget) return max(n_work, a_work); } -static void ionic_get_stats64(struct net_device *netdev, - struct rtnl_link_stats64 *ns) +void ionic_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *ns) { struct ionic_lif *lif = netdev_priv(netdev); struct ionic_lif_stats *ls; @@ -1509,17 +1526,25 @@ static void ionic_txrx_free(struct ionic_lif *lif) static int ionic_txrx_alloc(struct ionic_lif *lif) { + unsigned int sg_desc_sz; unsigned int flags; unsigned int i; int err = 0; + if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 && + lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz == + sizeof(struct ionic_txq_sg_desc_v1)) + sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1); + else + sg_desc_sz = sizeof(struct ionic_txq_sg_desc); + flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG; for (i = 0; i < lif->nxqs; i++) { err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags, lif->ntxq_descs, sizeof(struct ionic_txq_desc), sizeof(struct ionic_txq_comp), - sizeof(struct ionic_txq_sg_desc), + sg_desc_sz, lif->kern_pid, &lif->txqcqs[i].qcq); if (err) goto err_out; @@ -1682,7 +1707,7 @@ int ionic_stop(struct net_device *netdev) { struct ionic_lif *lif = netdev_priv(netdev); - if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) + if (!netif_device_present(netdev)) return 0; ionic_stop_queues(lif); @@ -1699,6 +1724,9 @@ static int ionic_get_vf_config(struct net_device *netdev, struct ionic *ionic = lif->ionic; int ret = 0; + if (!netif_device_present(netdev)) + return -EBUSY; + down_read(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -1726,6 +1754,9 @@ static int ionic_get_vf_stats(struct net_device *netdev, int vf, struct ionic_lif_stats *vs; int ret = 0; + if (!netif_device_present(netdev)) + return -EBUSY; + down_read(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -1761,6 +1792,9 @@ 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; + if (!netif_device_present(netdev)) + return -EBUSY; + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -1792,6 +1826,9 @@ static int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, if (proto != htons(ETH_P_8021Q)) return -EPROTONOSUPPORT; + if (!netif_device_present(netdev)) + return -EBUSY; + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -1818,6 +1855,9 @@ static int ionic_set_vf_rate(struct net_device *netdev, int vf, if (tx_min) return -EINVAL; + if (!netif_device_present(netdev)) + return -EBUSY; + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -1840,6 +1880,9 @@ static int ionic_set_vf_spoofchk(struct net_device *netdev, int vf, bool set) u8 data = set; /* convert to u8 for config */ int ret; + if (!netif_device_present(netdev)) + return -EBUSY; + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -1862,6 +1905,9 @@ static int ionic_set_vf_trust(struct net_device *netdev, int vf, bool set) u8 data = set; /* convert to u8 for config */ int ret; + if (!netif_device_present(netdev)) + return -EBUSY; + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -1898,6 +1944,9 @@ static int ionic_set_vf_link_state(struct net_device *netdev, int vf, int set) return -EINVAL; } + if (!netif_device_present(netdev)) + return -EBUSY; + down_write(&ionic->vf_op_lock); if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) { @@ -2065,9 +2114,17 @@ int ionic_lifs_alloc(struct ionic *ionic) /* only build the first lif, others are for later features */ set_bit(0, ionic->lifbits); + lif = ionic_lif_alloc(ionic, 0); + if (IS_ERR_OR_NULL(lif)) { + clear_bit(0, ionic->lifbits); + return -ENOMEM; + } - return PTR_ERR_OR_ZERO(lif); + lif->lif_type = IONIC_LIF_TYPE_CLASSIC; + ionic_lif_queue_identify(lif); + + return 0; } static void ionic_lif_reset(struct ionic_lif *lif) @@ -2101,6 +2158,7 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *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"); @@ -2116,6 +2174,8 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif) 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; @@ -2127,6 +2187,8 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif) 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) @@ -2206,9 +2268,9 @@ static void ionic_lif_deinit(struct ionic_lif *lif) 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); if (lif->netdev->features & NETIF_F_RXHASH) ionic_lif_rss_deinit(lif); @@ -2287,6 +2349,7 @@ static int ionic_lif_notifyq_init(struct ionic_lif *lif) .opcode = IONIC_CMD_Q_INIT, .lif_index = cpu_to_le16(lif->index), .type = q->type, + .ver = lif->qtype_info[q->type].version, .index = cpu_to_le32(q->index), .flags = cpu_to_le16(IONIC_QINIT_F_IRQ | IONIC_QINIT_F_ENA), @@ -2339,24 +2402,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 - err %d\n", - addr.sa_data, err); - 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); @@ -2421,9 +2494,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) @@ -2539,8 +2614,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; @@ -2563,6 +2636,80 @@ void ionic_lifs_unregister(struct ionic *ionic) unregister_netdev(ionic->master_lif->netdev); } +static void ionic_lif_queue_identify(struct ionic_lif *lif) +{ + struct ionic *ionic = lif->ionic; + union ionic_q_identity *q_ident; + struct ionic_dev *idev; + int qtype; + int err; + + idev = &lif->ionic->idev; + q_ident = (union ionic_q_identity *)&idev->dev_cmd_regs->data; + + for (qtype = 0; qtype < ARRAY_SIZE(ionic_qtype_versions); qtype++) { + struct ionic_qtype_info *qti = &lif->qtype_info[qtype]; + + /* filter out the ones we know about */ + switch (qtype) { + case IONIC_QTYPE_ADMINQ: + case IONIC_QTYPE_NOTIFYQ: + case IONIC_QTYPE_RXQ: + case IONIC_QTYPE_TXQ: + break; + default: + continue; + } + + memset(qti, 0, sizeof(*qti)); + + mutex_lock(&ionic->dev_cmd_lock); + ionic_dev_cmd_queue_identify(idev, lif->lif_type, qtype, + ionic_qtype_versions[qtype]); + err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); + if (!err) { + qti->version = q_ident->version; + qti->supported = q_ident->supported; + qti->features = le64_to_cpu(q_ident->features); + qti->desc_sz = le16_to_cpu(q_ident->desc_sz); + qti->comp_sz = le16_to_cpu(q_ident->comp_sz); + qti->sg_desc_sz = le16_to_cpu(q_ident->sg_desc_sz); + qti->max_sg_elems = le16_to_cpu(q_ident->max_sg_elems); + qti->sg_desc_stride = le16_to_cpu(q_ident->sg_desc_stride); + } + mutex_unlock(&ionic->dev_cmd_lock); + + if (err == -EINVAL) { + dev_err(ionic->dev, "qtype %d not supported\n", qtype); + continue; + } else if (err == -EIO) { + dev_err(ionic->dev, "q_ident failed, not supported on older FW\n"); + return; + } else if (err) { + dev_err(ionic->dev, "q_ident failed, qtype %d: %d\n", + qtype, err); + return; + } + + dev_dbg(ionic->dev, " qtype[%d].version = %d\n", + qtype, qti->version); + dev_dbg(ionic->dev, " qtype[%d].supported = 0x%02x\n", + qtype, qti->supported); + dev_dbg(ionic->dev, " qtype[%d].features = 0x%04llx\n", + qtype, qti->features); + dev_dbg(ionic->dev, " qtype[%d].desc_sz = %d\n", + qtype, qti->desc_sz); + dev_dbg(ionic->dev, " qtype[%d].comp_sz = %d\n", + qtype, qti->comp_sz); + dev_dbg(ionic->dev, " qtype[%d].sg_desc_sz = %d\n", + qtype, qti->sg_desc_sz); + dev_dbg(ionic->dev, " qtype[%d].max_sg_elems = %d\n", + qtype, qti->max_sg_elems); + dev_dbg(ionic->dev, " qtype[%d].sg_desc_stride = %d\n", + qtype, qti->sg_desc_stride); + } +} + int ionic_lif_identify(struct ionic *ionic, u8 lif_type, union ionic_lif_identity *lid) { |