Commit d2e9464e authored by David S. Miller's avatar David S. Miller

Merge branch 'ionic-pci-errors'

Shannon Nelson says:

====================
ionic: updates to PCI error handling

These are improvements to our PCI error handling, including FLR and
AER events.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e5bc1f4c c3a910e1
...@@ -215,9 +215,16 @@ static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs) ...@@ -215,9 +215,16 @@ static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs)
static void ionic_clear_pci(struct ionic *ionic) static void ionic_clear_pci(struct ionic *ionic)
{ {
ionic->idev.dev_info_regs = NULL;
ionic->idev.dev_cmd_regs = NULL;
ionic->idev.intr_status = NULL;
ionic->idev.intr_ctrl = NULL;
ionic_unmap_bars(ionic); ionic_unmap_bars(ionic);
pci_release_regions(ionic->pdev); pci_release_regions(ionic->pdev);
pci_disable_device(ionic->pdev);
if (atomic_read(&ionic->pdev->enable_cnt) > 0)
pci_disable_device(ionic->pdev);
} }
static int ionic_setup_one(struct ionic *ionic) static int ionic_setup_one(struct ionic *ionic)
...@@ -389,9 +396,13 @@ static void ionic_remove(struct pci_dev *pdev) ...@@ -389,9 +396,13 @@ static void ionic_remove(struct pci_dev *pdev)
{ {
struct ionic *ionic = pci_get_drvdata(pdev); struct ionic *ionic = pci_get_drvdata(pdev);
del_timer_sync(&ionic->watchdog_timer); timer_shutdown_sync(&ionic->watchdog_timer);
if (ionic->lif) { if (ionic->lif) {
/* prevent adminq cmds if already known as down */
if (test_and_clear_bit(IONIC_LIF_F_FW_RESET, ionic->lif->state))
set_bit(IONIC_LIF_F_FW_STOPPING, ionic->lif->state);
ionic_lif_unregister(ionic->lif); ionic_lif_unregister(ionic->lif);
ionic_devlink_unregister(ionic); ionic_devlink_unregister(ionic);
ionic_lif_deinit(ionic->lif); ionic_lif_deinit(ionic->lif);
...@@ -416,6 +427,8 @@ static void ionic_reset_prepare(struct pci_dev *pdev) ...@@ -416,6 +427,8 @@ static void ionic_reset_prepare(struct pci_dev *pdev)
dev_dbg(ionic->dev, "%s: device stopping\n", __func__); dev_dbg(ionic->dev, "%s: device stopping\n", __func__);
set_bit(IONIC_LIF_F_FW_RESET, lif->state);
del_timer_sync(&ionic->watchdog_timer); del_timer_sync(&ionic->watchdog_timer);
cancel_work_sync(&lif->deferred.work); cancel_work_sync(&lif->deferred.work);
...@@ -424,6 +437,7 @@ static void ionic_reset_prepare(struct pci_dev *pdev) ...@@ -424,6 +437,7 @@ static void ionic_reset_prepare(struct pci_dev *pdev)
ionic_txrx_free(lif); ionic_txrx_free(lif);
ionic_lif_deinit(lif); ionic_lif_deinit(lif);
ionic_qcqs_free(lif); ionic_qcqs_free(lif);
ionic_debugfs_del_lif(lif);
mutex_unlock(&lif->queue_lock); mutex_unlock(&lif->queue_lock);
ionic_dev_teardown(ionic); ionic_dev_teardown(ionic);
...@@ -455,10 +469,35 @@ static void ionic_reset_done(struct pci_dev *pdev) ...@@ -455,10 +469,35 @@ static void ionic_reset_done(struct pci_dev *pdev)
__func__, err ? "failed" : "done"); __func__, err ? "failed" : "done");
} }
static pci_ers_result_t ionic_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t error)
{
if (error == pci_channel_io_frozen) {
ionic_reset_prepare(pdev);
return PCI_ERS_RESULT_NEED_RESET;
}
return PCI_ERS_RESULT_NONE;
}
static void ionic_pci_error_resume(struct pci_dev *pdev)
{
struct ionic *ionic = pci_get_drvdata(pdev);
struct ionic_lif *lif = ionic->lif;
if (lif && test_bit(IONIC_LIF_F_FW_RESET, lif->state))
pci_reset_function_locked(pdev);
}
static const struct pci_error_handlers ionic_err_handler = { static const struct pci_error_handlers ionic_err_handler = {
/* FLR handling */ /* FLR handling */
.reset_prepare = ionic_reset_prepare, .reset_prepare = ionic_reset_prepare,
.reset_done = ionic_reset_done, .reset_done = ionic_reset_done,
/* PCI bus error detected on this device */
.error_detected = ionic_pci_error_detected,
.resume = ionic_pci_error_resume,
}; };
static struct pci_driver ionic_driver = { static struct pci_driver ionic_driver = {
......
...@@ -287,6 +287,9 @@ void ionic_debugfs_add_lif(struct ionic_lif *lif) ...@@ -287,6 +287,9 @@ void ionic_debugfs_add_lif(struct ionic_lif *lif)
void ionic_debugfs_del_lif(struct ionic_lif *lif) void ionic_debugfs_del_lif(struct ionic_lif *lif)
{ {
if (!lif->dentry)
return;
debugfs_remove_recursive(lif->dentry); debugfs_remove_recursive(lif->dentry);
lif->dentry = NULL; lif->dentry = NULL;
} }
......
...@@ -165,9 +165,19 @@ void ionic_dev_teardown(struct ionic *ionic) ...@@ -165,9 +165,19 @@ void ionic_dev_teardown(struct ionic *ionic)
} }
/* Devcmd Interface */ /* Devcmd Interface */
bool ionic_is_fw_running(struct ionic_dev *idev) static bool __ionic_is_fw_running(struct ionic_dev *idev, u8 *status_ptr)
{ {
u8 fw_status = ioread8(&idev->dev_info_regs->fw_status); u8 fw_status;
if (!idev->dev_info_regs) {
if (status_ptr)
*status_ptr = 0xff;
return false;
}
fw_status = ioread8(&idev->dev_info_regs->fw_status);
if (status_ptr)
*status_ptr = fw_status;
/* firmware is useful only if the running bit is set and /* firmware is useful only if the running bit is set and
* fw_status != 0xff (bad PCI read) * fw_status != 0xff (bad PCI read)
...@@ -175,6 +185,11 @@ bool ionic_is_fw_running(struct ionic_dev *idev) ...@@ -175,6 +185,11 @@ bool ionic_is_fw_running(struct ionic_dev *idev)
return (fw_status != 0xff) && (fw_status & IONIC_FW_STS_F_RUNNING); return (fw_status != 0xff) && (fw_status & IONIC_FW_STS_F_RUNNING);
} }
bool ionic_is_fw_running(struct ionic_dev *idev)
{
return __ionic_is_fw_running(idev, NULL);
}
int ionic_heartbeat_check(struct ionic *ionic) int ionic_heartbeat_check(struct ionic *ionic)
{ {
unsigned long check_time, last_check_time; unsigned long check_time, last_check_time;
...@@ -199,10 +214,8 @@ int ionic_heartbeat_check(struct ionic *ionic) ...@@ -199,10 +214,8 @@ int ionic_heartbeat_check(struct ionic *ionic)
goto do_check_time; goto do_check_time;
} }
fw_status = ioread8(&idev->dev_info_regs->fw_status);
/* If fw_status is not ready don't bother with the generation */ /* If fw_status is not ready don't bother with the generation */
if (!ionic_is_fw_running(idev)) { if (!__ionic_is_fw_running(idev, &fw_status)) {
fw_status_ready = false; fw_status_ready = false;
} else { } else {
fw_generation = fw_status & IONIC_FW_STS_F_GENERATION; fw_generation = fw_status & IONIC_FW_STS_F_GENERATION;
...@@ -321,6 +334,7 @@ void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp) ...@@ -321,6 +334,7 @@ void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp)
void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd) void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
{ {
idev->opcode = cmd->cmd.opcode;
memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd)); memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd));
iowrite32(0, &idev->dev_cmd_regs->done); iowrite32(0, &idev->dev_cmd_regs->done);
iowrite32(1, &idev->dev_cmd_regs->doorbell); iowrite32(1, &idev->dev_cmd_regs->doorbell);
......
...@@ -153,6 +153,7 @@ struct ionic_dev { ...@@ -153,6 +153,7 @@ struct ionic_dev {
bool fw_hb_ready; bool fw_hb_ready;
bool fw_status_ready; bool fw_status_ready;
u8 fw_generation; u8 fw_generation;
u8 opcode;
u64 __iomem *db_pages; u64 __iomem *db_pages;
dma_addr_t phy_db_pages; dma_addr_t phy_db_pages;
......
...@@ -3161,6 +3161,9 @@ static void ionic_lif_reset(struct ionic_lif *lif) ...@@ -3161,6 +3161,9 @@ static void ionic_lif_reset(struct ionic_lif *lif)
{ {
struct ionic_dev *idev = &lif->ionic->idev; struct ionic_dev *idev = &lif->ionic->idev;
if (!ionic_is_fw_running(idev))
return;
mutex_lock(&lif->ionic->dev_cmd_lock); mutex_lock(&lif->ionic->dev_cmd_lock);
ionic_dev_cmd_lif_reset(idev, lif->index); ionic_dev_cmd_lif_reset(idev, lif->index);
ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT); ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
......
...@@ -388,22 +388,28 @@ int ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx, ...@@ -388,22 +388,28 @@ int ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
do_msg); do_msg);
} }
int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) static int __ionic_adminq_post_wait(struct ionic_lif *lif,
struct ionic_admin_ctx *ctx,
const bool do_msg)
{ {
int err; int err;
if (!ionic_is_fw_running(&lif->ionic->idev))
return 0;
err = ionic_adminq_post(lif, ctx); err = ionic_adminq_post(lif, ctx);
return ionic_adminq_wait(lif, ctx, err, true); return ionic_adminq_wait(lif, ctx, err, do_msg);
} }
int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
{ {
int err; return __ionic_adminq_post_wait(lif, ctx, true);
}
err = ionic_adminq_post(lif, ctx);
return ionic_adminq_wait(lif, ctx, err, false); int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
{
return __ionic_adminq_post_wait(lif, ctx, false);
} }
static void ionic_dev_cmd_clean(struct ionic *ionic) static void ionic_dev_cmd_clean(struct ionic *ionic)
...@@ -443,7 +449,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds, ...@@ -443,7 +449,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
*/ */
max_wait = jiffies + (max_seconds * HZ); max_wait = jiffies + (max_seconds * HZ);
try_again: try_again:
opcode = readb(&idev->dev_cmd_regs->cmd.cmd.opcode); opcode = idev->opcode;
start_time = jiffies; start_time = jiffies;
for (fw_up = ionic_is_fw_running(idev); for (fw_up = ionic_is_fw_running(idev);
!done && fw_up && time_before(jiffies, max_wait); !done && fw_up && time_before(jiffies, max_wait);
......
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