Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a18dfc6 authored by Gavin Shan's avatar Gavin Shan Committed by Benjamin Herrenschmidt
Browse files

powerpc/eeh: Use cached capability for log dump



When calling into eeh_gather_pci_data() on pSeries platform, we
possiblly don't have pci_dev instance yet, but eeh_dev is always
ready. So we use cached capability from eeh_dev instead of pci_dev
for log dump there. In order to keep things unified, we also cache
PCI capability positions to eeh_dev for PowerNV as well.

Signed-off-by: default avatarGavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 2d86c385
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -99,7 +99,9 @@ struct eeh_dev {
	int config_addr;		/* Config address		*/
	int pe_config_addr;		/* PE config address		*/
	u32 config_space[16];		/* Saved PCI config space	*/
	u8 pcie_cap;			/* Saved PCIe capability	*/
	int pcix_cap;			/* Saved PCIx capability	*/
	int pcie_cap;			/* Saved PCIe capability	*/
	int aer_cap;			/* Saved AER capability		*/
	struct eeh_pe *pe;		/* Associated PE		*/
	struct list_head list;		/* Form link list in the PE	*/
	struct pci_controller *phb;	/* Associated PHB		*/
+17 −22
Original line number Diff line number Diff line
@@ -145,7 +145,6 @@ static struct eeh_stats eeh_stats;
static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
{
	struct device_node *dn = eeh_dev_to_of_node(edev);
	struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
	u32 cfg;
	int cap, i;
	int n = 0;
@@ -161,13 +160,8 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
	n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
	pr_warn("EEH: PCI cmd/status register: %08x\n", cfg);

	if (!dev) {
		pr_warn("EEH: no PCI device for this of node\n");
		return n;
	}

	/* Gather bridge-specific registers */
	if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
	if (edev->mode & EEH_DEV_BRIDGE) {
		eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);
		n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
		pr_warn("EEH: Bridge secondary status: %04x\n", cfg);
@@ -178,7 +172,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
	}

	/* Dump out the PCI-X command and status regs */
	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
	cap = edev->pcix_cap;
	if (cap) {
		eeh_ops->read_config(dn, cap, 4, &cfg);
		n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
@@ -189,22 +183,24 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
		pr_warn("EEH: PCI-X status: %08x\n", cfg);
	}

	/* If PCI-E capable, dump PCI-E cap 10, and the AER */
	if (pci_is_pcie(dev)) {
	/* If PCI-E capable, dump PCI-E cap 10 */
	cap = edev->pcie_cap;
	if (cap) {
		n += scnprintf(buf+n, len-n, "pci-e cap10:\n");
		pr_warn("EEH: PCI-E capabilities and status follow:\n");

		for (i=0; i<=8; i++) {
			eeh_ops->read_config(dn, dev->pcie_cap+4*i, 4, &cfg);
			eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
			n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
			pr_warn("EEH: PCI-E %02x: %08x\n", i, cfg);
		}
	}

		cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
	/* If AER capable, dump it */
	cap = edev->aer_cap;
	if (cap) {
		n += scnprintf(buf+n, len-n, "pci-e AER:\n");
			pr_warn("EEH: PCI-E AER capability register "
				"set follows:\n");
		pr_warn("EEH: PCI-E AER capability register set follows:\n");

		for (i=0; i<14; i++) {
			eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
@@ -212,7 +208,6 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
			pr_warn("EEH: PCI-E AER %02x: %08x\n", i, cfg);
		}
	}
	}

	return n;
}
+4 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
	edev->mode	&= 0xFFFFFF00;
	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
		edev->mode |= EEH_DEV_BRIDGE;
	edev->pcix_cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
	if (pci_is_pcie(dev)) {
		edev->pcie_cap = pci_pcie_cap(dev);

@@ -133,6 +134,9 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
			edev->mode |= EEH_DEV_ROOT_PORT;
		else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)
			edev->mode |= EEH_DEV_DS_PORT;

		edev->aer_cap = pci_find_ext_capability(dev,
							PCI_EXT_CAP_ID_ERR);
	}

	edev->config_addr	= ((dev->bus->number << 8) | dev->devfn);
+32 −0
Original line number Diff line number Diff line
@@ -175,6 +175,36 @@ static int pseries_eeh_find_cap(struct device_node *dn, int cap)
	return 0;
}

static int pseries_eeh_find_ecap(struct device_node *dn, int cap)
{
	struct pci_dn *pdn = PCI_DN(dn);
	struct eeh_dev *edev = of_node_to_eeh_dev(dn);
	u32 header;
	int pos = 256;
	int ttl = (4096 - 256) / 8;

	if (!edev || !edev->pcie_cap)
		return 0;
	if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL)
		return 0;
	else if (!header)
		return 0;

	while (ttl-- > 0) {
		if (PCI_EXT_CAP_ID(header) == cap && pos)
			return pos;

		pos = PCI_EXT_CAP_NEXT(header);
		if (pos < 256)
			break;

		if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL)
			break;
	}

	return 0;
}

/**
 * pseries_eeh_of_probe - EEH probe on the given device
 * @dn: OF node
@@ -220,7 +250,9 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
	 * or PCIe switch downstream port.
	 */
	edev->class_code = class_code;
	edev->pcix_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_PCIX);
	edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP);
	edev->aer_cap = pseries_eeh_find_ecap(dn, PCI_EXT_CAP_ID_ERR);
	edev->mode &= 0xFFFFFF00;
	if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
		edev->mode |= EEH_DEV_BRIDGE;