Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / drivers / net / ethernet / pensando / ionic / ionic_lif.c
index e795fa6..23c9e19 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/cpumask.h>
+#include <linux/crash_dump.h>
 
 #include "ionic.h"
 #include "ionic_bus.h"
@@ -29,9 +30,6 @@ static const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = {
                                      */
 };
 
-static void ionic_lif_rx_mode(struct ionic_lif *lif);
-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);
@@ -91,20 +89,21 @@ static void ionic_lif_deferred_work(struct work_struct *work)
                case IONIC_DW_TYPE_RX_MODE:
                        ionic_lif_rx_mode(lif);
                        break;
-               case IONIC_DW_TYPE_RX_ADDR_ADD:
-                       ionic_lif_addr_add(lif, w->addr);
-                       break;
-               case IONIC_DW_TYPE_RX_ADDR_DEL:
-                       ionic_lif_addr_del(lif, w->addr);
-                       break;
                case IONIC_DW_TYPE_LINK_STATUS:
                        ionic_link_status_check(lif);
                        break;
                case IONIC_DW_TYPE_LIF_RESET:
-                       if (w->fw_status)
+                       if (w->fw_status) {
                                ionic_lif_handle_fw_up(lif);
-                       else
+                       } else {
                                ionic_lif_handle_fw_down(lif);
+
+                               /* Fire off another watchdog to see
+                                * if the FW is already back rather than
+                                * waiting another whole cycle
+                                */
+                               mod_timer(&lif->ionic->watchdog_timer, jiffies + 1);
+                       }
                        break;
                default:
                        break;
@@ -850,10 +849,8 @@ int ionic_lif_create_hwstamp_txq(struct ionic_lif *lif)
        u64 features;
        int err;
 
-       mutex_lock(&lif->queue_lock);
-
        if (lif->hwstamp_txq)
-               goto out;
+               return 0;
 
        features = IONIC_Q_F_2X_CQ_DESC | IONIC_TXQ_F_HWSTAMP;
 
@@ -895,9 +892,6 @@ int ionic_lif_create_hwstamp_txq(struct ionic_lif *lif)
                }
        }
 
-out:
-       mutex_unlock(&lif->queue_lock);
-
        return 0;
 
 err_qcq_enable:
@@ -908,7 +902,6 @@ err_qcq_init:
        ionic_qcq_free(lif, txq);
        devm_kfree(lif->ionic->dev, txq);
 err_qcq_alloc:
-       mutex_unlock(&lif->queue_lock);
        return err;
 }
 
@@ -920,10 +913,8 @@ int ionic_lif_create_hwstamp_rxq(struct ionic_lif *lif)
        u64 features;
        int err;
 
-       mutex_lock(&lif->queue_lock);
-
        if (lif->hwstamp_rxq)
-               goto out;
+               return 0;
 
        features = IONIC_Q_F_2X_CQ_DESC | IONIC_RXQ_F_HWSTAMP;
 
@@ -961,9 +952,6 @@ int ionic_lif_create_hwstamp_rxq(struct ionic_lif *lif)
                }
        }
 
-out:
-       mutex_unlock(&lif->queue_lock);
-
        return 0;
 
 err_qcq_enable:
@@ -974,7 +962,6 @@ err_qcq_init:
        ionic_qcq_free(lif, rxq);
        devm_kfree(lif->ionic->dev, rxq);
 err_qcq_alloc:
-       mutex_unlock(&lif->queue_lock);
        return err;
 }
 
@@ -1077,7 +1064,11 @@ static int ionic_lif_add_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
        if (err && err != -EEXIST)
                return err;
 
-       return ionic_rx_filter_save(lif, 0, qid, 0, &ctx);
+       spin_lock_bh(&lif->rx_filters.lock);
+       err = ionic_rx_filter_save(lif, 0, qid, 0, &ctx, IONIC_FILTER_STATE_SYNCED);
+       spin_unlock_bh(&lif->rx_filters.lock);
+
+       return err;
 }
 
 int ionic_lif_set_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class)
@@ -1250,7 +1241,7 @@ void ionic_get_stats64(struct net_device *netdev,
        ns->tx_errors = ns->tx_aborted_errors;
 }
 
-static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
+int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
 {
        struct ionic_admin_ctx ctx = {
                .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
@@ -1260,27 +1251,83 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
                        .match = cpu_to_le16(IONIC_RX_FILTER_MATCH_MAC),
                },
        };
