summaryrefslogtreecommitdiffstats
path: root/platforms
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2016-12-08 10:51:39 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-12-13 16:27:09 +1100
commit4a6d1a70f0fe50ceb8176f2d6d0fc612f8e32589 (patch)
tree71574708d32dbe972b9eeae6c9095f482bfddb66 /platforms
parent7fe3de438b19545471d2fb72e54ed01a40b12706 (diff)
downloadblackbird-skiboot-4a6d1a70f0fe50ceb8176f2d6d0fc612f8e32589.tar.gz
blackbird-skiboot-4a6d1a70f0fe50ceb8176f2d6d0fc612f8e32589.zip
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.h1
-rw-r--r--platforms/astbmc/barreleye.c1
-rw-r--r--platforms/astbmc/firestone.c1
-rw-r--r--platforms/astbmc/garrison.c1
-rw-r--r--platforms/astbmc/habanero.c1
-rw-r--r--platforms/astbmc/p8dtu.c2
-rw-r--r--platforms/astbmc/slots.c87
7 files changed, 94 insertions, 0 deletions
diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h
index 3ef8dbf0..99958001 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 d3a93c36..554aacf1 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 d2c4d146..fc6575b1 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 ed504ac8..db886cbb 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 86e49bf7..0d3a01f5 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 ac7a1911..8d7f92f0 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 10a99bbd..aeca0072 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);
+}
OpenPOWER on IntegriCloud