Skip to content

Commit

Permalink
soc/power9/: switch away from FIT payload
Browse files Browse the repository at this point in the history
Load and set up FDT ourselves.

Change-Id: Id3380fb706d427ec8bb8083515e11ce93600c6f9
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
  • Loading branch information
SergiiDmytruk committed Mar 3, 2022
1 parent deca85a commit 64c091f
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 154 deletions.
30 changes: 0 additions & 30 deletions src/arch/ppc64/stages.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
#include <arch/stages.h>
#include <cpu/power/spr.h>
#include <timestamp.h>
#include <fit.h>
#include <bootmem.h>

void stage_entry(uintptr_t stage_arg)
{
Expand All @@ -27,31 +25,3 @@ void stage_entry(uintptr_t stage_arg)

main();
}

bool fit_payload_arch(struct prog *payload, struct fit_config_node *config,
struct region *kernel,
struct region *fdt,
struct region *initrd)
{
void *arg = NULL;

/* Mark as reserved for future allocations. */
bootmem_add_range(kernel->offset, kernel->size, BM_MEM_PAYLOAD);

/* Place FDT */
/* TODO: remove hardcoded size */
fdt->offset = 0xf0000000;
fdt->size = 318539;

/* Mark as reserved for future allocations. */
bootmem_add_range(fdt->offset, fdt->size, BM_MEM_PAYLOAD);

/* Kernel expects FDT as argument */
arg = (void *)fdt->offset;

prog_set_entry(payload, (void *)0x10 /* kernel->offset + 0x10 ? */, arg);

bootmem_dump_ranges();

return true;
}
1 change: 1 addition & 0 deletions src/mainboard/raptor-cs/talos-2/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ config BOARD_SPECIFIC_OPTIONS
select HAVE_DEBUG_RAM_SETUP
select IPMI_BT
select IPMI_BT_ROMSTAGE
select FLATTENED_DEVICE_TREE

config MEMLAYOUT_LD_FILE
string
Expand Down
216 changes: 92 additions & 124 deletions src/soc/ibm/power9/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#include <assert.h>
#include <drivers/ipmi/ipmi_bt.h>
#include <program_loading.h>
#include <fit.h>
#include <cbfs.h>
#include <device_tree.h>
#include <cpu/power/istep_13.h>
#include <cpu/power/istep_14.h>
#include <cpu/power/istep_18.h>
Expand All @@ -15,6 +16,24 @@
#include "chip.h"
#include "fsi.h"

#define SIZE_MASK PPC_BITMASK(13,23)
#define SIZE_SHIFT (63 - 23)
#define BASE_MASK PPC_BITMASK(24,47)
#define BASE_SHIFT (63 - 47)

/* Values in registers are in 4GB units, ram_resource() expects kilobytes. */
#define CONVERT_4GB_TO_KB(x) ((x) << 22)

static inline unsigned long base_k(uint64_t reg)
{
return CONVERT_4GB_TO_KB((reg & BASE_MASK) >> BASE_SHIFT);
}

static inline unsigned long size_k(uint64_t reg)
{
return CONVERT_4GB_TO_KB(((reg & SIZE_MASK) >> SIZE_SHIFT) + 1);
}

static uint64_t nominal_freq[MAX_CHIPS];

/*
Expand Down Expand Up @@ -242,122 +261,66 @@ static void fill_cpu_node(struct device_tree *tree,
dt_add_u32_prop(node, "tlb-sets", 4);
}

/*
* coreboot prepares one node with multiple "reg" entries (see fit_update_memory
* and functions called by it), while Skiboot expects multiple nodes, one region
* each. Both approaches are compliant with Devicetree Specification v0.3 so we
* can't say that one of them is wrong, they're just different.
*
* Probable cause for Skiboot choosing multi-node version is that it is possible
* to specify associativity, which may be important for NUMA systems.
*
* TODO: create these nodes from DIMM entries, when they are implemented.
*/
static void split_mem_node(struct device_tree *tree)
static void add_memory_node(struct device_tree *tree, uint8_t chip, uint64_t reg)
{
struct device_tree_node *old_node;
struct device_tree_node *new_region;
struct device_tree_property *prop;
const uint32_t *reg_data = NULL;
size_t count, size_bytes = 0, offset = 0;
/*
* Assume that, unless specified otherwise in "memory" node, defaults of 2
* are used for address and size cells.
*/
size_t address_cells = 2, size_cells = 2;
struct device_tree_node *node;
/* /memory@0123456789abcdef - 24 characters + null byte */
char path[26] = {};

old_node = dt_find_node_by_path(tree, "/memory", NULL, NULL, 0);
if (old_node == NULL)
die("No 'memory' node in device tree!\n");
union {uint32_t u32[2]; uint64_t u64;} addr = { .u64 = base_k(reg) * KiB };
union {uint32_t u32[2]; uint64_t u64;} size = { .u64 = size_k(reg) * KiB };

list_remove(&old_node->list_node);
snprintf(path, sizeof(path), "/memory@%llx", addr.u64);
node = dt_find_node_by_path(tree, path, NULL, NULL, 1);

list_for_each(prop, old_node->properties, list_node) {
if (!strcmp("reg", prop->prop.name)) {
size_bytes = prop->prop.size;
reg_data = (uint32_t *)prop->prop.data;
continue;
}
if (!strcmp("#address-cells", prop->prop.name)) {
address_cells = *(uint32_t *)prop->prop.data;
continue;
}
if (!strcmp("#size-cells", prop->prop.name)) {
size_cells = *(uint32_t *)prop->prop.data;
continue;
}
}
dt_add_string_prop(node, "device_type", (char *)"memory");
/* Use 2 cells each for address and size. This assumes BE. */
dt_add_reg_prop(node, &addr.u64, &size.u64, 1, 2, 2);

if (reg_data == NULL)
die("No 'reg' property in 'memory' node\n");

if (address_cells != 2 && address_cells != 1)
die("'#address_cells' property in 'memory' has invalid value (%d)\n",
address_cells);

if (size_cells != 2 && size_cells != 1)
die("'#size_cells' property in 'memory' has invalid value (%d)\n",
size_cells);
/* Don't know why the value needs to be shifted (group id + chip id?) */
dt_add_u32_prop(node, "ibm,chip-id", chip << 3);
}

