diff options
Diffstat (limited to 'hdata/memory.c')
-rwxr-xr-x[-rw-r--r--] | hdata/memory.c | 139 |
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++) { |