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: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
Родитель
2d86c385a1
Коммит
2a18dfc6ee
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче