ppc/pnv: Fix TIMA indirect access

When the TIMA of a CPU needs to be accessed from the indirect page,
the thread id of the target CPU is first stored in the PC_TCTXT_INDIR0
register. This thread id is relative to the chip and not to the system.

Introduce a helper routine to look for a CPU of a given PIR and fix
pnv_xive_get_indirect_tctx() to scan only the threads of the local
chip and not the whole machine.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20191125065820.927-8-clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Cédric Le Goater 2019-11-25 07:58:07 +01:00 committed by David Gibson
parent 5014c60261
commit 119eaa9d11
3 changed files with 26 additions and 6 deletions

View File

@ -1400,12 +1400,13 @@ static const MemoryRegionOps pnv_xive_ic_lsi_ops = {
*/
/*
* When the TIMA is accessed from the indirect page, the thread id
* (PIR) has to be configured in the IC registers before. This is used
* for resets and for debug purpose also.
* When the TIMA is accessed from the indirect page, the thread id of
* the target CPU is configured in the PC_TCTXT_INDIR0 register before
* use. This is used for resets and for debug purpose also.
*/
static XiveTCTX *pnv_xive_get_indirect_tctx(PnvXive *xive)
{
PnvChip *chip = xive->chip;
uint64_t tctxt_indir = xive->regs[PC_TCTXT_INDIR0 >> 3];
PowerPCCPU *cpu = NULL;
int pir;
@ -1415,15 +1416,15 @@ static XiveTCTX *pnv_xive_get_indirect_tctx(PnvXive *xive)
return NULL;
}
pir = GETFIELD(PC_TCTXT_INDIR_THRDID, tctxt_indir) & 0xff;
cpu = ppc_get_vcpu_by_pir(pir);
pir = (chip->chip_id << 8) | GETFIELD(PC_TCTXT_INDIR_THRDID, tctxt_indir);
cpu = pnv_chip_find_cpu(chip, pir);
if (!cpu) {
xive_error(xive, "IC: invalid PIR %x for indirect access", pir);
return NULL;
}
/* Check that HW thread is XIVE enabled */
if (!(xive->regs[PC_THREAD_EN_REG0 >> 3] & PPC_BIT(pir & 0x3f))) {
if (!pnv_xive_is_cpu_enabled(xive, cpu)) {
xive_error(xive, "IC: CPU %x is not enabled", pir);
}

View File

@ -1371,6 +1371,23 @@ static void pnv_chip_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV Chip";
}
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir)
{
int i, j;
for (i = 0; i < chip->nr_cores; i++) {
PnvCore *pc = chip->cores[i];
CPUCore *cc = CPU_CORE(pc);
for (j = 0; j < cc->nr_threads; j++) {
if (ppc_cpu_pir(pc->threads[j]) == pir) {
return pc->threads[j];
}
}
}
return NULL;
}
static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
{
PnvMachineState *pnv = PNV_MACHINE(xi);

View File

@ -162,6 +162,8 @@ typedef struct PnvChipClass {
#define PNV_CHIP_INDEX(chip) \
(((chip)->chip_id >> 2) * 2 + ((chip)->chip_id & 0x3))
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv")
#define PNV_MACHINE(obj) \
OBJECT_CHECK(PnvMachineState, (obj), TYPE_PNV_MACHINE)