Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/include/cpu/power/mvpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,44 @@
#include <stdbool.h>
#include <stdint.h>

/* Single bucket within #V keyword of version 3 */
struct voltage_data
{
uint16_t freq;
uint16_t vdd_voltage;
uint16_t idd_current;
uint16_t vcs_voltage;
uint16_t ics_current;
} __attribute__((__packed__));

/* Single bucket within #V keyword of version 3 */
struct voltage_bucket_data
{
uint8_t id;

struct voltage_data nominal;
struct voltage_data powersave;
struct voltage_data turbo;
struct voltage_data ultra_turbo;
struct voltage_data powerbus;

uint16_t sort_power_normal;
uint16_t sort_power_turbo;

uint8_t reserved[6];
} __attribute__((__packed__));

#define VOLTAGE_DATA_VERSION 3
#define VOLTAGE_BUCKET_COUNT 6

/* #V of LRP[0-5] in MVPD */
struct voltage_kwd
{
uint8_t version;
uint8_t pnp[3];
struct voltage_bucket_data buckets[VOLTAGE_BUCKET_COUNT];
} __attribute__((__packed__));

struct region_device;

void mvpd_pnor_main(void);
Expand All @@ -16,6 +54,15 @@ void mvpd_device_unmount(void);

const struct region_device *mvpd_device_ro(void);

/* Reads #V of one of LRP records (mind that there is only one buffer) */
const struct voltage_kwd *mvpd_get_voltage_data(int lrp);

/* Finds a specific keyword in MVPD partition and extracts it. *size is updated
* to reflect needed or used space in the buffer. */
bool mvpd_extract_keyword(const char *record_name, const char *kwd_name,
uint8_t *buf, uint32_t *size);

/* Finds a specific ring in MVPD partition and extracts it */
bool mvpd_extract_ring(const char *record_name, const char *kwd_name,
uint8_t chiplet_id, uint16_t ring_id, uint8_t *buf,
uint32_t buf_size);
Expand Down
52 changes: 52 additions & 0 deletions src/include/cpu/power/powerbus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef CPU_PPC64_POWERBUS_H
#define CPU_PPC64_POWERBUS_H

#include <stdint.h>

enum FABRIC_CORE_FLOOR_RATIO
{
FABRIC_CORE_FLOOR_RATIO_RATIO_8_8 = 0x0,
FABRIC_CORE_FLOOR_RATIO_RATIO_7_8 = 0x1,
FABRIC_CORE_FLOOR_RATIO_RATIO_6_8 = 0x2,
FABRIC_CORE_FLOOR_RATIO_RATIO_5_8 = 0x3,
FABRIC_CORE_FLOOR_RATIO_RATIO_4_8 = 0x4,
FABRIC_CORE_FLOOR_RATIO_RATIO_2_8 = 0x5,
};

enum FABRIC_CORE_CEILING_RATIO
{
FABRIC_CORE_CEILING_RATIO_RATIO_8_8 = 0x0,
FABRIC_CORE_CEILING_RATIO_RATIO_7_8 = 0x1,
FABRIC_CORE_CEILING_RATIO_RATIO_6_8 = 0x2,
FABRIC_CORE_CEILING_RATIO_RATIO_5_8 = 0x3,
FABRIC_CORE_CEILING_RATIO_RATIO_4_8 = 0x4,
FABRIC_CORE_CEILING_RATIO_RATIO_2_8 = 0x5,
};

#define NUM_EPSILON_READ_TIERS 3
#define NUM_EPSILON_WRITE_TIERS 2

/* Description of PowerBus configuration */
struct powerbus_cfg
{
/* Data computed from #V of LRP0 in MVPD, is MHz */
uint32_t freq_core_floor;
uint32_t freq_core_ceiling;
uint32_t fabric_freq;

/* Derived from data above */
enum FABRIC_CORE_FLOOR_RATIO core_floor_ratio;
enum FABRIC_CORE_CEILING_RATIO core_ceiling_ratio;

/* Derived from all data above */
/* ATTR_PROC_EPS_READ_CYCLES_T* */
uint32_t eps_r[NUM_EPSILON_READ_TIERS];
/* ATTR_PROC_EPS_WRITE_CYCLES_T* */
uint32_t eps_w[NUM_EPSILON_WRITE_TIERS];
};

const struct powerbus_cfg *powerbus_cfg(void);

#endif // CPU_PPC64_POWERBUS_H
3 changes: 3 additions & 0 deletions src/soc/ibm/power9/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ bootblock-y += bootblock.c
bootblock-y += rom_media.c
romstage-y += rom_media.c
romstage-y += romstage.c
romstage-y += mvpd.c
romstage-y += vpd.c
romstage-y += powerbus.c
romstage-y += istep_13_2.c
romstage-y += istep_13_3.c
romstage-y += istep_13_4.c
Expand All @@ -31,5 +33,6 @@ ramstage-y += mvpd.c
ramstage-y += vpd.c
ramstage-y += tor.c
ramstage-y += rs4.c
ramstage-y += powerbus.c

