drivers/pci/pcie/dpc.c

Source file repositories/reference/linux-study-clean/drivers/pci/pcie/dpc.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/pcie/dpc.c
Extension
.c
Size
14784 bytes
Lines
537
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: implementation source
Status
source implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

aer_get_device_error_info(&info, 0)) {
			aer_print_error(&info, 0);
			pci_aer_clear_nonfatal_status(pdev);
			pci_aer_clear_fatal_status(pdev);
		}
		break;
	case PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE:
	case PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE:
		pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID,
				     &source);
		pci_warn(pdev, "containment event, status:%#06x, %s received from %04x:%02x:%02x.%d\n",
			 status,
			 (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE) ?
				"ERR_FATAL" : "ERR_NONFATAL",
			 pci_domain_nr(pdev->bus), PCI_BUS_NUM(source),
			 PCI_SLOT(source), PCI_FUNC(source));
		break;
	case PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT:
		ext_reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT;
		pci_warn(pdev, "containment event, status:%#06x: %s detected\n",
			 status,
			 (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO) ?
			 "RP PIO error" :
			 (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER) ?
			 "software trigger" :
			 "reserved error");
		/* show RP PIO error detail information */
		if (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO &&
		    pdev->dpc_rp_extensions)
			dpc_process_rp_pio_error(pdev);
		break;
	}
}

static void pci_clear_surpdn_errors(struct pci_dev *pdev)
{
	if (pdev->dpc_rp_extensions)
		pci_write_config_dword(pdev, pdev->dpc_cap +
				       PCI_EXP_DPC_RP_PIO_STATUS, ~0);

	/*
	 * In practice, Surprise Down errors have been observed to also set
	 * error bits in the Status Register as well as the Fatal Error
	 * Detected bit in the Device Status Register.
	 */
	pci_write_config_word(pdev, PCI_STATUS, 0xffff);

	pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_FED);
}

static void dpc_handle_surprise_removal(struct pci_dev *pdev)
{
	if (!pcie_wait_for_link(pdev, false)) {
		pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
		goto out;
	}

	if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
		goto out;

	pci_aer_raw_clear_status(pdev);
	pci_clear_surpdn_errors(pdev);

	pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
			      PCI_EXP_DPC_STATUS_TRIGGER);

out:
	clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
	wake_up_all(&dpc_completed_waitqueue);
}

static bool dpc_is_surprise_removal(struct pci_dev *pdev)
{
	u16 status;

	if (!pdev->is_hotplug_bridge)
		return false;

	if (pci_read_config_word(pdev, pdev->aer_cap + PCI_ERR_UNCOR_STATUS,
				 &status))
		return false;

	return status & PCI_ERR_UNC_SURPDN;
}

static irqreturn_t dpc_handler(int irq, void *context)
{
	struct pci_dev *pdev = context;

	/*

Annotation

Implementation Notes