diff options
Diffstat (limited to 'roms/skiboot/platforms/astbmc/slots.c')
-rw-r--r-- | roms/skiboot/platforms/astbmc/slots.c | 259 |
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); +} |