endif
20 changes: 14 additions & 6 deletions src/soc/ibm/power9/istep_13_8.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#include <cpu/power/istep_13.h>
#include <cpu/power/powerbus.h>
#include <cpu/power/vpd_data.h>
#include <console/console.h>

#include "istep_13_scom.h"

#define ATTR_PG 0xE000000000000000ull
#define FREQ_PB_MHZ 1866

/*
* This function was generated from initfiles. Some of the registers used here
Expand All @@ -22,6 +22,8 @@
*/
static void p9n_mca_scom(int mcs_i, int mca_i)
{
const struct powerbus_cfg *pb_cfg = powerbus_cfg();

chiplet_id_t id = mcs_ids[mcs_i];
mca_data_t *mca = &mem_data.mcs[mcs_i].mca[mca_i];
const int mca_mul = 0x10;
Expand Down Expand Up @@ -108,10 +110,15 @@ static void p9n_mca_scom(int mcs_i, int mca_i)
[32-39] = (ATTR_PROC_EPS_READ_CYCLES_T2 + 6) / 4 // REMOTE_NODAL_EPSILON
[40-47] = (ATTR_PROC_EPS_READ_CYCLES_T2 + 6) / 4 // VECTOR_GROUP_EPSILON
*/
#define F(X) (((X) + 6) / 4)
scom_and_or_for_chiplet(nest, 0x05010826 + mca_i * mca_mul, ~PPC_BITMASK(0,47),
PPC_SHIFT(1, 7) /* FIXME: fill the rest with non-hardcoded values*/
| PPC_SHIFT(4, 15) | PPC_SHIFT(4, 23) | PPC_SHIFT(4, 31)
| PPC_SHIFT(0x19, 39) | PPC_SHIFT(0x19, 47));
PPC_SHIFT(1, 7)
| PPC_SHIFT(F(pb_cfg->eps_r[0]), 15)
| PPC_SHIFT(F(pb_cfg->eps_r[1]), 23)
| PPC_SHIFT(F(pb_cfg->eps_r[1]), 31)
| PPC_SHIFT(F(pb_cfg->eps_r[2]), 39)
| PPC_SHIFT(F(pb_cfg->eps_r[2]), 47));
#undef F
//~ static const uint32_t EPSILON_R_T0_LE[] = { 7, 7, 8, 8, 10, 22 }; // T0, T1
//~ static const uint32_t EPSILON_R_T2_LE[] = { 67, 69, 71, 74, 79, 103 }; // T2

Expand Down Expand Up @@ -468,9 +475,10 @@ static void p9n_mca_scom(int mcs_i, int mca_i)
/*
* From Hostboot:
* l_def_mn_freq_ratio = 1000 * ATTR_MSS_FREQ / ATTR_FREQ_PB_MHZ;
* ATTR_MSS_FREQ is in MT/s (sigh), ATTR_FREQ_PB_MHZ is 1866 MHz (from talos.xml).
* ATTR_MSS_FREQ is in MT/s (sigh).
*/
uint64_t mn_freq_ratio = 1000 * mem_data.speed / FREQ_PB_MHZ;
uint32_t pb_freq = pb_cfg->fabric_freq;
uint64_t mn_freq_ratio = 1000 * mem_data.speed / pb_freq;
uint64_t val_to_data = mn_freq_ratio < 915 ? 3 :
mn_freq_ratio < 1150 ? 4 :
mn_freq_ratio < 1300 ? 5 : 6;
Expand Down
131 changes: 104 additions & 27 deletions src/soc/ibm/power9/mvpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cpu/power/mvpd.h>

#include <assert.h>
#include <commonlib/region.h>
#include <console/console.h>
#include <cpu/power/vpd.h>
Expand Down Expand Up @@ -91,57 +92,133 @@ static struct ring_hdr *find_ring(uint8_t chiplet_id, uint16_t ring_id,
return NULL;
}

