blob: 3b32446adba2160e4b05f02f98aec850f63c747b [file] [log] [blame]
/*
* QTest testcase for PowerNV 10 interrupt controller (xive2)
* - Test cache flush/queue sync injection
*
* Copyright (c) 2024, IBM Corporation.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "libqtest.h"
#include "pnv-xive2-common.h"
#include "hw/intc/pnv_xive2_regs.h"
#include "hw/ppc/xive_regs.h"
#include "hw/ppc/xive2_regs.h"
#define PNV_XIVE2_QUEUE_IPI 0x00
#define PNV_XIVE2_QUEUE_HW 0x01
#define PNV_XIVE2_QUEUE_NXC 0x02
#define PNV_XIVE2_QUEUE_INT 0x03
#define PNV_XIVE2_QUEUE_OS 0x04
#define PNV_XIVE2_QUEUE_POOL 0x05
#define PNV_XIVE2_QUEUE_HARD 0x06
#define PNV_XIVE2_CACHE_ENDC 0x08
#define PNV_XIVE2_CACHE_ESBC 0x09
#define PNV_XIVE2_CACHE_EASC 0x0a
#define PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO 0x10
#define PNV_XIVE2_QUEUE_NXC_LD_LCL_CO 0x11
#define PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI 0x12
#define PNV_XIVE2_QUEUE_NXC_ST_LCL_CI 0x13
#define PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI 0x14
#define PNV_XIVE2_QUEUE_NXC_ST_RMT_CI 0x15
#define PNV_XIVE2_CACHE_NXC 0x18
#define PNV_XIVE2_SYNC_IPI 0x000
#define PNV_XIVE2_SYNC_HW 0x080
#define PNV_XIVE2_SYNC_NxC 0x100
#define PNV_XIVE2_SYNC_INT 0x180
#define PNV_XIVE2_SYNC_OS_ESC 0x200
#define PNV_XIVE2_SYNC_POOL_ESC 0x280
#define PNV_XIVE2_SYNC_HARD_ESC 0x300
#define PNV_XIVE2_SYNC_NXC_LD_LCL_NCO 0x800
#define PNV_XIVE2_SYNC_NXC_LD_LCL_CO 0x880
#define PNV_XIVE2_SYNC_NXC_ST_LCL_NCI 0x900
#define PNV_XIVE2_SYNC_NXC_ST_LCL_CI 0x980
#define PNV_XIVE2_SYNC_NXC_ST_RMT_NCI 0xA00
#define PNV_XIVE2_SYNC_NXC_ST_RMT_CI 0xA80
static uint64_t get_sync_addr(uint32_t src_pir, int ic_topo_id, int type)
{
int thread_nr = src_pir & 0x7f;
uint64_t addr = XIVE_SYNC_MEM + thread_nr * 512 + ic_topo_id * 32 + type;
return addr;
}
static uint8_t get_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id,
int type)
{
uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type);
return qtest_readb(qts, addr);
}
static void clr_sync(QTestState *qts, uint32_t src_pir, int ic_topo_id,
int type)
{
uint64_t addr = get_sync_addr(src_pir, ic_topo_id, type);
qtest_writeb(qts, addr, 0x0);
}
static void inject_cache_flush(QTestState *qts, int ic_topo_id,
uint64_t scom_addr)
{
(void)ic_topo_id;
pnv_xive_xscom_write(qts, scom_addr, 0);
}
static void inject_queue_sync(QTestState *qts, int ic_topo_id, uint64_t offset)
{
(void)ic_topo_id;
uint64_t addr = XIVE_IC_ADDR + (VST_SYNC << XIVE_PAGE_SHIFT) + offset;
qtest_writeq(qts, addr, 0);
}
static void inject_op(QTestState *qts, int ic_topo_id, int type)
{
switch (type) {
case PNV_XIVE2_QUEUE_IPI:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_IPI);
break;
case PNV_XIVE2_QUEUE_HW:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HW);
break;
case PNV_XIVE2_QUEUE_NXC:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NxC);
break;
case PNV_XIVE2_QUEUE_INT:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_INT);
break;
case PNV_XIVE2_QUEUE_OS:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_OS_ESC);
break;
case PNV_XIVE2_QUEUE_POOL:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_POOL_ESC);
break;
case PNV_XIVE2_QUEUE_HARD:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_HARD_ESC);
break;
case PNV_XIVE2_CACHE_ENDC:
inject_cache_flush(qts, ic_topo_id, X_VC_ENDC_FLUSH_INJECT);
break;
case PNV_XIVE2_CACHE_ESBC:
inject_cache_flush(qts, ic_topo_id, X_VC_ESBC_FLUSH_INJECT);
break;
case PNV_XIVE2_CACHE_EASC:
inject_cache_flush(qts, ic_topo_id, X_VC_EASC_FLUSH_INJECT);
break;
case PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_NCO);
break;
case PNV_XIVE2_QUEUE_NXC_LD_LCL_CO:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_LD_LCL_CO);
break;
case PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_NCI);
break;
case PNV_XIVE2_QUEUE_NXC_ST_LCL_CI:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_LCL_CI);
break;
case PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_NCI);
break;
case PNV_XIVE2_QUEUE_NXC_ST_RMT_CI:
inject_queue_sync(qts, ic_topo_id, PNV_XIVE2_SYNC_NXC_ST_RMT_CI);
break;
case PNV_XIVE2_CACHE_NXC:
inject_cache_flush(qts, ic_topo_id, X_PC_NXC_FLUSH_INJECT);
break;
default:
g_assert_not_reached();
break;
}
}
const uint8_t xive_inject_tests[] = {
PNV_XIVE2_QUEUE_IPI,
PNV_XIVE2_QUEUE_HW,
PNV_XIVE2_QUEUE_NXC,
PNV_XIVE2_QUEUE_INT,
PNV_XIVE2_QUEUE_OS,
PNV_XIVE2_QUEUE_POOL,
PNV_XIVE2_QUEUE_HARD,
PNV_XIVE2_CACHE_ENDC,
PNV_XIVE2_CACHE_ESBC,
PNV_XIVE2_CACHE_EASC,
PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO,
PNV_XIVE2_QUEUE_NXC_LD_LCL_CO,
PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI,
PNV_XIVE2_QUEUE_NXC_ST_LCL_CI,
PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI,
PNV_XIVE2_QUEUE_NXC_ST_RMT_CI,
PNV_XIVE2_CACHE_NXC,
};
void test_flush_sync_inject(QTestState *qts)
{
int ic_topo_id = 0;
/*
* Writes performed by qtest are not done in the context of a thread.
* This means that QEMU XIVE code doesn't have a way to determine what
* thread is originating the write. In order to allow for some testing,
* QEMU XIVE code will assume a PIR of 0 when unable to determine the
* source thread for cache flush and queue sync inject operations.
* See hw/intc/pnv_xive2.c: pnv_xive2_inject_notify() for details.
*/
int src_pir = 0;
int test_nr;
uint8_t byte;
printf("# ============================================================\n");
printf("# Starting cache flush/queue sync injection tests...\n");
for (test_nr = 0; test_nr < sizeof(xive_inject_tests);
test_nr++) {
int op_type = xive_inject_tests[test_nr];
printf("# Running test %d\n", test_nr);
/* start with status byte set to 0 */
clr_sync(qts, src_pir, ic_topo_id, op_type);
byte = get_sync(qts, src_pir, ic_topo_id, op_type);
g_assert_cmphex(byte, ==, 0);
/* request cache flush or queue sync operation */
inject_op(qts, ic_topo_id, op_type);
/* verify that status byte was written to 0xff */
byte = get_sync(qts, src_pir, ic_topo_id, op_type);
g_assert_cmphex(byte, ==, 0xff);
clr_sync(qts, src_pir, ic_topo_id, op_type);
}
}