Author: jhibbits Date: Tue May 8 13:23:39 2018 New Revision: 333363 URL: https://svnweb.freebsd.org/changeset/base/333363
Log: Fix wrong cpu0 identification Summary: chrp_cpuref_init() was relying on the boot strap processor to be the first child of /cpus. That was not always the case, specially on pseries with FDT. This change uses the "reg" property of each CPU instead and also adds several sanity checks to avoid unexpected behavior (maybe too many panics?). The main observed symptom was interrupts being missed by the main processor, leading to timeouts and the kernel aborting the boot. Submitted by: Leandro Lupori Reviewed by: nwhitehorn Differential Revision: https://reviews.freebsd.org/D15174 Modified: head/sys/powerpc/pseries/platform_chrp.c Modified: head/sys/powerpc/pseries/platform_chrp.c ============================================================================== --- head/sys/powerpc/pseries/platform_chrp.c Tue May 8 11:39:01 2018 (r333362) +++ head/sys/powerpc/pseries/platform_chrp.c Tue May 8 13:23:39 2018 (r333363) @@ -350,14 +350,26 @@ chrp_smp_get_bsp(platform_t plat, struct cpuref *cpure return (0); } +static void +get_cpu_reg(phandle_t cpu, cell_t *reg) +{ + int res; + + res = OF_getproplen(cpu, "reg"); + if (res != sizeof(cell_t)) + panic("Unexpected length for CPU property reg on Open Firmware\n"); + OF_getencprop(cpu, "reg", reg, res); +} + static int chrp_cpuref_init(void) { - phandle_t cpu, dev; + phandle_t cpu, dev, chosen, pbsp; + ihandle_t ibsp; char buf[32]; - int a, res; - cell_t interrupt_servers[32]; - uint64_t bsp; + int a, bsp, res, res2, tmp_cpuref_cnt; + static struct cpuref tmp_cpuref[MAXCPU]; + cell_t interrupt_servers[32], addr_cells, size_cells, reg, bsp_reg; if (platform_cpuref_valid) return (0); @@ -371,25 +383,77 @@ chrp_cpuref_init(void) dev = OF_peer(dev); } - bsp = 0; + /* Make sure that cpus reg property have 1 address cell and 0 size cells */ + res = OF_getproplen(dev, "#address-cells"); + res2 = OF_getproplen(dev, "#size-cells"); + if (res != res2 || res != sizeof(cell_t)) + panic("CPU properties #address-cells and #size-cells not found on Open Firmware\n"); + OF_getencprop(dev, "#address-cells", &addr_cells, sizeof(addr_cells)); + OF_getencprop(dev, "#size-cells", &size_cells, sizeof(size_cells)); + if (addr_cells != 1 || size_cells != 0) + panic("Unexpected values for CPU properties #address-cells and #size-cells on Open Firmware\n"); + + /* Look for boot CPU in /chosen/cpu and /chosen/fdtbootcpu */ + + chosen = OF_finddevice("/chosen"); + if (chosen == -1) + panic("Device /chosen not found on Open Firmware\n"); + + bsp_reg = -1; + + /* /chosen/cpu */ + if (OF_getproplen(chosen, "cpu") == sizeof(ihandle_t)) { + OF_getprop(chosen, "cpu", &ibsp, sizeof(ibsp)); + pbsp = OF_instance_to_package(ibsp); + if (pbsp != -1) + get_cpu_reg(pbsp, &bsp_reg); + } + + /* /chosen/fdtbootcpu */ + if (bsp_reg == -1) { + if (OF_getproplen(chosen, "fdtbootcpu") == sizeof(cell_t)) + OF_getprop(chosen, "fdtbootcpu", &bsp_reg, sizeof(bsp_reg)); + } + + if (bsp_reg == -1) + panic("Boot CPU not found on Open Firmware\n"); + + bsp = -1; + tmp_cpuref_cnt = 0; for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); if (res > 0 && strcmp(buf, "cpu") == 0) { res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s"); if (res > 0) { - - OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", interrupt_servers, res); - for (a = 0; a < res/sizeof(cell_t); a++) { - platform_cpuref[platform_cpuref_cnt].cr_hwref = interrupt_servers[a]; - platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; + get_cpu_reg(cpu, ®); + if (reg == bsp_reg) + bsp = tmp_cpuref_cnt; - platform_cpuref_cnt++; + for (a = 0; a < res/sizeof(cell_t); a++) { + tmp_cpuref[tmp_cpuref_cnt].cr_hwref = interrupt_servers[a]; + tmp_cpuref[tmp_cpuref_cnt].cr_cpuid = tmp_cpuref_cnt; + tmp_cpuref_cnt++; } } } + } + + if (bsp == -1) + panic("Boot CPU not found\n"); + + /* Map IDs, so BSP has CPUID 0 regardless of hwref */ + for (a = bsp; a < tmp_cpuref_cnt; a++) { + platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref; + platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; + platform_cpuref_cnt++; + } + for (a = 0; a < bsp; a++) { + platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref; + platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; + platform_cpuref_cnt++; } platform_cpuref_valid = 1; _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"