aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Currey <ruscur@russell.cc>2016-07-05 15:05:35 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-07-20 18:14:47 +1000
commit62bf371705955b4e32da9f3d18897333a0a34869 (patch)
treebfddb5ef1a780c6a8787db4b154e8d3ac1825bac
parent8126e4c69407c1f9957ab2313015f46a30e1f1ec (diff)
downloadskiboot-62bf371705955b4e32da9f3d18897333a0a34869.zip
skiboot-62bf371705955b4e32da9f3d18897333a0a34869.tar.gz
skiboot-62bf371705955b4e32da9f3d18897333a0a34869.tar.bz2
nvlink: Associate and allocate NPUs using slots
Allocating BDFNs to NPU devices and associating NPU devices with PCI devices of GPUs both rely on comparing PBCQ handles. This will fail if a system has multiple sets of GPUs behind a single PHB. Rework this to instead use slot locations. The following changes are introduced: - Groups of NPU links that connect to the same GPU are presented in the slot table entries as st_npu_slot, using ST_LOC_NPU_GROUP - NPU links are created with the ibm,npu-group-id property replacing the ibm,pbcq property, which is used in BDFN allocation and GPU association - Slot comparison is handled slightly differently for NPU devices as the function of the BDFN is ignored, since the device number represents the physical GPU the link is connected to - BDFN allocation for NPU devices is now derived from the groups in the slot table. For Garrison, the same BDFNs are generated as before. - Association with GPU PCI devices is performed by comparing the slot label. This means for future machines with NPUs that slot labels are compulsory to have NVLink functionality working. Signed-off-by: Russell Currey <ruscur@russell.cc> Reviewed-By: Alistair Popple <alistair@popple.id.au> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--hw/npu.c59
-rw-r--r--include/npu.h3
-rw-r--r--platforms/astbmc/astbmc.h8
-rw-r--r--platforms/astbmc/garrison.c59
-rw-r--r--platforms/astbmc/slots.c10
5 files changed, 62 insertions, 77 deletions
diff --git a/hw/npu.c b/hw/npu.c
index a0da887..aa2194a 100644
--- a/hw/npu.c
+++ b/hw/npu.c
@@ -30,6 +30,7 @@
#include <npu-regs.h>
#include <npu.h>
#include <xscom.h>
+#include <string.h>
/*
* Terminology:
@@ -503,25 +504,27 @@ static int __npu_dev_bind_pci_dev(struct phb *phb __unused,
{
struct npu_dev *dev = data;
struct dt_node *pci_dt_node;
- uint32_t npu_npcq_phandle;
+ char *pcislot;
/* Ignore non-nvidia PCI devices */
if ((pd->vdid & 0xffff) != 0x10de)
return 0;
- /* Find the PCI devices pbcq */
- for (pci_dt_node = pd->dn->parent;
- pci_dt_node && !dt_find_property(pci_dt_node, "ibm,pbcq");
+ /* Find the PCI device's slot location */
+ for (pci_dt_node = pd->dn;
+ pci_dt_node && !dt_find_property(pci_dt_node, "ibm,slot-label");
pci_dt_node = pci_dt_node->parent);
if (!pci_dt_node)
return 0;
- npu_npcq_phandle = dt_prop_get_u32(dev->dt_node, "ibm,npu-pbcq");
+ pcislot = (char *)dt_prop_get(pci_dt_node, "ibm,slot-label");
- if (dt_prop_get_u32(pci_dt_node, "ibm,pbcq") == npu_npcq_phandle &&
- (pd->vdid & 0xffff) == 0x10de)
- return 1;
+ prlog(PR_DEBUG, "NPU: comparing GPU %s and NPU %s\n",
+ pcislot, dev->slot_label);
+
+ if (streq(pcislot, dev->slot_label))
+ return 1;
return 0;
}
@@ -604,6 +607,9 @@ static int npu_dn_fixup(struct phb *phb,
if (dev->phb || dev->pd)
return 0;
+ /* NPU devices require a slot location to associate with GPUs */
+ dev->slot_label = dt_prop_get(pd->dn, "ibm,slot-label");
+
/* Bind the emulated PCI device with the real one, which can't
* be done until the PCI devices are populated. Once the real
* PCI device is identified, we also need fix the device-tree
@@ -1615,34 +1621,19 @@ static void npu_dev_create_cfg(struct npu_dev *dev)
NPU_DEV_CFG_INIT_RO(dev, PCI_CFG_INT_LINE, 4, 0x00000200);
}
-static uint32_t npu_allocate_bdfn(struct npu *p, uint32_t pbcq)
+static uint32_t npu_allocate_bdfn(struct npu *p, uint32_t group)
{
int i;
- int dev = -1;
- int bdfn = -1;
+ int bdfn = (group << 3);
- /* Find the highest function number alloacted to emulated PCI
- * devices associated with this GPU. */
- for(i = 0; i < p->total_devices; i++) {
- int dev_bdfn = p->devices[i].bdfn;
- dev = MAX(dev, dev_bdfn & 0xf8);
-
- if (dt_prop_get_u32(p->devices[i].dt_node,
- "ibm,npu-pbcq") == pbcq)
- bdfn = MAX(bdfn, dev_bdfn);
+ for (i = 0; i < p->total_devices; i++) {
+ if (p->devices[i].bdfn == bdfn) {
+ bdfn++;
+ break;
+ }
}
- if (bdfn >= 0)
- /* Device has already been allocated for this GPU so
- * assign the emulated PCI device the next
- * function. */
- return bdfn + 1;
- else if (dev >= 0)
- /* Otherwise allocate a new device and allocate
- * function 0. */
- return dev + (1 << 3);
- else
- return 0;
+ return bdfn;
}
static void npu_create_devices(struct dt_node *dn, struct npu *p)
@@ -1670,7 +1661,7 @@ static void npu_create_devices(struct dt_node *dn, struct npu *p)
p->phb.scan_map = 0;
dt_for_each_compatible(npu_dn, link, "ibm,npu-link") {
struct npu_dev_bar *bar;
- uint32_t pbcq;
+ uint32_t group_id;
uint64_t val;
uint32_t j;
@@ -1685,8 +1676,8 @@ static void npu_create_devices(struct dt_node *dn, struct npu *p)
/* We don't support MMIO PHY access yet */
dev->pl_base = NULL;
- pbcq = dt_prop_get_u32(link, "ibm,npu-pbcq");
- dev->bdfn = npu_allocate_bdfn(p, pbcq);
+ group_id = dt_prop_get_u32(link, "ibm,npu-group-id");
+ dev->bdfn = npu_allocate_bdfn(p, group_id);
/* This must be done after calling
* npu_allocate_bdfn() */
diff --git a/include/npu.h b/include/npu.h
index 778c985..800515a 100644
--- a/include/npu.h
+++ b/include/npu.h
@@ -148,6 +148,9 @@ struct npu_dev {
uint32_t procedure_status;
uint8_t pe_num;
+
+ /* Used to associate the NPU device with GPU PCI devices */
+ const char *slot_label;
};
/* NPU PHB descriptor */
diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h
index 23c31c7..322282e 100644
--- a/platforms/astbmc/astbmc.h
+++ b/platforms/astbmc/astbmc.h
@@ -20,6 +20,13 @@
#define ST_LOC_PHB(chip_id, phb_idx) ((chip_id) << 16 | (phb_idx))
#define ST_LOC_DEVFN(dev, fn) ((dev) << 3 | (fn))
+/*
+ * NPU groups are used to allocate device numbers. There is a 1 to 1
+ * correlation between a NPU group and a physical GPU. Links within a group
+ * are allocated as functions within a device, so groups must be numbered
+ * sequentially starting at 0.
+ */
+#define ST_LOC_NPU_GROUP(group_id) (group_id << 3)
struct slot_table_entry {
enum slot_table_etype {
@@ -27,6 +34,7 @@ struct slot_table_entry {
st_phb,
st_pluggable_slot,
st_builtin_dev,
+ st_npu_slot
} etype;
uint32_t location;
const char *name;
diff --git a/platforms/astbmc/garrison.c b/platforms/astbmc/garrison.c
index 3ff84a3..f400a51 100644
--- a/platforms/astbmc/garrison.c
+++ b/platforms/astbmc/garrison.c
@@ -63,23 +63,13 @@ static const struct slot_table_entry garrison_phb0_3_slot[] = {
static const struct slot_table_entry garrison_npu0_slots[] = {
{
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(0,0),
- .name = "GPU2",
- },
- {
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(0,1),
+ .etype = st_npu_slot,
+ .location = ST_LOC_NPU_GROUP(0),
.name = "GPU2",
},
{
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(1,0),
- .name = "GPU1",
- },
- {
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(1,1),
+ .etype = st_npu_slot,
+ .location = ST_LOC_NPU_GROUP(1),
.name = "GPU1",
},
{ .etype = st_end },
@@ -152,23 +142,13 @@ static const struct slot_table_entry garrison_phb1_3_slot[] = {
static const struct slot_table_entry garrison_npu1_slots[] = {
{
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(0,0),
- .name = "GPU4",
- },
- {
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(0,1),
+ .etype = st_npu_slot,
+ .location = ST_LOC_NPU_GROUP(0),
.name = "GPU4",
},
{
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(1,0),
- .name = "GPU3",
- },
- {
- .etype = st_pluggable_slot,
- .location = ST_LOC_DEVFN(1,1),
+ .etype = st_npu_slot,
+ .location = ST_LOC_NPU_GROUP(1),
.name = "GPU3",
},
{ .etype = st_end },
@@ -233,7 +213,7 @@ static const struct slot_table_entry garrison_phb_table[] = {
#define NPU_INDIRECT0 0x8000000008010c3f
#define NPU_INDIRECT1 0x8000000008010c7f
-static void create_link(struct dt_node *npu, struct dt_node *pbcq, int index)
+static void create_link(struct dt_node *npu, int group, int index)
{
struct dt_node *link;
uint32_t lane_mask;
@@ -255,12 +235,12 @@ static void create_link(struct dt_node *npu, struct dt_node *pbcq, int index)
}
dt_add_property_u64s(link, "ibm,npu-phy", phy);
dt_add_property_cells(link, "ibm,npu-lane-mask", lane_mask);
- dt_add_property_cells(link, "ibm,npu-pbcq", pbcq->phandle);
+ dt_add_property_cells(link, "ibm,npu-group-id", group);
}
static void dt_create_npu(void)
{
- struct dt_node *xscom, *npu, *pbcq;
+ struct dt_node *xscom, *npu;
char namebuf[32];
dt_for_each_compatible(dt_root, xscom, "ibm,xscom") {
@@ -275,17 +255,12 @@ static void dt_create_npu(void)
dt_add_property_cells(npu, "ibm,npu-index", 0);
dt_add_property_cells(npu, "ibm,npu-links", 4);
- /* On Garrison we have 2 links per GPU device. The
- * first 2 links go to the GPU connected via
- * pbcq@2012c00 the second two via pbcq@2012800. */
- pbcq = dt_find_by_name(xscom, "pbcq@2012c00");
- assert(pbcq);
- create_link(npu, pbcq, 0);
- create_link(npu, pbcq, 1);
- pbcq = dt_find_by_name(xscom, "pbcq@2012800");
- assert(pbcq);
- create_link(npu, pbcq, 4);
- create_link(npu, pbcq, 5);
+ /* On Garrison we have 2 links per GPU device. These are
+ * grouped together as per the slot tables above. */
+ create_link(npu, 0, 0);
+ create_link(npu, 0, 1);
+ create_link(npu, 1, 4);
+ create_link(npu, 1, 5);
}
}
diff --git a/platforms/astbmc/slots.c b/platforms/astbmc/slots.c
index 36547e1..678a3cc 100644
--- a/platforms/astbmc/slots.c
+++ b/platforms/astbmc/slots.c
@@ -54,6 +54,7 @@ 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)
@@ -70,7 +71,14 @@ static const struct slot_table_entry *match_slot_dev_entry(struct phb *phb,
prerror("SLOT: Bad PHB entry type in table !\n");
continue;
}
- if (ent->location == (pd->bdfn & 0xff))
+
+ /* 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;