diff options
author | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-12-08 10:51:39 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-12-13 16:27:09 +1100 |
commit | 4a6d1a70f0fe50ceb8176f2d6d0fc612f8e32589 (patch) | |
tree | 71574708d32dbe972b9eeae6c9095f482bfddb66 /platforms | |
parent | 7fe3de438b19545471d2fb72e54ed01a40b12706 (diff) | |
download | skiboot-4a6d1a70f0fe50ceb8176f2d6d0fc612f8e32589.zip skiboot-4a6d1a70f0fe50ceb8176f2d6d0fc612f8e32589.tar.gz skiboot-4a6d1a70f0fe50ceb8176f2d6d0fc612f8e32589.tar.bz2 |
BMC/PCI: Check slot tables against detected devices
On BMC machines, we have slot tables of built in PHBs, slots and devices
that are physically present in the system (such as the BMC itself). We
can use these tables to check what we *detected* against what *should*
be in the system and throw an error if they differ.
We have seen this occur a couple of times while still booting, giving the
user just an empty petitboot screen and not much else to go on. This
patch helps in that we get a skiboot error message, and at some point
in the future when we pump them up to the OS we could get a big friendly
error message telling you you're having a bad day.
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Acked-by: Russell Currey <ruscur@russell.cc>
[stewart@linux.vnet.ibm.com: add barreleye]
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'platforms')
-rw-r--r-- | platforms/astbmc/astbmc.h | 1 | ||||
-rw-r--r-- | platforms/astbmc/barreleye.c | 1 | ||||
-rw-r--r-- | platforms/astbmc/firestone.c | 1 | ||||
-rw-r--r-- | platforms/astbmc/garrison.c | 1 | ||||
-rw-r--r-- | platforms/astbmc/habanero.c | 1 | ||||
-rw-r--r-- | platforms/astbmc/p8dtu.c | 2 | ||||
-rw-r--r-- | platforms/astbmc/slots.c | 87 |
7 files changed, 94 insertions, 0 deletions
diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h index 3ef8dbf..9995800 100644 --- a/platforms/astbmc/astbmc.h +++ b/platforms/astbmc/astbmc.h @@ -49,6 +49,7 @@ extern int64_t astbmc_ipmi_power_down(uint64_t request); extern void astbmc_init(void); extern void astbmc_ext_irq_serirq_cpld(unsigned int chip_id); extern int pnor_init(void); +extern void check_all_slot_table(void); extern void slot_table_init(const struct slot_table_entry *top_table); extern void slot_table_get_slot_info(struct phb *phb, struct pci_device * pd); diff --git a/platforms/astbmc/barreleye.c b/platforms/astbmc/barreleye.c index d3a93c3..554aacf 100644 --- a/platforms/astbmc/barreleye.c +++ b/platforms/astbmc/barreleye.c @@ -163,6 +163,7 @@ DECLARE_PLATFORM(barreleye) = { .probe = barreleye_probe, .init = astbmc_init, .pci_get_slot_info = slot_table_get_slot_info, + .pci_probe_complete = check_all_slot_table, .external_irq = astbmc_ext_irq_serirq_cpld, .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, diff --git a/platforms/astbmc/firestone.c b/platforms/astbmc/firestone.c index d2c4d14..fc6575b 100644 --- a/platforms/astbmc/firestone.c +++ b/platforms/astbmc/firestone.c @@ -150,6 +150,7 @@ DECLARE_PLATFORM(firestone) = { .probe = firestone_probe, .init = astbmc_init, .pci_get_slot_info = slot_table_get_slot_info, + .pci_probe_complete = check_all_slot_table, .external_irq = astbmc_ext_irq_serirq_cpld, .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, diff --git a/platforms/astbmc/garrison.c b/platforms/astbmc/garrison.c index ed504ac..db886cb 100644 --- a/platforms/astbmc/garrison.c +++ b/platforms/astbmc/garrison.c @@ -297,6 +297,7 @@ DECLARE_PLATFORM(garrison) = { .probe = garrison_probe, .init = astbmc_init, .pci_get_slot_info = slot_table_get_slot_info, + .pci_probe_complete = check_all_slot_table, .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, .elog_commit = ipmi_elog_commit, diff --git a/platforms/astbmc/habanero.c b/platforms/astbmc/habanero.c index 86e49bf..0d3a01f 100644 --- a/platforms/astbmc/habanero.c +++ b/platforms/astbmc/habanero.c @@ -145,6 +145,7 @@ DECLARE_PLATFORM(habanero) = { .probe = habanero_probe, .init = astbmc_init, .pci_get_slot_info = slot_table_get_slot_info, + .pci_probe_complete = check_all_slot_table, .external_irq = astbmc_ext_irq_serirq_cpld, .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, diff --git a/platforms/astbmc/p8dtu.c b/platforms/astbmc/p8dtu.c index ac7a191..8d7f92f 100644 --- a/platforms/astbmc/p8dtu.c +++ b/platforms/astbmc/p8dtu.c @@ -240,6 +240,7 @@ DECLARE_PLATFORM(p8dtu1u) = { .bmc = &astbmc_smc, .init = astbmc_init, .pci_get_slot_info = slot_table_get_slot_info, + .pci_probe_complete = check_all_slot_table, .external_irq = astbmc_ext_irq_serirq_cpld, .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, @@ -256,6 +257,7 @@ DECLARE_PLATFORM(p8dtu2u) = { .bmc = &astbmc_smc, .init = astbmc_init, .pci_get_slot_info = slot_table_get_slot_info, + .pci_probe_complete = check_all_slot_table, .external_irq = astbmc_ext_irq_serirq_cpld, .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, diff --git a/platforms/astbmc/slots.c b/platforms/astbmc/slots.c index 10a99bb..aeca007 100644 --- a/platforms/astbmc/slots.c +++ b/platforms/astbmc/slots.c @@ -188,3 +188,90 @@ void slot_table_get_slot_info(struct phb *phb, struct pci_device *pd) pluggable = !!(ent->etype == st_pluggable_slot); init_slot_info(slot, pluggable, (void *)ent); } + +static int __pci_find_dev_by_location(struct phb *phb, + struct pci_device *pd, void *userdata) +{ + uint16_t location = *((uint16_t *)userdata); + + if (!phb || !pd) + return 0; + + if ((pd->bdfn & 0xff) == location) + return 1; + + return 0; +} + +static struct pci_device *pci_find_dev_by_location(struct phb *phb, uint16_t location) +{ + return pci_walk_dev(phb, NULL, __pci_find_dev_by_location, &location); +} + +static struct phb* get_phb_by_location(uint32_t location) +{ + struct phb *phb = NULL; + uint32_t chip_id, phb_idx; + + for_each_phb(phb) { + chip_id = dt_get_chip_id(phb->dt_node); + phb_idx = dt_prop_get_u32_def(phb->dt_node, + "ibm,phb-index", 0); + if (location == ST_LOC_PHB(chip_id, phb_idx)) + break; + } + + return phb; +} + +static int check_slot_table(struct phb *phb, + const struct slot_table_entry *parent) +{ + const struct slot_table_entry *ent; + struct pci_device *dev = NULL; + int r = 0; + + if (parent == NULL) + return 0; + + for (ent = parent; ent->etype != st_end; ent++) { + switch (ent->etype) { + case st_phb: + phb = get_phb_by_location(ent->location); + if (!phb) { + prlog(PR_ERR, "PCI: PHB %s (%x) not found\n", + ent->name, ent->location); + r++; + } + break; + case st_pluggable_slot: + case st_builtin_dev: + if (!phb) + break; + phb_lock(phb); + dev = pci_find_dev_by_location(phb, ent->location); + phb_unlock(phb); + if (!dev) { + prlog(PR_ERR, "PCI: built-in device not found: %s (loc: %x)\n", + ent->name, ent->location); + r++; + } + break; + case st_end: + case st_npu_slot: + break; + } + if (ent->children) + r+= check_slot_table(phb, ent->children); + } + return r; +} + +void check_all_slot_table(void) +{ + if (!slot_top_table) + return; + + prlog(PR_DEBUG, "PCI: Checking slot table against detected devices\n"); + check_slot_table(NULL, slot_top_table); +} |