count = size_bytes / (sizeof(uint32_t) * (address_cells + size_cells));
if (count * sizeof(uint32_t) * (address_cells + size_cells) != size_bytes)
die("'reg' property of 'memory' node has wrong size\n");
static void add_memory_nodes(struct device_tree *tree)
{
uint8_t chip;
uint8_t chips = fsi_get_present_chips();

for (size_t i = 0; i < count; i++) {
/*
* For newly created nodes always use 2 cells each for address and size,
* regardless of sizes created by fit_update_memory. This assumes BE.
*/
union {uint32_t u32[2]; uint64_t u64;} new_addr = {};
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++];
else {
new_addr.u32[0] = reg_data[offset++];
new_addr.u32[1] = reg_data[offset++];
}
/* Alternative is to use bootmem_walk_os_mem(), but this is simpler */
for (chip = 0; chip < MAX_CHIPS; chip++) {
int mcs_i;

if (size_cells == 1)
new_size.u32[1] = reg_data[offset++];
else {
new_size.u32[0] = reg_data[offset++];
new_size.u32[1] = reg_data[offset++];
}
if (!(chips & (1 << chip)))
continue;

snprintf(path, sizeof(path), "/memory@%llx", new_addr.u64);
new_region = dt_find_node_by_path(tree, path, NULL, NULL, 1);
for (mcs_i = 0; mcs_i < MCS_PER_PROC; mcs_i++) {
uint64_t reg;
chiplet_id_t nest = mcs_to_nest[mcs_ids[mcs_i]];

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);
/* These registers are undocumented, see istep 14.5. */
/* MCS_MCFGP */
reg = read_rscom_for_chiplet(chip, nest, 0x0501080A);
if (reg & PPC_BIT(0))
add_memory_node(tree, chip, reg);

/*
* 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);
/* MCS_MCFGPM */
reg = read_rscom_for_chiplet(chip, nest, 0x0501080C);
if (reg & PPC_BIT(0))
add_memory_node(tree, chip, reg);
}
}
};
}

/*
* 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)
static int dt_platform_update(struct device_tree *tree, uint8_t chips)
{
uint8_t chips = fsi_get_present_chips();

struct device_tree_node *cpus, *xscom;

split_mem_node(tree);
add_memory_nodes(tree);

/* Find xscom node, halt if not found */
/* TODO: is the address always the same? */
Expand Down Expand Up @@ -503,24 +466,6 @@ static void rng_init(uint8_t chips)
}
}

#define SIZE_MASK PPC_BITMASK(13,23)
#define SIZE_SHIFT (63 - 23)
#define BASE_MASK PPC_BITMASK(24,47)
#define BASE_SHIFT (63 - 47)

/* Values in registers are in 4GB units, ram_resource() expects kilobytes. */
#define CONVERT_4GB_TO_KB(x) ((x) << 22)

static inline unsigned long base_k(uint64_t reg)
{
return CONVERT_4GB_TO_KB((reg & BASE_MASK) >> BASE_SHIFT);
}

static inline unsigned long size_k(uint64_t reg)
{
return CONVERT_4GB_TO_KB(((reg & SIZE_MASK) >> SIZE_SHIFT) + 1);
}

static void enable_soc_dev(struct device *dev)
{
int chip, idx = 0;
Expand Down Expand Up @@ -574,16 +519,6 @@ static void enable_soc_dev(struct device *dev)
*/
build_homer_image((void *)(top * 1024), nominal_freq);

if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
struct device_tree_fixup *dt_fixup;

dt_fixup = malloc(sizeof(*dt_fixup));
if (dt_fixup) {
dt_fixup->fixup = dt_platform_fixup;
list_insert_after(&dt_fixup->list_node,
&device_tree_fixups);
}
}
rng_init(chips);
istep_18_11(chips, &tod_mdmt);
istep_18_12(chips, tod_mdmt);
Expand Down Expand Up @@ -642,10 +577,43 @@ static void activate_slave_cores(uint8_t chip)
}
}

static void * load_fdt(const char *dtb_file, uint8_t chips)
{
void *fdt;
void *fdt_rom;
struct device_tree *tree;

fdt_rom = cbfs_map(dtb_file, NULL);
if (fdt_rom == NULL)
die("Unable to load %s from CBFS\n", dtb_file);

tree = fdt_unflatten(fdt_rom);

dt_platform_update(tree, chips);

fdt = malloc(dt_flat_size(tree));
if (fdt == NULL)
die("Unable to allocate memory for flat device tree\n");

dt_flatten(tree, fdt);
return fdt;
}

void platform_prog_run(struct prog *prog)
{
uint8_t chips = fsi_get_present_chips();

void *fdt;
const char *dtb_file;

assert(chips == 0x01 || chips == 0x03);

dtb_file = (chips == 0x01 ? "1-cpu.dtb" : "2-cpus.dtb");
fdt = load_fdt(dtb_file, chips);

/* See asm/head.S in skiboot where fdt_entry starts at offset 0x10 */
prog_set_entry(prog, (void *)0x10, fdt);

/*
* Clear SMS_ATN aka EVT_ATN in BT_CTRL - Block Transfer IPMI protocol
*
Expand Down

0 comments on commit 64c091f

Please sign in to comment.