qemu/hw/riscv/riscv-iommu.h
Tomasz Jeznach 9d085a1c3c hw/riscv/riscv-iommu: add Address Translation Cache (IOATC)
The RISC-V IOMMU spec predicts that the IOMMU can use translation caches
to hold entries from the DDT. This includes implementation for all cache
commands that are marked as 'not implemented'.

There are some artifacts included in the cache that predicts s-stage and
g-stage elements, although we don't support it yet. We'll introduce them
next.

Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20241016204038.649340-9-dbarboza@ventanamicro.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2024-10-31 13:51:24 +10:00

130 lines
4.2 KiB
C

/*
* QEMU emulation of an RISC-V IOMMU
*
* Copyright (C) 2022-2023 Rivos Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_RISCV_IOMMU_STATE_H
#define HW_RISCV_IOMMU_STATE_H
#include "qom/object.h"
#include "hw/riscv/iommu.h"
struct RISCVIOMMUState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
uint32_t version; /* Reported interface version number */
uint32_t pid_bits; /* process identifier width */
uint32_t bus; /* PCI bus mapping for non-root endpoints */
uint64_t cap; /* IOMMU supported capabilities */
uint64_t fctl; /* IOMMU enabled features */
uint64_t icvec_avail_vectors; /* Available interrupt vectors in ICVEC */
bool enable_off; /* Enable out-of-reset OFF mode (DMA disabled) */
bool enable_msi; /* Enable MSI remapping */
bool enable_s_stage; /* Enable S/VS-Stage translation */
bool enable_g_stage; /* Enable G-Stage translation */
/* IOMMU Internal State */
uint64_t ddtp; /* Validated Device Directory Tree Root Pointer */
dma_addr_t cq_addr; /* Command queue base physical address */
dma_addr_t fq_addr; /* Fault/event queue base physical address */
dma_addr_t pq_addr; /* Page request queue base physical address */
uint32_t cq_mask; /* Command queue index bit mask */
uint32_t fq_mask; /* Fault/event queue index bit mask */
uint32_t pq_mask; /* Page request queue index bit mask */
/* interrupt notifier */
void (*notify)(RISCVIOMMUState *iommu, unsigned vector);
/* IOMMU State Machine */
QemuThread core_proc; /* Background processing thread */
QemuCond core_cond; /* Background processing wake up signal */
unsigned core_exec; /* Processing thread execution actions */
/* IOMMU target address space */
AddressSpace *target_as;
MemoryRegion *target_mr;
/* MSI / MRIF access trap */
AddressSpace trap_as;
MemoryRegion trap_mr;
GHashTable *ctx_cache; /* Device translation Context Cache */
GHashTable *iot_cache; /* IO Translated Address Cache */
unsigned iot_limit; /* IO Translation Cache size limit */
/* MMIO Hardware Interface */
MemoryRegion regs_mr;
uint8_t *regs_rw; /* register state (user write) */
uint8_t *regs_wc; /* write-1-to-clear mask */
uint8_t *regs_ro; /* read-only mask */
QLIST_ENTRY(RISCVIOMMUState) iommus;
QLIST_HEAD(, RISCVIOMMUSpace) spaces;
};
void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
Error **errp);
/* private helpers */
/* Register helper functions */
static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
unsigned idx, uint32_t set, uint32_t clr)
{
uint32_t val = ldl_le_p(s->regs_rw + idx);
stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
return val;
}
static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
uint32_t set)
{
stl_le_p(s->regs_rw + idx, set);
}
static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
{
return ldl_le_p(s->regs_rw + idx);
}
static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
uint64_t set, uint64_t clr)
{
uint64_t val = ldq_le_p(s->regs_rw + idx);
stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
return val;
}
static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
uint64_t set)
{
stq_le_p(s->regs_rw + idx, set);
}
static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
unsigned idx)
{
return ldq_le_p(s->regs_rw + idx);
}
#endif