These XIVE tests include: - General interrupt IRQ tests that: - enable and trigger an interrupt - acknowledge the interrupt - end of interrupt processing - Test the Pull Thread Context to Odd Thread Reporting Line - Test the different cache flush inject and queue sync inject operations Co-authored-by: Frederic Barrat <fbarrat@linux.ibm.com> Co-authored-by: Glenn Miles <milesg@linux.ibm.com> Co-authored-by: Michael Kowal <kowal@linux.ibm.com> Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> Signed-off-by: Glenn Miles <milesg@linux.ibm.com> Signed-off-by: Michael Kowal <kowal@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
		
			
				
	
	
		
			191 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * QTest testcase for PowerNV 10 interrupt controller (xive2)
 | 
						|
 *  - Common functions for XIVE2 tests
 | 
						|
 *
 | 
						|
 * 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"
 | 
						|
 | 
						|
 | 
						|
static uint64_t pnv_xscom_addr(uint32_t pcba)
 | 
						|
{
 | 
						|
    return P10_XSCOM_BASE | ((uint64_t) pcba << 3);
 | 
						|
}
 | 
						|
 | 
						|
static uint64_t pnv_xive_xscom_addr(uint32_t reg)
 | 
						|
{
 | 
						|
    return pnv_xscom_addr(XIVE_XSCOM + reg);
 | 
						|
}
 | 
						|
 | 
						|
uint64_t pnv_xive_xscom_read(QTestState *qts, uint32_t reg)
 | 
						|
{
 | 
						|
    return qtest_readq(qts, pnv_xive_xscom_addr(reg));
 | 
						|
}
 | 
						|
 | 
						|
void pnv_xive_xscom_write(QTestState *qts, uint32_t reg, uint64_t val)
 | 
						|
{
 | 
						|
    qtest_writeq(qts, pnv_xive_xscom_addr(reg), val);
 | 
						|
}
 | 
						|
 | 
						|
