blob: da3f03440c5d5b6753182f33af86f4e25be3e746 [file] [log] [blame]
/*
* 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_ats; /* Enable ATS support */
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