aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/platforms/astbmc/slots.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/platforms/astbmc/slots.c')
-rw-r--r--roms/skiboot/platforms/astbmc/slots.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/roms/skiboot/platforms/astbmc/slots.c b/roms/skiboot/platforms/astbmc/slots.c
new file mode 100644
index 000000000..622483a15
--- /dev/null
+++ b/roms/skiboot/platforms/astbmc/slots.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2015-2018 IBM Corp. */
+
+#include <skiboot.h>
+#include <device.h>
+#include <console.h>
+#include <chip.h>
+#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
+
+#include "astbmc.h"
+
+static const struct slot_table_entry *slot_top_table;
+
+void slot_table_init(const struct slot_table_entry *top_table)
+{
+ slot_top_table = top_table;
+}
+
+static const struct slot_table_entry *match_slot_phb_entry(struct phb *phb)
+{
+ uint32_t chip_id = dt_get_chip_id(phb->dt_node);
+ uint32_t phb_idx = dt_prop_get_u32_def(phb->dt_node,
+ "ibm,phb-index", 0);
+ const struct slot_table_entry *ent;
+
+ if (!slot_top_table)
+ return NULL;
+
+ for (ent = slot_top_table; ent->etype != st_end; ent++) {
+ if (ent->etype != st_phb) {
+ prerror("SLOT: Bad DEV entry type in table !\n");
+ continue;
+ }
+ if (ent->location == ST_LOC_PHB(chip_id, phb_idx))
+ return ent;
+ }
+ return NULL;
+}
+
+static const struct slot_table_entry *match_slot_dev_entry(struct phb *phb,
+ struct pci_device *pd)
+{
+ const struct slot_table_entry *parent, *ent;
+ uint32_t bdfn;
+
+ /* Find a parent recursively */
+ if (pd->parent)
+ parent = match_slot_dev_entry(phb, pd->parent);
+ else {
+ /* No parent, this is a root complex, find the PHB */
+ parent = match_slot_phb_entry(phb);
+ }
+ /* No parent ? Oops ... */
+ if (!parent || !parent->children)
+ return NULL;
+ for (ent = parent->children; ent->etype != st_end; ent++) {
+ if (ent->etype == st_phb) {
+ prerror("SLOT: Bad PHB entry type in table !\n");
+ continue;
+ }
+
+ /* NPU slots match on device, not function */
+ if (ent->etype == st_npu_slot)
+ bdfn = pd->bdfn & 0xf8;
+ else
+ bdfn = pd->bdfn & 0xff;
+
+ if (ent->location == bdfn)
+ return ent;
+ }
+ return NULL;
+}
+
+static void slot_table_add_properties(struct pci_slot *slot,
+ struct dt_node *np)
+{
+ struct slot_table_entry *ent = slot->data;
+
+ if (ent)
+ pci_slot_add_loc(slot, np, ent->name);
+ else
+ pci_slot_add_loc(slot, np, NULL);
+}
+
+void slot_table_add_slot_info(struct pci_device *pd,
+ const struct slot_table_entry *ent)
+{
+ struct pci_slot *slot;
+
+ if (!ent || !ent->name) {
+ slot = pcie_slot_create_dynamic(pd->phb, pd);
+ if (slot) {
+ slot->ops.add_properties = slot_table_add_properties;
+ slot->pluggable = true;
+ }
+
+ return;
+ }
+
+ slot = pcie_slot_create(pd->phb, pd);
+ assert(slot);
+
+ slot->pluggable = !!(ent->etype == st_pluggable_slot);
+ slot->ops.add_properties = slot_table_add_properties;
+ slot->power_limit = ent->power_limit;
+ slot->data = (void *)ent;
+}
+
+void slot_table_get_slot_info(struct phb *phb, struct pci_device *pd)
+{
+ const struct slot_table_entry *ent;
+
+ if (!pd || pd->slot)
+ return;
+
+ ent = match_slot_dev_entry(phb, pd);
+ slot_table_add_slot_info(pd, ent);
+}
+
+static void dt_slot_add_properties(struct pci_slot *slot,
+ struct dt_node *np)
+{
+ struct dt_node *slot_np = slot->data;
+ const char *label = NULL;
+
+ if (slot_np)
+ label = dt_prop_get_def(slot_np, "ibm,slot-label", NULL);
+
+ pci_slot_add_loc(slot, np, label);
+}
+
+void dt_slot_get_slot_info(struct phb *phb, struct pci_device *pd)
+{
+ struct dt_node *slot_np;
+ struct pci_slot *slot;
+ const char *name = NULL;
+ uint32_t power_limit = 0;
+ bool pluggable = false;
+
+ if (!pd || pd->slot)
+ return;
+
+ slot_np = map_pci_dev_to_slot(phb, pd);
+ if (slot_np) {
+ pluggable = dt_has_node_property(slot_np,
+ "ibm,pluggable", NULL);
+ power_limit = dt_prop_get_u32_def(slot_np,
+ "ibm,power-limit", 0);
+ name = dt_prop_get_def(slot_np, "ibm,slot-label", NULL);
+ }
+
+ if (!slot_np || !name) {
+ slot = pcie_slot_create_dynamic(phb, pd);
+ if (slot) {
+ slot->ops.add_properties = dt_slot_add_properties;
+ slot->pluggable = true;
+ slot->data = (void *)slot_np;
+ }
+
+ return;
+ }
+
+ slot = pcie_slot_create(phb, pd);
+ assert(slot);
+
+ slot->ops.add_properties = dt_slot_add_properties;
+ slot->pluggable = pluggable;
+ slot->power_limit = power_limit;
+ slot->data = (void *)slot_np;
+}
+
+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);
+}