/* Finds a specific ring in MVPD partition and extracts it */
bool mvpd_extract_ring(const char *record_name, const char *kwd_name,
uint8_t chiplet_id, uint16_t ring_id, uint8_t *buf,
uint32_t buf_size)
static const uint8_t *mvpd_get_keyword(const char *record_name,
const char *kwd_name,
size_t *kwd_size, void **mmaped_data)
{
const struct region_device *mvpd_device;
const struct region_device *mvpd_device = mvpd_device_ro();

uint8_t mvpd_buf[MVPD_TOC_SIZE];
struct mvpd_toc_entry *mvpd_toc = (struct mvpd_toc_entry *)mvpd_buf;

struct mvpd_toc_entry *cp00 = NULL;
uint16_t cp00_offset = 0;
const uint8_t *cp00_data = NULL;
uint16_t cp00_size = 0;
struct mvpd_toc_entry *toc_entry = NULL;
uint16_t record_offset = 0;
uint8_t *record_data = NULL;
uint16_t record_size = 0;

const uint8_t *rings = NULL;
size_t rings_size = 0;

struct ring_hdr *ring = NULL;
uint32_t ring_size = 0;

mvpd_device_init();
mvpd_device = mvpd_device_ro();
const uint8_t *kwd = NULL;

/* Copy all TOC at once */
if (rdev_readat(mvpd_device, mvpd_buf, 0,
sizeof(mvpd_buf)) != sizeof(mvpd_buf))
die("Failed to read MVPD TOC!\n");

cp00 = find_record(mvpd_toc, record_name);
if (cp00 == NULL)
toc_entry = find_record(mvpd_toc, record_name);
if (toc_entry == NULL)
die("Failed to find %s MVPD record!\n", record_name);
cp00_offset = le16toh(cp00->offset);
record_offset = le16toh(toc_entry->offset);

/* Read size of the record */
if (rdev_readat(mvpd_device, &cp00_size, cp00_offset,
sizeof(cp00_size)) != sizeof(cp00_size))
if (rdev_readat(mvpd_device, &record_size, record_offset,
sizeof(record_size)) != sizeof(record_size))
die("Failed to read size of %s!\n", record_name);

cp00_data = rdev_mmap(mvpd_device, cp00_offset, cp00_size);
if (!cp00_data)
record_data = rdev_mmap(mvpd_device, record_offset, record_size);
if (!record_data)
die("Failed to map %s record!\n", record_name);

rings = vpd_find_kwd(cp00_data, record_name, kwd_name, &rings_size);
kwd = vpd_find_kwd(record_data, record_name, kwd_name, kwd_size);
if (kwd == NULL)
die("Failed to find %s keyword in %s!\n", kwd_name,
record_name);

*mmaped_data = record_data;
return kwd;
}

bool mvpd_extract_keyword(const char *record_name, const char *kwd_name,
uint8_t *buf, uint32_t *size)
{
void *mmaped_data = NULL;

const uint8_t *kwd = NULL;
size_t kwd_size = 0;
bool copied_data = false;

mvpd_device_init();

kwd = mvpd_get_keyword(record_name, kwd_name, &kwd_size, &mmaped_data);
if (kwd == NULL)
die("Failed to find %s keyword in %s!\n", kwd_name,
record_name);

if (*size >= kwd_size) {
memcpy(buf, kwd, kwd_size);
copied_data = true;
}

*size = kwd_size;

if (rdev_munmap(mvpd_device_ro(), mmaped_data))
die("Failed to unmap %s record!\n", record_name);

return copied_data;
}

const struct voltage_kwd *mvpd_get_voltage_data(int lrp)
{
static int inited_lrp = -1;
static uint8_t buf[sizeof(struct voltage_kwd)];

char record_name[] = { 'L', 'R', 'P', '0' + lrp };
uint32_t buf_size = sizeof(buf);
struct voltage_kwd *voltage = (void *)buf;

assert(lrp >= 0 && lrp < 6);
if (inited_lrp == lrp)
return voltage;

inited_lrp = -1;

if (!mvpd_extract_keyword(record_name, "#V", buf, &buf_size)) {
printk(BIOS_ERR, "Failed to read LRP0 record from MVPD\n");
return NULL;
}

if (voltage->version != VOLTAGE_DATA_VERSION) {
printk(BIOS_ERR, "Only version %d of voltage data is supported, got: %d\n",
VOLTAGE_DATA_VERSION, voltage->version);
return NULL;
}

inited_lrp = lrp;
return voltage;
}

/* Finds a specific ring in MVPD partition and extracts it */
bool mvpd_extract_ring(const char *record_name, const char *kwd_name,
uint8_t chiplet_id, uint16_t ring_id, uint8_t *buf,
uint32_t buf_size)
{
void *mmaped_data = NULL;

const uint8_t *rings = NULL;
size_t rings_size = 0;

struct ring_hdr *ring = NULL;
uint32_t ring_size = 0;

mvpd_device_init();

rings = mvpd_get_keyword(record_name, kwd_name, &rings_size,
&mmaped_data);
if (rings == NULL)
die("Failed to find %s keyword in %s!\n", kwd_name,
record_name);

ring = find_ring(chiplet_id, ring_id, rings, rings_size);
if (ring == NULL) {
if (rdev_munmap(mvpd_device, (void *)cp00_data))
if (rdev_munmap(mvpd_device_ro(), mmaped_data))
die("Failed to unmap %s record!\n", record_name);

return false;
Expand All @@ -151,7 +228,7 @@ bool mvpd_extract_ring(const char *record_name, const char *kwd_name,
if (buf_size >= ring_size)
memcpy(buf, ring, ring_size);

if (rdev_munmap(mvpd_device, (void *)cp00_data))
if (rdev_munmap(mvpd_device_ro(), mmaped_data))
die("Failed to unmap %s record!\n", record_name);

return (buf_size >= ring_size);
Expand Down
Loading