Message ID | 20200924044236.130586-5-amitay@ozlabs.org |
---|---|
State | Superseded |
Headers | show |
Series | Add p10 support to libpdbg | expand |
On Thu, 24 Sep 2020 at 04:43, Amitay Isaacs <amitay@ozlabs.org> wrote: > +++ b/libpdbg/p10_fapi_targets.c > +static uint64_t p10_eq_translate(struct eq *eq, uint64_t addr) > +{ > + addr = set_chiplet_id(addr, EQ0_CHIPLET_ID + pdbg_target_index(t(eq))); > + > + return addr; > +} > + > +struct eq p10_eq = { static? Can all of these definitions be const too? > + .target = { > + .name = "POWER10 eq", > + .compatible = "ibm,power10-eq", > + .class = "eq", > + .translate = translate_cast(p10_eq_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_eq); > + > +#define NUM_CORES_PER_EQ 4 > +static uint64_t p10_core_translate(struct core *c, uint64_t addr) > +{ > + int region = 0; > + int chip_unitnum = pdbg_target_index(t(c)); > + > + switch(chip_unitnum % NUM_CORES_PER_EQ) { > + case 0: > + region = 8; > + break; > + case 1: > + region = 4; > + break; > + case 2: > + region = 2; > + break; > + case 3: > + region = 1; > + break; > + } > + addr = set_chiplet_id(addr, EQ0_CHIPLET_ID + pdbg_target_index(t(c)) / 4); > + addr &= 0xFFFFFFFFFFFF0FFFULL; > + addr |= ((region & 0xF) << 12); > + > + return addr; > +} > + > +struct core p10_core = { static? > + .target = { > + .name = "POWER10 core", > + .compatible = "ibm,power10-core", > + .class = "core", > + .translate = translate_cast(p10_core_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_core); > + > +static uint64_t p10_pec_translate(struct pec *pec, uint64_t addr) > +{ > + int chip_unitnum = pdbg_target_index(t(pec)); > + > + if (get_chiplet_id(addr) >= N0_CHIPLET_ID && > + get_chiplet_id(addr) <= N1_CHIPLET_ID) > + return set_chiplet_id(addr, > + chip_unitnum ? N0_CHIPLET_ID : N1_CHIPLET_ID ); > + else > + return set_chiplet_id(addr, PCI0_CHIPLET_ID + pdbg_target_index(t(pec))); > +} > + > +struct pec p10_pec = { static? > + .target = { > + .name = "POWER10 pec", > + .compatible = "ibm,power10-pec", > + .class = "pec", > + .translate = translate_cast(p10_pec_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_pec); > + > +static uint64_t p10_phb_translate(struct phb *phb, uint64_t addr) > +{ > + int chip_unitnum = pdbg_target_index(t(phb)); > + > + if (get_chiplet_id(addr) >= N0_CHIPLET_ID && get_chiplet_id(addr) <= N1_CHIPLET_ID) { > + addr = set_chiplet_id(addr, chip_unitnum / 3 ? N0_CHIPLET_ID : N1_CHIPLET_ID); > + return set_sat_id(addr, 1 + chip_unitnum % 3); > + } else { > + addr = set_chiplet_id(addr, chip_unitnum / 3 + PCI0_CHIPLET_ID); > + if (get_ring_id(addr) == 2) { > + if (get_sat_id(addr) >= 1 && get_sat_id(addr) <= 3) > + return set_sat_id(addr, 1 + chip_unitnum % 3); > + else > + return set_sat_id(addr, 4 + chip_unitnum % 3); > + } > + } > + > + /* We'll never get here due to the assert but gcc complains */ Is this an old comment? > + return addr; > +} > + > +struct phb p10_phb = { > + .target = { > + .name = "POWER10 phb", > + .compatible = "ibm,power10-phb", > + .class = "phb", > + .translate = translate_cast(p10_phb_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_phb); > + > +static uint64_t p10_nmmu_translate(struct nmmu *nmmu, uint64_t addr) > +{ > + return set_chiplet_id(addr, pdbg_target_index(t(nmmu)) + N0_CHIPLET_ID); > +} > + > +struct nmmu p10_nmmu = { static? > + .target = { > + .name = "POWER10 nmmu", > + .compatible = "ibm,power10-nmmu", > + .class = "nmmu", > + .translate = translate_cast(p10_nmmu_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_nmmu); > + > +static uint64_t p10_iohs_translate(struct iohs *iohs, uint64_t addr) > +{ > + int chip_unitnum = pdbg_target_index(t(iohs)); > + > + if (get_chiplet_id(addr) >= AXON0_CHIPLET_ID && > + get_chiplet_id(addr) <= AXON7_CHIPLET_ID) > + addr = set_chiplet_id(addr, AXON0_CHIPLET_ID + chip_unitnum); > + else if (get_chiplet_id(addr) >= PAU0_CHIPLET_ID && > + get_chiplet_id(addr) <= PAU3_CHIPLET_ID) { > + addr = set_chiplet_id(addr, chip_unitnum/2 + PAU0_CHIPLET_ID); > + } else > + /* We should bail here with an assert but it makes testing hard and we > + * should never hit it anyway as all code will have been validated > + * through the EKB CI process (LOL). */ > + assert(1); > + > + if (get_chiplet_id(addr) >= PAU0_CHIPLET_ID && > + get_chiplet_id(addr) <= PAU3_CHIPLET_ID) { > + if (chip_unitnum % 2) > + addr = set_io_group_addr(addr, 0x1); > + else > + addr = set_io_group_addr(addr, 0x0); > + } > + > + return addr; > +} > + > +struct iohs p10_iohs = { static? > + .target = { > + .name = "POWER10 iohs", > + .compatible = "ibm,power10-iohs", > + .class = "iohs", > + .translate = translate_cast(p10_iohs_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_iohs); > + > +/* We take a struct pdbg_target and avoid the casting here as the translation is > + * the same for both target types. */ > +static uint64_t p10_mimc_translate(struct pdbg_target *mimc, uint64_t addr) > +{ > + return set_chiplet_id(addr, pdbg_target_index(mimc) + MC0_CHIPLET_ID); > +} > + > +struct mi p10_mi = { static? > + .target = { > + .name = "POWER10 mi", > + .compatible = "ibm,power10-mi", > + .class = "mi", > + .translate = p10_mimc_translate, > + }, > +}; > +DECLARE_HW_UNIT(p10_mi); > + > +struct mc p10_mc = { static? > + .target = { > + .name = "POWER10 mc", > + .compatible = "ibm,power10-mc", > + .class = "mc", > + .translate = p10_mimc_translate, > + }, > +}; > +DECLARE_HW_UNIT(p10_mc); > + > +static uint64_t p10_mcc_translate(struct mcc *mcc, uint64_t addr) > +{ > + int chip_unitnum = pdbg_target_index(t(mcc)); > + uint8_t offset = get_sat_offset(addr); > + > + addr = set_chiplet_id(addr, chip_unitnum/2 + MC0_CHIPLET_ID); > + if (chip_unitnum % 2) { > + switch (get_sat_id(addr)) { > + case 0x4: > + addr = set_sat_id(addr, 0x5); > + break; > + case 0x8: > + addr = set_sat_id(addr, 0x9); > + break; > + case 0x0: > + if (offset >= 0x22 && offset <= 0x2b) > + addr = set_sat_offset(addr, offset + 0x10); > + break; > + case 0xd: > + if (offset >= 0x00 && offset <= 0x1f) > + addr = set_sat_offset(addr, offset + 0x20); > + break; > + } > + } else { > + switch (get_sat_id(addr)) { > + case 0x5: > + addr = set_sat_id(addr, 0x4); > + break; > + case 0x9: > + addr = set_sat_id(addr, 0x8); > + break; > + case 0x0: > + if (offset >= 0x32 && offset <= 0x3b) > + addr = set_sat_offset(addr, offset - 0x10); > + break; > + case 0xd: > + if (offset >= 0x20 && offset <= 0x3f) > + addr = set_sat_offset(addr, offset - 0x20); > + break; > + } > + } > + > + return addr; > +} > + > +struct mcc p10_mcc = { static? > + .target = { > + .name = "POWER10 mcc", > + .compatible = "ibm,power10-mcc", > + .class = "mcc", > + .translate = translate_cast(p10_mcc_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_mcc); > + > +static uint64_t p10_omic_translate(struct omic *omic, uint64_t addr) > +{ > + int chip_unitnum = pdbg_target_index(t(omic)); > + int chiplet_id = get_chiplet_id(addr); > + > + if (chiplet_id >= PAU0_CHIPLET_ID && chiplet_id <= PAU3_CHIPLET_ID) { > + if (chip_unitnum == 0 || chip_unitnum == 1) > + addr = set_chiplet_id(addr, PAU0_CHIPLET_ID); > + else if (chip_unitnum == 2 || chip_unitnum == 3) > + addr = set_chiplet_id(addr, PAU2_CHIPLET_ID); > + else if (chip_unitnum == 4 || chip_unitnum == 5) > + addr = set_chiplet_id(addr, PAU1_CHIPLET_ID); > + else if (chip_unitnum == 6 || chip_unitnum == 7) > + addr = set_chiplet_id(addr, PAU3_CHIPLET_ID); > + else > + assert(0); > + > + if (chip_unitnum % 2) > + addr = set_io_group_addr(addr, 0x3); > + else > + addr = set_io_group_addr(addr, 0x2); > + } else { > + addr = set_chiplet_id(addr, chip_unitnum/2 + MC0_CHIPLET_ID); > + > + if (chip_unitnum % 2) > + addr = set_ring_id(addr, 0x6); > + else > + addr = set_ring_id(addr, 0x5); > + } > + > + return addr; > +} > + > +static struct omic p10_omic = { > + .target = { > + .name = "POWER10 omic", > + .compatible = "ibm,power10-omic", > + .class = "omic", > + .translate = translate_cast(p10_omic_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_omic); > + > +static uint64_t p10_omi_translate(struct omi *omi, uint64_t addr) > +{ > + int chip_unitnum = pdbg_target_index(t(omi)); > + int chiplet_id = get_chiplet_id(addr); > + > + if (chiplet_id >= PAU0_CHIPLET_ID && chiplet_id <= PAU3_CHIPLET_ID) { > + if (chip_unitnum >= 0 && chip_unitnum <= 3) > + addr = set_chiplet_id(addr, PAU0_CHIPLET_ID); > + else if (chip_unitnum >= 4 && chip_unitnum <= 7) > + addr = set_chiplet_id(addr, PAU2_CHIPLET_ID); > + else if (chip_unitnum >= 8 && chip_unitnum <= 11) > + addr = set_chiplet_id(addr, PAU1_CHIPLET_ID); > + else if (chip_unitnum >= 12 && chip_unitnum <= 15) > + addr = set_chiplet_id(addr, PAU3_CHIPLET_ID); > + else > + assert(0); > + > + if (chip_unitnum % 2) > + addr = set_io_lane(addr, 8 + get_io_lane(addr) % 8); > + else > + addr = set_io_lane(addr, get_io_lane(addr) % 8); > + > + if ((chip_unitnum / 2) % 2) > + addr = set_io_group_addr(addr, 0x3); > + else > + addr = set_io_group_addr(addr, 0x2); > + } else { > + addr = set_chiplet_id(addr, chip_unitnum/4 + MC0_CHIPLET_ID); > + > + if (get_sat_offset(addr) >= 16 && get_sat_offset(addr) <= 47) { > + if (chip_unitnum % 2) > + addr = set_sat_offset(addr, 32 + get_sat_offset(addr) % 16); > + else > + addr = set_sat_offset(addr, 16 + get_sat_offset(addr) % 16); > + } else { > + if (chip_unitnum % 2) > + addr = set_sat_offset(addr, 56 + get_sat_offset(addr) % 4); > + else > + addr = set_sat_offset(addr, 48 + get_sat_offset(addr) % 4); > + } > + > + if ((chip_unitnum / 2) %2) > + addr = set_ring_id(addr, 0x6); > + else > + addr = set_ring_id(addr, 0x5); > + } > + > + return addr; > +} > + > +static struct omi p10_omi = { > + .target = { > + .name = "POWER10 omi", > + .compatible = "ibm,power10-omi", > + .class = "omi", > + .translate = translate_cast(p10_omi_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_omi); > + > +static uint64_t p10_pauc_translate(struct pauc *pauc, uint64_t addr) > +{ > + return set_chiplet_id(addr, pdbg_target_index(t(pauc)) + PAU0_CHIPLET_ID); > +} > + > +static struct pauc p10_pauc = { > + .target = { > + .name = "POWER10 pauc", > + .compatible = "ibm,power10-pauc", > + .class = "pauc", > + .translate = translate_cast(p10_pauc_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_pauc); > + > +static uint64_t p10_pau_translate(struct pau *pau, uint64_t addr) > +{ > + int chip_unitnum = pdbg_target_index(t(pau)); > + > + addr = set_chiplet_id(addr, chip_unitnum/2 + PAU0_CHIPLET_ID); > + > + switch (chip_unitnum) { > + case 0: > + case 3: > + case 4: > + case 6: > + if (get_ring_id(addr) == 0x4) > + addr = set_ring_id(addr, 0x2); > + else if (get_ring_id(addr) == 0x5) > + addr = set_ring_id(addr, 0x3); > + break; > + > + case 1: > + case 2: > + case 5: > + case 7: > + if (get_ring_id(addr) == 0x2) > + addr = set_ring_id(addr, 0x4); > + else if (get_ring_id(addr) == 0x3) > + addr = set_ring_id(addr, 0x5); > + break; > + } > + > + return addr; > +} > + > +struct pau p10_pau = { static? > + .target = { > + .name = "POWER10 pau", > + .compatible = "ibm,power10-pau", > + .class = "pau", > + .translate = translate_cast(p10_pau_translate), > + }, > +}; > +DECLARE_HW_UNIT(p10_pau); > + > +#define HEADER_CHECK_DATA ((uint64_t) 0xc0ffee03 << 32) > + > +static int p10_chiplet_getring(struct chiplet *chiplet, uint64_t ring_addr, int64_t ring_len, uint32_t result[]) > +{ > + uint64_t scan_type_addr; > + uint64_t scan_data_addr; > + uint64_t scan_header_addr; > + uint64_t scan_type_data; > + uint64_t set_pulse = 1; > + uint64_t bits = 32; > + uint64_t data; > + > + /* We skip the first word in the results so we can write it later as it > + * should contain the header read out at the end */ > + int i = 0; I don't follow what this is on about. Also, i is not used before it's set to 1 below. > + > + scan_type_addr = (ring_addr & 0x7fff0000) | 0x7; > + scan_data_addr = (scan_type_addr & 0xffff0000) | 0x8000; > + scan_header_addr = scan_data_addr & 0xffffe000; > + > + scan_type_data = (ring_addr & 0xfff0) << 13; > + scan_type_data |= 0x800 >> (ring_addr & 0xf); > + scan_type_data <<= 32; > + > + pib_write(&chiplet->target, scan_type_addr, scan_type_data); > + pib_write(&chiplet->target, scan_header_addr, HEADER_CHECK_DATA); > + > + /* The final 32 bit read is the header which we do at the end */ > + ring_len -= 32; > + i = 1; > + > + while (ring_len > 0) { > + ring_len -= bits; > + if (set_pulse) { > + scan_data_addr |= 0x4000; > + set_pulse = 0; > + } else > + scan_data_addr &= ~0x4000ULL; > + > + scan_data_addr &= ~0xffull; > + scan_data_addr |= bits; > + pib_read(&chiplet->target, scan_data_addr, &data); > + > + /* Discard lower 32 bits */ > + /* TODO: We always read 64-bits from the ring on P9 so we could > + * optimise here by reading 64-bits at a time, but I'm not > + * confident I've figured that out and 32-bits is what Hostboot > + * does and seems to work. */ > + data >>= 32; > + > + /* Left-align data */ > + data <<= 32 - bits; > + result[i++] = data; > + if (ring_len > 0 && (ring_len < bits)) > + bits = ring_len; > + } > + > + pib_read(&chiplet->target, scan_header_addr | 0x20, &data); > + data &= 0xffffffff00000000; > + result[0] = data >> 32; > + if (data != HEADER_CHECK_DATA) > + printf("WARNING: Header check failed. Make sure you specified the right ring length!\n" > + "Ring data is probably corrupt now.\n"); > + > + return 0; > +} > + > +#define NET_CTRL0 0xf0040 > +#define NET_CTRL0_CHIPLET_ENABLE PPC_BIT(0) > +static int p10_chiplet_probe(struct pdbg_target *target) > +{ > + uint64_t value; > + > + if (pib_read(target, NET_CTRL0, &value)) > + return -1; > + > + if (!(value & NET_CTRL0_CHIPLET_ENABLE)) > + return -1; > + > + return 0; > +} > + > +static uint64_t p10_chiplet_translate(struct chiplet *chiplet, uint64_t addr) > +{ > + return set_chiplet_id(addr, pdbg_target_index(t(chiplet))); > +} > + > +static struct chiplet p10_chiplet = { > + .target = { > + .name = "POWER10 Chiplet", > + .compatible = "ibm,power10-chiplet", > + .class = "chiplet", > + .probe = p10_chiplet_probe, > + .translate = translate_cast(p10_chiplet_translate), > + }, > + .getring = p10_chiplet_getring, > +}; > +DECLARE_HW_UNIT(p10_chiplet); > + > +static int p10_thread_probe(struct pdbg_target *target) > +{ > + struct thread *thread = target_to_thread(target); > + > + thread->id = pdbg_target_index(target); > + > + return 0; > +} > + > +static struct thread p10_thread = { > + .target = { > + .name = "POWER10 Thread", > + .compatible = "ibm,power10-thread", > + .class = "thread", > + .probe = p10_thread_probe, > + }, > +}; > +DECLARE_HW_UNIT(p10_thread); > + > +static uint64_t no_translate(struct pdbg_target *target, uint64_t addr) > +{ > + /* No translation performed */ > + return 0; > +} > + > +static struct fc p10_fc = { > + .target = { > + .name = "POWER10 Fused Core", > + .compatible = "ibm,power10-fc", > + .class = "fc", > + .translate = no_translate, > + }, > +}; > +DECLARE_HW_UNIT(p10_fc); > + > +__attribute__((constructor)) > +static void register_p10_fapi_targets(void) > +{ > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_eq_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_core_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pec_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_phb_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_nmmu_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pau_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_iohs_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_mi_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_mc_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_mcc_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_omic_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_omi_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pauc_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pau_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_chiplet_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_thread_hw_unit); > + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_fc_hw_unit); > +} > diff --git a/libpdbg/p10_scom_addr.h b/libpdbg/p10_scom_addr.h > new file mode 100644 > index 0000000..f307e46 > --- /dev/null > +++ b/libpdbg/p10_scom_addr.h > @@ -0,0 +1,133 @@ > +/* Copyright 2018 IBM Corp. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > + * implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#ifndef LIBPDBG_SCOM_ADDR > +#define LIBPDBG_SCOM_ADDR > + > +/* Helpers and defines from the ekb. See p10_scom_addr.H */ > + > +/* P10 Chiplet ID enumeration */ > +enum { > + PIB_CHIPLET_ID = 0x00, ///< PIB chiplet (FSI) > + PERV_CHIPLET_ID = 0x01, ///< TP chiplet > + > + N0_CHIPLET_ID = 0x02, ///< Nest0 (North) chiplet > + N1_CHIPLET_ID = 0x03, ///< Nest1 (South) chiplet > + > + PCI0_CHIPLET_ID = 0x08, ///< PCIe0 chiplet > + PCI1_CHIPLET_ID = 0x09, ///< PCIe1 chiplet > + > + MC0_CHIPLET_ID = 0x0C, ///< MC0 chiplet > + MC1_CHIPLET_ID = 0x0D, ///< MC1 chiplet > + MC2_CHIPLET_ID = 0x0E, ///< MC2 chiplet > + MC3_CHIPLET_ID = 0x0F, ///< MC3 chiplet > + > + PAU0_CHIPLET_ID = 0x10, ///< PAU0 chiplet > + PAU1_CHIPLET_ID = 0x11, ///< PAU1 chiplet > + PAU2_CHIPLET_ID = 0x12, ///< PAU2 chiplet > + PAU3_CHIPLET_ID = 0x13, ///< PAU3 chiplet > + > + AXON0_CHIPLET_ID = 0x18, ///< AXON0 chiplet (high speed io) > + AXON1_CHIPLET_ID = 0x19, ///< AXON1 chiplet (high speed io) > + AXON2_CHIPLET_ID = 0x1A, ///< AXON2 chiplet (high speed io) > + AXON3_CHIPLET_ID = 0x1B, ///< AXON3 chiplet (high speed io) > + AXON4_CHIPLET_ID = 0x1C, ///< AXON4 chiplet (high speed io) > + AXON5_CHIPLET_ID = 0x1D, ///< AXON5 chiplet (high speed io) > + AXON6_CHIPLET_ID = 0x1E, ///< AXON6 chiplet (high speed io) > + AXON7_CHIPLET_ID = 0x1F, ///< AXON7 chiplet (high speed io) > + > + EQ0_CHIPLET_ID = 0x20, ///< Quad0 chiplet (super chiplet) > + EQ1_CHIPLET_ID = 0x21, ///< Quad1 chiplet (super chiplet) > + EQ2_CHIPLET_ID = 0x22, ///< Quad2 chiplet (super chiplet) > + EQ3_CHIPLET_ID = 0x23, ///< Quad3 chiplet (super chiplet) > + EQ4_CHIPLET_ID = 0x24, ///< Quad4 chiplet (super chiplet) > + EQ5_CHIPLET_ID = 0x25, ///< Quad5 chiplet (super chiplet) > + EQ6_CHIPLET_ID = 0x26, ///< Quad6 chiplet (super chiplet) > + EQ7_CHIPLET_ID = 0x27, ///< Quad7 chiplet (super chiplet) > +}; > + > +/* Extract pervasive chiplet ID from SCOM address */ > +static uint8_t get_chiplet_id(uint64_t addr) > +{ > + return ((addr >> 24) & 0x3F); > +} > + > +/* Modify SCOM address to update pervasive chiplet ID */ > +static uint64_t set_chiplet_id(uint64_t addr, uint8_t chiplet_id) > +{ > + addr &= 0xFFFFFFFFC0FFFFFFULL; > + addr |= ((chiplet_id & 0x3F) << 24); > + return addr; > +} > + > +static uint8_t get_ring_id(uint64_t addr) > +{ > + return (addr >> 10) & 0xF; > +} > + > +static uint64_t set_ring_id(uint64_t addr, uint64_t ring) > +{ > + addr &= 0xFFFFFFFFFFFF03FFULL; > + addr |= ((ring & 0x3F) << 10); > + return addr; > +} > + > +static uint32_t get_io_lane(uint64_t addr) > +{ > + return (addr >> 32) & 0x1F; > +} > + > +static uint64_t set_io_lane(uint64_t addr, uint64_t lane) > +{ > + addr &= 0xFFFFFFE0FFFFFFFFULL; > + addr |= (lane & 0x1F) << 32; > + return addr; > +} > + > +static uint8_t get_sat_id(uint64_t addr) > +{ > + return ((addr >> 6) & 0xF); > +} > + > +/* Modify SCOM address to update satellite ID field */ > +static uint64_t set_sat_id(uint64_t addr, uint8_t sat_id) > +{ > + addr &= 0xFFFFFFFFFFFFFC3FULL; > + addr |= ((sat_id & 0xF) << 6); > + return addr; > +} > + > +static uint8_t get_sat_offset(uint64_t addr) > +{ > + return addr & 0x3F; > +} > + > +static uint64_t set_sat_offset(uint64_t addr, uint8_t sat_offset) > +{ > + addr &= 0xFFFFFFFFFFFFFFC0ULL; > + addr |= (sat_offset & 0x3F); > + return addr; > +} > + > +static uint64_t set_io_group_addr(uint64_t addr, uint64_t group_addr) > +{ > + addr &= 0xFFFFFC1FFFFFFFFFULL; > + addr |= (group_addr & 0x1F) << 37; > + > + return addr; > +} > + > +#endif > -- > 2.26.2 > > -- > Pdbg mailing list > Pdbg@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/pdbg
diff --git a/Makefile.am b/Makefile.am index d4f7dc1..779c52c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -180,6 +180,8 @@ libpdbg_la_SOURCES = \ libpdbg/p9chip.c \ libpdbg/p9_fapi_targets.c \ libpdbg/p9_scom_addr.h \ + libpdbg/p10_fapi_targets.c \ + libpdbg/p10_scom_addr.h \ libpdbg/sbefifo.c \ libpdbg/sprs.h \ libpdbg/target.c \ diff --git a/libpdbg/hwunit.h b/libpdbg/hwunit.h index ee825bb..52fdaf0 100644 --- a/libpdbg/hwunit.h +++ b/libpdbg/hwunit.h @@ -306,4 +306,18 @@ struct capp { }; #define target_to_capp(x) container_of(x, struct capp, target) +struct omi { + struct pdbg_target target; +}; +#define target_to_omi(x) container_of(x, struct omi, target) + +struct omic { + struct pdbg_target target; +}; +#define target_to_omic(x) container_of(x, struct omic, target) + +struct mcc { + struct pdbg_target target; +}; +#define target_to_mcc(x) container_of(x, struct mcc, target) #endif /* __HWUNIT_H */ diff --git a/libpdbg/p10_fapi_targets.c b/libpdbg/p10_fapi_targets.c new file mode 100644 index 0000000..76299f5 --- /dev/null +++ b/libpdbg/p10_fapi_targets.c @@ -0,0 +1,583 @@ +/* Copyright 2020 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <inttypes.h> + +#include "hwunit.h" +#include "bitutils.h" +#include "p10_scom_addr.h" + +#define t(x) (&(x)->target) + +static uint64_t p10_eq_translate(struct eq *eq, uint64_t addr) +{ + addr = set_chiplet_id(addr, EQ0_CHIPLET_ID + pdbg_target_index(t(eq))); + + return addr; +} + +struct eq p10_eq = { + .target = { + .name = "POWER10 eq", + .compatible = "ibm,power10-eq", + .class = "eq", + .translate = translate_cast(p10_eq_translate), + }, +}; +DECLARE_HW_UNIT(p10_eq); + +#define NUM_CORES_PER_EQ 4 +static uint64_t p10_core_translate(struct core *c, uint64_t addr) +{ + int region = 0; + int chip_unitnum = pdbg_target_index(t(c)); + + switch(chip_unitnum % NUM_CORES_PER_EQ) { + case 0: + region = 8; + break; + case 1: + region = 4; + break; + case 2: + region = 2; + break; + case 3: + region = 1; + break; + } + addr = set_chiplet_id(addr, EQ0_CHIPLET_ID + pdbg_target_index(t(c)) / 4); + addr &= 0xFFFFFFFFFFFF0FFFULL; + addr |= ((region & 0xF) << 12); + + return addr; +} + +struct core p10_core = { + .target = { + .name = "POWER10 core", + .compatible = "ibm,power10-core", + .class = "core", + .translate = translate_cast(p10_core_translate), + }, +}; +DECLARE_HW_UNIT(p10_core); + +static uint64_t p10_pec_translate(struct pec *pec, uint64_t addr) +{ + int chip_unitnum = pdbg_target_index(t(pec)); + + if (get_chiplet_id(addr) >= N0_CHIPLET_ID && + get_chiplet_id(addr) <= N1_CHIPLET_ID) + return set_chiplet_id(addr, + chip_unitnum ? N0_CHIPLET_ID : N1_CHIPLET_ID ); + else + return set_chiplet_id(addr, PCI0_CHIPLET_ID + pdbg_target_index(t(pec))); +} + +struct pec p10_pec = { + .target = { + .name = "POWER10 pec", + .compatible = "ibm,power10-pec", + .class = "pec", + .translate = translate_cast(p10_pec_translate), + }, +}; +DECLARE_HW_UNIT(p10_pec); + +static uint64_t p10_phb_translate(struct phb *phb, uint64_t addr) +{ + int chip_unitnum = pdbg_target_index(t(phb)); + + if (get_chiplet_id(addr) >= N0_CHIPLET_ID && get_chiplet_id(addr) <= N1_CHIPLET_ID) { + addr = set_chiplet_id(addr, chip_unitnum / 3 ? N0_CHIPLET_ID : N1_CHIPLET_ID); + return set_sat_id(addr, 1 + chip_unitnum % 3); + } else { + addr = set_chiplet_id(addr, chip_unitnum / 3 + PCI0_CHIPLET_ID); + if (get_ring_id(addr) == 2) { + if (get_sat_id(addr) >= 1 && get_sat_id(addr) <= 3) + return set_sat_id(addr, 1 + chip_unitnum % 3); + else + return set_sat_id(addr, 4 + chip_unitnum % 3); + } + } + + /* We'll never get here due to the assert but gcc complains */ + return addr; +} + +struct phb p10_phb = { + .target = { + .name = "POWER10 phb", + .compatible = "ibm,power10-phb", + .class = "phb", + .translate = translate_cast(p10_phb_translate), + }, +}; +DECLARE_HW_UNIT(p10_phb); + +static uint64_t p10_nmmu_translate(struct nmmu *nmmu, uint64_t addr) +{ + return set_chiplet_id(addr, pdbg_target_index(t(nmmu)) + N0_CHIPLET_ID); +} + +struct nmmu p10_nmmu = { + .target = { + .name = "POWER10 nmmu", + .compatible = "ibm,power10-nmmu", + .class = "nmmu", + .translate = translate_cast(p10_nmmu_translate), + }, +}; +DECLARE_HW_UNIT(p10_nmmu); + +static uint64_t p10_iohs_translate(struct iohs *iohs, uint64_t addr) +{ + int chip_unitnum = pdbg_target_index(t(iohs)); + + if (get_chiplet_id(addr) >= AXON0_CHIPLET_ID && + get_chiplet_id(addr) <= AXON7_CHIPLET_ID) + addr = set_chiplet_id(addr, AXON0_CHIPLET_ID + chip_unitnum); + else if (get_chiplet_id(addr) >= PAU0_CHIPLET_ID && + get_chiplet_id(addr) <= PAU3_CHIPLET_ID) { + addr = set_chiplet_id(addr, chip_unitnum/2 + PAU0_CHIPLET_ID); + } else + /* We should bail here with an assert but it makes testing hard and we + * should never hit it anyway as all code will have been validated + * through the EKB CI process (LOL). */ + assert(1); + + if (get_chiplet_id(addr) >= PAU0_CHIPLET_ID && + get_chiplet_id(addr) <= PAU3_CHIPLET_ID) { + if (chip_unitnum % 2) + addr = set_io_group_addr(addr, 0x1); + else + addr = set_io_group_addr(addr, 0x0); + } + + return addr; +} + +struct iohs p10_iohs = { + .target = { + .name = "POWER10 iohs", + .compatible = "ibm,power10-iohs", + .class = "iohs", + .translate = translate_cast(p10_iohs_translate), + }, +}; +DECLARE_HW_UNIT(p10_iohs); + +/* We take a struct pdbg_target and avoid the casting here as the translation is + * the same for both target types. */ +static uint64_t p10_mimc_translate(struct pdbg_target *mimc, uint64_t addr) +{ + return set_chiplet_id(addr, pdbg_target_index(mimc) + MC0_CHIPLET_ID); +} + +struct mi p10_mi = { + .target = { + .name = "POWER10 mi", + .compatible = "ibm,power10-mi", + .class = "mi", + .translate = p10_mimc_translate, + }, +}; +DECLARE_HW_UNIT(p10_mi); + +struct mc p10_mc = { + .target = { + .name = "POWER10 mc", + .compatible = "ibm,power10-mc", + .class = "mc", + .translate = p10_mimc_translate, + }, +}; +DECLARE_HW_UNIT(p10_mc); + +static uint64_t p10_mcc_translate(struct mcc *mcc, uint64_t addr) +{ + int chip_unitnum = pdbg_target_index(t(mcc)); + uint8_t offset = get_sat_offset(addr); + + addr = set_chiplet_id(addr, chip_unitnum/2 + MC0_CHIPLET_ID); + if (chip_unitnum % 2) { + switch (get_sat_id(addr)) { + case 0x4: + addr = set_sat_id(addr, 0x5); + break; + case 0x8: + addr = set_sat_id(addr, 0x9); + break; + case 0x0: + if (offset >= 0x22 && offset <= 0x2b) + addr = set_sat_offset(addr, offset + 0x10); + break; + case 0xd: + if (offset >= 0x00 && offset <= 0x1f) + addr = set_sat_offset(addr, offset + 0x20); + break; + } + } else { + switch (get_sat_id(addr)) { + case 0x5: + addr = set_sat_id(addr, 0x4); + break; + case 0x9: + addr = set_sat_id(addr, 0x8); + break; + case 0x0: + if (offset >= 0x32 && offset <= 0x3b) + addr = set_sat_offset(addr, offset - 0x10); + break; + case 0xd: + if (offset >= 0x20 && offset <= 0x3f) + addr = set_sat_offset(addr, offset - 0x20); + break; + } + } + + return addr; +} + +struct mcc p10_mcc = { + .target = { + .name = "POWER10 mcc", + .compatible = "ibm,power10-mcc", + .class = "mcc", + .translate = translate_cast(p10_mcc_translate), + }, +}; +DECLARE_HW_UNIT(p10_mcc); + +static uint64_t p10_omic_translate(struct omic *omic, uint64_t addr) +{ + int chip_unitnum = pdbg_target_index(t(omic)); + int chiplet_id = get_chiplet_id(addr); + + if (chiplet_id >= PAU0_CHIPLET_ID && chiplet_id <= PAU3_CHIPLET_ID) { + if (chip_unitnum == 0 || chip_unitnum == 1) + addr = set_chiplet_id(addr, PAU0_CHIPLET_ID); + else if (chip_unitnum == 2 || chip_unitnum == 3) + addr = set_chiplet_id(addr, PAU2_CHIPLET_ID); + else if (chip_unitnum == 4 || chip_unitnum == 5) + addr = set_chiplet_id(addr, PAU1_CHIPLET_ID); + else if (chip_unitnum == 6 || chip_unitnum == 7) + addr = set_chiplet_id(addr, PAU3_CHIPLET_ID); + else + assert(0); + + if (chip_unitnum % 2) + addr = set_io_group_addr(addr, 0x3); + else + addr = set_io_group_addr(addr, 0x2); + } else { + addr = set_chiplet_id(addr, chip_unitnum/2 + MC0_CHIPLET_ID); + + if (chip_unitnum % 2) + addr = set_ring_id(addr, 0x6); + else + addr = set_ring_id(addr, 0x5); + } + + return addr; +} + +static struct omic p10_omic = { + .target = { + .name = "POWER10 omic", + .compatible = "ibm,power10-omic", + .class = "omic", + .translate = translate_cast(p10_omic_translate), + }, +}; +DECLARE_HW_UNIT(p10_omic); + +static uint64_t p10_omi_translate(struct omi *omi, uint64_t addr) +{ + int chip_unitnum = pdbg_target_index(t(omi)); + int chiplet_id = get_chiplet_id(addr); + + if (chiplet_id >= PAU0_CHIPLET_ID && chiplet_id <= PAU3_CHIPLET_ID) { + if (chip_unitnum >= 0 && chip_unitnum <= 3) + addr = set_chiplet_id(addr, PAU0_CHIPLET_ID); + else if (chip_unitnum >= 4 && chip_unitnum <= 7) + addr = set_chiplet_id(addr, PAU2_CHIPLET_ID); + else if (chip_unitnum >= 8 && chip_unitnum <= 11) + addr = set_chiplet_id(addr, PAU1_CHIPLET_ID); + else if (chip_unitnum >= 12 && chip_unitnum <= 15) + addr = set_chiplet_id(addr, PAU3_CHIPLET_ID); + else + assert(0); + + if (chip_unitnum % 2) + addr = set_io_lane(addr, 8 + get_io_lane(addr) % 8); + else + addr = set_io_lane(addr, get_io_lane(addr) % 8); + + if ((chip_unitnum / 2) % 2) + addr = set_io_group_addr(addr, 0x3); + else + addr = set_io_group_addr(addr, 0x2); + } else { + addr = set_chiplet_id(addr, chip_unitnum/4 + MC0_CHIPLET_ID); + + if (get_sat_offset(addr) >= 16 && get_sat_offset(addr) <= 47) { + if (chip_unitnum % 2) + addr = set_sat_offset(addr, 32 + get_sat_offset(addr) % 16); + else + addr = set_sat_offset(addr, 16 + get_sat_offset(addr) % 16); + } else { + if (chip_unitnum % 2) + addr = set_sat_offset(addr, 56 + get_sat_offset(addr) % 4); + else + addr = set_sat_offset(addr, 48 + get_sat_offset(addr) % 4); + } + + if ((chip_unitnum / 2) %2) + addr = set_ring_id(addr, 0x6); + else + addr = set_ring_id(addr, 0x5); + } + + return addr; +} + +static struct omi p10_omi = { + .target = { + .name = "POWER10 omi", + .compatible = "ibm,power10-omi", + .class = "omi", + .translate = translate_cast(p10_omi_translate), + }, +}; +DECLARE_HW_UNIT(p10_omi); + +static uint64_t p10_pauc_translate(struct pauc *pauc, uint64_t addr) +{ + return set_chiplet_id(addr, pdbg_target_index(t(pauc)) + PAU0_CHIPLET_ID); +} + +static struct pauc p10_pauc = { + .target = { + .name = "POWER10 pauc", + .compatible = "ibm,power10-pauc", + .class = "pauc", + .translate = translate_cast(p10_pauc_translate), + }, +}; +DECLARE_HW_UNIT(p10_pauc); + +static uint64_t p10_pau_translate(struct pau *pau, uint64_t addr) +{ + int chip_unitnum = pdbg_target_index(t(pau)); + + addr = set_chiplet_id(addr, chip_unitnum/2 + PAU0_CHIPLET_ID); + + switch (chip_unitnum) { + case 0: + case 3: + case 4: + case 6: + if (get_ring_id(addr) == 0x4) + addr = set_ring_id(addr, 0x2); + else if (get_ring_id(addr) == 0x5) + addr = set_ring_id(addr, 0x3); + break; + + case 1: + case 2: + case 5: + case 7: + if (get_ring_id(addr) == 0x2) + addr = set_ring_id(addr, 0x4); + else if (get_ring_id(addr) == 0x3) + addr = set_ring_id(addr, 0x5); + break; + } + + return addr; +} + +struct pau p10_pau = { + .target = { + .name = "POWER10 pau", + .compatible = "ibm,power10-pau", + .class = "pau", + .translate = translate_cast(p10_pau_translate), + }, +}; +DECLARE_HW_UNIT(p10_pau); + +#define HEADER_CHECK_DATA ((uint64_t) 0xc0ffee03 << 32) + +static int p10_chiplet_getring(struct chiplet *chiplet, uint64_t ring_addr, int64_t ring_len, uint32_t result[]) +{ + uint64_t scan_type_addr; + uint64_t scan_data_addr; + uint64_t scan_header_addr; + uint64_t scan_type_data; + uint64_t set_pulse = 1; + uint64_t bits = 32; + uint64_t data; + + /* We skip the first word in the results so we can write it later as it + * should contain the header read out at the end */ + int i = 0; + + scan_type_addr = (ring_addr & 0x7fff0000) | 0x7; + scan_data_addr = (scan_type_addr & 0xffff0000) | 0x8000; + scan_header_addr = scan_data_addr & 0xffffe000; + + scan_type_data = (ring_addr & 0xfff0) << 13; + scan_type_data |= 0x800 >> (ring_addr & 0xf); + scan_type_data <<= 32; + + pib_write(&chiplet->target, scan_type_addr, scan_type_data); + pib_write(&chiplet->target, scan_header_addr, HEADER_CHECK_DATA); + + /* The final 32 bit read is the header which we do at the end */ + ring_len -= 32; + i = 1; + + while (ring_len > 0) { + ring_len -= bits; + if (set_pulse) { + scan_data_addr |= 0x4000; + set_pulse = 0; + } else + scan_data_addr &= ~0x4000ULL; + + scan_data_addr &= ~0xffull; + scan_data_addr |= bits; + pib_read(&chiplet->target, scan_data_addr, &data); + + /* Discard lower 32 bits */ + /* TODO: We always read 64-bits from the ring on P9 so we could + * optimise here by reading 64-bits at a time, but I'm not + * confident I've figured that out and 32-bits is what Hostboot + * does and seems to work. */ + data >>= 32; + + /* Left-align data */ + data <<= 32 - bits; + result[i++] = data; + if (ring_len > 0 && (ring_len < bits)) + bits = ring_len; + } + + pib_read(&chiplet->target, scan_header_addr | 0x20, &data); + data &= 0xffffffff00000000; + result[0] = data >> 32; + if (data != HEADER_CHECK_DATA) + printf("WARNING: Header check failed. Make sure you specified the right ring length!\n" + "Ring data is probably corrupt now.\n"); + + return 0; +} + +#define NET_CTRL0 0xf0040 +#define NET_CTRL0_CHIPLET_ENABLE PPC_BIT(0) +static int p10_chiplet_probe(struct pdbg_target *target) +{ + uint64_t value; + + if (pib_read(target, NET_CTRL0, &value)) + return -1; + + if (!(value & NET_CTRL0_CHIPLET_ENABLE)) + return -1; + + return 0; +} + +static uint64_t p10_chiplet_translate(struct chiplet *chiplet, uint64_t addr) +{ + return set_chiplet_id(addr, pdbg_target_index(t(chiplet))); +} + +static struct chiplet p10_chiplet = { + .target = { + .name = "POWER10 Chiplet", + .compatible = "ibm,power10-chiplet", + .class = "chiplet", + .probe = p10_chiplet_probe, + .translate = translate_cast(p10_chiplet_translate), + }, + .getring = p10_chiplet_getring, +}; +DECLARE_HW_UNIT(p10_chiplet); + +static int p10_thread_probe(struct pdbg_target *target) +{ + struct thread *thread = target_to_thread(target); + + thread->id = pdbg_target_index(target); + + return 0; +} + +static struct thread p10_thread = { + .target = { + .name = "POWER10 Thread", + .compatible = "ibm,power10-thread", + .class = "thread", + .probe = p10_thread_probe, + }, +}; +DECLARE_HW_UNIT(p10_thread); + +static uint64_t no_translate(struct pdbg_target *target, uint64_t addr) +{ + /* No translation performed */ + return 0; +} + +static struct fc p10_fc = { + .target = { + .name = "POWER10 Fused Core", + .compatible = "ibm,power10-fc", + .class = "fc", + .translate = no_translate, + }, +}; +DECLARE_HW_UNIT(p10_fc); + +__attribute__((constructor)) +static void register_p10_fapi_targets(void) +{ + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_eq_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_core_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pec_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_phb_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_nmmu_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pau_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_iohs_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_mi_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_mc_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_mcc_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_omic_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_omi_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pauc_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pau_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_chiplet_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_thread_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_fc_hw_unit); +} diff --git a/libpdbg/p10_scom_addr.h b/libpdbg/p10_scom_addr.h new file mode 100644 index 0000000..f307e46 --- /dev/null +++ b/libpdbg/p10_scom_addr.h @@ -0,0 +1,133 @@ +/* Copyright 2018 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBPDBG_SCOM_ADDR +#define LIBPDBG_SCOM_ADDR + +/* Helpers and defines from the ekb. See p10_scom_addr.H */ + +/* P10 Chiplet ID enumeration */ +enum { + PIB_CHIPLET_ID = 0x00, ///< PIB chiplet (FSI) + PERV_CHIPLET_ID = 0x01, ///< TP chiplet + + N0_CHIPLET_ID = 0x02, ///< Nest0 (North) chiplet + N1_CHIPLET_ID = 0x03, ///< Nest1 (South) chiplet + + PCI0_CHIPLET_ID = 0x08, ///< PCIe0 chiplet + PCI1_CHIPLET_ID = 0x09, ///< PCIe1 chiplet + + MC0_CHIPLET_ID = 0x0C, ///< MC0 chiplet + MC1_CHIPLET_ID = 0x0D, ///< MC1 chiplet + MC2_CHIPLET_ID = 0x0E, ///< MC2 chiplet + MC3_CHIPLET_ID = 0x0F, ///< MC3 chiplet + + PAU0_CHIPLET_ID = 0x10, ///< PAU0 chiplet + PAU1_CHIPLET_ID = 0x11, ///< PAU1 chiplet + PAU2_CHIPLET_ID = 0x12, ///< PAU2 chiplet + PAU3_CHIPLET_ID = 0x13, ///< PAU3 chiplet + + AXON0_CHIPLET_ID = 0x18, ///< AXON0 chiplet (high speed io) + AXON1_CHIPLET_ID = 0x19, ///< AXON1 chiplet (high speed io) + AXON2_CHIPLET_ID = 0x1A, ///< AXON2 chiplet (high speed io) + AXON3_CHIPLET_ID = 0x1B, ///< AXON3 chiplet (high speed io) + AXON4_CHIPLET_ID = 0x1C, ///< AXON4 chiplet (high speed io) + AXON5_CHIPLET_ID = 0x1D, ///< AXON5 chiplet (high speed io) + AXON6_CHIPLET_ID = 0x1E, ///< AXON6 chiplet (high speed io) + AXON7_CHIPLET_ID = 0x1F, ///< AXON7 chiplet (high speed io) + + EQ0_CHIPLET_ID = 0x20, ///< Quad0 chiplet (super chiplet) + EQ1_CHIPLET_ID = 0x21, ///< Quad1 chiplet (super chiplet) + EQ2_CHIPLET_ID = 0x22, ///< Quad2 chiplet (super chiplet) + EQ3_CHIPLET_ID = 0x23, ///< Quad3 chiplet (super chiplet) + EQ4_CHIPLET_ID = 0x24, ///< Quad4 chiplet (super chiplet) + EQ5_CHIPLET_ID = 0x25, ///< Quad5 chiplet (super chiplet) + EQ6_CHIPLET_ID = 0x26, ///< Quad6 chiplet (super chiplet) + EQ7_CHIPLET_ID = 0x27, ///< Quad7 chiplet (super chiplet) +}; + +/* Extract pervasive chiplet ID from SCOM address */ +static uint8_t get_chiplet_id(uint64_t addr) +{ + return ((addr >> 24) & 0x3F); +} + +/* Modify SCOM address to update pervasive chiplet ID */ +static uint64_t set_chiplet_id(uint64_t addr, uint8_t chiplet_id) +{ + addr &= 0xFFFFFFFFC0FFFFFFULL; + addr |= ((chiplet_id & 0x3F) << 24); + return addr; +} + +static uint8_t get_ring_id(uint64_t addr) +{ + return (addr >> 10) & 0xF; +} + +static uint64_t set_ring_id(uint64_t addr, uint64_t ring) +{ + addr &= 0xFFFFFFFFFFFF03FFULL; + addr |= ((ring & 0x3F) << 10); + return addr; +} + +static uint32_t get_io_lane(uint64_t addr) +{ + return (addr >> 32) & 0x1F; +} + +static uint64_t set_io_lane(uint64_t addr, uint64_t lane) +{ + addr &= 0xFFFFFFE0FFFFFFFFULL; + addr |= (lane & 0x1F) << 32; + return addr; +} + +static uint8_t get_sat_id(uint64_t addr) +{ + return ((addr >> 6) & 0xF); +} + +/* Modify SCOM address to update satellite ID field */ +static uint64_t set_sat_id(uint64_t addr, uint8_t sat_id) +{ + addr &= 0xFFFFFFFFFFFFFC3FULL; + addr |= ((sat_id & 0xF) << 6); + return addr; +} + +static uint8_t get_sat_offset(uint64_t addr) +{ + return addr & 0x3F; +} + +static uint64_t set_sat_offset(uint64_t addr, uint8_t sat_offset) +{ + addr &= 0xFFFFFFFFFFFFFFC0ULL; + addr |= (sat_offset & 0x3F); + return addr; +} + +static uint64_t set_io_group_addr(uint64_t addr, uint64_t group_addr) +{ + addr &= 0xFFFFFC1FFFFFFFFFULL; + addr |= (group_addr & 0x1F) << 37; + + return addr; +} + +#endif