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)
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);
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)
......@@ -389,9 +396,13 @@ static void ionic_remove(struct pci_dev *pdev)
{
struct ionic *ionic = pci_get_drvdata(pdev);
del_timer_sync(&ionic->watchdog_timer);
timer_shutdown_sync(&ionic->watchdog_timer);
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_devlink_unregister(ionic);
ionic_lif_deinit(ionic->lif);
......@@ -416,6 +427,8 @@ static void ionic_reset_prepare(struct pci_dev *pdev)
dev_dbg(ionic->dev, "%s: device stopping\n", __func__);
set_bit(IONIC_LIF_F_FW_RESET, lif->state);
del_timer_sync(&ionic->watchdog_timer);
cancel_work_sync(&lif->deferred.work);
......@@ -424,6 +437,7 @@ static void ionic_reset_prepare(struct pci_dev *pdev)
ionic_txrx_free(lif);
ionic_lif_deinit(lif);
ionic_qcqs_free(lif);
ionic_debugfs_del_lif(lif);
mutex_unlock(&lif->queue_lock);
ionic_dev_teardown(ionic);
......@@ -455,10 +469,35 @@ static void ionic_reset_done(struct pci_dev *pdev)
__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 = {
/* FLR handling */
.reset_prepare = ionic_reset_prepare,
.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 = {
......
......@@ -287,6 +287,9 @@ void ionic_debugfs_add_lif(struct ionic_lif *lif)
void ionic_debugfs_del_lif(struct ionic_lif *lif)
{
if (!lif->dentry)
return;
debugfs_remove_recursive(lif->dentry);
lif->dentry = NULL;
}
......
......@@ -165,9 +165,19 @@ void ionic_dev_teardown(struct ionic *ionic)
}
/* 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
* fw_status != 0xff (bad PCI read)
......@@ -175,6 +185,11 @@ bool ionic_is_fw_running(struct ionic_dev *idev)
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)
{
unsigned long check_time, last_check_time;
......@@ -199,10 +214,8 @@ int ionic_heartbeat_check(struct ionic *ionic)
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 (!ionic_is_fw_running(idev)) {
if (!__ionic_is_fw_running(idev, &fw_status)) {
fw_status_ready = false;
} else {
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)
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));
iowrite32(0, &idev->dev_cmd_regs->done);
iowrite32(1, &idev->dev_cmd_regs->doorbell);
......
......@@ -153,6 +153,7 @@ struct ionic_dev {
bool fw_hb_ready;
bool fw_status_ready;
u8 fw_generation;
u8 opcode;
u64 __iomem *db_pages;
dma_addr_t phy_db_pages;
......
......@@ -3161,6 +3161,9 @@ static void ionic_lif_reset(struct ionic_lif *lif)
{
struct ionic_dev *idev = &lif->ionic->idev;
if (!ionic_is_fw_running(idev))
return;
mutex_lock(&lif->ionic->dev_cmd_lock);
ionic_dev_cmd_lif_reset(idev, lif->index);
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,
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;
if (!ionic_is_fw_running(&lif->ionic->idev))
return 0;
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;
err = ionic_adminq_post(lif, ctx);
return __ionic_adminq_post_wait(lif, ctx, true);
}
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)
......@@ -443,7 +449,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
*/
max_wait = jiffies + (max_seconds * HZ);
try_again:
opcode = readb(&idev->dev_cmd_regs->cmd.cmd.opcode);
opcode = idev->opcode;
start_time = jiffies;
for (fw_up = ionic_is_fw_running(idev);
!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