static void xive_get_struct(QTestState *qts, uint64_t src, void *dest,
 | 
						|
                            size_t size)
 | 
						|
{
 | 
						|
    uint8_t *destination = (uint8_t *)dest;
 | 
						|
    size_t i;
 | 
						|
 | 
						|
    for (i = 0; i < size; i++) {
 | 
						|
        *(destination + i) = qtest_readb(qts, src + i);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void xive_copy_struct(QTestState *qts, void *src, uint64_t dest,
 | 
						|
                             size_t size)
 | 
						|
{
 | 
						|
    uint8_t *source = (uint8_t *)src;
 | 
						|
    size_t i;
 | 
						|
 | 
						|
    for (i = 0; i < size; i++) {
 | 
						|
        qtest_writeb(qts, dest + i, *(source + i));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
uint64_t xive_get_queue_addr(uint32_t end_index)
 | 
						|
{
 | 
						|
    return XIVE_QUEUE_MEM + (uint64_t)end_index * XIVE_QUEUE_SIZE;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t get_esb(QTestState *qts, uint32_t index, uint8_t page,
 | 
						|
                uint32_t offset)
 | 
						|
{
 | 
						|
    uint64_t addr;
 | 
						|
 | 
						|
    addr = XIVE_ESB_ADDR + ((uint64_t)index << (XIVE_PAGE_SHIFT + 1));
 | 
						|
    if (page == 1) {
 | 
						|
        addr += 1 << XIVE_PAGE_SHIFT;
 | 
						|
    }
 | 
						|
    return qtest_readb(qts, addr + offset);
 | 
						|
}
 | 
						|
 | 
						|
void set_esb(QTestState *qts, uint32_t index, uint8_t page,
 | 
						|
             uint32_t offset, uint32_t val)
 | 
						|
{
 | 
						|
    uint64_t addr;
 | 
						|
 | 
						|
    addr = XIVE_ESB_ADDR + ((uint64_t)index << (XIVE_PAGE_SHIFT + 1));
 | 
						|
    if (page == 1) {
 | 
						|
        addr += 1 << XIVE_PAGE_SHIFT;
 | 
						|
    }
 | 
						|
    return qtest_writel(qts, addr + offset, cpu_to_be32(val));
 | 
						|
}
 | 
						|
 | 
						|
void get_nvp(QTestState *qts, uint32_t index, Xive2Nvp* nvp)
 | 
						|
{
 | 
						|
    uint64_t addr = XIVE_NVP_MEM + (uint64_t)index * sizeof(Xive2Nvp);
 | 
						|
    xive_get_struct(qts, addr, nvp, sizeof(Xive2Nvp));
 | 
						|
}
 | 
						|
 | 
						|
void set_nvp(QTestState *qts, uint32_t index, uint8_t first)
 | 
						|
{
 | 
						|
    uint64_t nvp_addr;
 | 
						|
    Xive2Nvp nvp;
 | 
						|
    uint64_t report_addr;
 | 
						|
 | 
						|
    nvp_addr = XIVE_NVP_MEM + (uint64_t)index * sizeof(Xive2Nvp);
 | 
						|
    report_addr = (XIVE_REPORT_MEM + (uint64_t)index * XIVE_REPORT_SIZE) >> 8;
 | 
						|
 | 
						|
    memset(&nvp, 0, sizeof(nvp));
 | 
						|
    nvp.w0 = xive_set_field32(NVP2_W0_VALID, 0, 1);
 | 
						|
    nvp.w0 = xive_set_field32(NVP2_W0_PGOFIRST, nvp.w0, first);
 | 
						|
    nvp.w6 = xive_set_field32(NVP2_W6_REPORTING_LINE, nvp.w6,
 | 
						|
                              (report_addr >> 24) & 0xfffffff);
 | 
						|
    nvp.w7 = xive_set_field32(NVP2_W7_REPORTING_LINE, nvp.w7,
 | 
						|
                              report_addr & 0xffffff);
 | 
						|
    xive_copy_struct(qts, &nvp, nvp_addr, sizeof(nvp));
 | 
						|
}
 | 
						|
 | 
						|
static uint64_t get_cl_pair_addr(Xive2Nvp *nvp)
 | 
						|
{
 | 
						|
    uint64_t upper = xive_get_field32(0x0fffffff, nvp->w6);
 | 
						|
    uint64_t lower = xive_get_field32(0xffffff00, nvp->w7);
 | 
						|
    return (upper << 32) | (lower << 8);
 | 
						|
}
 | 
						|
 | 
						|
void get_cl_pair(QTestState *qts, Xive2Nvp *nvp, uint8_t *cl_pair)
 | 
						|
{
 | 
						|
    uint64_t addr = get_cl_pair_addr(nvp);
 | 
						|
    xive_get_struct(qts, addr, cl_pair, XIVE_REPORT_SIZE);
 | 
						|
}
 | 
						|
 | 
						|
void set_cl_pair(QTestState *qts, Xive2Nvp *nvp, uint8_t *cl_pair)
 | 
						|
{
 | 
						|
    uint64_t addr = get_cl_pair_addr(nvp);
 | 
						|
    xive_copy_struct(qts, cl_pair, addr, XIVE_REPORT_SIZE);
 | 
						|
}
 | 
						|
 | 
						|
void set_nvg(QTestState *qts, uint32_t index, uint8_t next)
 | 
						|
{
 | 
						|
    uint64_t nvg_addr;
 | 
						|
    Xive2Nvgc nvg;
 | 
						|
 | 
						|
    nvg_addr = XIVE_NVG_MEM + (uint64_t)index * sizeof(Xive2Nvgc);
 | 
						|
 | 
						|
    memset(&nvg, 0, sizeof(nvg));
 | 
						|
    nvg.w0 = xive_set_field32(NVGC2_W0_VALID, 0, 1);
 | 
						|
    nvg.w0 = xive_set_field32(NVGC2_W0_PGONEXT, nvg.w0, next);
 | 
						|
    xive_copy_struct(qts, &nvg, nvg_addr, sizeof(nvg));
 | 
						|
}
 | 
						|
 | 
						|
void set_eas(QTestState *qts, uint32_t index, uint32_t end_index,
 | 
						|
             uint32_t data)
 | 
						|
{
 | 
						|
    uint64_t eas_addr;
 | 
						|
    Xive2Eas eas;
 | 
						|
 | 
						|
    eas_addr = XIVE_EAS_MEM + (uint64_t)index * sizeof(Xive2Eas);
 | 
						|
 | 
						|
    memset(&eas, 0, sizeof(eas));
 | 
						|
    eas.w = xive_set_field64(EAS2_VALID, 0, 1);
 | 
						|
    eas.w = xive_set_field64(EAS2_END_INDEX, eas.w, end_index);
 | 
						|
    eas.w = xive_set_field64(EAS2_END_DATA, eas.w, data);
 | 
						|
    xive_copy_struct(qts, &eas, eas_addr, sizeof(eas));
 | 
						|
}
 | 
						|
 | 
						|
void set_end(QTestState *qts, uint32_t index, uint32_t nvp_index,
 | 
						|
             uint8_t priority, bool i)
 | 
						|
{
 | 
						|
    uint64_t end_addr, queue_addr, queue_hi, queue_lo;
 | 
						|
    uint8_t queue_size;
 | 
						|
    Xive2End end;
 | 
						|
 | 
						|
    end_addr = XIVE_END_MEM + (uint64_t)index * sizeof(Xive2End);
 | 
						|
    queue_addr = xive_get_queue_addr(index);
 | 
						|
    queue_hi = (queue_addr >> 32) & END2_W2_EQ_ADDR_HI;
 | 
						|
    queue_lo = queue_addr & END2_W3_EQ_ADDR_LO;
 | 
						|
    queue_size = ctz16(XIVE_QUEUE_SIZE) - 12;
 | 
						|
 | 
						|
    memset(&end, 0, sizeof(end));
 | 
						|
    end.w0 = xive_set_field32(END2_W0_VALID, 0, 1);
 | 
						|
    end.w0 = xive_set_field32(END2_W0_ENQUEUE, end.w0, 1);
 | 
						|
    end.w0 = xive_set_field32(END2_W0_UCOND_NOTIFY, end.w0, 1);
 | 
						|
    end.w0 = xive_set_field32(END2_W0_BACKLOG, end.w0, 1);
 | 
						|
 | 
						|
    end.w1 = xive_set_field32(END2_W1_GENERATION, 0, 1);
 | 
						|
 | 
						|
    end.w2 = cpu_to_be32(queue_hi);
 | 
						|
 | 
						|
    end.w3 = cpu_to_be32(queue_lo);
 | 
						|
    end.w3 = xive_set_field32(END2_W3_QSIZE, end.w3, queue_size);
 | 
						|
 | 
						|
    end.w6 = xive_set_field32(END2_W6_IGNORE, 0, i);
 | 
						|
    end.w6 = xive_set_field32(END2_W6_VP_OFFSET, end.w6, nvp_index);
 | 
						|
 | 
						|
    end.w7 = xive_set_field32(END2_W7_F0_PRIORITY, 0, priority);
 | 
						|
    xive_copy_struct(qts, &end, end_addr, sizeof(end));
 | 
						|
}
 | 
						|
 |