static bool __memory_parse(struct dt_node *root) { struct HDIF_common_hdr *ms_vpd; const struct msvpd_ms_addr_config *msac; const struct msvpd_total_config_ms *tcms; unsigned int size; ms_vpd = get_hdif(&spira.ntuples.ms_vpd, MSVPD_HDIF_SIG); if (!ms_vpd) { prerror("MS VPD: invalid\n"); op_display(OP_FATAL, OP_MOD_MEM, 0x0000); return false; } if (be32_to_cpu(spira.ntuples.ms_vpd.act_len) < sizeof(*ms_vpd)) { prerror("MS VPD: invalid size %u\n", be32_to_cpu(spira.ntuples.ms_vpd.act_len)); op_display(OP_FATAL, OP_MOD_MEM, 0x0001); return false; } prlog(PR_DEBUG, "MS VPD: is at %p\n", ms_vpd); msac = HDIF_get_idata(ms_vpd, MSVPD_IDATA_MS_ADDR_CONFIG, &size); if (!CHECK_SPPTR(msac) || size < sizeof(*msac)) { prerror("MS VPD: bad msac size %u @ %p\n", size, msac); op_display(OP_FATAL, OP_MOD_MEM, 0x0002); return false; } prlog(PR_DEBUG, "MS VPD: MSAC is at %p\n", msac); dt_add_property_u64(dt_root, DT_PRIVATE "maxmem", be64_to_cpu(msac->max_configured_ms_address)); tcms = HDIF_get_idata(ms_vpd, MSVPD_IDATA_TOTAL_CONFIG_MS, &size); if (!CHECK_SPPTR(tcms) || size < sizeof(*tcms)) { prerror("MS VPD: Bad tcms size %u @ %p\n", size, tcms); op_display(OP_FATAL, OP_MOD_MEM, 0x0003); return false; } prlog(PR_DEBUG, "MS VPD: TCMS is at %p\n", tcms); prlog(PR_DEBUG, "MS VPD: Maximum configured address: 0x%llx\n", (long long)be64_to_cpu(msac->max_configured_ms_address)); prlog(PR_DEBUG, "MS VPD: Maximum possible address: 0x%llx\n", (long long)be64_to_cpu(msac->max_possible_ms_address)); get_msareas(root, ms_vpd); prlog(PR_INFO, "MS VPD: Total MB of RAM: 0x%llx\n", (long long)be64_to_cpu(tcms->total_in_mb)); return true; }
static struct dt_node *flash_add_dt_node(struct flash *flash, int id) { int i; int rc; const char *name; bool ecc; struct ffs_handle *ffs; int ffs_part_num, ffs_part_start, ffs_part_size; struct dt_node *flash_node; struct dt_node *partition_container_node; struct dt_node *partition_node; flash_node = dt_new_addr(opal_node, "flash", id); dt_add_property_strings(flash_node, "compatible", "ibm,opal-flash"); dt_add_property_cells(flash_node, "ibm,opal-id", id); dt_add_property_u64(flash_node, "reg", flash->size); dt_add_property_cells(flash_node, "ibm,flash-block-size", flash->block_size); if (flash->no_erase) dt_add_property(flash_node, "no-erase", NULL, 0); /* we fix to 32-bits */ dt_add_property_cells(flash_node, "#address-cells", 1); dt_add_property_cells(flash_node, "#size-cells", 1); /* Add partition container node */ partition_container_node = dt_new(flash_node, "partitions"); dt_add_property_strings(partition_container_node, "compatible", "fixed-partitions"); /* we fix to 32-bits */ dt_add_property_cells(partition_container_node, "#address-cells", 1); dt_add_property_cells(partition_container_node, "#size-cells", 1); /* Add partitions */ for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) { name = part_name_map[i].name; rc = ffs_init(0, flash->size, flash->bl, &ffs, 1); if (rc) { prerror("FLASH: Can't open ffs handle\n"); continue; } rc = ffs_lookup_part(ffs, name, &ffs_part_num); if (rc) { /* This is not an error per-se, some partitions * are purposefully absent, don't spam the logs */ prlog(PR_DEBUG, "FLASH: No %s partition\n", name); continue; } rc = ffs_part_info(ffs, ffs_part_num, NULL, &ffs_part_start, NULL, &ffs_part_size, &ecc); if (rc) { prerror("FLASH: Failed to get %s partition info\n", name); continue; } partition_node = dt_new_addr(partition_container_node, "partition", ffs_part_start); dt_add_property_strings(partition_node, "label", name); dt_add_property_cells(partition_node, "reg", ffs_part_start, ffs_part_size); if (part_name_map[i].id != RESOURCE_ID_KERNEL_FW) { /* Mark all partitions other than the full PNOR and the boot kernel * firmware as read only. These two partitions are the only partitions * that are properly erase block aligned at this time. */ dt_add_property(partition_node, "read-only", NULL, 0); } } partition_node = dt_new_addr(partition_container_node, "partition", 0); dt_add_property_strings(partition_node, "label", "PNOR"); dt_add_property_cells(partition_node, "reg", 0, flash->size); return flash_node; }
int nx_cfg_rx_fifo(struct dt_node *node, const char *compat, const char *priority, u32 gcid, u32 pid, u32 tid, u64 umac_bar, u64 umac_notify) { u64 cfg; int rc, size; uint64_t fifo; u32 lpid = 0xfff; /* All 1's for 12 bits in UMAC notify match reg */ #define MATCH_ENABLE 1 fifo = (uint64_t) local_alloc(gcid, RX_FIFO_SIZE, RX_FIFO_SIZE); assert(fifo); /* * When configuring the address of the Rx FIFO into the Receive FIFO * BAR, we should _NOT_ shift the address into bits 8:53. Instead we * should copy the address as is and VAS/NX will extract relevant bits. */ /* * Section 5.21 of P9 NX Workbook Version 2.42 shows Receive FIFO BAR * 54:56 represents FIFO size * 000 = 1KB, 8 CRBs * 001 = 2KB, 16 CRBs * 010 = 4KB, 32 CRBs * 011 = 8KB, 64 CRBs * 100 = 16KB, 128 CRBs * 101 = 32KB, 256 CRBs * 110 = 111 reserved */ size = RX_FIFO_SIZE / 1024; cfg = SETFIELD(NX_P9_RX_FIFO_BAR_SIZE, fifo, ilog2(size)); rc = xscom_write(gcid, umac_bar, cfg); if (rc) { prerror("NX%d: ERROR: Setting UMAC FIFO bar failure %d\n", gcid, rc); return rc; } else prlog(PR_DEBUG, "NX%d: Setting UMAC FIFO bar 0x%016lx\n", gcid, (unsigned long)cfg); rc = xscom_read(gcid, umac_notify, &cfg); if (rc) return rc; /* * VAS issues asb_notify with the unique ID to identify the target * co-processor/engine. Logical partition ID (lpid), process ID (pid), * and thread ID (tid) combination is used to define the unique ID * in the system. Export these values in device-tree such that the * driver configure RxFIFO with VAS. Set these values in RxFIFO notify * match register for each engine which compares the ID with each * request. * To define unique indentification, 0xfff (1's for 12 bits), * co-processor type, and counter within coprocessor type are used * for lpid, pid, and tid respectively. */ cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_LPID, cfg, lpid); cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_PID, cfg, pid); cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_TID, cfg, tid); cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_MATCH_ENABLE, cfg, MATCH_ENABLE); rc = xscom_write(gcid, umac_notify, cfg); if (rc) { prerror("NX%d: ERROR: Setting UMAC notify match failure %d\n", gcid, rc); return rc; } else prlog(PR_DEBUG, "NX%d: Setting UMAC notify match 0x%016lx\n", gcid, (unsigned long)cfg); dt_add_property_string(node, "compatible", compat); dt_add_property_string(node, "priority", priority); dt_add_property_u64(node, "rx-fifo-address", fifo); dt_add_property_cells(node, "rx-fifo-size", RX_FIFO_SIZE); dt_add_property_cells(node, "lpid", lpid); dt_add_property_cells(node, "pid", pid); dt_add_property_cells(node, "tid", tid); return 0; }
struct dt_node * add_core_common(struct dt_node *cpus, const struct sppcia_cpu_cache *cache, const struct sppaca_cpu_timebase *tb, uint32_t int_server, bool okay) { const char *name; struct dt_node *cpu; uint32_t version; uint64_t freq; const uint8_t pa_features_p7[] = { 6, 0, 0xf6, 0x3f, 0xc7, 0x00, 0x80, 0xc0 }; const uint8_t pa_features_p7p[] = { 6, 0, 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xc0 }; const uint8_t pa_features_p8[] = { 24, 0, 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xd0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, }; const uint8_t pa_features_p9n_dd20[] = { 64, 0, 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xd0, 0x80, 0x00, /* 0 .. 7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 .. 15 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 16 .. 23 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 24 .. 31 */ 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, /* 32 .. 39 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 40 .. 47 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 .. 55 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 56 .. 63 */ }; const uint8_t pa_features_p9[] = { 64, 0, 0xf6, 0x3f, 0xc7, 0xc0, 0x80, 0xd0, 0x80, 0x00, /* 0 .. 7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 .. 15 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 16 .. 23 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 24 .. 31 */ 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, /* 32 .. 39 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 40 .. 47 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 .. 55 */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 56 .. 63 */ }; const uint8_t *pa_features; size_t pa_features_size; prlog(PR_INFO, " Cache: I=%u D=%u/%u/%u/%u\n", be32_to_cpu(cache->icache_size_kb), be32_to_cpu(cache->l1_dcache_size_kb), be32_to_cpu(cache->l2_dcache_size_kb), be32_to_cpu(cache->l3_dcache_size_kb), be32_to_cpu(cache->l35_dcache_size_kb)); /* Use the boot CPU PVR to make up a CPU name in the device-tree * since the HDAT doesn't seem to tell.... */ version = mfspr(SPR_PVR); switch(PVR_TYPE(version)) { case PVR_TYPE_P7: name = "PowerPC,POWER7"; pa_features = pa_features_p7; pa_features_size = sizeof(pa_features_p7); break; case PVR_TYPE_P7P: name = "PowerPC,POWER7+"; pa_features = pa_features_p7p; pa_features_size = sizeof(pa_features_p7p); break; case PVR_TYPE_P8E: case PVR_TYPE_P8: case PVR_TYPE_P8NVL: name = "PowerPC,POWER8"; pa_features = pa_features_p8; pa_features_size = sizeof(pa_features_p8); break; case PVR_TYPE_P9: case PVR_TYPE_P9P: name = "PowerPC,POWER9"; if (is_power9n(version) && (PVR_VERS_MAJ(version) == 2) && (PVR_VERS_MIN(version) == 0)) { /* P9N DD2.0 */ pa_features = pa_features_p9n_dd20; pa_features_size = sizeof(pa_features_p9n_dd20); } else { pa_features = pa_features_p9; pa_features_size = sizeof(pa_features_p9); } break; default: name = "PowerPC,Unknown"; pa_features = NULL; } cpu = dt_new_addr(cpus, name, int_server); assert(cpu); dt_add_property_string(cpu, "device_type", "cpu"); dt_add_property_string(cpu, "status", okay ? "okay" : "bad"); dt_add_property_cells(cpu, "reg", int_server); dt_add_property_cells(cpu, "cpu-version", version); dt_add_property(cpu, "64-bit", NULL, 0); dt_add_property(cpu, "32-64-bridge", NULL, 0); dt_add_property(cpu, "graphics", NULL, 0); dt_add_property(cpu, "general-purpose", NULL, 0); dt_add_property_cells(cpu, "ibm,processor-segment-sizes", 0x1c, 0x28, 0xffffffff, 0xffffffff); dt_add_property_cells(cpu, "ibm,processor-page-sizes", 0xc, 0x10, 0x18, 0x22); if (proc_gen == proc_gen_p9) dt_add_property_cells(cpu, "ibm,processor-radix-AP-encodings", 0x0000000c, 0xa0000010, 0x20000015, 0x4000001e); /* Page size encodings appear to be the same for P7 and P8 */ dt_add_property_cells(cpu, "ibm,segment-page-sizes", 0x0c, 0x000, 3, 0x0c, 0x0000, /* 4K seg 4k pages */ 0x10, 0x0007, /* 4K seg 64k pages */ 0x18, 0x0038, /* 4K seg 16M pages */ 0x10, 0x110, 2, 0x10, 0x0001, /* 64K seg 64k pages */ 0x18, 0x0008, /* 64K seg 16M pages */ 0x18, 0x100, 1, 0x18, 0x0000, /* 16M seg 16M pages */ 0x22, 0x120, 1, 0x22, 0x0003); /* 16G seg 16G pages */ if (pa_features) { dt_add_property(cpu, "ibm,pa-features", pa_features, pa_features_size); } dt_add_property_cells(cpu, "ibm,slb-size", 0x20); dt_add_property_cells(cpu, "ibm,vmx", 0x2); dt_add_property_cells(cpu, "ibm,dfp", 0x2); dt_add_property_cells(cpu, "ibm,purr", 0x1); dt_add_property_cells(cpu, "ibm,spurr", 0x1); /* * Do not create "clock-frequency" if the frequency doesn't * fit in a single cell */ freq = ((uint64_t)be32_to_cpu(tb->actual_clock_speed)) * 1000000ul; if (freq <= 0xfffffffful) dt_add_property_cells(cpu, "clock-frequency", freq); dt_add_property_u64(cpu, "ibm,extended-clock-frequency", freq); /* FIXME: Hardcoding is bad. */ dt_add_property_cells(cpu, "timebase-frequency", 512000000); dt_add_property_cells(cpu, "ibm,extended-timebase-frequency", 0, 512000000); dt_add_property_cells(cpu, "reservation-granule-size", be32_to_cpu(cache->reservation_size)); dt_add_property_cells(cpu, "d-tlb-size", be32_to_cpu(cache->dtlb_entries)); dt_add_property_cells(cpu, "i-tlb-size", be32_to_cpu(cache->itlb_entries)); /* Assume unified TLB */ dt_add_property_cells(cpu, "tlb-size", be32_to_cpu(cache->dtlb_entries)); dt_add_property_cells(cpu, "d-tlb-sets", be32_to_cpu(cache->dtlb_assoc_sets)); dt_add_property_cells(cpu, "i-tlb-sets", be32_to_cpu(cache->itlb_assoc_sets)); dt_add_property_cells(cpu, "tlb-sets", be32_to_cpu(cache->dtlb_assoc_sets)); dt_add_property_cells(cpu, "d-cache-block-size", be32_to_cpu(cache->dcache_block_size)); dt_add_property_cells(cpu, "i-cache-block-size", be32_to_cpu(cache->icache_block_size)); dt_add_property_cells(cpu, "d-cache-size", be32_to_cpu(cache->l1_dcache_size_kb)*1024); dt_add_property_cells(cpu, "i-cache-size", be32_to_cpu(cache->icache_size_kb)*1024); dt_add_property_cells(cpu, "i-cache-sets", be32_to_cpu(cache->icache_assoc_sets)); dt_add_property_cells(cpu, "d-cache-sets", be32_to_cpu(cache->dcache_assoc_sets)); if (cache->icache_line_size != cache->icache_block_size) dt_add_property_cells(cpu, "i-cache-line-size", be32_to_cpu(cache->icache_line_size)); if (cache->l1_dcache_line_size != cache->dcache_block_size) dt_add_property_cells(cpu, "d-cache-line-size", be32_to_cpu(cache->l1_dcache_line_size)); return cpu; }
void memcons_add_properties(void) { dt_add_property_u64(opal_node, "ibm,opal-memcons", (u64) &memcons); }