void add_core_attr(struct dt_node *cpu, uint32_t attr) { if (attr & CPU_ATTR_UNIFIED_PL1) dt_add_property(cpu, "cache-unified", NULL, 0); if (attr & CPU_ATTR_SPLIT_TLB) dt_add_property(cpu, "tlb-split", NULL, 0); if (attr & CPU_ATTR_TLBIA) dt_add_property(cpu, "tlbia", NULL, 0); if (attr & CPU_ATTR_PERF_MONITOR) dt_add_property_cells(cpu, "performance-monitor", 0, 1); if (attr & CPU_ATTR_EXTERN_CONT) dt_add_property(cpu, "external-control", NULL, 0); }
void lxvpd_add_slot_properties(struct pci_slot *slot, struct dt_node *np) { struct phb *phb = slot->phb; struct lxvpd_pci_slot *s = slot->data; char loc_code[LOC_CODE_SIZE]; size_t base_loc_code_len, slot_label_len; /* Check if we have platform specific slot */ if (!s || !np) return; /* Check PHB base location code */ if (!phb->base_loc_code) return; /* Check location length is valid */ base_loc_code_len = strlen(phb->base_loc_code); slot_label_len = strlen(s->label); if ((base_loc_code_len + slot_label_len + 1) >= LOC_CODE_SIZE) return; /* Location code */ strcpy(loc_code, phb->base_loc_code); strcat(loc_code, "-"); strcat(loc_code, s->label); dt_add_property(np, "ibm,slot-location-code", loc_code, strlen(loc_code) + 1); dt_add_property_string(np, "ibm,slot-label", s->label); }
void vpd_iohub_load(struct dt_node *hub_node) { char record[4] = "LXR0"; const void *valid_lx; uint8_t lx_size; int r; const uint32_t *p; const uint8_t *lx; unsigned int lxrn; p = dt_prop_get_def(hub_node, "ibm,vpd-lx-info", NULL); if (!p) return; lxrn = p[0]; lx = (const char *)&p[1]; /* verify the lid preload has started */ if (!vpd_lid || !vpd_lid_no) { prlog(PR_WARNING, "VPD: WARNING: Unable to load VPD lid"); return; } r = fsp_wait_lid_loaded(vpd_lid_no); if (r) goto fail; /* Validate it */ if (lxrn < 9) record[3] = '0' + lxrn; else memcpy(record, "VINI", 4); valid_lx = vpd_find(vpd_lid, vpd_lid_size, record, "LX", &lx_size); if (!valid_lx || lx_size != 8) { prerror("VPD: Cannot find validation LX record\n"); goto fail; } if (memcmp(valid_lx, lx, 8) != 0) { prerror("VPD: LX record mismatch !\n"); goto fail; } printf("VPD: Loaded %zu bytes\n", vpd_lid_size); dt_add_property(hub_node, "ibm,io-vpd", vpd_lid, vpd_lid_size); free(vpd_lid); return; fail: free(vpd_lid); vpd_lid = NULL; prerror("VPD: Failed to load VPD LID\n"); return; }
void slca_vpd_add_loc_code(struct dt_node *node, uint16_t slca_index) { const char *fru_loc_code; char loc_code[LOC_CODE_SIZE]; memset(loc_code, 0, sizeof(loc_code)); fru_loc_code = slca_get_loc_code_index(slca_index); if (!fru_loc_code) return; strncpy(loc_code, fru_loc_code, LOC_CODE_SIZE - 1); dt_add_property(node, "ibm,loc-code", loc_code, strlen(loc_code) + 1); }
static void add_mem_node(uint64_t start, uint64_t len) { struct dt_node *mem; u64 reg[2]; char *name; name = (char*)malloc(sizeof("memory@") + STR_MAX_CHARS(reg[0])); assert(name); /* reg contains start and length */ reg[0] = cpu_to_be64(start); reg[1] = cpu_to_be64(len); sprintf(name, "memory@%llx", (long long)start); mem = dt_new(dt_root, name); dt_add_property_string(mem, "device_type", "memory"); dt_add_property(mem, "reg", reg, sizeof(reg)); free(name); }
static void trace_add_dt_props(void) { unsigned int i; u64 *prop, tmask; prop = malloc(sizeof(u64) * 2 * debug_descriptor.num_traces); for (i = 0; i < debug_descriptor.num_traces; i++) { prop[i * 2] = cpu_to_fdt64(debug_descriptor.trace_phys[i]); prop[i * 2 + 1] = cpu_to_fdt64(debug_descriptor.trace_size[i]); } dt_add_property(opal_node, "ibm,opal-traces", prop, sizeof(u64) * 2 * i); free(prop); tmask = (uint64_t)&debug_descriptor.trace_mask; dt_add_property_cells(opal_node, "ibm,opal-trace-mask", hi32(tmask), lo32(tmask)); }
void vpd_iohub_load(struct dt_node *hub_node) { void *vpd; size_t sz; const uint32_t *p; unsigned int lx_idx; const char *lxr; p = dt_prop_get_def(hub_node, "ibm,vpd-lx-info", NULL); if (!p) return; lx_idx = p[0]; lxr = (const char *)&p[1]; vpd = vpd_lid_load(lxr, lx_idx, &sz); if (!vpd) { prerror("VPD: Failed to load VPD LID\n"); } else { dt_add_property(hub_node, "ibm,io-vpd", vpd, sz); free(vpd); } }
static struct dt_node *create_cache_node(struct dt_node *cpus, const struct sppcia_cpu_cache *cache, const char *name, uint32_t unit_addr, int okay) { struct dt_node *node; node = dt_new_addr(cpus, name, unit_addr); assert(node); dt_add_property_string(node, "device_type", "cache"); dt_add_property_cells(node, "reg", unit_addr); dt_add_property_string(node, "status", okay ? "okay" : "bad"); dt_add_property(node, "cache-unified", NULL, 0); /* Assume cache associavitity sets is same for L2, L3 and L3.5 */ dt_add_property_cells(node, "d-cache-sets", be32_to_cpu(cache->l2_cache_assoc_sets)); dt_add_property_cells(node, "i-cache-sets", be32_to_cpu(cache->l2_cache_assoc_sets)); return node; }
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; }
void force_dummy_console(void) { if (!dummy_console_enabled()) dt_add_property(dt_chosen, "sapphire,enable-dummy-console", NULL, 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[] = { 6, 0, 0xf6, 0x3f, 0xc7, 0x00, 0x80, 0xc0 }; printf(" 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"; break; case PVR_TYPE_P7P: name = "PowerPC,POWER7+"; break; case PVR_TYPE_P8E: case PVR_TYPE_P8: name = "PowerPC,POWER8"; break; default: name = "PowerPC,Unknown"; } 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); /* 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 */ dt_add_property(cpu, "ibm,pa-features", pa_features, sizeof(pa_features)); 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_cells(cpu, "ibm,extended-clock-frequency", hi32(freq), lo32(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; }
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; }