+       int nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
+       bool mc = is_multicast_ether_addr(addr);
        struct ionic_rx_filter *f;
-       int err;
+       int err = 0;
+
+       memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
 
-       /* don't bother if we already have it */
        spin_lock_bh(&lif->rx_filters.lock);
        f = ionic_rx_filter_by_addr(lif, addr);
+       if (f) {
+               /* don't bother if we already have it and it is sync'd */
+               if (f->state == IONIC_FILTER_STATE_SYNCED) {
+                       spin_unlock_bh(&lif->rx_filters.lock);
+                       return 0;
+               }
+
+               /* mark preemptively as sync'd to block any parallel attempts */
+               f->state = IONIC_FILTER_STATE_SYNCED;
+       } else {
+               /* save as SYNCED to catch any DEL requests while processing */
+               err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+                                          IONIC_FILTER_STATE_SYNCED);
+       }
        spin_unlock_bh(&lif->rx_filters.lock);
-       if (f)
-               return 0;
+       if (err)
+               return err;
 
        netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
 
-       memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
-       err = ionic_adminq_post_wait(lif, &ctx);
-       if (err && err != -EEXIST)
-               return err;
+       /* Don't bother with the write to FW if we know there's no room,
+        * we can try again on the next sync attempt.
+        */
+       if ((lif->nucast + lif->nmcast) >= nfilters)
+               err = -ENOSPC;
+       else
+               err = ionic_adminq_post_wait(lif, &ctx);
+
+       spin_lock_bh(&lif->rx_filters.lock);
+       if (err && err != -EEXIST) {
+               /* set the state back to NEW so we can try again later */
+               f = ionic_rx_filter_by_addr(lif, addr);
+               if (f && f->state == IONIC_FILTER_STATE_SYNCED)
+                       f->state = IONIC_FILTER_STATE_NEW;
+
+               spin_unlock_bh(&lif->rx_filters.lock);
+
+               if (err == -ENOSPC)
+                       return 0;
+               else
+                       return err;
+       }
 
-       return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
+       if (mc)
+               lif->nmcast++;
+       else
+               lif->nucast++;
+
+       f = ionic_rx_filter_by_addr(lif, addr);
+       if (f && f->state == IONIC_FILTER_STATE_OLD) {
+               /* Someone requested a delete while we were adding
+                * so update the filter info with the results from the add
+                * and the data will be there for the delete on the next
+                * sync cycle.
+                */
+               err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+                                          IONIC_FILTER_STATE_OLD);
+       } else {
+               err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+                                          IONIC_FILTER_STATE_SYNCED);
+       }
+
+       spin_unlock_bh(&lif->rx_filters.lock);
+
+       return err;
 }
 
-static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
+int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
 {
        struct ionic_admin_ctx ctx = {
                .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
@@ -1290,6 +1337,7 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
                },
        };
        struct ionic_rx_filter *f;
+       int state;
        int err;
 
        spin_lock_bh(&lif->rx_filters.lock);
@@ -1302,65 +1350,37 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
        netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n",
                   addr, f->filter_id);
 
+       state = f->state;
        ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
        ionic_rx_filter_free(lif, f);
-       spin_unlock_bh(&lif->rx_filters.lock);
-
-       err = ionic_adminq_post_wait(lif, &ctx);
-       if (err && err != -EEXIST)
-               return err;
 
-       return 0;
-}
+       if (is_multicast_ether_addr(addr) && lif->nmcast)
+               lif->nmcast--;
+       else if (!is_multicast_ether_addr(addr) && lif->nucast)
+               lif->nucast--;
 
