From ee59e7b3590fa74478d9a4f3724a051cf80118d1 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 5 Aug 2021 01:52:10 +0300 Subject: [PATCH 1/8] soc/power9/mvpd.c: rename several variables Change-Id: If092c16bf39195c065fd979894ec02dd94a2f250 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/mvpd.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/soc/ibm/power9/mvpd.c b/src/soc/ibm/power9/mvpd.c index 01bfd84b3a1..85ec5ecfe5c 100644 --- a/src/soc/ibm/power9/mvpd.c +++ b/src/soc/ibm/power9/mvpd.c @@ -101,10 +101,10 @@ bool mvpd_extract_ring(const char *record_name, const char *kwd_name, 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; + const uint8_t *record_data = NULL; + uint16_t record_size = 0; const uint8_t *rings = NULL; size_t rings_size = 0; @@ -120,28 +120,28 @@ bool mvpd_extract_ring(const char *record_name, const char *kwd_name, 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); + rings = vpd_find_kwd(record_data, record_name, kwd_name, &rings_size); 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, (void *)record_data)) die("Failed to unmap %s record!\n", record_name); return false; @@ -151,7 +151,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, (void *)record_data)) die("Failed to unmap %s record!\n", record_name); return (buf_size >= ring_size); From b0eeeb417136e801773910f1c1ae871a8151db33 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 5 Aug 2021 01:53:54 +0300 Subject: [PATCH 2/8] soc/power9/mvpd.c: extract mvpd_get_keyword() Change-Id: I22d4d380b878af1fa4bde4ceda79c970efad9093 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/mvpd.c | 50 ++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/soc/ibm/power9/mvpd.c b/src/soc/ibm/power9/mvpd.c index 85ec5ecfe5c..e866e7130e6 100644 --- a/src/soc/ibm/power9/mvpd.c +++ b/src/soc/ibm/power9/mvpd.c @@ -91,29 +91,21 @@ 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 *toc_entry = NULL; uint16_t record_offset = 0; - const uint8_t *record_data = NULL; + 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, @@ -134,14 +126,38 @@ bool mvpd_extract_ring(const char *record_name, const char *kwd_name, if (!record_data) die("Failed to map %s record!\n", record_name); - rings = vpd_find_kwd(record_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_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 *)record_data)) + if (rdev_munmap(mvpd_device_ro(), mmaped_data)) die("Failed to unmap %s record!\n", record_name); return false; @@ -151,7 +167,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 *)record_data)) + if (rdev_munmap(mvpd_device_ro(), mmaped_data)) die("Failed to unmap %s record!\n", record_name); return (buf_size >= ring_size); From a7ee870cc4787507abc607a92b14749d2f9cfc64 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 5 Aug 2021 01:54:50 +0300 Subject: [PATCH 3/8] soc/power9/mvpd.c: add mvpd_extract_keyword() Change-Id: I1a6dfa7fbd90bb9528b70d8f469c4a66f62697a1 Signed-off-by: Sergii Dmytruk --- src/include/cpu/power/mvpd.h | 6 ++++++ src/soc/ibm/power9/mvpd.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/include/cpu/power/mvpd.h b/src/include/cpu/power/mvpd.h index 39dfe9ab6b6..0a6e45eb1b9 100644 --- a/src/include/cpu/power/mvpd.h +++ b/src/include/cpu/power/mvpd.h @@ -16,6 +16,12 @@ void mvpd_device_unmount(void); const struct region_device *mvpd_device_ro(void); +/* 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); diff --git a/src/soc/ibm/power9/mvpd.c b/src/soc/ibm/power9/mvpd.c index e866e7130e6..a441f09e05b 100644 --- a/src/soc/ibm/power9/mvpd.c +++ b/src/soc/ibm/power9/mvpd.c @@ -135,6 +135,36 @@ static const uint8_t *mvpd_get_keyword(const char *record_name, 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; +} + +/* 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) From ab5a774a997333fb3147877a5223e36734e4fe5c Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 5 Aug 2021 01:57:56 +0300 Subject: [PATCH 4/8] soc/power9: implement istep 8.6 as powerbus.c Change-Id: I04b4a384fb0ea4bb4071ddd5f1ab3c6d1417363a Signed-off-by: Sergii Dmytruk --- src/include/cpu/power/mvpd.h | 38 ++++ src/include/cpu/power/powerbus.h | 52 +++++ src/soc/ibm/power9/Makefile.inc | 3 + src/soc/ibm/power9/powerbus.c | 317 +++++++++++++++++++++++++++++++ 4 files changed, 410 insertions(+) create mode 100644 src/include/cpu/power/powerbus.h create mode 100644 src/soc/ibm/power9/powerbus.c diff --git a/src/include/cpu/power/mvpd.h b/src/include/cpu/power/mvpd.h index 0a6e45eb1b9..e27bf30b28a 100644 --- a/src/include/cpu/power/mvpd.h +++ b/src/include/cpu/power/mvpd.h @@ -6,6 +6,44 @@ #include #include +/* 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); diff --git a/src/include/cpu/power/powerbus.h b/src/include/cpu/power/powerbus.h new file mode 100644 index 00000000000..d2598b9648a --- /dev/null +++ b/src/include/cpu/power/powerbus.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef CPU_PPC64_POWERBUS_H +#define CPU_PPC64_POWERBUS_H + +#include + +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 diff --git a/src/soc/ibm/power9/Makefile.inc b/src/soc/ibm/power9/Makefile.inc index 1947126a1f9..41ba0308867 100644 --- a/src/soc/ibm/power9/Makefile.inc +++ b/src/soc/ibm/power9/Makefile.inc @@ -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 @@ -31,5 +33,6 @@ ramstage-y += mvpd.c ramstage-y += vpd.c ramstage-y += tor.c ramstage-y += rs4.c +romstage-y += powerbus.c endif diff --git a/src/soc/ibm/power9/powerbus.c b/src/soc/ibm/power9/powerbus.c new file mode 100644 index 00000000000..220f04ae210 --- /dev/null +++ b/src/soc/ibm/power9/powerbus.c @@ -0,0 +1,317 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +#include +#include +#include +#include + +#define EPSILON_MAX_VALUE 0xFFFFFFFF + +#define MBOX_SCRATCH_REG1 0x00050038 +#define MBOX_SCRATCH_REG6_GROUP_PUMP_MODE (1 << 23) + +/* + * EPS table type. + * From src/import/chips/p9/procedures/xml/attribute_info/nest_attributes.xml + */ +#define EPS_TYPE_LE 0x01 +#define EPS_TYPE_HE 0x02 +#define EPS_TYPE_HE_F8 0x03 + +/* From src/import/chips/p9/procedures/hwp/nest/p9_fbc_eff_config.C */ +/* LE epsilon (2 chips per-group) */ +static const uint32_t EPSILON_R_T0_LE[] = { 7, 7, 8, 8, 10, 22 }; +static const uint32_t EPSILON_R_T1_LE[] = { 7, 7, 8, 8, 10, 22 }; +static const uint32_t EPSILON_R_T2_LE[] = { 67, 69, 71, 74, 79, 103 }; +static const uint32_t EPSILON_W_T0_LE[] = { 0, 0, 0, 0, 0, 5 }; +static const uint32_t EPSILON_W_T1_LE[] = { 15, 16, 17, 19, 21, 33 }; + +/* HE epsilon (4 chips per-group) */ +static const uint32_t EPSILON_R_T0_HE[] = { 7, 7, 8, 8, 10, 22 }; +static const uint32_t EPSILON_R_T1_HE[] = { 92, 94, 96, 99, 104, 128 }; +static const uint32_t EPSILON_R_T2_HE[] = { 209, 210, 213, 216, 221, 245 }; +static const uint32_t EPSILON_W_T0_HE[] = { 28, 29, 30, 32, 34, 46 }; +static const uint32_t EPSILON_W_T1_HE[] = { 117, 118, 119, 121, 123, 135 }; + +/* HE epsilon (flat 4 Zeppelin) */ +static const uint32_t EPSILON_R_T0_F4[] = { 7, 7, 8, 8, 10, 22 }; +static const uint32_t EPSILON_R_T1_F4[] = { 7, 7, 8, 8, 10, 22 }; +static const uint32_t EPSILON_R_T2_F4[] = { 83, 84, 87, 90, 95, 119 }; +static const uint32_t EPSILON_W_T0_F4[] = { 0, 0, 0, 0, 0, 5 }; +static const uint32_t EPSILON_W_T1_F4[] = { 18, 19, 20, 22, 24, 36 }; + +/* HE epsilon (flat 8 configuration) */ +static const uint32_t EPSILON_R_T0_F8[] = { 7, 7, 8, 8, 10, 22 }; +static const uint32_t EPSILON_R_T1_F8[] = { 7, 7, 8, 8, 10, 22 }; +static const uint32_t EPSILON_R_T2_F8[] = { 148, 149, 152, 155, 160, 184 }; +static const uint32_t EPSILON_W_T0_F8[] = { 0, 0, 0, 0, 0, 5 }; +static const uint32_t EPSILON_W_T1_F8[] = { 76, 77, 78, 80, 82, 94 }; + +/* See get_first_valid_pdV_pbFreq() in Hostboot */ + +static bool read_voltage_data(struct powerbus_cfg *cfg) +{ + uint8_t buf[512]; + uint32_t buf_size = sizeof(buf); + struct voltage_kwd *voltage = (void *)buf; + + bool success = false; + int i = 0; + + /* ATTR_FREQ_PB_MHZ, equal to the first non-zero PowerBus frequency */ + uint32_t pb_freq = 0; + /* ATTR_FREQ_CORE_CEILING_MHZ, equal to the minimum of turbo frequencies */ + uint32_t freq_ceiling = 0; + /* ATTR_FREQ_CORE_FLOOR_MHZ, equal to the maximum of powersave frequencies */ + uint32_t freq_floor = 0; + + /* Using LRP0 because frequencies are the same in all LRP records */ + success = mvpd_extract_keyword("LRP0", "#V", buf, &buf_size); + if (!success) { + printk(BIOS_ERR, "Failed to read LRP0 record from MVPD\n"); + return false; + } + + 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 false; + } + + for (i = 0; i < VOLTAGE_BUCKET_COUNT; ++i) { + struct voltage_bucket_data *bucket = &voltage->buckets[i]; + if (bucket->id == 0) + continue; + + if (pb_freq == 0 && bucket->powerbus.freq != 0) + pb_freq = bucket->powerbus.freq; + + if (bucket->powersave.freq != 0 && + (freq_floor == 0 || bucket->powersave.freq > freq_floor)) { + freq_floor = bucket->powersave.freq; + } + + if (bucket->turbo.freq != 0 && + (freq_ceiling == 0 || bucket->turbo.freq < freq_ceiling)) { + freq_ceiling = bucket->turbo.freq; + } + } + + cfg->fabric_freq = pb_freq; + cfg->freq_core_floor = freq_floor; + cfg->freq_core_ceiling = freq_ceiling; + + return true; +} + +static bool calculate_frequencies(struct powerbus_cfg *cfg) +{ + const uint32_t pb_freq = cfg->fabric_freq; + const uint32_t freq_floor = cfg->freq_core_floor; + const uint32_t freq_ceiling = cfg->freq_core_ceiling; + + enum FABRIC_CORE_FLOOR_RATIO floor_ratio; + enum FABRIC_CORE_CEILING_RATIO ceiling_ratio; + + /* breakpoint ratio: core floor 4.0, pb 2.0 (cache floor :: pb = 8/8) */ + if (freq_floor >= (2 * pb_freq)) { + floor_ratio = FABRIC_CORE_FLOOR_RATIO_RATIO_8_8; + /* breakpoint ratio: core floor 3.5, pb 2.0 (cache floor :: pb = 7/8) */ + } else if ((4 * freq_floor) >= (7 * pb_freq)) { + floor_ratio = FABRIC_CORE_FLOOR_RATIO_RATIO_7_8; + /* breakpoint ratio: core floor 3.0, pb 2.0 (cache floor :: pb = 6/8) */ + } else if ((2 * freq_floor) >= (3 * pb_freq)) { + floor_ratio = FABRIC_CORE_FLOOR_RATIO_RATIO_6_8; + /* breakpoint ratio: core floor 2.5, pb 2.0 (cache floor :: pb = 5/8) */ + } else if ((4 * freq_floor) >= (5 * pb_freq)) { + floor_ratio = FABRIC_CORE_FLOOR_RATIO_RATIO_5_8; + /* breakpoint ratio: core floor 2.0, pb 2.0 (cache floor :: pb = 4/8) */ + } else if (freq_floor >= pb_freq) { + floor_ratio = FABRIC_CORE_FLOOR_RATIO_RATIO_4_8; + /* breakpoint ratio: core floor 1.0, pb 2.0 (cache floor :: pb = 2/8) */ + } else if ((2 * freq_floor) >= pb_freq) { + floor_ratio = FABRIC_CORE_FLOOR_RATIO_RATIO_2_8; + } else { + printk(BIOS_ERR, "Unsupported core ceiling/PB frequency ratio = (%d/%d)\n", + freq_floor, pb_freq); + return false; + } + + /* breakpoint ratio: core ceiling 4.0, pb 2.0 (cache ceiling :: pb = 8/8) */ + if (freq_ceiling >= (2 * pb_freq)) { + ceiling_ratio = FABRIC_CORE_CEILING_RATIO_RATIO_8_8; + /* breakpoint ratio: core ceiling 3.5, pb 2.0 (cache ceiling :: pb = 7/8) */ + } else if ((4 * freq_ceiling) >= (7 * pb_freq)) { + ceiling_ratio = FABRIC_CORE_CEILING_RATIO_RATIO_7_8; + /* breakpoint ratio: core ceiling 3.0, pb 2.0 (cache ceiling :: pb = 6/8) */ + } else if ((2 * freq_ceiling) >= (3 * pb_freq)) { + ceiling_ratio = FABRIC_CORE_CEILING_RATIO_RATIO_6_8; + /* breakpoint ratio: core ceiling 2.5, pb 2.0 (cache ceiling :: pb = 5/8) */ + } else if ((4 * freq_ceiling) >= (5 * pb_freq)) { + ceiling_ratio = FABRIC_CORE_CEILING_RATIO_RATIO_5_8; + /* breakpoint ratio: core ceiling 2.0, pb 2.0 (cache ceiling :: pb = 4/8) */ + } else if (freq_ceiling >= pb_freq) { + ceiling_ratio = FABRIC_CORE_CEILING_RATIO_RATIO_4_8; + /* breakpoint ratio: core ceiling 1.0, pb 2.0 (cache ceiling :: pb = 2/8) */ + } else if ((2 * freq_ceiling) >= pb_freq) { + ceiling_ratio = FABRIC_CORE_CEILING_RATIO_RATIO_2_8; + } else { + printk(BIOS_ERR, "Unsupported core ceiling/PB frequency ratio = (%d/%d)\n", + freq_ceiling, pb_freq); + return false; + } + + cfg->core_floor_ratio = floor_ratio; + cfg->core_ceiling_ratio = ceiling_ratio; + return true; +} + +static void config_guardband_epsilon(uint8_t gb_percentage, uint32_t *target_value) +{ + uint32_t delta = (*target_value * gb_percentage) / 100; + delta += ((*target_value * gb_percentage) % 100) ? 1 : 0; + + /* Clamp to maximum value if necessary */ + if (delta > (EPSILON_MAX_VALUE - *target_value)) { + printk(BIOS_DEBUG, "Guardband application generated out-of-range target value," + " clamping to maximum value!\n"); + *target_value = EPSILON_MAX_VALUE; + } else { + *target_value += delta; + } +} + +static void dump_epsilons(struct powerbus_cfg *cfg) +{ + uint32_t i; + + for (i = 0; i < NUM_EPSILON_READ_TIERS; i++) + printk(BIOS_DEBUG, " R_T[%d] = %d\n", i, cfg->eps_r[i]); + + for (i = 0; i < NUM_EPSILON_WRITE_TIERS; i++) + printk(BIOS_DEBUG, " W_T[%d] = %d\n", i, cfg->eps_w[i]); +} + +static void calculate_epsilons(struct powerbus_cfg *cfg) +{ + const enum FABRIC_CORE_FLOOR_RATIO floor_ratio = cfg->core_floor_ratio; + const enum FABRIC_CORE_CEILING_RATIO ceiling_ratio = cfg->core_ceiling_ratio; + const uint32_t pb_freq = cfg->fabric_freq; + const uint32_t freq_ceiling = cfg->freq_core_ceiling; + + uint32_t *eps_r = cfg->eps_r; + uint32_t *eps_w = cfg->eps_w; + + uint8_t eps_table_type = EPS_TYPE_LE; /* ATTR_PROC_EPS_TABLE_TYPE from talos.xml */ + + uint64_t scratch_reg6 = read_scom(MBOX_SCRATCH_REG1 + 5); + /* ATTR_PROC_FABRIC_PUMP_MODE, it's either node or group pump mode */ + bool node_pump_mode = !(scratch_reg6 & MBOX_SCRATCH_REG6_GROUP_PUMP_MODE); + + switch (eps_table_type) { + case EPS_TYPE_HE: + if (node_pump_mode) { + eps_r[0] = EPSILON_R_T0_HE[floor_ratio]; + eps_r[1] = EPSILON_R_T1_HE[floor_ratio]; + eps_r[2] = EPSILON_R_T2_HE[floor_ratio]; + + eps_w[0] = EPSILON_W_T0_HE[floor_ratio]; + eps_w[1] = EPSILON_W_T1_HE[floor_ratio]; + } else { + eps_r[0] = EPSILON_R_T0_F4[floor_ratio]; + eps_r[1] = EPSILON_R_T1_F4[floor_ratio]; + eps_r[2] = EPSILON_R_T2_F4[floor_ratio]; + + eps_w[0] = EPSILON_W_T0_F4[floor_ratio]; + eps_w[1] = EPSILON_W_T1_F4[floor_ratio]; + } + + break; + case EPS_TYPE_HE_F8: + eps_r[0] = EPSILON_R_T0_F8[floor_ratio]; + + if (node_pump_mode) + eps_r[1] = EPSILON_R_T1_F8[floor_ratio]; + else + eps_r[1] = EPSILON_R_T0_F8[floor_ratio]; + + eps_r[2] = EPSILON_R_T2_F8[floor_ratio]; + + eps_w[0] = EPSILON_W_T0_F8[floor_ratio]; + eps_w[1] = EPSILON_W_T1_F8[floor_ratio]; + break; + case EPS_TYPE_LE: + eps_r[0] = EPSILON_R_T0_LE[floor_ratio]; + + if (node_pump_mode) + eps_r[1] = EPSILON_R_T1_LE[floor_ratio]; + else + eps_r[1] = EPSILON_R_T0_LE[floor_ratio]; + + eps_r[2] = EPSILON_R_T2_LE[floor_ratio]; + + eps_w[0] = EPSILON_W_T0_LE[floor_ratio]; + eps_w[1] = EPSILON_W_T1_LE[floor_ratio]; + break; + default: + printk(BIOS_WARNING, "Invalid epsilon table type 0x%.8X", eps_table_type); + break; + } + + /* Dump base epsilon values */ + printk(BIOS_DEBUG, "Base epsilon values read from table:\n"); + dump_epsilons(cfg); + + /* Scale base epsilon values if core is running 2x nest frequency */ + if (ceiling_ratio == FABRIC_CORE_CEILING_RATIO_RATIO_8_8) { + uint32_t i; + + uint8_t scale_percentage = 100 * freq_ceiling / (2 * pb_freq); + if (scale_percentage < 100) + die("scale_percentage is too small!"); + scale_percentage -= 100; + + printk(BIOS_DEBUG, "Scaling based on ceiling frequency\n"); + + /* scale/apply guardband read epsilons */ + for (i = 0; i < NUM_EPSILON_READ_TIERS; i++) + config_guardband_epsilon(scale_percentage, &eps_r[i]); + + /* Scale write epsilons */ + for (i = 0; i < NUM_EPSILON_WRITE_TIERS; i++) + config_guardband_epsilon(scale_percentage, &eps_w[i]); + } + + printk(BIOS_DEBUG, "Final epsilon values:\n"); + dump_epsilons(cfg); + + /* + * Check relationship of epsilon counters: + * read tier values are strictly increasing + * write tier values are strictly increasing + */ + if (eps_r[0] > eps_r[1] || eps_r[1] > eps_r[2] || eps_w[0] > eps_w[1]) + printk(BIOS_WARNING, "Invalid relationship between base epsilon values\n"); +} + +const struct powerbus_cfg *powerbus_cfg(void) +{ + static struct powerbus_cfg cfg; + + static bool init_done; + if (init_done) + return &cfg; + + if (!read_voltage_data(&cfg)) + die("Failed to read voltage data"); + + if (!calculate_frequencies(&cfg)) + die("Incorrect core or PowerBus frequency"); + + calculate_epsilons(&cfg); + + init_done = true; + return &cfg; +} From 66591128a2dd5cdcdb77107cacb0616a5f76fec2 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 5 Aug 2021 01:58:26 +0300 Subject: [PATCH 5/8] soc/power9/istep_13_8.c: use powerbus.c unit Change-Id: I0efe478537ec03afe71677e3d64d7468cd552162 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/istep_13_8.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/soc/ibm/power9/istep_13_8.c b/src/soc/ibm/power9/istep_13_8.c index cb47e6fc048..b1f9f29853f 100644 --- a/src/soc/ibm/power9/istep_13_8.c +++ b/src/soc/ibm/power9/istep_13_8.c @@ -1,13 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #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 @@ -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; @@ -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 @@ -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; From 32a46b205d56b67b1af51c4d1b5656c9cef949dc Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 5 Aug 2021 02:30:33 +0300 Subject: [PATCH 6/8] soc/power9/powerbus.c: assume EPS_TYPE_LE Change-Id: Ie9ba1aee13794218c8f71d52104cdcf9a4e7e365 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/powerbus.c | 85 ++++++----------------------------- 1 file changed, 13 insertions(+), 72 deletions(-) diff --git a/src/soc/ibm/power9/powerbus.c b/src/soc/ibm/power9/powerbus.c index 220f04ae210..891f23dd7af 100644 --- a/src/soc/ibm/power9/powerbus.c +++ b/src/soc/ibm/power9/powerbus.c @@ -28,27 +28,6 @@ static const uint32_t EPSILON_R_T2_LE[] = { 67, 69, 71, 74, 79, 103 } static const uint32_t EPSILON_W_T0_LE[] = { 0, 0, 0, 0, 0, 5 }; static const uint32_t EPSILON_W_T1_LE[] = { 15, 16, 17, 19, 21, 33 }; -/* HE epsilon (4 chips per-group) */ -static const uint32_t EPSILON_R_T0_HE[] = { 7, 7, 8, 8, 10, 22 }; -static const uint32_t EPSILON_R_T1_HE[] = { 92, 94, 96, 99, 104, 128 }; -static const uint32_t EPSILON_R_T2_HE[] = { 209, 210, 213, 216, 221, 245 }; -static const uint32_t EPSILON_W_T0_HE[] = { 28, 29, 30, 32, 34, 46 }; -static const uint32_t EPSILON_W_T1_HE[] = { 117, 118, 119, 121, 123, 135 }; - -/* HE epsilon (flat 4 Zeppelin) */ -static const uint32_t EPSILON_R_T0_F4[] = { 7, 7, 8, 8, 10, 22 }; -static const uint32_t EPSILON_R_T1_F4[] = { 7, 7, 8, 8, 10, 22 }; -static const uint32_t EPSILON_R_T2_F4[] = { 83, 84, 87, 90, 95, 119 }; -static const uint32_t EPSILON_W_T0_F4[] = { 0, 0, 0, 0, 0, 5 }; -static const uint32_t EPSILON_W_T1_F4[] = { 18, 19, 20, 22, 24, 36 }; - -/* HE epsilon (flat 8 configuration) */ -static const uint32_t EPSILON_R_T0_F8[] = { 7, 7, 8, 8, 10, 22 }; -static const uint32_t EPSILON_R_T1_F8[] = { 7, 7, 8, 8, 10, 22 }; -static const uint32_t EPSILON_R_T2_F8[] = { 148, 149, 152, 155, 160, 184 }; -static const uint32_t EPSILON_W_T0_F8[] = { 0, 0, 0, 0, 0, 5 }; -static const uint32_t EPSILON_W_T1_F8[] = { 76, 77, 78, 80, 82, 94 }; - /* See get_first_valid_pdV_pbFreq() in Hostboot */ static bool read_voltage_data(struct powerbus_cfg *cfg) @@ -204,61 +183,23 @@ static void calculate_epsilons(struct powerbus_cfg *cfg) uint32_t *eps_r = cfg->eps_r; uint32_t *eps_w = cfg->eps_w; - uint8_t eps_table_type = EPS_TYPE_LE; /* ATTR_PROC_EPS_TABLE_TYPE from talos.xml */ - uint64_t scratch_reg6 = read_scom(MBOX_SCRATCH_REG1 + 5); /* ATTR_PROC_FABRIC_PUMP_MODE, it's either node or group pump mode */ bool node_pump_mode = !(scratch_reg6 & MBOX_SCRATCH_REG6_GROUP_PUMP_MODE); - switch (eps_table_type) { - case EPS_TYPE_HE: - if (node_pump_mode) { - eps_r[0] = EPSILON_R_T0_HE[floor_ratio]; - eps_r[1] = EPSILON_R_T1_HE[floor_ratio]; - eps_r[2] = EPSILON_R_T2_HE[floor_ratio]; - - eps_w[0] = EPSILON_W_T0_HE[floor_ratio]; - eps_w[1] = EPSILON_W_T1_HE[floor_ratio]; - } else { - eps_r[0] = EPSILON_R_T0_F4[floor_ratio]; - eps_r[1] = EPSILON_R_T1_F4[floor_ratio]; - eps_r[2] = EPSILON_R_T2_F4[floor_ratio]; - - eps_w[0] = EPSILON_W_T0_F4[floor_ratio]; - eps_w[1] = EPSILON_W_T1_F4[floor_ratio]; - } - - break; - case EPS_TYPE_HE_F8: - eps_r[0] = EPSILON_R_T0_F8[floor_ratio]; - - if (node_pump_mode) - eps_r[1] = EPSILON_R_T1_F8[floor_ratio]; - else - eps_r[1] = EPSILON_R_T0_F8[floor_ratio]; - - eps_r[2] = EPSILON_R_T2_F8[floor_ratio]; - - eps_w[0] = EPSILON_W_T0_F8[floor_ratio]; - eps_w[1] = EPSILON_W_T1_F8[floor_ratio]; - break; - case EPS_TYPE_LE: - eps_r[0] = EPSILON_R_T0_LE[floor_ratio]; - - if (node_pump_mode) - eps_r[1] = EPSILON_R_T1_LE[floor_ratio]; - else - eps_r[1] = EPSILON_R_T0_LE[floor_ratio]; - - eps_r[2] = EPSILON_R_T2_LE[floor_ratio]; - - eps_w[0] = EPSILON_W_T0_LE[floor_ratio]; - eps_w[1] = EPSILON_W_T1_LE[floor_ratio]; - break; - default: - printk(BIOS_WARNING, "Invalid epsilon table type 0x%.8X", eps_table_type); - break; - } + /* Assuming that ATTR_PROC_EPS_TABLE_TYPE = EPS_TYPE_LE in talos.xml is always correct*/ + + eps_r[0] = EPSILON_R_T0_LE[floor_ratio]; + + if (node_pump_mode) + eps_r[1] = EPSILON_R_T1_LE[floor_ratio]; + else + eps_r[1] = EPSILON_R_T0_LE[floor_ratio]; + + eps_r[2] = EPSILON_R_T2_LE[floor_ratio]; + + eps_w[0] = EPSILON_W_T0_LE[floor_ratio]; + eps_w[1] = EPSILON_W_T1_LE[floor_ratio]; /* Dump base epsilon values */ printk(BIOS_DEBUG, "Base epsilon values read from table:\n"); From 5658eba347df23c1b70e4d02c52731f905e1e92a Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 12 Aug 2021 19:29:48 +0300 Subject: [PATCH 7/8] soc/power9/mvpd.c: add mvpd_get_voltage_data() Change-Id: Ie7550e4158a7483a938c6fbe90abae77361c723b Signed-off-by: Sergii Dmytruk --- src/include/cpu/power/mvpd.h | 3 +++ src/soc/ibm/power9/mvpd.c | 31 +++++++++++++++++++++++++++++++ src/soc/ibm/power9/powerbus.c | 20 +++----------------- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/include/cpu/power/mvpd.h b/src/include/cpu/power/mvpd.h index e27bf30b28a..cda62ff4a0a 100644 --- a/src/include/cpu/power/mvpd.h +++ b/src/include/cpu/power/mvpd.h @@ -54,6 +54,9 @@ 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, diff --git a/src/soc/ibm/power9/mvpd.c b/src/soc/ibm/power9/mvpd.c index a441f09e05b..2c172a27455 100644 --- a/src/soc/ibm/power9/mvpd.c +++ b/src/soc/ibm/power9/mvpd.c @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -164,6 +165,36 @@ bool mvpd_extract_keyword(const char *record_name, const char *kwd_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, diff --git a/src/soc/ibm/power9/powerbus.c b/src/soc/ibm/power9/powerbus.c index 891f23dd7af..cdce3c0ab9d 100644 --- a/src/soc/ibm/power9/powerbus.c +++ b/src/soc/ibm/power9/powerbus.c @@ -32,12 +32,8 @@ static const uint32_t EPSILON_W_T1_LE[] = { 15, 16, 17, 19, 21, 33 } static bool read_voltage_data(struct powerbus_cfg *cfg) { - uint8_t buf[512]; - uint32_t buf_size = sizeof(buf); - struct voltage_kwd *voltage = (void *)buf; - - bool success = false; int i = 0; + const struct voltage_kwd *voltage = NULL; /* ATTR_FREQ_PB_MHZ, equal to the first non-zero PowerBus frequency */ uint32_t pb_freq = 0; @@ -47,20 +43,10 @@ static bool read_voltage_data(struct powerbus_cfg *cfg) uint32_t freq_floor = 0; /* Using LRP0 because frequencies are the same in all LRP records */ - success = mvpd_extract_keyword("LRP0", "#V", buf, &buf_size); - if (!success) { - printk(BIOS_ERR, "Failed to read LRP0 record from MVPD\n"); - return false; - } - - 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 false; - } + voltage = mvpd_get_voltage_data(0); for (i = 0; i < VOLTAGE_BUCKET_COUNT; ++i) { - struct voltage_bucket_data *bucket = &voltage->buckets[i]; + const struct voltage_bucket_data *bucket = &voltage->buckets[i]; if (bucket->id == 0) continue; From 0b9b191ec2ef099f06892e6b70e975f623329f56 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 17 Aug 2021 00:05:26 +0300 Subject: [PATCH 8/8] Review corrections Change-Id: I223bbfcb9dbdd43eff0b022a3d7968de06052b52 Signed-off-by: Sergii Dmytruk --- src/soc/ibm/power9/Makefile.inc | 2 +- src/soc/ibm/power9/powerbus.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/soc/ibm/power9/Makefile.inc b/src/soc/ibm/power9/Makefile.inc index 41ba0308867..eb76fe4625e 100644 --- a/src/soc/ibm/power9/Makefile.inc +++ b/src/soc/ibm/power9/Makefile.inc @@ -33,6 +33,6 @@ ramstage-y += mvpd.c ramstage-y += vpd.c ramstage-y += tor.c ramstage-y += rs4.c -romstage-y += powerbus.c +ramstage-y += powerbus.c endif diff --git a/src/soc/ibm/power9/powerbus.c b/src/soc/ibm/power9/powerbus.c index cdce3c0ab9d..96a2cf23d1d 100644 --- a/src/soc/ibm/power9/powerbus.c +++ b/src/soc/ibm/power9/powerbus.c @@ -12,13 +12,7 @@ #define MBOX_SCRATCH_REG1 0x00050038 #define MBOX_SCRATCH_REG6_GROUP_PUMP_MODE (1 << 23) -/* - * EPS table type. - * From src/import/chips/p9/procedures/xml/attribute_info/nest_attributes.xml - */ -#define EPS_TYPE_LE 0x01 -#define EPS_TYPE_HE 0x02 -#define EPS_TYPE_HE_F8 0x03 +#define EPS_GUARDBAND 20 /* From src/import/chips/p9/procedures/hwp/nest/p9_fbc_eff_config.C */ /* LE epsilon (2 chips per-group) */ @@ -169,11 +163,13 @@ static void calculate_epsilons(struct powerbus_cfg *cfg) uint32_t *eps_r = cfg->eps_r; uint32_t *eps_w = cfg->eps_w; + uint32_t i; + uint64_t scratch_reg6 = read_scom(MBOX_SCRATCH_REG1 + 5); /* ATTR_PROC_FABRIC_PUMP_MODE, it's either node or group pump mode */ bool node_pump_mode = !(scratch_reg6 & MBOX_SCRATCH_REG6_GROUP_PUMP_MODE); - /* Assuming that ATTR_PROC_EPS_TABLE_TYPE = EPS_TYPE_LE in talos.xml is always correct*/ + /* Assuming that ATTR_PROC_EPS_TABLE_TYPE = EPS_TYPE_LE in talos.xml is always correct */ eps_r[0] = EPSILON_R_T0_LE[floor_ratio]; @@ -193,8 +189,6 @@ static void calculate_epsilons(struct powerbus_cfg *cfg) /* Scale base epsilon values if core is running 2x nest frequency */ if (ceiling_ratio == FABRIC_CORE_CEILING_RATIO_RATIO_8_8) { - uint32_t i; - uint8_t scale_percentage = 100 * freq_ceiling / (2 * pb_freq); if (scale_percentage < 100) die("scale_percentage is too small!"); @@ -202,16 +196,22 @@ static void calculate_epsilons(struct powerbus_cfg *cfg) printk(BIOS_DEBUG, "Scaling based on ceiling frequency\n"); - /* scale/apply guardband read epsilons */ for (i = 0; i < NUM_EPSILON_READ_TIERS; i++) config_guardband_epsilon(scale_percentage, &eps_r[i]); - /* Scale write epsilons */ for (i = 0; i < NUM_EPSILON_WRITE_TIERS; i++) config_guardband_epsilon(scale_percentage, &eps_w[i]); } - printk(BIOS_DEBUG, "Final epsilon values:\n"); + for (i = 0; i < NUM_EPSILON_READ_TIERS; i++) + config_guardband_epsilon(EPS_GUARDBAND, &eps_r[i]); + + for (i = 0; i < NUM_EPSILON_WRITE_TIERS; i++) + config_guardband_epsilon(EPS_GUARDBAND, &eps_w[i]); + + /* Dump final epsilon values */ + printk(BIOS_DEBUG, "Scaled epsilon values based on %s%d percent guardband:\n", + (EPS_GUARDBAND >= 0 ? "+" : "-"), EPS_GUARDBAND); dump_epsilons(cfg); /*