OCCFLG are scratch registers that can be shared with OCC firmware. Log reads and writes to the registers as a reminder when we run into more OCC code.
Add RW, WO_CLEAR and WO_OR SCOM Type enums in pnv_occ.c Signed-off-by: Chalapathi V <[email protected]> Signed-off-by: Caleb Schlossin <[email protected]> --- hw/ppc/pnv_occ.c | 55 +++++++++++++++++++++++++++++++++++++--- include/hw/ppc/pnv_occ.h | 4 +++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c index 24b789c191..e605ae0fbc 100644 --- a/hw/ppc/pnv_occ.c +++ b/hw/ppc/pnv_occ.c @@ -195,6 +195,49 @@ static const TypeInfo pnv_occ_power8_type_info = { #define P9_OCB_OCI_OCCMISC_CLEAR 0x6081 #define P9_OCB_OCI_OCCMISC_OR 0x6082 +/* OCC scratch registers for flag setting */ +#define P9_OCCFLG0 0x60ac +#define P9_OCCFLG7_OR 0x60c3 + +enum ScomType { + SCOM_TYPE_RW = 0, + SCOM_TYPE_WO_CLEAR = 1, + SCOM_TYPE_WO_OR = 2, +}; + +static void rw_occ_flag_regs(PnvOCC *occ, uint32_t offset, bool read, + uint64_t *val) +{ + int flag_num; + int flag_type; + + /* + * Each OCCFLG register has SCOM0 - RW, SCOM1 - WO_CLEAR, SCOM2 - WO_OR + * hence devide by 3 to get flag index and mod 3 to get SCOM type. + */ + flag_num = (offset - P9_OCCFLG0) / 3; + flag_type = (offset - P9_OCCFLG0) % 3; + + if (read) { + if (flag_type) { + qemu_log_mask(LOG_GUEST_ERROR, "OCC: Write only register: Ox%" + PRIx32 "\n", offset); + return; + } + *val = occ->occflags[flag_num]; + } else { + switch (flag_type) { + case SCOM_TYPE_RW: + occ->occflags[flag_num] = *val; + break; + case SCOM_TYPE_WO_CLEAR: + occ->occflags[flag_num] &= ~(*val); + break; + case SCOM_TYPE_WO_OR: + occ->occflags[flag_num] |= *val; + } + } +} static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr, unsigned size) @@ -207,8 +250,11 @@ static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr, case P9_OCB_OCI_OCCMISC: val = occ->occmisc; break; + case P9_OCCFLG0 ... P9_OCCFLG7_OR: + rw_occ_flag_regs(occ, offset, 1, &val); + break; default: - qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" + qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register read: Ox%" HWADDR_PRIx "\n", addr >> 3); } return val; @@ -229,9 +275,12 @@ static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr, break; case P9_OCB_OCI_OCCMISC: pnv_occ_set_misc(occ, val); - break; + break; + case P9_OCCFLG0 ... P9_OCCFLG7_OR: + rw_occ_flag_regs(occ, offset, 0, &val); + break; default: - qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%" + qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register write: Ox%" HWADDR_PRIx "\n", addr >> 3); } } diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h index 013ea2e53e..8c9f1416eb 100644 --- a/include/hw/ppc/pnv_occ.h +++ b/include/hw/ppc/pnv_occ.h @@ -47,6 +47,10 @@ struct PnvOCC { /* OCC Misc interrupt */ uint64_t occmisc; + /* OCC Flags */ +#define NR_FLAG_REGS 8 + uint32_t occflags[NR_FLAG_REGS]; + qemu_irq psi_irq; /* OCCs operate on regions of HOMER memory */ -- 2.47.3
