From fac5c9bb6475b1e24bd25c08593e71d38df293d9 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 20 Feb 2022 01:09:42 +0200 Subject: [PATCH 1/7] mb/raptor-cs/talos-2/devicetree.dts: update for second CPU Assumption is that it can still work for one CPU. Change-Id: Ic8612b747a8036c6bb6711dc05d36515ea190346 Signed-off-by: Sergii Dmytruk --- .../raptor-cs/talos-2/devicetree.dts | 393 ++++++++++++++++++ 1 file changed, 393 insertions(+) diff --git a/src/mainboard/raptor-cs/talos-2/devicetree.dts b/src/mainboard/raptor-cs/talos-2/devicetree.dts index f25907c7816..49c4681c443 100644 --- a/src/mainboard/raptor-cs/talos-2/devicetree.dts +++ b/src/mainboard/raptor-cs/talos-2/devicetree.dts @@ -41,6 +41,13 @@ ibm,chip-id = <0x00>; }; + sensor@4 { + compatible = "ibm,ipmi-sensor"; + ibm,chip-id = <0x08>; + ipmi-sensor-type = <0x07>; + reg = <0x04>; + }; + sensor@6 { compatible = "ibm,ipmi-sensor"; reg = <0x06>; @@ -48,6 +55,13 @@ ibm,chip-id = <0x00>; }; + sensor@7 { + compatible = "ibm,ipmi-sensor"; + ibm,chip-id = <0x08>; + ipmi-sensor-type = <0x01>; + reg = <0x07>; + }; + sensor@8 { compatible = "ibm,ipmi-sensor"; reg = <0x08>; @@ -55,6 +69,13 @@ ibm,chip-id = <0x00>; }; + sensor@9 { + compatible = "ibm,ipmi-sensor"; + ibm,chip-id = <0x08>; + ipmi-sensor-type = <0x07>; + reg = <0x09>; + }; + sensor@a { compatible = "ibm,ipmi-sensor"; reg = <0x0a>; @@ -85,6 +106,24 @@ ipmi-sensor-type = <0x0c>; }; + sensor@13 { + compatible = "ibm,ipmi-sensor"; + ipmi-sensor-type = <0x0c>; + reg = <0x13>; + }; + + sensor@15 { + compatible = "ibm,ipmi-sensor"; + ipmi-sensor-type = <0x0c>; + reg = <0x15>; + }; + + sensor@19 { + compatible = "ibm,ipmi-sensor"; + ipmi-sensor-type = <0x0c>; + reg = <0x19>; + }; + sensor@1b { compatible = "ibm,ipmi-sensor"; reg = <0x1b>; @@ -109,6 +148,24 @@ ipmi-sensor-type = <0x01>; }; + sensor@23 { + compatible = "ibm,ipmi-sensor"; + ipmi-sensor-type = <0x01>; + reg = <0x23>; + }; + + sensor@25 { + compatible = "ibm,ipmi-sensor"; + ipmi-sensor-type = <0x01>; + reg = <0x25>; + }; + + sensor@29 { + compatible = "ibm,ipmi-sensor"; + ipmi-sensor-type = <0x01>; + reg = <0x29>; + }; + sensor@8b { compatible = "ibm,ipmi-sensor"; reg = <0x8b>; @@ -326,6 +383,103 @@ builtin { }; }; + + root-complex@8,0 { + #address-cells = <0x02>; + #size-cells = <0x00>; + compatible = "ibm,pcie-port", "ibm,pcie-root-port"; + ibm,chip-id = <0x08>; + ibm,slot-label = "SLOT2"; + reg = <0x08 0x00>; + + pluggable { + ibm,slot-label = "SLOT2"; + lane-mask = <0xffff>; + max-power = <0x00>; + mrw-slot-id = <0x02>; + }; + }; + + root-complex@8,3 { + #address-cells = <0x02>; + #size-cells = <0x00>; + compatible = "ibm,pcie-port", "ibm,pcie-root-port"; + ibm,chip-id = <0x08>; + ibm,slot-label = "SLOT1"; + reg = <0x08 0x03>; + + pluggable { + ibm,slot-label = "SLOT1"; + lane-mask = <0xff00>; + max-power = <0x00>; + mrw-slot-id = <0x01>; + }; + }; + + root-complex@8,4 { + #address-cells = <0x02>; + #size-cells = <0x00>; + compatible = "ibm,pcie-port", "ibm,pcie-root-port"; + ibm,chip-id = <0x08>; + ibm,slot-label = "SLOT0"; + reg = <0x08 0x04>; + + pluggable { + ibm,slot-label = "SLOT0"; + lane-mask = <0xf0>; + max-power = <0x00>; + }; + }; + + root-complex@8,5 { + #address-cells = <0x02>; + #size-cells = <0x00>; + compatible = "ibm,pcie-port", "ibm,pcie-root-port"; + ibm,chip-id = <0x08>; + lane-mask = <0x0f>; + reg = <0x08 0x05>; + + switch-up@10b5,8725 { + #address-cells = <0x01>; + #size-cells = <0x00>; + ibm,pluggable; + reg = <0x10b5 0x8725>; + upstream-port = <0x01>; + + down-port@4 { + compatible = "ibm,pcie-port"; + ibm,pluggable; + ibm,slot-label = "GPU3"; + reg = <0x04>; + + builtin { + ibm,slot-label = "GPU3"; + }; + }; + + down-port@5 { + compatible = "ibm,pcie-port"; + ibm,pluggable; + ibm,slot-label = "GPU4"; + reg = <0x05>; + + builtin { + ibm,slot-label = "GPU4"; + }; + }; + + down-port@d { + compatible = "ibm,pcie-port"; + ibm,pluggable; + ibm,slot-label = "GPU5"; + reg = <0x0d>; + + builtin { + ibm,slot-label = "GPU5"; + }; + }; + }; + }; }; lpcm-opb@6030000000000 { @@ -575,4 +729,243 @@ force-assign-bars; }; }; + + xscom@623fc00000000 { + #address-cells = <0x01>; + #size-cells = <0x01>; + bus-frequency = <0x00 0x1bce39a0>; + compatible = "ibm,xscom\0ibm,power9-xscom"; + ibm,chip-id = <0x08>; + ibm,proc-chip-id = <0x01>; + reg = <0x623fc 0x00 0x08 0x00>; + scom-controller; + + chiptod@40000 { + reg = <0x40000 0x34>; + compatible = "ibm,power-chiptod\0ibm,power9-chiptod"; + secondary; + }; + + i2cm@a1000 { + #address-cells = <0x01>; + #size-cells = <0x00>; + chip-engine# = <0x01>; + clock-frequency = <0x6f38e68>; + compatible = "ibm,power8-i2cm\0ibm,power9-i2cm"; + reg = <0xa1000 0x1000>; + + i2c-bus@0 { + #address-cells = <0x01>; + #size-cells = <0x00>; + bus-frequency = <0xf4240>; + compatible = "ibm,opal-i2c\0ibm,power8-i2c-port\0ibm,power9-i2c-port"; + reg = <0x00>; + + eeprom@50 { + compatible = "atmel,24c512"; + label = "module-vpd"; + link-id = <0x10000>; + reg = <0x50>; + }; + }; + + i2c-bus@2 { + #address-cells = <0x01>; + #size-cells = <0x00>; + bus-frequency = <0xf4240>; + compatible = "ibm,opal-i2c\0ibm,power8-i2c-port\0ibm,power9-i2c-port"; + reg = <0x02>; + + eeprom@50 { + compatible = "atmel,24c128"; + label = "module-vpd"; + link-id = <0x1000b>; + reg = <0x50>; + }; + }; + }; + + i2cm@a3000 { + #address-cells = <0x01>; + #size-cells = <0x00>; + chip-engine# = <0x03>; + clock-frequency = <0x6f38e68>; + compatible = "ibm,power8-i2cm\0ibm,power9-i2cm"; + reg = <0xa3000 0x1000>; + + i2c-bus@0 { + #address-cells = <0x01>; + #size-cells = <0x00>; + bus-frequency = <0x61a80>; + compatible = "ibm,opal-i2c\0ibm,power8-i2c-port\0ibm,power9-i2c-port"; + reg = <0x00>; + + eeprom@50 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x10011>; + reg = <0x50>; + }; + + eeprom@51 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x10009>; + reg = <0x51>; + }; + + eeprom@52 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x10001>; + reg = <0x52>; + }; + + eeprom@53 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x10002>; + reg = <0x53>; + }; + }; + + i2c-bus@1 { + #address-cells = <0x01>; + #size-cells = <0x00>; + bus-frequency = <0x61a80>; + compatible = "ibm,opal-i2c\0ibm,power8-i2c-port\0ibm,power9-i2c-port"; + reg = <0x01>; + + eeprom@54 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x1000a>; + reg = <0x54>; + }; + + eeprom@55 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x1000c>; + reg = <0x55>; + }; + + eeprom@56 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x1000e>; + reg = <0x56>; + }; + + eeprom@57 { + compatible = "spd"; + label = "dimm-spd"; + link-id = <0x1000f>; + reg = <0x57>; + }; + }; + }; + + nmmu@5012c40 { + compatible = "ibm,power9-nest-mmu"; + reg = <0x5012c40 0x20>; + }; + + nx@2010000 { + compatible = "ibm,power9-nx"; + reg = <0x2010000 0x4000>; + }; + + pbcq@4010c00 { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "ibm,power9-pbcq"; + ibm,hub-id = <0x01>; + ibm,pec-index = <0x00>; + reg = <0x4010c00 0x100 0xd010800 0x200>; + + stack@0 { + compatible = "ibm,power9-phb-stack"; + ibm,lane-eq = <0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x77777777 0x77777777 0x77777777 0x77777777>; + ibm,phb-index = <0x00>; + reg = <0x00>; + status = "okay"; + }; + }; + + pbcq@4011000 { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "ibm,power9-pbcq"; + ibm,hub-id = <0x01>; + ibm,pec-index = <0x01>; + reg = <0x4011000 0x100 0xe010800 0x200>; + + stack@0 { + compatible = "ibm,power9-phb-stack"; + ibm,lane-eq = <0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x77777777 0x77777777 0x77777777 0x77777777>; + ibm,phb-index = <0x01>; + reg = <0x00>; + status = "okay"; + }; + + stack@1 { + compatible = "ibm,power9-phb-stack"; + ibm,lane-eq = <0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x77777777 0x77777777 0x77777777 0x77777777>; + ibm,phb-index = <0x02>; + reg = <0x01>; + status = "okay"; + }; + }; + + pbcq@4011400 { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "ibm,power9-pbcq"; + ibm,hub-id = <0x01>; + ibm,pec-index = <0x02>; + reg = <0x4011400 0x100 0xf010800 0x200>; + + stack@0 { + compatible = "ibm,power9-phb-stack"; + ibm,lane-eq = <0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x77777777 0x77777777 0x77777777 0x77777777>; + ibm,phb-index = <0x03>; + reg = <0x00>; + status = "okay"; + }; + + stack@1 { + compatible = "ibm,power9-phb-stack"; + ibm,lane-eq = <0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x77777777 0x77777777 0x77777777 0x77777777>; + ibm,phb-index = <0x04>; + reg = <0x01>; + status = "disabled"; + }; + + stack@2 { + compatible = "ibm,power9-phb-stack"; + ibm,lane-eq = <0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x54545454 0x77777777 0x77777777 0x77777777 0x77777777>; + ibm,phb-index = <0x05>; + reg = <0x02>; + status = "disabled"; + }; + }; + + psihb@5012900 { + reg = <0x5012900 0x100>; + compatible = "ibm,power9-psihb-x\0ibm,psihb-x"; + }; + + vas@3011800 { + reg = <0x3011800 0x300>; + compatible = "ibm,power9-vas-x"; + ibm,vas-id = <0x01>; + }; + + xive@5013000 { + reg = <0x5013000 0x300>; + compatible = "ibm,power9-xive-x"; + force-assign-bars; + }; + }; }; From 676c8bbf36eb8a8bea644e34bf9d22f6c6a3bb96 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 20 Feb 2022 15:38:29 +0200 Subject: [PATCH 2/7] soc/power9/chip.c: fixup DT for two CPUs Change-Id: Ib1c8831c792ccce61925408ea19fddca682b476e Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/chip.c | 74 ++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/src/soc/ibm/power9/chip.c b/src/soc/ibm/power9/chip.c index daf69eb0f05..6df7179d5ee 100644 --- a/src/soc/ibm/power9/chip.c +++ b/src/soc/ibm/power9/chip.c @@ -122,11 +122,10 @@ static void fill_l2_node(struct device_tree *tree, dt_add_u32_prop(node, "d-cache-sets", 8); dt_add_u32_prop(node, "i-cache-size", 512 * KiB); dt_add_u32_prop(node, "i-cache-sets", 8); - } static void fill_cpu_node(struct device_tree *tree, - struct device_tree_node *node, uint32_t pir, + struct device_tree_node *node, uint8_t chip, uint32_t pir, uint32_t next_lvl_phandle) { /* Mandatory/standard properties */ @@ -152,8 +151,8 @@ static void fill_cpu_node(struct device_tree *tree, dt_add_u32_prop(node, "reg", pir); dt_add_u32_prop(node, "ibm,pir", pir); - /* Chip ID of this core */ - dt_add_u32_prop(node, "ibm,chip-id", 0); /* FIXME for second CPU */ + /* Chip ID of this core, not sure why it's shifted (group id + chip id?) */ + dt_add_u32_prop(node, "ibm,chip-id", chip << 3); /* * Interrupt server numbers (aka HW processor numbers) of all threads @@ -207,15 +206,14 @@ static void fill_cpu_node(struct device_tree *tree, * Old-style core clock frequency. Only create this property if the * frequency fits in a 32-bit number. Do not create it if it doesn't. */ - /* TODO: update these 3 uses of nominal_freq to be chip-specific */ - if ((nominal_freq[0] >> 32) == 0) - dt_add_u32_prop(node, "clock-frequency", nominal_freq[0]); + if ((nominal_freq[chip] >> 32) == 0) + dt_add_u32_prop(node, "clock-frequency", nominal_freq[chip]); /* * Mandatory: 64-bit version of the core clock frequency, always create * this property. */ - dt_add_u64_prop(node, "ibm,extended-clock-frequency", nominal_freq[0]); + dt_add_u64_prop(node, "ibm,extended-clock-frequency", nominal_freq[chip]); /* Timebase freq has a fixed value, always use that */ dt_add_u32_prop(node, "timebase-frequency", 512 * MHz); @@ -314,6 +312,7 @@ static void split_mem_node(struct device_tree *tree) union {uint32_t u32[2]; uint64_t u64;} new_size = {}; /* /memory@0123456789abcdef - 24 characters + null byte */ char path[26] = {}; + uint8_t chip; if (address_cells == 1) new_addr.u32[1] = reg_data[offset++]; @@ -334,7 +333,15 @@ static void split_mem_node(struct device_tree *tree) dt_add_string_prop(new_region, "device_type", (char *)"memory"); dt_add_reg_prop(new_region, &new_addr.u64, &new_size.u64, 1, 2, 2); - dt_add_u32_prop(new_region, "ibm,chip-id", 0 /* FIXME for second CPU */); + + /* + * This is for ATTR_PROC_FABRIC_PUMP_MODE == PUMP_MODE_CHIP_IS_GROUP, + * when chip ID is actually a group ID and "chip ID" field is zero. + * + * Don't know why the value needs to be shifted (group id + chip id?). + */ + chip = (new_addr.u64 >> 45) & 0xF; + dt_add_u32_prop(new_region, "ibm,chip-id", chip << 3); } }; @@ -344,11 +351,11 @@ static void split_mem_node(struct device_tree *tree) * chain, only first option is possible. */ static int dt_platform_fixup(struct device_tree_fixup *fixup, - struct device_tree *tree) + struct device_tree *tree) { + uint8_t chips = fsi_get_present_chips(); + struct device_tree_node *cpus, *xscom; - uint64_t cores = read_scom(0x0006C090); - assert(cores != 0); split_mem_node(tree); @@ -356,15 +363,36 @@ static int dt_platform_fixup(struct device_tree_fixup *fixup, /* TODO: is the address always the same? */ xscom = dt_find_node_by_path(tree, "/xscom@603fc00000000", NULL, NULL, 0); if (xscom == NULL) - die("No 'xscom' node in device tree!\n"); + die("No 'xscom' node for chip#0 in device tree!\n"); + + /* Check for xscom node of the second CPU (assuming group pump mode) */ + xscom = dt_find_node_by_path(tree, "/xscom@623fc00000000", NULL, NULL, 0); + if (chips & 0x2) { + if (xscom == NULL) + die("No 'xscom' node for chip#1 in device tree!\n"); + } else { + if (xscom != NULL) + die("Found 'xscom' node for missing chip#1 in device tree!\n"); + } /* Find "cpus" node */ cpus = dt_find_node_by_path(tree, "/cpus", NULL, NULL, 0); if (cpus == NULL) die("No 'cpus' node in device tree!\n"); - for (int core_id = 0; core_id <= 24; core_id++) { - if (IS_EC_FUNCTIONAL(core_id, cores)) { + for (uint8_t chip = 0; chip < MAX_CHIPS; chip++) { + uint64_t cores; + + if (!(chips & (1 << chip))) + continue; + + cores = read_rscom(chip, 0x0006C090); + assert(cores != 0); + + for (int core_id = 0; core_id < MAX_CORES_PER_CHIP; core_id++) { + if (!IS_EC_FUNCTIONAL(core_id, cores)) + continue; + /* * Not sure who is the original author of this comment, it is * duplicated in Hostboot and Skiboot, and now also here. It @@ -372,12 +400,12 @@ static int dt_platform_fixup(struct device_tree_fixup *fixup, * of thread 0 of _first_ core in pair, both for L2 and L3. */ /* - * Cache nodes. Those are siblings of the processor nodes under /cpus and - * represent the various level of caches. + * Cache nodes. Those are siblings of the processor nodes under /cpus + * and represent the various level of caches. * * The unit address (and reg property) is mostly free-for-all as long as - * there is no collisions. On HDAT machines we use the following encoding - * which I encourage you to also follow to limit surprises: + * there is no collisions. On HDAT machines we use the following + * encoding which I encourage you to also follow to limit surprises: * * L2 : (0x20 << 24) | PIR (PIR is PIR value of thread 0 of core) * L3 : (0x30 << 24) | PIR @@ -387,7 +415,11 @@ static int dt_platform_fixup(struct device_tree_fixup *fixup, * own "l2-cache" (or "next-level-cache") property, so the core node * points to the L2, the L2 points to the L3 etc... */ - uint32_t pir = core_id * 4; + /* + * This is for ATTR_PROC_FABRIC_PUMP_MODE == PUMP_MODE_CHIP_IS_GROUP, + * when chip ID is actually a group ID and "chip ID" field is zero. + */ + uint32_t pir = PPC_PLACE(chip, 49, 4) | PPC_PLACE(core_id, 57, 5); uint32_t l2_pir = (0x20 << 24) | (pir & ~7); uint32_t l3_pir = (0x30 << 24) | (pir & ~7); /* "/cpus/l?-cache@12345678" -> 23 characters + terminator */ @@ -420,7 +452,7 @@ static int dt_platform_fixup(struct device_tree_fixup *fixup, fill_l2_node(tree, l2_node, l2_pir, l3_node->phandle); } - fill_cpu_node(tree, cpu_node, pir, l2_node->phandle); + fill_cpu_node(tree, cpu_node, chip, pir, l2_node->phandle); } } From e77e86ecafc739abe3f6e0a165d3f1345a7aca08 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 20 Feb 2022 15:40:51 +0200 Subject: [PATCH 3/7] soc/power9/chip.c: activate slave cores on two CPUs Change-Id: I51915169640631ab9406202ea3112044aec07dd7 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/chip.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/soc/ibm/power9/chip.c b/src/soc/ibm/power9/chip.c index 6df7179d5ee..2e7c894c03d 100644 --- a/src/soc/ibm/power9/chip.c +++ b/src/soc/ibm/power9/chip.c @@ -596,14 +596,20 @@ static void enable_soc_dev(struct device *dev) istep_18_12(chips, tod_mdmt); } -static void activate_slave_cores(void) +static void activate_slave_cores(uint8_t chip) { enum { DOORBELL_MSG_TYPE = 0x0000000028000000 }; uint8_t i; /* Read OCC CCSR written by the code earlier */ - const uint64_t functional_cores = read_scom(0x0006C090); + const uint64_t functional_cores = read_rscom(chip, 0x0006C090); + + /* + * This is for ATTR_PROC_FABRIC_PUMP_MODE == PUMP_MODE_CHIP_IS_GROUP, + * when chip ID is actually a group ID and "chip ID" field is zero. + */ + const uint64_t chip_msg = DOORBELL_MSG_TYPE | PPC_PLACE(chip, 49, 4); /* Find and process the first core in a separate loop to slightly * simplify processing of all the other cores by removing a conditional */ @@ -615,10 +621,10 @@ static void activate_slave_cores(void) continue; /* Message value for thread 0 of the current core */ - core_msg = DOORBELL_MSG_TYPE | (i << 2); + core_msg = chip_msg | (i << 2); /* Skip sending doorbell to the current thread of the current core */ - for (thread = 1; thread < 4; ++thread) { + for (thread = (chip == 0 ? 1 : 0); thread < 4; ++thread) { register uint64_t msg = core_msg | thread; asm volatile("msgsnd %0" :: "r" (msg)); } @@ -634,7 +640,7 @@ static void activate_slave_cores(void) continue; /* Message value for thread 0 of the i-th core */ - core_msg = DOORBELL_MSG_TYPE | (i << 2); + core_msg = chip_msg | (i << 2); for (thread = 0; thread < 4; ++thread) { register uint64_t msg = core_msg | thread; @@ -645,6 +651,8 @@ static void activate_slave_cores(void) void platform_prog_run(struct prog *prog) { + uint8_t chips = fsi_get_present_chips(); + /* * Clear SMS_ATN aka EVT_ATN in BT_CTRL - Block Transfer IPMI protocol * @@ -667,7 +675,10 @@ void platform_prog_run(struct prog *prog) * activated threads start execution before current thread jumps into * the payload. */ - activate_slave_cores(); + for (uint8_t chip = 0; chip < MAX_CHIPS; chip++) { + if (chips & (1 << chip)) + activate_slave_cores(chip); + } } struct chip_operations soc_ibm_power9_ops = { From d6010cea24f464167c50a0997ebba4947c62739a Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 21 Mar 2022 21:30:30 +0200 Subject: [PATCH 4/7] soc/power9/chip.c: validate PCIe nodes of DT Put validation into a separate function. Change-Id: Ie04da44b1beb6010afe8cda527340e5d234cc4e1 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/chip.c | 81 +++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/src/soc/ibm/power9/chip.c b/src/soc/ibm/power9/chip.c index 2e7c894c03d..aad6866de35 100644 --- a/src/soc/ibm/power9/chip.c +++ b/src/soc/ibm/power9/chip.c @@ -14,6 +14,13 @@ #include "istep_13_scom.h" #include "chip.h" #include "fsi.h" +#include "pci.h" + +/* + * Chip ID, not sure why it's shifted (group id + chip id?). + * Might be specific to group pump mode. + */ +#define CHIP_ID(chip) ((chip) << 3) static uint64_t nominal_freq[MAX_CHIPS]; @@ -151,8 +158,8 @@ static void fill_cpu_node(struct device_tree *tree, dt_add_u32_prop(node, "reg", pir); dt_add_u32_prop(node, "ibm,pir", pir); - /* Chip ID of this core, not sure why it's shifted (group id + chip id?) */ - dt_add_u32_prop(node, "ibm,chip-id", chip << 3); + /* Chip ID of this core */ + dt_add_u32_prop(node, "ibm,chip-id", CHIP_ID(chip)); /* * Interrupt server numbers (aka HW processor numbers) of all threads @@ -337,29 +344,39 @@ static void split_mem_node(struct device_tree *tree) /* * This is for ATTR_PROC_FABRIC_PUMP_MODE == PUMP_MODE_CHIP_IS_GROUP, * when chip ID is actually a group ID and "chip ID" field is zero. - * - * Don't know why the value needs to be shifted (group id + chip id?). */ chip = (new_addr.u64 >> 45) & 0xF; - dt_add_u32_prop(new_region, "ibm,chip-id", chip << 3); + dt_add_u32_prop(new_region, "ibm,chip-id", CHIP_ID(chip)); } -}; +} -/* - * Device tree passed to Skiboot has to have phandles set either for all nodes - * or none at all. Because relative phandles are set for cpu->l2_cache->l3_cache - * chain, only first option is possible. - */ -static int dt_platform_fixup(struct device_tree_fixup *fixup, - struct device_tree *tree) +/* Finds first root complex for a given chip that's present in DT else returns NULL */ +static bool dt_contains_pcie(struct device_tree *tree, uint8_t chip_id) { - uint8_t chips = fsi_get_present_chips(); + int phb; - struct device_tree_node *cpus, *xscom; + /* See comment before pec0_lane_cfg global variable in istep_10_10.c */ + for (phb = 0; phb < MAX_PHB_PER_PROC; phb++) { + struct device_tree_node *node; - split_mem_node(tree); + char path[40]; + snprintf(path, sizeof(path), "/ibm,pcie-slots/root-complex@%d,%d", chip_id, + phb); + + node = dt_find_node_by_path(tree, path, NULL, NULL, 0); + if (node != NULL) + return true; + } + + return false; +} + +/* Checks input device tree for sanity and dies on failure */ +static void validate_dt(struct device_tree *tree, uint8_t chips) +{ + struct device_tree_node *xscom; + bool found_pcie; - /* Find xscom node, halt if not found */ /* TODO: is the address always the same? */ xscom = dt_find_node_by_path(tree, "/xscom@603fc00000000", NULL, NULL, 0); if (xscom == NULL) @@ -375,6 +392,36 @@ static int dt_platform_fixup(struct device_tree_fixup *fixup, die("Found 'xscom' node for missing chip#1 in device tree!\n"); } + if (!dt_contains_pcie(tree, /*chip_id=*/0)) + die("No 'root-complex' nodes for chip#0 in device tree!\n"); + + /* Check for xscom node of the second CPU (assuming group pump mode) */ + found_pcie = dt_contains_pcie(tree, /*chip_id=*/CHIP_ID(1)); + if (chips & 0x2) { + if (!found_pcie) + die("No 'root-complex' node for chip#1 in device tree!\n"); + } else { + if (found_pcie) + die("Found 'root-complex' node for missing chip#1 in device tree!\n"); + } +} + +/* + * Device tree passed to Skiboot has to have phandles set either for all nodes + * or none at all. Because relative phandles are set for cpu->l2_cache->l3_cache + * chain, only first option is possible. + */ +static int dt_platform_fixup(struct device_tree_fixup *fixup, + struct device_tree *tree) +{ + uint8_t chips = fsi_get_present_chips(); + + struct device_tree_node *cpus; + + validate_dt(tree, chips); + + split_mem_node(tree); + /* Find "cpus" node */ cpus = dt_find_node_by_path(tree, "/cpus", NULL, NULL, 0); if (cpus == NULL) From 9064f4866391826c9afbe8d4410e5e3ee275fc84 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 22 Mar 2022 19:49:16 +0200 Subject: [PATCH 5/7] soc/power9/i2c.c: fix SPD data shared between chips Change-Id: I58f9204eee786f9bda1e14ffa2992a75f4b773a5 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/i2c.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/soc/ibm/power9/i2c.c b/src/soc/ibm/power9/i2c.c index d95d6aca1f9..bbb6c29f714 100644 --- a/src/soc/ibm/power9/i2c.c +++ b/src/soc/ibm/power9/i2c.c @@ -73,11 +73,12 @@ static int get_spd(uint8_t bus, u8 *spd, u8 addr) return 0; } -static u8 spd_data[CONFIG_DIMM_MAX * CONFIG_DIMM_SPD_SIZE]; +static u8 spd_data[MAX_CHIPS][CONFIG_DIMM_MAX][CONFIG_DIMM_SPD_SIZE]; void get_spd_i2c(uint8_t bus, struct spd_block *blk) { u8 i; + u8 chip = bus / I2C_BUSES_PER_CPU; for (i = 0 ; i < CONFIG_DIMM_MAX; i++) { if (blk->addr_map[i] == 0) { @@ -85,8 +86,8 @@ void get_spd_i2c(uint8_t bus, struct spd_block *blk) continue; } - if (get_spd(bus, &spd_data[i * CONFIG_DIMM_SPD_SIZE], blk->addr_map[i]) == 0) - blk->spd_array[i] = &spd_data[i * CONFIG_DIMM_SPD_SIZE]; + if (get_spd(bus, spd_data[chip][i], blk->addr_map[i]) == 0) + blk->spd_array[i] = spd_data[chip][i]; else blk->spd_array[i] = NULL; } From e8257cfaf79f83453e361be6a1725c3d04f564c1 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Wed, 23 Mar 2022 16:16:24 +0200 Subject: [PATCH 6/7] soc/power9/: pass mem_data from romstage to ramstage It's needed as a source of information for building device tree. Change-Id: I306d384186c4677452d531d490cde495b1129204 Signed-off-by: Sergii Dmytruk --- src/include/cpu/power/proc.h | 1 + src/soc/ibm/power9/chip.c | 41 +++++++++++++++++++++++++++++++++++ src/soc/ibm/power9/romstage.c | 37 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/src/include/cpu/power/proc.h b/src/include/cpu/power/proc.h index 28a9b1ea44f..c7b208044fa 100644 --- a/src/include/cpu/power/proc.h +++ b/src/include/cpu/power/proc.h @@ -17,6 +17,7 @@ #define MCA_PER_PROC (MCA_PER_MCS * MCS_PER_PROC) #define DIMMS_PER_MCA 2 #define DIMMS_PER_MCS (DIMMS_PER_MCA * MCA_PER_MCS) +#define DIMMS_PER_PROC (DIMMS_PER_MCS * MCS_PER_PROC) #define I2C_BUSES_PER_CPU 4 #define SPD_I2C_BUS 3 diff --git a/src/soc/ibm/power9/chip.c b/src/soc/ibm/power9/chip.c index aad6866de35..a20569ecd3d 100644 --- a/src/soc/ibm/power9/chip.c +++ b/src/soc/ibm/power9/chip.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include +#include #include #include #include @@ -22,6 +24,9 @@ */ #define CHIP_ID(chip) ((chip) << 3) +/* Copy of data put together by the romstage */ +mcbist_data_t mem_data[MAX_CHIPS]; + static uint64_t nominal_freq[MAX_CHIPS]; /* @@ -732,3 +737,39 @@ struct chip_operations soc_ibm_power9_ops = { CHIP_NAME("POWER9") .enable_dev = enable_soc_dev, }; + +/* Restores global mem_data variable from cbmem */ +static void restore_mem_data(int is_recovery) +{ + const struct cbmem_entry *entry; + uint8_t *data; + int dimm_i; + + (void)is_recovery; /* unused */ + + entry = cbmem_entry_find(CBMEM_ID_MEMINFO); + if (entry == NULL) + die("Failed to find mem_data entry in CBMEM in ramstage!"); + + /* Layout: mem_data itself then SPD data of each dimm which has it */ + data = cbmem_entry_start(entry); + + memcpy(&mem_data, data, sizeof(mem_data)); + data += sizeof(mem_data); + + for (dimm_i = 0; dimm_i < MAX_CHIPS * DIMMS_PER_PROC; dimm_i++) { + int chip = dimm_i / DIMMS_PER_PROC; + int mcs = (dimm_i % DIMMS_PER_PROC) / DIMMS_PER_MCS; + int mca = (dimm_i % DIMMS_PER_MCS) / DIMMS_PER_MCA; + int dimm = dimm_i % DIMMS_PER_MCA; + + rdimm_data_t *dimm_data = &mem_data[chip].mcs[mcs].mca[mca].dimm[dimm]; + if (dimm_data->spd == NULL) + continue; + + /* We're not deleting the entry so this is valid */ + dimm_data->spd = data; + data += CONFIG_DIMM_SPD_SIZE; + } +} +RAMSTAGE_CBMEM_INIT_HOOK(restore_mem_data); diff --git a/src/soc/ibm/power9/romstage.c b/src/soc/ibm/power9/romstage.c index 684d6e9bbfa..d96ba1f489f 100644 --- a/src/soc/ibm/power9/romstage.c +++ b/src/soc/ibm/power9/romstage.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "fsi.h" @@ -443,3 +444,39 @@ void main(void) cbmem_initialize_empty(); run_ramstage(); } + +/* Stores global mem_data variable into cbmem for future use by ramstage */ +static void store_mem_data(int is_recovery) +{ + const struct cbmem_entry *entry; + uint8_t *data; + int dimm_i; + + (void)is_recovery; /* unused */ + + /* Layout: mem_data itself then SPD data of each dimm which has it */ + entry = cbmem_entry_add(CBMEM_ID_MEMINFO, sizeof(mem_data) + + MAX_CHIPS * DIMMS_PER_PROC * CONFIG_DIMM_SPD_SIZE); + if (entry == NULL) + die("Failed to add mem_data entry to CBMEM in romstage!"); + + data = cbmem_entry_start(entry); + + memcpy(data, &mem_data, sizeof(mem_data)); + data += sizeof(mem_data); + + for (dimm_i = 0; dimm_i < MAX_CHIPS * DIMMS_PER_PROC; dimm_i++) { + int chip = dimm_i / DIMMS_PER_PROC; + int mcs = (dimm_i % DIMMS_PER_PROC) / DIMMS_PER_MCS; + int mca = (dimm_i % DIMMS_PER_MCS) / DIMMS_PER_MCA; + int dimm = dimm_i % DIMMS_PER_MCA; + + rdimm_data_t *dimm_data = &mem_data[chip].mcs[mcs].mca[mca].dimm[dimm]; + if (dimm_data->spd == NULL) + continue; + + memcpy(data, dimm_data->spd, CONFIG_DIMM_SPD_SIZE); + data += CONFIG_DIMM_SPD_SIZE; + } +} +ROMSTAGE_CBMEM_INIT_HOOK(store_mem_data); From 487d707176aead9443a0f92053d6359ccba455c2 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Wed, 23 Mar 2022 16:19:30 +0200 Subject: [PATCH 7/7] soc/power9/chip.c: generate DIMM sensor nodes for DT Two nodes per installed DIMM: state (presence) and temperature sensors. Change-Id: I297c4820679491699fcdfea173d6fbd01eddbe75 Signed-off-by: Sergii Dmytruk --- .../raptor-cs/talos-2/devicetree.dts | 84 ------------------- src/soc/ibm/power9/chip.c | 44 ++++++++++ 2 files changed, 44 insertions(+), 84 deletions(-) diff --git a/src/mainboard/raptor-cs/talos-2/devicetree.dts b/src/mainboard/raptor-cs/talos-2/devicetree.dts index 49c4681c443..b42857e2107 100644 --- a/src/mainboard/raptor-cs/talos-2/devicetree.dts +++ b/src/mainboard/raptor-cs/talos-2/devicetree.dts @@ -82,90 +82,6 @@ ipmi-sensor-type = <0xc1>; }; - sensor@b { - compatible = "ibm,ipmi-sensor"; - reg = <0x0b>; - ipmi-sensor-type = <0x0c>; - }; - - sensor@d { - compatible = "ibm,ipmi-sensor"; - reg = <0x0d>; - ipmi-sensor-type = <0x0c>; - }; - - sensor@f { - compatible = "ibm,ipmi-sensor"; - reg = <0x0f>; - ipmi-sensor-type = <0x0c>; - }; - - sensor@11 { - compatible = "ibm,ipmi-sensor"; - reg = <0x11>; - ipmi-sensor-type = <0x0c>; - }; - - sensor@13 { - compatible = "ibm,ipmi-sensor"; - ipmi-sensor-type = <0x0c>; - reg = <0x13>; - }; - - sensor@15 { - compatible = "ibm,ipmi-sensor"; - ipmi-sensor-type = <0x0c>; - reg = <0x15>; - }; - - sensor@19 { - compatible = "ibm,ipmi-sensor"; - ipmi-sensor-type = <0x0c>; - reg = <0x19>; - }; - - sensor@1b { - compatible = "ibm,ipmi-sensor"; - reg = <0x1b>; - ipmi-sensor-type = <0x01>; - }; - - sensor@1d { - compatible = "ibm,ipmi-sensor"; - reg = <0x1d>; - ipmi-sensor-type = <0x01>; - }; - - sensor@1f { - compatible = "ibm,ipmi-sensor"; - reg = <0x1f>; - ipmi-sensor-type = <0x01>; - }; - - sensor@21 { - compatible = "ibm,ipmi-sensor"; - reg = <0x21>; - ipmi-sensor-type = <0x01>; - }; - - sensor@23 { - compatible = "ibm,ipmi-sensor"; - ipmi-sensor-type = <0x01>; - reg = <0x23>; - }; - - sensor@25 { - compatible = "ibm,ipmi-sensor"; - ipmi-sensor-type = <0x01>; - reg = <0x25>; - }; - - sensor@29 { - compatible = "ibm,ipmi-sensor"; - ipmi-sensor-type = <0x01>; - reg = <0x29>; - }; - sensor@8b { compatible = "ibm,ipmi-sensor"; reg = <0x8b>; diff --git a/src/soc/ibm/power9/chip.c b/src/soc/ibm/power9/chip.c index a20569ecd3d..363241ab982 100644 --- a/src/soc/ibm/power9/chip.c +++ b/src/soc/ibm/power9/chip.c @@ -411,6 +411,49 @@ static void validate_dt(struct device_tree *tree, uint8_t chips) } } +/* Mind that this function creates nodes without chip ID, but some types of sensors need it */ +static void add_sensor_node(struct device_tree *tree, uint8_t number, uint8_t ipmi_type) +{ + char path[32]; + struct device_tree_node *node; + + snprintf(path, sizeof(path), "/bmc/sensors/sensor@%x", number); + node = dt_find_node_by_path(tree, path, NULL, NULL, 1); + + dt_add_string_prop(node, "compatible", "ibm,ipmi-sensor"); + dt_add_u32_prop(node, "reg", number); + dt_add_u32_prop(node, "ipmi-sensor-type", ipmi_type); +} + +static void add_dimm_sensor_nodes(struct device_tree *tree, uint8_t chips) +{ + enum { + /* Base numbers for sensor ids */ + DIMM_STATE_BASE = 0x0B, + DIMM_TEMP_BASE = 0x1B, + + /* IPMI sensor types */ + STATE_IPMI_SENSOR = 0x0C, + TEMP_IPMI_SENSOR = 0x01, + }; + + int dimm_i; + for (dimm_i = 0; dimm_i < MAX_CHIPS * DIMMS_PER_PROC; dimm_i++) { + int chip = dimm_i / DIMMS_PER_PROC; + int mcs = (dimm_i % DIMMS_PER_PROC) / DIMMS_PER_MCS; + int mca = (dimm_i % DIMMS_PER_MCS) / DIMMS_PER_MCA; + int dimm = dimm_i % DIMMS_PER_MCA; + + if (!(chips & (1 << chip))) + continue; + if (!mem_data[chip].mcs[mcs].mca[mca].dimm[dimm].present) + continue; + + add_sensor_node(tree, DIMM_STATE_BASE + dimm_i, STATE_IPMI_SENSOR); + add_sensor_node(tree, DIMM_TEMP_BASE + dimm_i, TEMP_IPMI_SENSOR); + } +} + /* * Device tree passed to Skiboot has to have phandles set either for all nodes * or none at all. Because relative phandles are set for cpu->l2_cache->l3_cache @@ -426,6 +469,7 @@ static int dt_platform_fixup(struct device_tree_fixup *fixup, validate_dt(tree, chips); split_mem_node(tree); + add_dimm_sensor_nodes(tree, chips); /* Find "cpus" node */ cpus = dt_find_node_by_path(tree, "/cpus", NULL, NULL, 0);