summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/pensando/ionic/ionic_lif.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/pensando/ionic/ionic_lif.c')
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.c303
1 files changed, 179 insertions, 124 deletions
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index e795fa63ca12..23c9e196a784 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -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) {