-static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add)
-{
-       unsigned int nmfilters;
-       unsigned int nufilters;
+       spin_unlock_bh(&lif->rx_filters.lock);
 
-       if (add) {
-               /* Do we have space for this filter?  We test the counters
-                * here before checking the need for deferral so that we
-                * can return an overflow error to the stack.
-                */
-               nmfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
-               nufilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
-
-               if ((is_multicast_ether_addr(addr) && lif->nmcast < nmfilters))
-                       lif->nmcast++;
-               else if (!is_multicast_ether_addr(addr) &&
-                        lif->nucast < nufilters)
-                       lif->nucast++;
-               else
-                       return -ENOSPC;
-       } else {
-               if (is_multicast_ether_addr(addr) && lif->nmcast)
-                       lif->nmcast--;
-               else if (!is_multicast_ether_addr(addr) && lif->nucast)
-                       lif->nucast--;
+       if (state != IONIC_FILTER_STATE_NEW) {
+               err = ionic_adminq_post_wait(lif, &ctx);
+               if (err && err != -EEXIST)
+                       return err;
        }
 
-       netdev_dbg(lif->netdev, "rx_filter %s %pM\n",
-                  add ? "add" : "del", addr);
-       if (add)
-               return ionic_lif_addr_add(lif, addr);
-       else
-               return ionic_lif_addr_del(lif, addr);
-
        return 0;
 }
 
 static int ionic_addr_add(struct net_device *netdev, const u8 *addr)
 {
-       return ionic_lif_addr(netdev_priv(netdev), addr, ADD_ADDR);
+       return ionic_lif_list_addr(netdev_priv(netdev), addr, ADD_ADDR);
 }
 
 static int ionic_addr_del(struct net_device *netdev, const u8 *addr)
 {
-       return ionic_lif_addr(netdev_priv(netdev), addr, DEL_ADDR);
+       return ionic_lif_list_addr(netdev_priv(netdev), addr, DEL_ADDR);
 }
 
-static void ionic_lif_rx_mode(struct ionic_lif *lif)
+void ionic_lif_rx_mode(struct ionic_lif *lif)
 {
        struct net_device *netdev = lif->netdev;
        unsigned int nfilters;
@@ -1381,32 +1401,26 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif)
        rx_mode |= (nd_flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0;
        rx_mode |= (nd_flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0;
 
-       /* sync unicast addresses
-        * next check to see if we're in an overflow state
+       /* sync the mac filters */
+       ionic_rx_filter_sync(lif);
+
+       /* check for overflow state
         *    if so, we track that we overflowed and enable NIC PROMISC
         *    else if the overflow is set and not needed
         *       we remove our overflow flag and check the netdev flags
         *       to see if we can disable NIC PROMISC
         */
-       __dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
        nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
-       if (netdev_uc_count(netdev) + 1 > nfilters) {
+       if ((lif->nucast + lif->nmcast) >= nfilters) {
                rx_mode |= IONIC_RX_MODE_F_PROMISC;
+               rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
                lif->uc_overflow = true;
+               lif->mc_overflow = true;
        } else if (lif->uc_overflow) {
                lif->uc_overflow = false;
+               lif->mc_overflow = false;
                if (!(nd_flags & IFF_PROMISC))
                        rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
-       }
-
-       /* same for multicast */
-       __dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
-       nfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
-       if (netdev_mc_count(netdev) > nfilters) {
-               rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
-               lif->mc_overflow = true;
-       } else if (lif->mc_overflow) {
-               lif->mc_overflow = false;
                if (!(nd_flags & IFF_ALLMULTI))
                        rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
        }
@@ -1449,28 +1463,26 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif)
        mutex_unlock(&lif->config_lock);
 }
 
-static void ionic_set_rx_mode(struct net_device *netdev, bool can_sleep)
+static void ionic_ndo_set_rx_mode(struct net_device *netdev)
 {
        struct ionic_lif *lif = netdev_priv(netdev);
        struct ionic_deferred_work *work;
 
-       if (!can_sleep) {
-               work = kzalloc(sizeof(*work), GFP_ATOMIC);
-               if (!work) {
-                       netdev_err(lif->netdev, "rxmode change dropped\n");
-                       return;
-               }
-               work->type = IONIC_DW_TYPE_RX_MODE;
-               netdev_dbg(lif->netdev, "deferred: rx_mode\n");
-               ionic_lif_deferred_enqueue(&lif->deferred, work);
-       } else {
-               ionic_lif_rx_mode(lif);
-       }
-}
+       /* Sync the kernel filter list with the driver filter list */
+       __dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
+       __dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
 
-static void ionic_ndo_set_rx_mode(struct net_device *netdev)
-{
-       ionic_set_rx_mode(netdev, CAN_NOT_SLEEP);
+       /* Shove off the rest of the rxmode work to the work task
+        * which will include syncing the filters to the firmware.
+        */
+       work = kzalloc(sizeof(*work), GFP_ATOMIC);
+       if (!work) {
+               netdev_err(lif->netdev, "rxmode change dropped\n");
+               return;
+       }
+       work->type = IONIC_DW_TYPE_RX_MODE;
+       netdev_dbg(lif->netdev, "deferred: rx_mode\n");
+       ionic_lif_deferred_enqueue(&lif->deferred, work);
 }
 
 static __le64 ionic_netdev_features_to_nic(netdev_features_t features)
@@ -1599,7 +1611,6 @@ static int ionic_init_nic_features(struct ionic_lif *lif)
        features = NETIF_F_HW_VLAN_CTAG_TX |
                   NETIF_F_HW_VLAN_CTAG_RX |
                   NETIF_F_HW_VLAN_CTAG_FILTER |
-                  NETIF_F_RXHASH |
                   NETIF_F_SG |
                   NETIF_F_HW_CSUM |
                   NETIF_F_RXCSUM |
@@ -1607,6 +1618,9 @@ static int ionic_init_nic_features(struct ionic_lif *lif)
                   NETIF_F_TSO6 |
                   NETIF_F_TSO_ECN;
 
+       if (lif->nxqs > 1)
+               features |= NETIF_F_RXHASH;
+
        err = ionic_set_nic_features(lif, features);
        if (err)
                return err;
@@ -1689,13 +1703,13 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
        if (!is_zero_ether_addr(netdev->dev_addr)) {
                netdev_info(netdev, "deleting mac addr %pM\n",
                            netdev->dev_addr);
-               ionic_addr_del(netdev, netdev->dev_addr);
+               ionic_lif_addr_del(netdev_priv(netdev), netdev->dev_addr);
        }
 
        eth_commit_mac_addr_change(netdev, addr);
        netdev_info(netdev, "updating mac addr %pM\n", mac);
 
-       return ionic_addr_add(netdev, mac);
+       return ionic_lif_addr_add(netdev_priv(netdev), mac);
 }
 
 static void ionic_stop_queues_reconfig(struct ionic_lif *lif)
@@ -1801,7 +1815,12 @@ static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
        if (err)
                return err;
 
-       return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
+       spin_lock_bh(&lif->rx_filters.lock);
+       err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx,
+                                  IONIC_FILTER_STATE_SYNCED);
+       spin_unlock_bh(&lif->rx_filters.lock);
+
+       return err;
 }
 
 static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
