diff mbox series

[3/4] hdata/memory: Add support for memory-buffer mmio

Message ID 20200402111356.1413-3-oohall@gmail.com
State Accepted
Headers show
Series [1/4] hw/xscom: Add scom infrastructure | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (ec7be0894c652bfda961418d79dd19838678abfc)
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present

Commit Message

Oliver O'Halloran April 2, 2020, 11:13 a.m. UTC
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>
---
 hdata/memory.c | 139 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 125 insertions(+), 14 deletions(-)
 mode change 100644 => 100755 hdata/memory.c
diff mbox series

Patch

diff --git a/hdata/memory.c b/hdata/memory.c
old mode 100644
new mode 100755
index 6d060f7f04cf..7ce92750278f
--- 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++) {