aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2020-04-02 22:13:55 +1100
committerOliver O'Halloran <oohall@gmail.com>2020-04-08 14:38:33 +1000
commit38b5c3179d59489320e116b810ab21eec8205657 (patch)
tree88b7f98ad55ab20c4fd191e5f1e9530144273414
parent9b612fff557f67f001b4772c180a50a9cb92e6bb (diff)
downloadskiboot-38b5c3179d59489320e116b810ab21eec8205657.zip
skiboot-38b5c3179d59489320e116b810ab21eec8205657.tar.gz
skiboot-38b5c3179d59489320e116b810ab21eec8205657.tar.bz2
hdata/memory: Add support for memory-buffer mmio
HDAT now allows associating a set of MMIO address ranges with an MSAREA. This is to allow for exporting the MMIO register space associated with a memory-buffer chip to the hypervisor so we can wire up access to that for PRD. The DT format is similar to the old centaur memory-buffer@<addr> nodes that we had on P8 OpenPower systems. The biggest difference is that the HDAT format allows for multiple memory ranges on each "chip" and each of these ranges may have a different register size. Cc: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
-rwxr-xr-x[-rw-r--r--]hdata/memory.c139
1 files changed, 125 insertions, 14 deletions
diff --git a/hdata/memory.c b/hdata/memory.c
index 6d060f7..7ce9275 100644..100755
--- a/hdata/memory.c
+++ b/hdata/memory.c
@@ -55,10 +55,17 @@ struct HDIF_ms_area_address_range {
#define PHYS_ATTR_STATUS_NOT_SAVED 0x08
#define PHYS_ATTR_STATUS_MEM_INVALID 0xff
+/* Memory Controller ID for Nimbus P9 systems */
#define MS_CONTROLLER_MCBIST_ID(id) GETFIELD(PPC_BITMASK32(0, 1), id)
#define MS_CONTROLLER_MCS_ID(id) GETFIELD(PPC_BITMASK32(4, 7), id)
#define MS_CONTROLLER_MCA_ID(id) GETFIELD(PPC_BITMASK32(8, 15), id)
+/* Memory Controller ID for P9 AXONE systems */
+#define MS_CONTROLLER_MC_ID(id) GETFIELD(PPC_BITMASK32(0, 1), id)
+#define MS_CONTROLLER_MI_ID(id) GETFIELD(PPC_BITMASK32(4, 7), id)
+#define MS_CONTROLLER_MCC_ID(id) GETFIELD(PPC_BITMASK32(8, 15), id)
+#define MS_CONTROLLER_OMI_ID(id) GETFIELD(PPC_BITMASK32(16, 31), id)
+
struct HDIF_ms_area_id {
__be16 id;
#define MS_PTYPE_RISER_CARD 0x8000
@@ -73,6 +80,20 @@ struct HDIF_ms_area_id {
__be16 share_id;
} __packed;
+
+// FIXME: it should be 9, current HDATs are broken
+#define MSAREA_IDATA_MMIO_IDX 8
+struct HDIF_ms_area_ocmb_mmio {
+ __be64 range_start;
+ __be64 range_end;
+ __be32 controller_id;
+ __be32 proc_chip_id;
+ __be64 hbrt_id;
+#define OCMB_SCOM_8BYTE_ACCESS PPC_BIT(0)
+#define OCMB_SCOM_4BYTE_ACCESS PPC_BIT(1)
+ __be64 flags;
+} __packed;
+
static void append_chip_id(struct dt_node *mem, u32 id)
{
struct dt_property *prop;
@@ -366,7 +387,7 @@ static void vpd_parse_spd(struct dt_node *dimm, const char *spd, u32 size)
dt_add_property_cells(dimm, "manufacturer-id", be16_to_cpu(*vendor));
}
-static void add_mca_dimm_info(struct dt_node *mca,
+static void add_dimm_info(struct dt_node *parent,
const struct HDIF_common_hdr *msarea)
{
unsigned int i, size;
@@ -394,11 +415,11 @@ static void add_mca_dimm_info(struct dt_node *mca,
continue;
/* Use Resource ID to add dimm node */
- dimm = dt_find_by_name_addr(mca, "dimm",
+ dimm = dt_find_by_name_addr(parent, "dimm",
be16_to_cpu(fru_id->rsrc_id));
if (dimm)
continue;
- dimm= dt_new_addr(mca, "dimm", be16_to_cpu(fru_id->rsrc_id));
+ dimm= dt_new_addr(parent, "dimm", be16_to_cpu(fru_id->rsrc_id));
assert(dimm);
dt_add_property_cells(dimm, "reg", be16_to_cpu(fru_id->rsrc_id));
@@ -439,21 +460,13 @@ static inline void dt_add_mem_reg_property(struct dt_node *node, u64 addr)
dt_add_property_cells(node, "reg", addr);
}
-static void add_memory_controller(const struct HDIF_common_hdr *msarea,
+static void add_memory_controller_p9n(const struct HDIF_common_hdr *msarea,
const struct HDIF_ms_area_address_range *arange)
{
- uint32_t chip_id, version;
+ uint32_t chip_id;
uint32_t controller_id, mcbist_id, mcs_id, mca_id;
struct dt_node *xscom, *mcbist, *mcs, *mca;
- /*
- * Memory hierarchy may change between processor version. Presently
- * it's only creating memory hierarchy for P9 (Nimbus) and P9P (Axone).
- */
- version = PVR_TYPE(mfspr(SPR_PVR));
- if (version != PVR_TYPE_P9 && version != PVR_TYPE_P9P)
- return;
-
chip_id = pcid_to_chip_id(be32_to_cpu(arange->chip));
controller_id = be32_to_cpu(arange->controller_id);
xscom = find_xscom_for_chip(chip_id);
@@ -489,7 +502,103 @@ static void add_memory_controller(const struct HDIF_common_hdr *msarea,
dt_add_mem_reg_property(mca, mca_id);
}
- add_mca_dimm_info(mca, msarea);
+ add_dimm_info(mca, msarea);
+}
+
+static void add_memory_buffer_mmio(const struct HDIF_common_hdr *msarea)
+{
+ const struct HDIF_ms_area_ocmb_mmio *mmio;
+ uint64_t min_addr = ~0ull, hbrt_id = 0;
+ const struct HDIF_array_hdr *array;
+ unsigned int i, count, ranges = 0;
+ struct dt_node *membuf;
+ uint64_t *reg, *flags;
+
+ if (be32_to_cpu(msarea->version) < 0x50) {
+ prlog(PR_WARNING, "MS AREA: Inconsistent MSAREA version %x for P9P system",
+ be32_to_cpu(msarea->version));
+ return;
+ }
+
+ array = HDIF_get_iarray(msarea, MSAREA_IDATA_MMIO_IDX, &count);
+ if (!array || count <= 0) {
+ prerror("MS AREA: No OCMB MMIO array at MS Area %p\n", msarea);
+ return;
+ }
+
+ reg = zalloc(count * 2 * sizeof(*reg));
+ flags = zalloc(count * sizeof(*flags));
+
+ /* grab the hbrt id from the first range. */
+ HDIF_iarray_for_each(array, i, mmio) {
+ hbrt_id = be64_to_cpu(mmio->hbrt_id);
+ break;
+ }
+
+ prlog(PR_DEBUG, "Adding memory buffer MMIO ranges for %"PRIx64"\n",
+ hbrt_id);
+
+ HDIF_iarray_for_each(array, i, mmio) {
+ uint64_t start, end;
+
+ if (hbrt_id != be64_to_cpu(mmio->hbrt_id)) {
+ prerror("HBRT ID mismatch!\n");
+ continue;
+ }
+
+ start = cleanup_addr(be64_to_cpu(mmio->range_start));
+ end = cleanup_addr(be64_to_cpu(mmio->range_end));
+ if (start < min_addr)
+ min_addr = start;
+
+ prlog(PR_DEBUG, " %"PRIx64" - [%016"PRIx64"-%016"PRIx64")\n",
+ hbrt_id, start, end);
+
+ reg[2 * ranges ] = cpu_to_be64(start);
+ reg[2 * ranges + 1] = cpu_to_be64(end - start + 1);
+ flags[ranges] = mmio->flags; /* both are BE */
+ ranges++;
+ }
+
+ membuf = dt_find_by_name_addr(dt_root, "memory-buffer", min_addr);
+ if (membuf) {
+ prerror("attempted to duplicate %s\n", membuf->name);
+ goto out;
+ }
+
+ membuf = dt_new_addr(dt_root, "memory-buffer", min_addr);
+ assert(membuf);
+
+ dt_add_property_string(membuf, "compatible", "ibm,explorer");
+ dt_add_property_cells(membuf, "ibm,chip-id", hbrt_id);
+
+ /*
+ * FIXME: We should probably be sorting the address ranges based
+ * on the starting address.
+ */
+ dt_add_property(membuf, "reg", reg, sizeof(*reg) * 2 * ranges);
+ dt_add_property(membuf, "flags", flags, sizeof(*flags) * ranges);
+
+out:
+ free(flags);
+ free(reg);
+}
+
+static void add_memory_controller(const struct HDIF_common_hdr *msarea,
+ const struct HDIF_ms_area_address_range *arange)
+{
+ const uint32_t version = PVR_TYPE(mfspr(SPR_PVR));
+ /*
+ * Memory hierarchy may change between processor version. Presently
+ * it's only creating memory hierarchy for P9 (Nimbus) and P9P (Axone).
+ */
+
+ if (version == PVR_TYPE_P9)
+ return add_memory_controller_p9n(msarea, arange);
+ else if (version == PVR_TYPE_P9P)
+ return; //return add_memory_controller_p9p(msarea, arange);
+ else
+ return;
}
static void get_msareas(struct dt_node *root,
@@ -569,6 +678,8 @@ static void get_msareas(struct dt_node *root,
/* Add RAM Area VPD */
vpd_add_ram_area(msarea);
+ add_memory_buffer_mmio(msarea);
+
/* This offset is from the arr, not the header! */
arange = (void *)arr + be32_to_cpu(arr->offset);
for (j = 0; j < be32_to_cpu(arr->ecnt); j++) {