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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d2e9464e63
@ -215,9 +215,16 @@ out:
|
||||
|
||||
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 @@ err_out:
|
||||
__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 @@ 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 (!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(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
|
||||
{
|
||||
return __ionic_adminq_post_wait(lif, ctx, true);
|
||||
}
|
||||
|
||||
int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ionic_adminq_post(lif, ctx);
|
||||
|
||||
return ionic_adminq_wait(lif, ctx, err, false);
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user