Commit 34ad9377 authored by David S. Miller's avatar David S. Miller

Merge branch 'ionic-error-recovery'

Shannon Nelson says:

====================
ionic error recovery

This set of patches comes mostly from error recovery path testing,
as well as a couple of upstream review comments.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7b419e65 9e15410d
...@@ -266,6 +266,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -266,6 +266,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(dev, "Cannot identify device: %d, aborting\n", err); dev_err(dev, "Cannot identify device: %d, aborting\n", err);
goto err_out_teardown; goto err_out_teardown;
} }
ionic_debugfs_add_ident(ionic);
err = ionic_init(ionic); err = ionic_init(ionic);
if (err) { if (err) {
...@@ -286,14 +287,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -286,14 +287,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_reset; goto err_out_reset;
} }
/* Configure LIFs */ /* Allocate and init the LIF */
err = ionic_lif_identify(ionic, IONIC_LIF_TYPE_CLASSIC,
&ionic->ident.lif);
if (err) {
dev_err(dev, "Cannot identify LIFs: %d, aborting\n", err);
goto err_out_port_reset;
}
err = ionic_lif_size(ionic); err = ionic_lif_size(ionic);
if (err) { if (err) {
dev_err(dev, "Cannot size LIF: %d, aborting\n", err); dev_err(dev, "Cannot size LIF: %d, aborting\n", err);
......
...@@ -96,6 +96,7 @@ enum ionic_status_code { ...@@ -96,6 +96,7 @@ enum ionic_status_code {
IONIC_RC_ERROR = 29, /* Generic error */ IONIC_RC_ERROR = 29, /* Generic error */
IONIC_RC_ERDMA = 30, /* Generic RDMA error */ IONIC_RC_ERDMA = 30, /* Generic RDMA error */
IONIC_RC_EVFID = 31, /* VF ID does not exist */ IONIC_RC_EVFID = 31, /* VF ID does not exist */
IONIC_RC_EBAD_FW = 32, /* FW file is invalid or corrupted */
}; };
enum ionic_notifyq_opcode { enum ionic_notifyq_opcode {
......
...@@ -62,6 +62,7 @@ static void ionic_lif_deferred_work(struct work_struct *work) ...@@ -62,6 +62,7 @@ static void ionic_lif_deferred_work(struct work_struct *work)
struct ionic_deferred *def = &lif->deferred; struct ionic_deferred *def = &lif->deferred;
struct ionic_deferred_work *w = NULL; struct ionic_deferred_work *w = NULL;
do {
spin_lock_bh(&def->lock); spin_lock_bh(&def->lock);
if (!list_empty(&def->list)) { if (!list_empty(&def->list)) {
w = list_first_entry(&def->list, w = list_first_entry(&def->list,
...@@ -70,7 +71,9 @@ static void ionic_lif_deferred_work(struct work_struct *work) ...@@ -70,7 +71,9 @@ static void ionic_lif_deferred_work(struct work_struct *work)
} }
spin_unlock_bh(&def->lock); spin_unlock_bh(&def->lock);
if (w) { if (!w)
break;
switch (w->type) { switch (w->type) {
case IONIC_DW_TYPE_RX_MODE: case IONIC_DW_TYPE_RX_MODE:
ionic_lif_rx_mode(lif, w->rx_mode); ionic_lif_rx_mode(lif, w->rx_mode);
...@@ -94,8 +97,8 @@ static void ionic_lif_deferred_work(struct work_struct *work) ...@@ -94,8 +97,8 @@ static void ionic_lif_deferred_work(struct work_struct *work)
break; break;
} }
kfree(w); kfree(w);
schedule_work(&def->work); w = NULL;
} } while (true);
} }
void ionic_lif_deferred_enqueue(struct ionic_deferred *def, void ionic_lif_deferred_enqueue(struct ionic_deferred *def,
...@@ -161,8 +164,10 @@ void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep) ...@@ -161,8 +164,10 @@ void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep)
if (!can_sleep) { if (!can_sleep) {
work = kzalloc(sizeof(*work), GFP_ATOMIC); work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work) if (!work) {
clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
return; return;
}
work->type = IONIC_DW_TYPE_LINK_STATUS; work->type = IONIC_DW_TYPE_LINK_STATUS;
ionic_lif_deferred_enqueue(&lif->deferred, work); ionic_lif_deferred_enqueue(&lif->deferred, work);
...@@ -259,31 +264,29 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq) ...@@ -259,31 +264,29 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq)
return ionic_adminq_post_wait(lif, &ctx); return ionic_adminq_post_wait(lif, &ctx);
} }
static int ionic_qcq_disable(struct ionic_qcq *qcq) static int ionic_qcq_disable(struct ionic_qcq *qcq, bool send_to_hw)
{ {
struct ionic_queue *q = &qcq->q; struct ionic_queue *q;
struct ionic_lif *lif = q->lif; struct ionic_lif *lif;
struct ionic_dev *idev; int err = 0;
struct device *dev;
struct ionic_admin_ctx ctx = { struct ionic_admin_ctx ctx = {
.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work), .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
.cmd.q_control = { .cmd.q_control = {
.opcode = IONIC_CMD_Q_CONTROL, .opcode = IONIC_CMD_Q_CONTROL,
.lif_index = cpu_to_le16(lif->index),
.type = q->type,
.index = cpu_to_le32(q->index),
.oper = IONIC_Q_DISABLE, .oper = IONIC_Q_DISABLE,
}, },
}; };
idev = &lif->ionic->idev; if (!qcq)
dev = lif->ionic->dev; return -ENXIO;
dev_dbg(dev, "q_disable.index %d q_disable.qtype %d\n", q = &qcq->q;
ctx.cmd.q_control.index, ctx.cmd.q_control.type); lif = q->lif;
if (qcq->flags & IONIC_QCQ_F_INTR) { if (qcq->flags & IONIC_QCQ_F_INTR) {
struct ionic_dev *idev = &lif->ionic->idev;
cancel_work_sync(&qcq->dim.work); cancel_work_sync(&qcq->dim.work);
ionic_intr_mask(idev->intr_ctrl, qcq->intr.index, ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
IONIC_INTR_MASK_SET); IONIC_INTR_MASK_SET);
...@@ -292,7 +295,17 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq) ...@@ -292,7 +295,17 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq)
napi_disable(&qcq->napi); napi_disable(&qcq->napi);
} }
return ionic_adminq_post_wait(lif, &ctx); if (send_to_hw) {
ctx.cmd.q_control.lif_index = cpu_to_le16(lif->index);
ctx.cmd.q_control.type = q->type;
ctx.cmd.q_control.index = cpu_to_le32(q->index);
dev_dbg(lif->ionic->dev, "q_disable.index %d q_disable.qtype %d\n",
ctx.cmd.q_control.index, ctx.cmd.q_control.type);
err = ionic_adminq_post_wait(lif, &ctx);
}
return err;
} }
static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq) static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
...@@ -518,6 +531,30 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, ...@@ -518,6 +531,30 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
goto err_out_free_cq_info; goto err_out_free_cq_info;
} }
if (flags & IONIC_QCQ_F_NOTIFYQ) {
int q_size, cq_size;
/* q & cq need to be contiguous in case of notifyq */
q_size = ALIGN(num_descs * desc_size, PAGE_SIZE);
cq_size = ALIGN(num_descs * cq_desc_size, PAGE_SIZE);
new->q_size = PAGE_SIZE + q_size + cq_size;
new->q_base = dma_alloc_coherent(dev, new->q_size,
&new->q_base_pa, GFP_KERNEL);
if (!new->q_base) {
netdev_err(lif->netdev, "Cannot allocate qcq DMA memory\n");
err = -ENOMEM;
goto err_out_free_cq_info;
}
q_base = PTR_ALIGN(new->q_base, PAGE_SIZE);
q_base_pa = ALIGN(new->q_base_pa, PAGE_SIZE);
ionic_q_map(&new->q, q_base, q_base_pa);
cq_base = PTR_ALIGN(q_base + q_size, PAGE_SIZE);
cq_base_pa = ALIGN(new->q_base_pa + q_size, PAGE_SIZE);
ionic_cq_map(&new->cq, cq_base, cq_base_pa);
ionic_cq_bind(&new->cq, &new->q);
} else {
new->q_size = PAGE_SIZE + (num_descs * desc_size); new->q_size = PAGE_SIZE + (num_descs * desc_size);
new->q_base = dma_alloc_coherent(dev, new->q_size, &new->q_base_pa, new->q_base = dma_alloc_coherent(dev, new->q_size, &new->q_base_pa,
GFP_KERNEL); GFP_KERNEL);
...@@ -542,6 +579,7 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, ...@@ -542,6 +579,7 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
cq_base_pa = ALIGN(new->cq_base_pa, PAGE_SIZE); cq_base_pa = ALIGN(new->cq_base_pa, PAGE_SIZE);
ionic_cq_map(&new->cq, cq_base, cq_base_pa); ionic_cq_map(&new->cq, cq_base, cq_base_pa);
ionic_cq_bind(&new->cq, &new->q); ionic_cq_bind(&new->cq, &new->q);
}
if (flags & IONIC_QCQ_F_SG) { if (flags & IONIC_QCQ_F_SG) {
new->sg_size = PAGE_SIZE + (num_descs * sg_desc_size); new->sg_size = PAGE_SIZE + (num_descs * sg_desc_size);
...@@ -984,7 +1022,6 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr) ...@@ -984,7 +1022,6 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add, static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add,
bool can_sleep) bool can_sleep)
{ {
struct ionic *ionic = lif->ionic;
struct ionic_deferred_work *work; struct ionic_deferred_work *work;
unsigned int nmfilters; unsigned int nmfilters;
unsigned int nufilters; unsigned int nufilters;
...@@ -994,8 +1031,8 @@ static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add, ...@@ -994,8 +1031,8 @@ static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add,
* here before checking the need for deferral so that we * here before checking the need for deferral so that we
* can return an overflow error to the stack. * can return an overflow error to the stack.
*/ */
nmfilters = le32_to_cpu(ionic->ident.lif.eth.max_mcast_filters); nmfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
nufilters = le32_to_cpu(ionic->ident.lif.eth.max_ucast_filters); nufilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
if ((is_multicast_ether_addr(addr) && lif->nmcast < nmfilters)) if ((is_multicast_ether_addr(addr) && lif->nmcast < nmfilters))
lif->nmcast++; lif->nmcast++;
...@@ -1124,12 +1161,9 @@ static void ionic_dev_uc_sync(struct net_device *netdev, bool from_ndo) ...@@ -1124,12 +1161,9 @@ static void ionic_dev_uc_sync(struct net_device *netdev, bool from_ndo)
static void ionic_set_rx_mode(struct net_device *netdev, bool from_ndo) static void ionic_set_rx_mode(struct net_device *netdev, bool from_ndo)
{ {
struct ionic_lif *lif = netdev_priv(netdev); struct ionic_lif *lif = netdev_priv(netdev);
struct ionic_identity *ident;
unsigned int nfilters; unsigned int nfilters;
unsigned int rx_mode; unsigned int rx_mode;
ident = &lif->ionic->ident;
rx_mode = IONIC_RX_MODE_F_UNICAST; rx_mode = IONIC_RX_MODE_F_UNICAST;
rx_mode |= (netdev->flags & IFF_MULTICAST) ? IONIC_RX_MODE_F_MULTICAST : 0; rx_mode |= (netdev->flags & IFF_MULTICAST) ? IONIC_RX_MODE_F_MULTICAST : 0;
rx_mode |= (netdev->flags & IFF_BROADCAST) ? IONIC_RX_MODE_F_BROADCAST : 0; rx_mode |= (netdev->flags & IFF_BROADCAST) ? IONIC_RX_MODE_F_BROADCAST : 0;
...@@ -1144,7 +1178,7 @@ static void ionic_set_rx_mode(struct net_device *netdev, bool from_ndo) ...@@ -1144,7 +1178,7 @@ static void ionic_set_rx_mode(struct net_device *netdev, bool from_ndo)
* to see if we can disable NIC PROMISC * to see if we can disable NIC PROMISC
*/ */
ionic_dev_uc_sync(netdev, from_ndo); ionic_dev_uc_sync(netdev, from_ndo);
nfilters = le32_to_cpu(ident->lif.eth.max_ucast_filters); nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
if (netdev_uc_count(netdev) + 1 > nfilters) { if (netdev_uc_count(netdev) + 1 > nfilters) {
rx_mode |= IONIC_RX_MODE_F_PROMISC; rx_mode |= IONIC_RX_MODE_F_PROMISC;
lif->uc_overflow = true; lif->uc_overflow = true;
...@@ -1156,7 +1190,7 @@ static void ionic_set_rx_mode(struct net_device *netdev, bool from_ndo) ...@@ -1156,7 +1190,7 @@ static void ionic_set_rx_mode(struct net_device *netdev, bool from_ndo)
/* same for multicast */ /* same for multicast */
ionic_dev_uc_sync(netdev, from_ndo); ionic_dev_uc_sync(netdev, from_ndo);
nfilters = le32_to_cpu(ident->lif.eth.max_mcast_filters); nfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
if (netdev_mc_count(netdev) > nfilters) { if (netdev_mc_count(netdev) > nfilters) {
rx_mode |= IONIC_RX_MODE_F_ALLMULTI; rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
lif->mc_overflow = true; lif->mc_overflow = true;
...@@ -1594,22 +1628,16 @@ static void ionic_lif_rss_deinit(struct ionic_lif *lif) ...@@ -1594,22 +1628,16 @@ static void ionic_lif_rss_deinit(struct ionic_lif *lif)
static void ionic_txrx_disable(struct ionic_lif *lif) static void ionic_txrx_disable(struct ionic_lif *lif)
{ {
unsigned int i; unsigned int i;
int err; int err = 0;
if (lif->txqcqs) { if (lif->txqcqs) {
for (i = 0; i < lif->nxqs; i++) { for (i = 0; i < lif->nxqs; i++)
err = ionic_qcq_disable(lif->txqcqs[i]); err = ionic_qcq_disable(lif->txqcqs[i], (err != -ETIMEDOUT));
if (err == -ETIMEDOUT)
break;
}
} }
if (lif->rxqcqs) { if (lif->rxqcqs) {
for (i = 0; i < lif->nxqs; i++) { for (i = 0; i < lif->nxqs; i++)
err = ionic_qcq_disable(lif->rxqcqs[i]); err = ionic_qcq_disable(lif->rxqcqs[i], (err != -ETIMEDOUT));
if (err == -ETIMEDOUT)
break;
}
} }
} }
...@@ -1761,9 +1789,16 @@ static int ionic_txrx_init(struct ionic_lif *lif) ...@@ -1761,9 +1789,16 @@ static int ionic_txrx_init(struct ionic_lif *lif)
static int ionic_txrx_enable(struct ionic_lif *lif) static int ionic_txrx_enable(struct ionic_lif *lif)
{ {
int derr = 0;
int i, err; int i, err;
for (i = 0; i < lif->nxqs; i++) { for (i = 0; i < lif->nxqs; i++) {
if (!(lif->rxqcqs[i] && lif->txqcqs[i])) {
dev_err(lif->ionic->dev, "%s: bad qcq %d\n", __func__, i);
err = -ENXIO;
goto err_out;
}
ionic_rx_fill(&lif->rxqcqs[i]->q); ionic_rx_fill(&lif->rxqcqs[i]->q);
err = ionic_qcq_enable(lif->rxqcqs[i]); err = ionic_qcq_enable(lif->rxqcqs[i]);
if (err) if (err)
...@@ -1771,8 +1806,7 @@ static int ionic_txrx_enable(struct ionic_lif *lif) ...@@ -1771,8 +1806,7 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
err = ionic_qcq_enable(lif->txqcqs[i]); err = ionic_qcq_enable(lif->txqcqs[i]);
if (err) { if (err) {
if (err != -ETIMEDOUT) derr = ionic_qcq_disable(lif->rxqcqs[i], (err != -ETIMEDOUT));
ionic_qcq_disable(lif->rxqcqs[i]);
goto err_out; goto err_out;
} }
} }
...@@ -1781,12 +1815,8 @@ static int ionic_txrx_enable(struct ionic_lif *lif) ...@@ -1781,12 +1815,8 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
err_out: err_out:
while (i--) { while (i--) {
err = ionic_qcq_disable(lif->txqcqs[i]); derr = ionic_qcq_disable(lif->txqcqs[i], (derr != -ETIMEDOUT));
if (err == -ETIMEDOUT) derr = ionic_qcq_disable(lif->rxqcqs[i], (derr != -ETIMEDOUT));
break;
err = ionic_qcq_disable(lif->rxqcqs[i]);
if (err == -ETIMEDOUT)
break;
} }
return err; return err;
...@@ -2391,7 +2421,12 @@ int ionic_lif_alloc(struct ionic *ionic) ...@@ -2391,7 +2421,12 @@ int ionic_lif_alloc(struct ionic *ionic)
lif->identity = lid; lif->identity = lid;
lif->lif_type = IONIC_LIF_TYPE_CLASSIC; lif->lif_type = IONIC_LIF_TYPE_CLASSIC;
ionic_lif_identify(ionic, lif->lif_type, lif->identity); err = ionic_lif_identify(ionic, lif->lif_type, lif->identity);
if (err) {
dev_err(ionic->dev, "Cannot identify type %d: %d\n",
lif->lif_type, err);
goto err_out_free_netdev;
}
lif->netdev->min_mtu = max_t(unsigned int, ETH_MIN_MTU, lif->netdev->min_mtu = max_t(unsigned int, ETH_MIN_MTU,
le32_to_cpu(lif->identity->eth.min_frame_size)); le32_to_cpu(lif->identity->eth.min_frame_size));
lif->netdev->max_mtu = lif->netdev->max_mtu =
...@@ -2522,7 +2557,15 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif) ...@@ -2522,7 +2557,15 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
dev_info(ionic->dev, "FW Up: restarting LIFs\n"); dev_info(ionic->dev, "FW Up: restarting LIFs\n");
ionic_init_devinfo(ionic); ionic_init_devinfo(ionic);
ionic_port_init(ionic); err = ionic_identify(ionic);
if (err)
goto err_out;
err = ionic_port_identify(ionic);
if (err)
goto err_out;
err = ionic_port_init(ionic);
if (err)
goto err_out;
err = ionic_qcqs_alloc(lif); err = ionic_qcqs_alloc(lif);
if (err) if (err)
goto err_out; goto err_out;
......
...@@ -64,6 +64,8 @@ static const char *ionic_error_to_str(enum ionic_status_code code) ...@@ -64,6 +64,8 @@ static const char *ionic_error_to_str(enum ionic_status_code code)
return "IONIC_RC_ERROR"; return "IONIC_RC_ERROR";
case IONIC_RC_ERDMA: case IONIC_RC_ERDMA:
return "IONIC_RC_ERDMA"; return "IONIC_RC_ERDMA";
case IONIC_RC_EBAD_FW:
return "IONIC_RC_EBAD_FW";
default: default:
return "IONIC_RC_UNKNOWN"; return "IONIC_RC_UNKNOWN";
} }
...@@ -429,17 +431,23 @@ int ionic_identify(struct ionic *ionic) ...@@ -429,17 +431,23 @@ int ionic_identify(struct ionic *ionic)
sz = min(sizeof(ident->dev), sizeof(idev->dev_cmd_regs->data)); sz = min(sizeof(ident->dev), sizeof(idev->dev_cmd_regs->data));
memcpy_fromio(&ident->dev, &idev->dev_cmd_regs->data, sz); memcpy_fromio(&ident->dev, &idev->dev_cmd_regs->data, sz);
} }
mutex_unlock(&ionic->dev_cmd_lock); mutex_unlock(&ionic->dev_cmd_lock);
if (err) if (err) {
goto err_out_unmap; dev_err(ionic->dev, "Cannot identify ionic: %dn", err);
goto err_out;
}
ionic_debugfs_add_ident(ionic); err = ionic_lif_identify(ionic, IONIC_LIF_TYPE_CLASSIC,
&ionic->ident.lif);
if (err) {
dev_err(ionic->dev, "Cannot identify LIFs: %d\n", err);
goto err_out;
}
return 0; return 0;
err_out_unmap: err_out:
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment