Message ID | 20240716195633.12679-2-kowal@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | XIVE changes for Cache Watch, VSTs, STT and info pic | expand |
On 7/16/24 21:56, Michael Kowal wrote: > From: Frederic Barrat <fbarrat@linux.ibm.com> > > XIVE offers a 'cache watch facility', which allows software to read/update > a potentially cached table entry with no software lock. There's one such > facility in the Virtualization Controller (VC) to update the ESB and END > entries and one in the Presentation Controller (PC) to update the > NVP/NVG/NVC entries. > > Each facility has 4 cache watch engines to control the updates and > firmware can request an available engine by querying the hardware > 'watch_assign' register of the VC or PC. The engine is then reserved and > is released after the data is updated by reading the 'watch_spec' register > (which also allows to check for a conflict during the update). > If no engine is available, the special value 0xFF is returned and > firmware is expected to repeat the request until an engine becomes > available. > > Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> > Signed-off-by: Michael Kowal <kowal@linux.vnet.ibm.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Thanks, C. > --- > hw/intc/pnv_xive2_regs.h | 90 ++++++++++++++ > hw/intc/pnv_xive2.c | 251 +++++++++++++++++++++++++++++++++------ > 2 files changed, 305 insertions(+), 36 deletions(-) > > diff --git a/hw/intc/pnv_xive2_regs.h b/hw/intc/pnv_xive2_regs.h > index 7165dc8704..f8e4a677c6 100644 > --- a/hw/intc/pnv_xive2_regs.h > +++ b/hw/intc/pnv_xive2_regs.h > @@ -283,6 +283,15 @@ > #define VC_ENDC_SYNC_QUEUE_HARD PPC_BIT(6) > #define VC_QUEUE_COUNT 7 > > +/* ENDC cache watch assign */ > +#define X_VC_ENDC_WATCH_ASSIGN 0x186 > +#define VC_ENDC_WATCH_ASSIGN 0x430 > + > +/* ENDC configuration register */ > +#define X_VC_ENDC_CFG 0x188 > +#define VC_ENDC_CFG 0x440 > +#define VC_ENDC_CFG_CACHE_WATCH_ASSIGN PPC_BITMASK(32, 35) > + > /* ENDC cache watch specification 0 */ > #define X_VC_ENDC_WATCH0_SPEC 0x1A0 > #define VC_ENDC_WATCH0_SPEC 0x500 > @@ -302,6 +311,42 @@ > #define VC_ENDC_WATCH0_DATA2 0x530 > #define VC_ENDC_WATCH0_DATA3 0x538 > > +/* ENDC cache watch 1 */ > +#define X_VC_ENDC_WATCH1_SPEC 0x1A8 > +#define VC_ENDC_WATCH1_SPEC 0x540 > +#define X_VC_ENDC_WATCH1_DATA0 0x1AC > +#define X_VC_ENDC_WATCH1_DATA1 0x1AD > +#define X_VC_ENDC_WATCH1_DATA2 0x1AE > +#define X_VC_ENDC_WATCH1_DATA3 0x1AF > +#define VC_ENDC_WATCH1_DATA0 0x560 > +#define VC_ENDC_WATCH1_DATA1 0x568 > +#define VC_ENDC_WATCH1_DATA2 0x570 > +#define VC_ENDC_WATCH1_DATA3 0x578 > + > +/* ENDC cache watch 2 */ > +#define X_VC_ENDC_WATCH2_SPEC 0x1B0 > +#define VC_ENDC_WATCH2_SPEC 0x580 > +#define X_VC_ENDC_WATCH2_DATA0 0x1B4 > +#define X_VC_ENDC_WATCH2_DATA1 0x1B5 > +#define X_VC_ENDC_WATCH2_DATA2 0x1B6 > +#define X_VC_ENDC_WATCH2_DATA3 0x1B7 > +#define VC_ENDC_WATCH2_DATA0 0x5A0 > +#define VC_ENDC_WATCH2_DATA1 0x5A8 > +#define VC_ENDC_WATCH2_DATA2 0x5B0 > +#define VC_ENDC_WATCH2_DATA3 0x5B8 > + > +/* ENDC cache watch 3 */ > +#define X_VC_ENDC_WATCH3_SPEC 0x1B8 > +#define VC_ENDC_WATCH3_SPEC 0x5C0 > +#define X_VC_ENDC_WATCH3_DATA0 0x1BC > +#define X_VC_ENDC_WATCH3_DATA1 0x1BD > +#define X_VC_ENDC_WATCH3_DATA2 0x1BE > +#define X_VC_ENDC_WATCH3_DATA3 0x1BF > +#define VC_ENDC_WATCH3_DATA0 0x5E0 > +#define VC_ENDC_WATCH3_DATA1 0x5E8 > +#define VC_ENDC_WATCH3_DATA2 0x5F0 > +#define VC_ENDC_WATCH3_DATA3 0x5F8 > + > /* > * PC LSB1 > */ > @@ -358,6 +403,15 @@ > #define PC_NXC_FLUSH_POLL_BLOCK_ID_MASK PPC_BITMASK(36, 39) > #define PC_NXC_FLUSH_POLL_OFFSET_MASK PPC_BITMASK(40, 63) /* 24-bit */ > > +/* NxC Cache watch assign */ > +#define X_PC_NXC_WATCH_ASSIGN 0x286 > +#define PC_NXC_WATCH_ASSIGN 0x430 > + > +/* NxC Proc config */ > +#define X_PC_NXC_PROC_CONFIG 0x28A > +#define PC_NXC_PROC_CONFIG 0x450 > +#define PC_NXC_PROC_CONFIG_WATCH_ASSIGN PPC_BITMASK(0, 3) > + > /* NxC Cache Watch 0 Specification */ > #define X_PC_NXC_WATCH0_SPEC 0x2A0 > #define PC_NXC_WATCH0_SPEC 0x500 > @@ -381,6 +435,42 @@ > #define PC_NXC_WATCH0_DATA2 0x530 > #define PC_NXC_WATCH0_DATA3 0x538 > > +/* NxC Cache Watch 1 */ > +#define X_PC_NXC_WATCH1_SPEC 0x2A8 > +#define PC_NXC_WATCH1_SPEC 0x540 > +#define X_PC_NXC_WATCH1_DATA0 0x2AC > +#define X_PC_NXC_WATCH1_DATA1 0x2AD > +#define X_PC_NXC_WATCH1_DATA2 0x2AE > +#define X_PC_NXC_WATCH1_DATA3 0x2AF > +#define PC_NXC_WATCH1_DATA0 0x560 > +#define PC_NXC_WATCH1_DATA1 0x568 > +#define PC_NXC_WATCH1_DATA2 0x570 > +#define PC_NXC_WATCH1_DATA3 0x578 > + > +/* NxC Cache Watch 2 */ > +#define X_PC_NXC_WATCH2_SPEC 0x2B0 > +#define PC_NXC_WATCH2_SPEC 0x580 > +#define X_PC_NXC_WATCH2_DATA0 0x2B4 > +#define X_PC_NXC_WATCH2_DATA1 0x2B5 > +#define X_PC_NXC_WATCH2_DATA2 0x2B6 > +#define X_PC_NXC_WATCH2_DATA3 0x2B7 > +#define PC_NXC_WATCH2_DATA0 0x5A0 > +#define PC_NXC_WATCH2_DATA1 0x5A8 > +#define PC_NXC_WATCH2_DATA2 0x5B0 > +#define PC_NXC_WATCH2_DATA3 0x5B8 > + > +/* NxC Cache Watch 3 */ > +#define X_PC_NXC_WATCH3_SPEC 0x2B8 > +#define PC_NXC_WATCH3_SPEC 0x5C0 > +#define X_PC_NXC_WATCH3_DATA0 0x2BC > +#define X_PC_NXC_WATCH3_DATA1 0x2BD > +#define X_PC_NXC_WATCH3_DATA2 0x2BE > +#define X_PC_NXC_WATCH3_DATA3 0x2BF > +#define PC_NXC_WATCH3_DATA0 0x5E0 > +#define PC_NXC_WATCH3_DATA1 0x5E8 > +#define PC_NXC_WATCH3_DATA2 0x5F0 > +#define PC_NXC_WATCH3_DATA3 0x5F8 > + > /* > * TCTXT Registers > */ > diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c > index 2fb4fa29d4..af9ab68fc6 100644 > --- a/hw/intc/pnv_xive2.c > +++ b/hw/intc/pnv_xive2.c > @@ -329,40 +329,48 @@ static int pnv_xive2_write_end(Xive2Router *xrtr, uint8_t blk, uint32_t idx, > word_number); > } > > -static int pnv_xive2_end_update(PnvXive2 *xive) > +static int pnv_xive2_end_update(PnvXive2 *xive, uint8_t watch_engine) > { > - uint8_t blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, > - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); > - uint32_t idx = GETFIELD(VC_ENDC_WATCH_INDEX, > - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); > - int i; > + uint8_t blk; > + uint32_t idx; > + int i, spec_reg, data_reg; > uint64_t endc_watch[4]; > > + assert(watch_engine < ARRAY_SIZE(endc_watch)); > + > + spec_reg = (VC_ENDC_WATCH0_SPEC + watch_engine * 0x40) >> 3; > + data_reg = (VC_ENDC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; > + blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, xive->vc_regs[spec_reg]); > + idx = GETFIELD(VC_ENDC_WATCH_INDEX, xive->vc_regs[spec_reg]); > + > for (i = 0; i < ARRAY_SIZE(endc_watch); i++) { > - endc_watch[i] = > - cpu_to_be64(xive->vc_regs[(VC_ENDC_WATCH0_DATA0 >> 3) + i]); > + endc_watch[i] = cpu_to_be64(xive->vc_regs[data_reg + i]); > } > > return pnv_xive2_vst_write(xive, VST_END, blk, idx, endc_watch, > XIVE_VST_WORD_ALL); > } > > -static void pnv_xive2_end_cache_load(PnvXive2 *xive) > +static void pnv_xive2_end_cache_load(PnvXive2 *xive, uint8_t watch_engine) > { > - uint8_t blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, > - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); > - uint32_t idx = GETFIELD(VC_ENDC_WATCH_INDEX, > - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); > + uint8_t blk; > + uint32_t idx; > uint64_t endc_watch[4] = { 0 }; > - int i; > + int i, spec_reg, data_reg; > + > + assert(watch_engine < ARRAY_SIZE(endc_watch)); > + > + spec_reg = (VC_ENDC_WATCH0_SPEC + watch_engine * 0x40) >> 3; > + data_reg = (VC_ENDC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; > + blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, xive->vc_regs[spec_reg]); > + idx = GETFIELD(VC_ENDC_WATCH_INDEX, xive->vc_regs[spec_reg]); > > if (pnv_xive2_vst_read(xive, VST_END, blk, idx, endc_watch)) { > xive2_error(xive, "VST: no END entry %x/%x !?", blk, idx); > } > > for (i = 0; i < ARRAY_SIZE(endc_watch); i++) { > - xive->vc_regs[(VC_ENDC_WATCH0_DATA0 >> 3) + i] = > - be64_to_cpu(endc_watch[i]); > + xive->vc_regs[data_reg + i] = be64_to_cpu(endc_watch[i]); > } > } > > @@ -379,40 +387,48 @@ static int pnv_xive2_write_nvp(Xive2Router *xrtr, uint8_t blk, uint32_t idx, > word_number); > } > > -static int pnv_xive2_nvp_update(PnvXive2 *xive) > +static int pnv_xive2_nvp_update(PnvXive2 *xive, uint8_t watch_engine) > { > - uint8_t blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, > - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); > - uint32_t idx = GETFIELD(PC_NXC_WATCH_INDEX, > - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); > - int i; > + uint8_t blk; > + uint32_t idx; > + int i, spec_reg, data_reg; > uint64_t nxc_watch[4]; > > + assert(watch_engine < ARRAY_SIZE(nxc_watch)); > + > + spec_reg = (PC_NXC_WATCH0_SPEC + watch_engine * 0x40) >> 3; > + data_reg = (PC_NXC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; > + blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, xive->pc_regs[spec_reg]); > + idx = GETFIELD(PC_NXC_WATCH_INDEX, xive->pc_regs[spec_reg]); > + > for (i = 0; i < ARRAY_SIZE(nxc_watch); i++) { > - nxc_watch[i] = > - cpu_to_be64(xive->pc_regs[(PC_NXC_WATCH0_DATA0 >> 3) + i]); > + nxc_watch[i] = cpu_to_be64(xive->pc_regs[data_reg + i]); > } > > return pnv_xive2_vst_write(xive, VST_NVP, blk, idx, nxc_watch, > XIVE_VST_WORD_ALL); > } > > -static void pnv_xive2_nvp_cache_load(PnvXive2 *xive) > +static void pnv_xive2_nvp_cache_load(PnvXive2 *xive, uint8_t watch_engine) > { > - uint8_t blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, > - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); > - uint32_t idx = GETFIELD(PC_NXC_WATCH_INDEX, > - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); > + uint8_t blk; > + uint32_t idx; > uint64_t nxc_watch[4] = { 0 }; > - int i; > + int i, spec_reg, data_reg; > + > + assert(watch_engine < ARRAY_SIZE(nxc_watch)); > + > + spec_reg = (PC_NXC_WATCH0_SPEC + watch_engine * 0x40) >> 3; > + data_reg = (PC_NXC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; > + blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, xive->pc_regs[spec_reg]); > + idx = GETFIELD(PC_NXC_WATCH_INDEX, xive->pc_regs[spec_reg]); > > if (pnv_xive2_vst_read(xive, VST_NVP, blk, idx, nxc_watch)) { > xive2_error(xive, "VST: no NVP entry %x/%x !?", blk, idx); > } > > for (i = 0; i < ARRAY_SIZE(nxc_watch); i++) { > - xive->pc_regs[(PC_NXC_WATCH0_DATA0 >> 3) + i] = > - be64_to_cpu(nxc_watch[i]); > + xive->pc_regs[data_reg + i] = be64_to_cpu(nxc_watch[i]); > } > } > > @@ -964,12 +980,70 @@ static const MemoryRegionOps pnv_xive2_ic_cq_ops = { > }, > }; > > +static uint8_t pnv_xive2_cache_watch_assign(uint64_t engine_mask, > + uint64_t *state) > +{ > + uint8_t val = 0xFF; > + int i; > + > + for (i = 3; i >= 0; i--) { > + if (BIT(i) & engine_mask) { > + if (!(BIT(i) & *state)) { > + *state |= BIT(i); > + val = 3 - i; > + break; > + } > + } > + } > + return val; > +} > + > +static void pnv_xive2_cache_watch_release(uint64_t *state, uint8_t watch_engine) > +{ > + uint8_t engine_bit = 3 - watch_engine; > + > + if (*state & BIT(engine_bit)) { > + *state &= ~BIT(engine_bit); > + } > +} > + > +static uint8_t pnv_xive2_endc_cache_watch_assign(PnvXive2 *xive) > +{ > + uint64_t engine_mask = GETFIELD(VC_ENDC_CFG_CACHE_WATCH_ASSIGN, > + xive->vc_regs[VC_ENDC_CFG >> 3]); > + uint64_t state = xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3]; > + uint8_t val; > + > + /* > + * We keep track of which engines are currently busy in the > + * VC_ENDC_WATCH_ASSIGN register directly. When the firmware reads > + * the register, we don't return its value but the ID of an engine > + * it can use. > + * There are 4 engines. 0xFF means no engine is available. > + */ > + val = pnv_xive2_cache_watch_assign(engine_mask, &state); > + if (val != 0xFF) { > + xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3] = state; > + } > + return val; > +} > + > +static void pnv_xive2_endc_cache_watch_release(PnvXive2 *xive, > + uint8_t watch_engine) > +{ > + uint64_t state = xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3]; > + > + pnv_xive2_cache_watch_release(&state, watch_engine); > + xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3] = state; > +} > + > static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset, > unsigned size) > { > PnvXive2 *xive = PNV_XIVE2(opaque); > uint64_t val = 0; > uint32_t reg = offset >> 3; > + uint8_t watch_engine; > > switch (offset) { > /* > @@ -1000,24 +1074,44 @@ static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset, > val = xive->vc_regs[reg]; > break; > > + case VC_ENDC_WATCH_ASSIGN: > + val = pnv_xive2_endc_cache_watch_assign(xive); > + break; > + > + case VC_ENDC_CFG: > + val = xive->vc_regs[reg]; > + break; > + > /* > * END cache updates > */ > case VC_ENDC_WATCH0_SPEC: > + case VC_ENDC_WATCH1_SPEC: > + case VC_ENDC_WATCH2_SPEC: > + case VC_ENDC_WATCH3_SPEC: > + watch_engine = (offset - VC_ENDC_WATCH0_SPEC) >> 6; > xive->vc_regs[reg] &= ~(VC_ENDC_WATCH_FULL | VC_ENDC_WATCH_CONFLICT); > + pnv_xive2_endc_cache_watch_release(xive, watch_engine); > val = xive->vc_regs[reg]; > break; > > case VC_ENDC_WATCH0_DATA0: > + case VC_ENDC_WATCH1_DATA0: > + case VC_ENDC_WATCH2_DATA0: > + case VC_ENDC_WATCH3_DATA0: > /* > * Load DATA registers from cache with data requested by the > * SPEC register > */ > - pnv_xive2_end_cache_load(xive); > + watch_engine = (offset - VC_ENDC_WATCH0_DATA0) >> 6; > + pnv_xive2_end_cache_load(xive, watch_engine); > val = xive->vc_regs[reg]; > break; > > case VC_ENDC_WATCH0_DATA1 ... VC_ENDC_WATCH0_DATA3: > + case VC_ENDC_WATCH1_DATA1 ... VC_ENDC_WATCH1_DATA3: > + case VC_ENDC_WATCH2_DATA1 ... VC_ENDC_WATCH2_DATA3: > + case VC_ENDC_WATCH3_DATA1 ... VC_ENDC_WATCH3_DATA3: > val = xive->vc_regs[reg]; > break; > > @@ -1063,6 +1157,7 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset, > { > PnvXive2 *xive = PNV_XIVE2(opaque); > uint32_t reg = offset >> 3; > + uint8_t watch_engine; > > switch (offset) { > /* > @@ -1095,19 +1190,32 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset, > /* EAS update */ > break; > > + case VC_ENDC_CFG: > + break; > + > /* > * END cache updates > */ > case VC_ENDC_WATCH0_SPEC: > + case VC_ENDC_WATCH1_SPEC: > + case VC_ENDC_WATCH2_SPEC: > + case VC_ENDC_WATCH3_SPEC: > val &= ~VC_ENDC_WATCH_CONFLICT; /* HW will set this bit */ > break; > > case VC_ENDC_WATCH0_DATA1 ... VC_ENDC_WATCH0_DATA3: > + case VC_ENDC_WATCH1_DATA1 ... VC_ENDC_WATCH1_DATA3: > + case VC_ENDC_WATCH2_DATA1 ... VC_ENDC_WATCH2_DATA3: > + case VC_ENDC_WATCH3_DATA1 ... VC_ENDC_WATCH3_DATA3: > break; > case VC_ENDC_WATCH0_DATA0: > + case VC_ENDC_WATCH1_DATA0: > + case VC_ENDC_WATCH2_DATA0: > + case VC_ENDC_WATCH3_DATA0: > /* writing to DATA0 triggers the cache write */ > + watch_engine = (offset - VC_ENDC_WATCH0_DATA0) >> 6; > xive->vc_regs[reg] = val; > - pnv_xive2_end_update(xive); > + pnv_xive2_end_update(xive, watch_engine); > break; > > > @@ -1157,12 +1265,43 @@ static const MemoryRegionOps pnv_xive2_ic_vc_ops = { > }, > }; > > +static uint8_t pnv_xive2_nxc_cache_watch_assign(PnvXive2 *xive) > +{ > + uint64_t engine_mask = GETFIELD(PC_NXC_PROC_CONFIG_WATCH_ASSIGN, > + xive->pc_regs[PC_NXC_PROC_CONFIG >> 3]); > + uint64_t state = xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3]; > + uint8_t val; > + > + /* > + * We keep track of which engines are currently busy in the > + * PC_NXC_WATCH_ASSIGN register directly. When the firmware reads > + * the register, we don't return its value but the ID of an engine > + * it can use. > + * There are 4 engines. 0xFF means no engine is available. > + */ > + val = pnv_xive2_cache_watch_assign(engine_mask, &state); > + if (val != 0xFF) { > + xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3] = state; > + } > + return val; > +} > + > +static void pnv_xive2_nxc_cache_watch_release(PnvXive2 *xive, > + uint8_t watch_engine) > +{ > + uint64_t state = xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3]; > + > + pnv_xive2_cache_watch_release(&state, watch_engine); > + xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3] = state; > +} > + > static uint64_t pnv_xive2_ic_pc_read(void *opaque, hwaddr offset, > unsigned size) > { > PnvXive2 *xive = PNV_XIVE2(opaque); > uint64_t val = -1; > uint32_t reg = offset >> 3; > + uint8_t watch_engine; > > switch (offset) { > /* > @@ -1173,24 +1312,44 @@ static uint64_t pnv_xive2_ic_pc_read(void *opaque, hwaddr offset, > val = xive->pc_regs[reg]; > break; > > + case PC_NXC_WATCH_ASSIGN: > + val = pnv_xive2_nxc_cache_watch_assign(xive); > + break; > + > + case PC_NXC_PROC_CONFIG: > + val = xive->pc_regs[reg]; > + break; > + > /* > * cache updates > */ > case PC_NXC_WATCH0_SPEC: > + case PC_NXC_WATCH1_SPEC: > + case PC_NXC_WATCH2_SPEC: > + case PC_NXC_WATCH3_SPEC: > + watch_engine = (offset - PC_NXC_WATCH0_SPEC) >> 6; > xive->pc_regs[reg] &= ~(PC_NXC_WATCH_FULL | PC_NXC_WATCH_CONFLICT); > + pnv_xive2_nxc_cache_watch_release(xive, watch_engine); > val = xive->pc_regs[reg]; > break; > > case PC_NXC_WATCH0_DATA0: > + case PC_NXC_WATCH1_DATA0: > + case PC_NXC_WATCH2_DATA0: > + case PC_NXC_WATCH3_DATA0: > /* > * Load DATA registers from cache with data requested by the > * SPEC register > */ > - pnv_xive2_nvp_cache_load(xive); > + watch_engine = (offset - PC_NXC_WATCH0_DATA0) >> 6; > + pnv_xive2_nvp_cache_load(xive, watch_engine); > val = xive->pc_regs[reg]; > break; > > case PC_NXC_WATCH0_DATA1 ... PC_NXC_WATCH0_DATA3: > + case PC_NXC_WATCH1_DATA1 ... PC_NXC_WATCH1_DATA3: > + case PC_NXC_WATCH2_DATA1 ... PC_NXC_WATCH2_DATA3: > + case PC_NXC_WATCH3_DATA1 ... PC_NXC_WATCH3_DATA3: > val = xive->pc_regs[reg]; > break; > > @@ -1219,6 +1378,7 @@ static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset, > { > PnvXive2 *xive = PNV_XIVE2(opaque); > uint32_t reg = offset >> 3; > + uint8_t watch_engine; > > switch (offset) { > > @@ -1231,19 +1391,32 @@ static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset, > case PC_VSD_TABLE_DATA: > break; > > + case PC_NXC_PROC_CONFIG: > + break; > + > /* > * cache updates > */ > case PC_NXC_WATCH0_SPEC: > + case PC_NXC_WATCH1_SPEC: > + case PC_NXC_WATCH2_SPEC: > + case PC_NXC_WATCH3_SPEC: > val &= ~PC_NXC_WATCH_CONFLICT; /* HW will set this bit */ > break; > > case PC_NXC_WATCH0_DATA1 ... PC_NXC_WATCH0_DATA3: > + case PC_NXC_WATCH1_DATA1 ... PC_NXC_WATCH1_DATA3: > + case PC_NXC_WATCH2_DATA1 ... PC_NXC_WATCH2_DATA3: > + case PC_NXC_WATCH3_DATA1 ... PC_NXC_WATCH3_DATA3: > break; > case PC_NXC_WATCH0_DATA0: > + case PC_NXC_WATCH1_DATA0: > + case PC_NXC_WATCH2_DATA0: > + case PC_NXC_WATCH3_DATA0: > /* writing to DATA0 triggers the cache write */ > + watch_engine = (offset - PC_NXC_WATCH0_DATA0) >> 6; > xive->pc_regs[reg] = val; > - pnv_xive2_nvp_update(xive); > + pnv_xive2_nvp_update(xive, watch_engine); > break; > > /* case PC_NXC_FLUSH_CTRL: */ > @@ -1814,6 +1987,12 @@ static void pnv_xive2_reset(void *dev) > xive->cq_regs[CQ_XIVE_CFG >> 3] |= > SETFIELD(CQ_XIVE_CFG_HYP_HARD_BLOCK_ID, 0ull, xive->chip->chip_id); > > + /* VC and PC cache watch assign mechanism */ > + xive->vc_regs[VC_ENDC_CFG >> 3] = > + SETFIELD(VC_ENDC_CFG_CACHE_WATCH_ASSIGN, 0ull, 0b0111); > + xive->pc_regs[PC_NXC_PROC_CONFIG >> 3] = > + SETFIELD(PC_NXC_PROC_CONFIG_WATCH_ASSIGN, 0ull, 0b0111); > + > /* Set default page size to 64k */ > xive->ic_shift = xive->esb_shift = xive->end_shift = 16; > xive->nvc_shift = xive->nvpg_shift = xive->tm_shift = 16;
diff --git a/hw/intc/pnv_xive2_regs.h b/hw/intc/pnv_xive2_regs.h index 7165dc8704..f8e4a677c6 100644 --- a/hw/intc/pnv_xive2_regs.h +++ b/hw/intc/pnv_xive2_regs.h @@ -283,6 +283,15 @@ #define VC_ENDC_SYNC_QUEUE_HARD PPC_BIT(6) #define VC_QUEUE_COUNT 7 +/* ENDC cache watch assign */ +#define X_VC_ENDC_WATCH_ASSIGN 0x186 +#define VC_ENDC_WATCH_ASSIGN 0x430 + +/* ENDC configuration register */ +#define X_VC_ENDC_CFG 0x188 +#define VC_ENDC_CFG 0x440 +#define VC_ENDC_CFG_CACHE_WATCH_ASSIGN PPC_BITMASK(32, 35) + /* ENDC cache watch specification 0 */ #define X_VC_ENDC_WATCH0_SPEC 0x1A0 #define VC_ENDC_WATCH0_SPEC 0x500 @@ -302,6 +311,42 @@ #define VC_ENDC_WATCH0_DATA2 0x530 #define VC_ENDC_WATCH0_DATA3 0x538 +/* ENDC cache watch 1 */ +#define X_VC_ENDC_WATCH1_SPEC 0x1A8 +#define VC_ENDC_WATCH1_SPEC 0x540 +#define X_VC_ENDC_WATCH1_DATA0 0x1AC +#define X_VC_ENDC_WATCH1_DATA1 0x1AD +#define X_VC_ENDC_WATCH1_DATA2 0x1AE +#define X_VC_ENDC_WATCH1_DATA3 0x1AF +#define VC_ENDC_WATCH1_DATA0 0x560 +#define VC_ENDC_WATCH1_DATA1 0x568 +#define VC_ENDC_WATCH1_DATA2 0x570 +#define VC_ENDC_WATCH1_DATA3 0x578 + +/* ENDC cache watch 2 */ +#define X_VC_ENDC_WATCH2_SPEC 0x1B0 +#define VC_ENDC_WATCH2_SPEC 0x580 +#define X_VC_ENDC_WATCH2_DATA0 0x1B4 +#define X_VC_ENDC_WATCH2_DATA1 0x1B5 +#define X_VC_ENDC_WATCH2_DATA2 0x1B6 +#define X_VC_ENDC_WATCH2_DATA3 0x1B7 +#define VC_ENDC_WATCH2_DATA0 0x5A0 +#define VC_ENDC_WATCH2_DATA1 0x5A8 +#define VC_ENDC_WATCH2_DATA2 0x5B0 +#define VC_ENDC_WATCH2_DATA3 0x5B8 + +/* ENDC cache watch 3 */ +#define X_VC_ENDC_WATCH3_SPEC 0x1B8 +#define VC_ENDC_WATCH3_SPEC 0x5C0 +#define X_VC_ENDC_WATCH3_DATA0 0x1BC +#define X_VC_ENDC_WATCH3_DATA1 0x1BD +#define X_VC_ENDC_WATCH3_DATA2 0x1BE +#define X_VC_ENDC_WATCH3_DATA3 0x1BF +#define VC_ENDC_WATCH3_DATA0 0x5E0 +#define VC_ENDC_WATCH3_DATA1 0x5E8 +#define VC_ENDC_WATCH3_DATA2 0x5F0 +#define VC_ENDC_WATCH3_DATA3 0x5F8 + /* * PC LSB1 */ @@ -358,6 +403,15 @@ #define PC_NXC_FLUSH_POLL_BLOCK_ID_MASK PPC_BITMASK(36, 39) #define PC_NXC_FLUSH_POLL_OFFSET_MASK PPC_BITMASK(40, 63) /* 24-bit */ +/* NxC Cache watch assign */ +#define X_PC_NXC_WATCH_ASSIGN 0x286 +#define PC_NXC_WATCH_ASSIGN 0x430 + +/* NxC Proc config */ +#define X_PC_NXC_PROC_CONFIG 0x28A +#define PC_NXC_PROC_CONFIG 0x450 +#define PC_NXC_PROC_CONFIG_WATCH_ASSIGN PPC_BITMASK(0, 3) + /* NxC Cache Watch 0 Specification */ #define X_PC_NXC_WATCH0_SPEC 0x2A0 #define PC_NXC_WATCH0_SPEC 0x500 @@ -381,6 +435,42 @@ #define PC_NXC_WATCH0_DATA2 0x530 #define PC_NXC_WATCH0_DATA3 0x538 +/* NxC Cache Watch 1 */ +#define X_PC_NXC_WATCH1_SPEC 0x2A8 +#define PC_NXC_WATCH1_SPEC 0x540 +#define X_PC_NXC_WATCH1_DATA0 0x2AC +#define X_PC_NXC_WATCH1_DATA1 0x2AD +#define X_PC_NXC_WATCH1_DATA2 0x2AE +#define X_PC_NXC_WATCH1_DATA3 0x2AF +#define PC_NXC_WATCH1_DATA0 0x560 +#define PC_NXC_WATCH1_DATA1 0x568 +#define PC_NXC_WATCH1_DATA2 0x570 +#define PC_NXC_WATCH1_DATA3 0x578 + +/* NxC Cache Watch 2 */ +#define X_PC_NXC_WATCH2_SPEC 0x2B0 +#define PC_NXC_WATCH2_SPEC 0x580 +#define X_PC_NXC_WATCH2_DATA0 0x2B4 +#define X_PC_NXC_WATCH2_DATA1 0x2B5 +#define X_PC_NXC_WATCH2_DATA2 0x2B6 +#define X_PC_NXC_WATCH2_DATA3 0x2B7 +#define PC_NXC_WATCH2_DATA0 0x5A0 +#define PC_NXC_WATCH2_DATA1 0x5A8 +#define PC_NXC_WATCH2_DATA2 0x5B0 +#define PC_NXC_WATCH2_DATA3 0x5B8 + +/* NxC Cache Watch 3 */ +#define X_PC_NXC_WATCH3_SPEC 0x2B8 +#define PC_NXC_WATCH3_SPEC 0x5C0 +#define X_PC_NXC_WATCH3_DATA0 0x2BC +#define X_PC_NXC_WATCH3_DATA1 0x2BD +#define X_PC_NXC_WATCH3_DATA2 0x2BE +#define X_PC_NXC_WATCH3_DATA3 0x2BF +#define PC_NXC_WATCH3_DATA0 0x5E0 +#define PC_NXC_WATCH3_DATA1 0x5E8 +#define PC_NXC_WATCH3_DATA2 0x5F0 +#define PC_NXC_WATCH3_DATA3 0x5F8 + /* * TCTXT Registers */ diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index 2fb4fa29d4..af9ab68fc6 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -329,40 +329,48 @@ static int pnv_xive2_write_end(Xive2Router *xrtr, uint8_t blk, uint32_t idx, word_number); } -static int pnv_xive2_end_update(PnvXive2 *xive) +static int pnv_xive2_end_update(PnvXive2 *xive, uint8_t watch_engine) { - uint8_t blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); - uint32_t idx = GETFIELD(VC_ENDC_WATCH_INDEX, - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); - int i; + uint8_t blk; + uint32_t idx; + int i, spec_reg, data_reg; uint64_t endc_watch[4]; + assert(watch_engine < ARRAY_SIZE(endc_watch)); + + spec_reg = (VC_ENDC_WATCH0_SPEC + watch_engine * 0x40) >> 3; + data_reg = (VC_ENDC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; + blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, xive->vc_regs[spec_reg]); + idx = GETFIELD(VC_ENDC_WATCH_INDEX, xive->vc_regs[spec_reg]); + for (i = 0; i < ARRAY_SIZE(endc_watch); i++) { - endc_watch[i] = - cpu_to_be64(xive->vc_regs[(VC_ENDC_WATCH0_DATA0 >> 3) + i]); + endc_watch[i] = cpu_to_be64(xive->vc_regs[data_reg + i]); } return pnv_xive2_vst_write(xive, VST_END, blk, idx, endc_watch, XIVE_VST_WORD_ALL); } -static void pnv_xive2_end_cache_load(PnvXive2 *xive) +static void pnv_xive2_end_cache_load(PnvXive2 *xive, uint8_t watch_engine) { - uint8_t blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); - uint32_t idx = GETFIELD(VC_ENDC_WATCH_INDEX, - xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]); + uint8_t blk; + uint32_t idx; uint64_t endc_watch[4] = { 0 }; - int i; + int i, spec_reg, data_reg; + + assert(watch_engine < ARRAY_SIZE(endc_watch)); + + spec_reg = (VC_ENDC_WATCH0_SPEC + watch_engine * 0x40) >> 3; + data_reg = (VC_ENDC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; + blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, xive->vc_regs[spec_reg]); + idx = GETFIELD(VC_ENDC_WATCH_INDEX, xive->vc_regs[spec_reg]); if (pnv_xive2_vst_read(xive, VST_END, blk, idx, endc_watch)) { xive2_error(xive, "VST: no END entry %x/%x !?", blk, idx); } for (i = 0; i < ARRAY_SIZE(endc_watch); i++) { - xive->vc_regs[(VC_ENDC_WATCH0_DATA0 >> 3) + i] = - be64_to_cpu(endc_watch[i]); + xive->vc_regs[data_reg + i] = be64_to_cpu(endc_watch[i]); } } @@ -379,40 +387,48 @@ static int pnv_xive2_write_nvp(Xive2Router *xrtr, uint8_t blk, uint32_t idx, word_number); } -static int pnv_xive2_nvp_update(PnvXive2 *xive) +static int pnv_xive2_nvp_update(PnvXive2 *xive, uint8_t watch_engine) { - uint8_t blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); - uint32_t idx = GETFIELD(PC_NXC_WATCH_INDEX, - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); - int i; + uint8_t blk; + uint32_t idx; + int i, spec_reg, data_reg; uint64_t nxc_watch[4]; + assert(watch_engine < ARRAY_SIZE(nxc_watch)); + + spec_reg = (PC_NXC_WATCH0_SPEC + watch_engine * 0x40) >> 3; + data_reg = (PC_NXC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; + blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, xive->pc_regs[spec_reg]); + idx = GETFIELD(PC_NXC_WATCH_INDEX, xive->pc_regs[spec_reg]); + for (i = 0; i < ARRAY_SIZE(nxc_watch); i++) { - nxc_watch[i] = - cpu_to_be64(xive->pc_regs[(PC_NXC_WATCH0_DATA0 >> 3) + i]); + nxc_watch[i] = cpu_to_be64(xive->pc_regs[data_reg + i]); } return pnv_xive2_vst_write(xive, VST_NVP, blk, idx, nxc_watch, XIVE_VST_WORD_ALL); } -static void pnv_xive2_nvp_cache_load(PnvXive2 *xive) +static void pnv_xive2_nvp_cache_load(PnvXive2 *xive, uint8_t watch_engine) { - uint8_t blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); - uint32_t idx = GETFIELD(PC_NXC_WATCH_INDEX, - xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]); + uint8_t blk; + uint32_t idx; uint64_t nxc_watch[4] = { 0 }; - int i; + int i, spec_reg, data_reg; + + assert(watch_engine < ARRAY_SIZE(nxc_watch)); + + spec_reg = (PC_NXC_WATCH0_SPEC + watch_engine * 0x40) >> 3; + data_reg = (PC_NXC_WATCH0_DATA0 + watch_engine * 0x40) >> 3; + blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, xive->pc_regs[spec_reg]); + idx = GETFIELD(PC_NXC_WATCH_INDEX, xive->pc_regs[spec_reg]); if (pnv_xive2_vst_read(xive, VST_NVP, blk, idx, nxc_watch)) { xive2_error(xive, "VST: no NVP entry %x/%x !?", blk, idx); } for (i = 0; i < ARRAY_SIZE(nxc_watch); i++) { - xive->pc_regs[(PC_NXC_WATCH0_DATA0 >> 3) + i] = - be64_to_cpu(nxc_watch[i]); + xive->pc_regs[data_reg + i] = be64_to_cpu(nxc_watch[i]); } } @@ -964,12 +980,70 @@ static const MemoryRegionOps pnv_xive2_ic_cq_ops = { }, }; +static uint8_t pnv_xive2_cache_watch_assign(uint64_t engine_mask, + uint64_t *state) +{ + uint8_t val = 0xFF; + int i; + + for (i = 3; i >= 0; i--) { + if (BIT(i) & engine_mask) { + if (!(BIT(i) & *state)) { + *state |= BIT(i); + val = 3 - i; + break; + } + } + } + return val; +} + +static void pnv_xive2_cache_watch_release(uint64_t *state, uint8_t watch_engine) +{ + uint8_t engine_bit = 3 - watch_engine; + + if (*state & BIT(engine_bit)) { + *state &= ~BIT(engine_bit); + } +} + +static uint8_t pnv_xive2_endc_cache_watch_assign(PnvXive2 *xive) +{ + uint64_t engine_mask = GETFIELD(VC_ENDC_CFG_CACHE_WATCH_ASSIGN, + xive->vc_regs[VC_ENDC_CFG >> 3]); + uint64_t state = xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3]; + uint8_t val; + + /* + * We keep track of which engines are currently busy in the + * VC_ENDC_WATCH_ASSIGN register directly. When the firmware reads + * the register, we don't return its value but the ID of an engine + * it can use. + * There are 4 engines. 0xFF means no engine is available. + */ + val = pnv_xive2_cache_watch_assign(engine_mask, &state); + if (val != 0xFF) { + xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3] = state; + } + return val; +} + +static void pnv_xive2_endc_cache_watch_release(PnvXive2 *xive, + uint8_t watch_engine) +{ + uint64_t state = xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3]; + + pnv_xive2_cache_watch_release(&state, watch_engine); + xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3] = state; +} + static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset, unsigned size) { PnvXive2 *xive = PNV_XIVE2(opaque); uint64_t val = 0; uint32_t reg = offset >> 3; + uint8_t watch_engine; switch (offset) { /* @@ -1000,24 +1074,44 @@ static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset, val = xive->vc_regs[reg]; break; + case VC_ENDC_WATCH_ASSIGN: + val = pnv_xive2_endc_cache_watch_assign(xive); + break; + + case VC_ENDC_CFG: + val = xive->vc_regs[reg]; + break; + /* * END cache updates */ case VC_ENDC_WATCH0_SPEC: + case VC_ENDC_WATCH1_SPEC: + case VC_ENDC_WATCH2_SPEC: + case VC_ENDC_WATCH3_SPEC: + watch_engine = (offset - VC_ENDC_WATCH0_SPEC) >> 6; xive->vc_regs[reg] &= ~(VC_ENDC_WATCH_FULL | VC_ENDC_WATCH_CONFLICT); + pnv_xive2_endc_cache_watch_release(xive, watch_engine); val = xive->vc_regs[reg]; break; case VC_ENDC_WATCH0_DATA0: + case VC_ENDC_WATCH1_DATA0: + case VC_ENDC_WATCH2_DATA0: + case VC_ENDC_WATCH3_DATA0: /* * Load DATA registers from cache with data requested by the * SPEC register */ - pnv_xive2_end_cache_load(xive); + watch_engine = (offset - VC_ENDC_WATCH0_DATA0) >> 6; + pnv_xive2_end_cache_load(xive, watch_engine); val = xive->vc_regs[reg]; break; case VC_ENDC_WATCH0_DATA1 ... VC_ENDC_WATCH0_DATA3: + case VC_ENDC_WATCH1_DATA1 ... VC_ENDC_WATCH1_DATA3: + case VC_ENDC_WATCH2_DATA1 ... VC_ENDC_WATCH2_DATA3: + case VC_ENDC_WATCH3_DATA1 ... VC_ENDC_WATCH3_DATA3: val = xive->vc_regs[reg]; break; @@ -1063,6 +1157,7 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset, { PnvXive2 *xive = PNV_XIVE2(opaque); uint32_t reg = offset >> 3; + uint8_t watch_engine; switch (offset) { /* @@ -1095,19 +1190,32 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset, /* EAS update */ break; + case VC_ENDC_CFG: + break; + /* * END cache updates */ case VC_ENDC_WATCH0_SPEC: + case VC_ENDC_WATCH1_SPEC: + case VC_ENDC_WATCH2_SPEC: + case VC_ENDC_WATCH3_SPEC: val &= ~VC_ENDC_WATCH_CONFLICT; /* HW will set this bit */ break; case VC_ENDC_WATCH0_DATA1 ... VC_ENDC_WATCH0_DATA3: + case VC_ENDC_WATCH1_DATA1 ... VC_ENDC_WATCH1_DATA3: + case VC_ENDC_WATCH2_DATA1 ... VC_ENDC_WATCH2_DATA3: + case VC_ENDC_WATCH3_DATA1 ... VC_ENDC_WATCH3_DATA3: break; case VC_ENDC_WATCH0_DATA0: + case VC_ENDC_WATCH1_DATA0: + case VC_ENDC_WATCH2_DATA0: + case VC_ENDC_WATCH3_DATA0: /* writing to DATA0 triggers the cache write */ + watch_engine = (offset - VC_ENDC_WATCH0_DATA0) >> 6; xive->vc_regs[reg] = val; - pnv_xive2_end_update(xive); + pnv_xive2_end_update(xive, watch_engine); break; @@ -1157,12 +1265,43 @@ static const MemoryRegionOps pnv_xive2_ic_vc_ops = { }, }; +static uint8_t pnv_xive2_nxc_cache_watch_assign(PnvXive2 *xive) +{ + uint64_t engine_mask = GETFIELD(PC_NXC_PROC_CONFIG_WATCH_ASSIGN, + xive->pc_regs[PC_NXC_PROC_CONFIG >> 3]); + uint64_t state = xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3]; + uint8_t val; + + /* + * We keep track of which engines are currently busy in the + * PC_NXC_WATCH_ASSIGN register directly. When the firmware reads + * the register, we don't return its value but the ID of an engine + * it can use. + * There are 4 engines. 0xFF means no engine is available. + */ + val = pnv_xive2_cache_watch_assign(engine_mask, &state); + if (val != 0xFF) { + xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3] = state; + } + return val; +} + +static void pnv_xive2_nxc_cache_watch_release(PnvXive2 *xive, + uint8_t watch_engine) +{ + uint64_t state = xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3]; + + pnv_xive2_cache_watch_release(&state, watch_engine); + xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3] = state; +} + static uint64_t pnv_xive2_ic_pc_read(void *opaque, hwaddr offset, unsigned size) { PnvXive2 *xive = PNV_XIVE2(opaque); uint64_t val = -1; uint32_t reg = offset >> 3; + uint8_t watch_engine; switch (offset) { /* @@ -1173,24 +1312,44 @@ static uint64_t pnv_xive2_ic_pc_read(void *opaque, hwaddr offset, val = xive->pc_regs[reg]; break; + case PC_NXC_WATCH_ASSIGN: + val = pnv_xive2_nxc_cache_watch_assign(xive); + break; + + case PC_NXC_PROC_CONFIG: + val = xive->pc_regs[reg]; + break; + /* * cache updates */ case PC_NXC_WATCH0_SPEC: + case PC_NXC_WATCH1_SPEC: + case PC_NXC_WATCH2_SPEC: + case PC_NXC_WATCH3_SPEC: + watch_engine = (offset - PC_NXC_WATCH0_SPEC) >> 6; xive->pc_regs[reg] &= ~(PC_NXC_WATCH_FULL | PC_NXC_WATCH_CONFLICT); + pnv_xive2_nxc_cache_watch_release(xive, watch_engine); val = xive->pc_regs[reg]; break; case PC_NXC_WATCH0_DATA0: + case PC_NXC_WATCH1_DATA0: + case PC_NXC_WATCH2_DATA0: + case PC_NXC_WATCH3_DATA0: /* * Load DATA registers from cache with data requested by the * SPEC register */ - pnv_xive2_nvp_cache_load(xive); + watch_engine = (offset - PC_NXC_WATCH0_DATA0) >> 6; + pnv_xive2_nvp_cache_load(xive, watch_engine); val = xive->pc_regs[reg]; break; case PC_NXC_WATCH0_DATA1 ... PC_NXC_WATCH0_DATA3: + case PC_NXC_WATCH1_DATA1 ... PC_NXC_WATCH1_DATA3: + case PC_NXC_WATCH2_DATA1 ... PC_NXC_WATCH2_DATA3: + case PC_NXC_WATCH3_DATA1 ... PC_NXC_WATCH3_DATA3: val = xive->pc_regs[reg]; break; @@ -1219,6 +1378,7 @@ static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset, { PnvXive2 *xive = PNV_XIVE2(opaque); uint32_t reg = offset >> 3; + uint8_t watch_engine; switch (offset) { @@ -1231,19 +1391,32 @@ static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset, case PC_VSD_TABLE_DATA: break; + case PC_NXC_PROC_CONFIG: + break; + /* * cache updates */ case PC_NXC_WATCH0_SPEC: + case PC_NXC_WATCH1_SPEC: + case PC_NXC_WATCH2_SPEC: + case PC_NXC_WATCH3_SPEC: val &= ~PC_NXC_WATCH_CONFLICT; /* HW will set this bit */ break; case PC_NXC_WATCH0_DATA1 ... PC_NXC_WATCH0_DATA3: + case PC_NXC_WATCH1_DATA1 ... PC_NXC_WATCH1_DATA3: + case PC_NXC_WATCH2_DATA1 ... PC_NXC_WATCH2_DATA3: + case PC_NXC_WATCH3_DATA1 ... PC_NXC_WATCH3_DATA3: break; case PC_NXC_WATCH0_DATA0: + case PC_NXC_WATCH1_DATA0: + case PC_NXC_WATCH2_DATA0: + case PC_NXC_WATCH3_DATA0: /* writing to DATA0 triggers the cache write */ + watch_engine = (offset - PC_NXC_WATCH0_DATA0) >> 6; xive->pc_regs[reg] = val; - pnv_xive2_nvp_update(xive); + pnv_xive2_nvp_update(xive, watch_engine); break; /* case PC_NXC_FLUSH_CTRL: */ @@ -1814,6 +1987,12 @@ static void pnv_xive2_reset(void *dev) xive->cq_regs[CQ_XIVE_CFG >> 3] |= SETFIELD(CQ_XIVE_CFG_HYP_HARD_BLOCK_ID, 0ull, xive->chip->chip_id); + /* VC and PC cache watch assign mechanism */ + xive->vc_regs[VC_ENDC_CFG >> 3] = + SETFIELD(VC_ENDC_CFG_CACHE_WATCH_ASSIGN, 0ull, 0b0111); + xive->pc_regs[PC_NXC_PROC_CONFIG >> 3] = + SETFIELD(PC_NXC_PROC_CONFIG_WATCH_ASSIGN, 0ull, 0b0111); + /* Set default page size to 64k */ xive->ic_shift = xive->esb_shift = xive->end_shift = 16; xive->nvc_shift = xive->nvpg_shift = xive->tm_shift = 16;