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

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
Loading
Loading
Loading
Loading
+41 −2
Original line number Diff line number Diff line
@@ -215,8 +215,15 @@ 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);

	if (atomic_read(&ionic->pdev->enable_cnt) > 0)
		pci_disable_device(ionic->pdev);
}

@@ -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 = {
+3 −0
Original line number Diff line number Diff line
@@ -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;
}
+19 −5
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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);
Loading