aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-08-11 14:55:18 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-10-11 15:13:17 +1100
commit5b43f79e3bebf4f504013c1155c2d23856324d91 (patch)
treec2629f869a558616b9e8e3531a10757b38f34d4a
parentde7ffb4e49f831fc30aea9e82fcd1f68d61059d6 (diff)
downloadskiboot-5b43f79e3bebf4f504013c1155c2d23856324d91.zip
skiboot-5b43f79e3bebf4f504013c1155c2d23856324d91.tar.gz
skiboot-5b43f79e3bebf4f504013c1155c2d23856324d91.tar.bz2
platforms/astbmc: Support dynamic PCI slot
We might insert a PCIe switch to PHB direct slot and the downstream ports of the PCIe switch supports PCI hotplug. This creates dynamic PCI slots for the downstream ports in the scenario: * The dynamic PCI slot's label has fixed encoding: "S<domain><bus_num>". * No associated platform slot. * The management on dynamic PCI slot relies on the generic layer implemented in pcie-slot.c. Requested-by: Li Meng <shlimeng@cn.ibm.com> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--platforms/astbmc/slots.c52
1 files changed, 46 insertions, 6 deletions
diff --git a/platforms/astbmc/slots.c b/platforms/astbmc/slots.c
index ff69e99..10a99bb 100644
--- a/platforms/astbmc/slots.c
+++ b/platforms/astbmc/slots.c
@@ -17,6 +17,7 @@
#include <device.h>
#include <console.h>
#include <chip.h>
+#include <pci-cfg.h>
#include <pci.h>
#include <pci-slot.h>
@@ -88,17 +89,24 @@ static void add_slot_properties(struct pci_slot *slot,
struct dt_node *np)
{
struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
struct slot_table_entry *ent = slot->data;
size_t base_loc_code_len, slot_label_len;
- char loc_code[LOC_CODE_SIZE];
+ char label[8], loc_code[LOC_CODE_SIZE];
- if (!np || !ent)
+ if (!np)
return;
- dt_add_property_string(np, "ibm,slot-label", ent->name);
+ if (ent) {
+ dt_add_property_string(np, "ibm,slot-label", ent->name);
+ slot_label_len = strlen(ent->name);
+ } else {
+ snprintf(label, 8, "S%04x%02x", phb->opal_id, pd->secondary_bus);
+ dt_add_property_string(np, "ibm,slot-label", label);
+ slot_label_len = strlen(label);
+ }
base_loc_code_len = phb->base_loc_code ? strlen(phb->base_loc_code) : 0;
- slot_label_len = strlen(ent->name);
if ((base_loc_code_len + slot_label_len + 1) >= LOC_CODE_SIZE)
return;
@@ -110,7 +118,10 @@ static void add_slot_properties(struct pci_slot *slot,
loc_code[0] = '\0';
}
- strcat(loc_code, ent->name);
+ if (ent)
+ strcat(loc_code, ent->name);
+ else
+ strcat(loc_code, label);
dt_add_property(np, "ibm,slot-location-code",
loc_code, strlen(loc_code) + 1);
}
@@ -130,6 +141,33 @@ static void init_slot_info(struct pci_slot *slot, bool pluggable, void *data)
slot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_NONE;
}
+static void create_dynamic_slot(struct phb *phb, struct pci_device *pd)
+{
+ uint32_t ecap, val;
+ struct pci_slot *slot;
+
+ if (!phb || !pd || pd->slot)
+ return;
+
+ /* Try to create slot whose details aren't provided by platform.
+ * We only care the downstream ports of PCIe switch that connects
+ * to root port.
+ */
+ if (pd->dev_type != PCIE_TYPE_SWITCH_DNPORT ||
+ !pd->parent || !pd->parent->parent ||
+ pd->parent->parent->parent)
+ return;
+
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCAP, &val);
+ if (!(val & PCICAP_EXP_SLOTCAP_HPLUG_CAP))
+ return;
+
+ slot = pcie_slot_create(phb, pd);
+ assert(slot);
+ init_slot_info(slot, true, NULL);
+}
+
void slot_table_get_slot_info(struct phb *phb, struct pci_device *pd)
{
const struct slot_table_entry *ent;
@@ -139,8 +177,10 @@ void slot_table_get_slot_info(struct phb *phb, struct pci_device *pd)
if (!pd || pd->slot)
return;
ent = match_slot_dev_entry(phb, pd);
- if (!ent || !ent->name)
+ if (!ent || !ent->name) {
+ create_dynamic_slot(phb, pd);
return;
+ }
slot = pcie_slot_create(phb, pd);
assert(slot);