@@ -2104,7 +2123,7 @@ static int ionic_txrx_init(struct ionic_lif *lif)
        if (lif->netdev->features & NETIF_F_RXHASH)
                ionic_lif_rss_init(lif);
 
-       ionic_set_rx_mode(lif->netdev, CAN_SLEEP);
+       ionic_lif_rx_mode(lif);
 
        return 0;
 
@@ -2202,9 +2221,11 @@ static int ionic_open(struct net_device *netdev)
        if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
                netdev_info(netdev, "clearing broken state\n");
 
+       mutex_lock(&lif->queue_lock);
+
        err = ionic_txrx_alloc(lif);
        if (err)
-               return err;
+               goto err_unlock;
 
        err = ionic_txrx_init(lif);
        if (err)
@@ -2225,12 +2246,21 @@ static int ionic_open(struct net_device *netdev)
                        goto err_txrx_deinit;
        }
 
+       /* If hardware timestamping is enabled, but the queues were freed by
+        * ionic_stop, those need to be reallocated and initialized, too.
+        */
+       ionic_lif_hwstamp_recreate_queues(lif);
+
+       mutex_unlock(&lif->queue_lock);
+
        return 0;
 
 err_txrx_deinit:
        ionic_txrx_deinit(lif);
 err_txrx_free:
        ionic_txrx_free(lif);
+err_unlock:
+       mutex_unlock(&lif->queue_lock);
        return err;
 }
 
@@ -2250,14 +2280,16 @@ static int ionic_stop(struct net_device *netdev)
        if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
                return 0;
 
+       mutex_lock(&lif->queue_lock);
        ionic_stop_queues(lif);
        ionic_txrx_deinit(lif);
        ionic_txrx_free(lif);
+       mutex_unlock(&lif->queue_lock);
 
        return 0;
 }
 
-static int ionic_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+static int ionic_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
        struct ionic_lif *lif = netdev_priv(netdev);
 
@@ -2519,7 +2551,7 @@ static int ionic_set_vf_link_state(struct net_device *netdev, int vf, int set)
 static const struct net_device_ops ionic_netdev_ops = {
        .ndo_open               = ionic_open,
        .ndo_stop               = ionic_stop,
-       .ndo_do_ioctl           = ionic_do_ioctl,
+       .ndo_eth_ioctl          = ionic_eth_ioctl,
        .ndo_start_xmit         = ionic_start_xmit,
        .ndo_get_stats64        = ionic_get_stats64,
        .ndo_set_rx_mode        = ionic_ndo_set_rx_mode,
@@ -2580,22 +2612,26 @@ int ionic_reconfigure_queues(struct ionic_lif *lif,
        struct ionic_qcq **tx_qcqs = NULL;
        struct ionic_qcq **rx_qcqs = NULL;
        unsigned int flags, i;
-       int err = -ENOMEM;
+       int err = 0;
 
        /* allocate temporary qcq arrays to hold new queue structs */
        if (qparam->nxqs != lif->nxqs || qparam->ntxq_descs != lif->ntxq_descs) {
                tx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->ntxqs_per_lif,
                                       sizeof(struct ionic_qcq *), GFP_KERNEL);
-               if (!tx_qcqs)
+               if (!tx_qcqs) {
+                       err = -ENOMEM;
                        goto err_out;
+               }
        }
        if (qparam->nxqs != lif->nxqs ||
            qparam->nrxq_descs != lif->nrxq_descs ||
            qparam->rxq_features != lif->rxq_features) {
                rx_qcqs = devm_kcalloc(lif->ionic->dev, lif->ionic->nrxqs_per_lif,
                                       sizeof(struct ionic_qcq *), GFP_KERNEL);
-               if (!rx_qcqs)
+               if (!rx_qcqs) {
+                       err = -ENOMEM;
                        goto err_out;
+               }
        }
 
        /* allocate new desc_info and rings, but leave the interrupt setup
@@ -2774,6 +2810,9 @@ err_out:
                ionic_qcq_free(lif, lif->rxqcqs[i]);
        }
 
+       if (err)
+               netdev_info(lif->netdev, "%s: failed %d\n", __func__, err);
+
        return err;
 }
 
@@ -2827,8 +2866,14 @@ int ionic_lif_alloc(struct ionic *ionic)
 
        lif->ionic = ionic;
        lif->index = 0;
-       lif->ntxq_descs = IONIC_DEF_TXRX_DESC;
-       lif->nrxq_descs = IONIC_DEF_TXRX_DESC;
+
+       if (is_kdump_kernel()) {
+               lif->ntxq_descs = IONIC_MIN_TXRX_DESC;
+               lif->nrxq_descs = IONIC_MIN_TXRX_DESC;
+       } else {
+               lif->ntxq_descs = IONIC_DEF_TXRX_DESC;
+               lif->nrxq_descs = IONIC_DEF_TXRX_DESC;
+       }
 
        /* Convert the default coalesce value to actual hw resolution */
        lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT;
@@ -3179,7 +3224,7 @@ static int ionic_station_set(struct ionic_lif *lif)
                 */
                if (!ether_addr_equal(ctx.comp.lif_getattr.mac,
                                      netdev->dev_addr))
-                       ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR);
+                       ionic_lif_addr_add(lif, netdev->dev_addr);
        } else {
                /* Update the netdev mac with the device's mac */
                memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len);
@@ -3196,7 +3241,7 @@ static int ionic_station_set(struct ionic_lif *lif)
 
        netdev_dbg(lif->netdev, "adding station MAC addr %pM\n",
                   netdev->dev_addr);
-       ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR);
+       ionic_lif_addr_add(lif, netdev->dev_addr);
 
        return 0;
 }
@@ -3514,6 +3559,7 @@ int ionic_lif_size(struct ionic *ionic)
        unsigned int min_intrs;
        int err;
 
+       /* retrieve basic values from FW */
        lc = &ident->lif.eth.config;
        dev_nintrs = le32_to_cpu(ident->dev.nintrs);
        neqs_per_lif = le32_to_cpu(ident->lif.rdma.eq_qtype.qid_count);
@@ -3521,6 +3567,15 @@ int ionic_lif_size(struct ionic *ionic)
        ntxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_TXQ]);
        nrxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_RXQ]);
 
+       /* limit values to play nice with kdump */
+       if (is_kdump_kernel()) {
+               dev_nintrs = 2;
+               neqs_per_lif = 0;
+               nnqs_per_lif = 0;
+               ntxqs_per_lif = 1;
+               nrxqs_per_lif = 1;
+       }
+
        /* reserve last queue id for hardware timestamping */
        if (lc->features & cpu_to_le64(IONIC_ETH_HW_TIMESTAMP)) {
                if (ntxqs_per_lif <= 1 || nrxqs_per_lif <= 1) {