#ifndef _AMDVI_PRIV_H_
#define _AMDVI_PRIV_H_
#include <contrib/dev/acpica/include/acpi.h>
#define BIT(n) (1ULL << (n))
#define REG_BITS(x, n, m) (((x) >> (m)) & \
((1 << (((n) - (m)) + 1)) - 1))
#define AMDVI_PCI_CAP_IOTLB BIT(0)
#define AMDVI_PCI_CAP_HT BIT(1)
#define AMDVI_PCI_CAP_NPCACHE BIT(2)
#define AMDVI_PCI_CAP_EFR BIT(3)
#define AMDVI_PCI_CAP_EXT BIT(4)
#define AMDVI_EX_FEA_PREFSUP BIT(0)
#define AMDVI_EX_FEA_PPRSUP BIT(1)
#define AMDVI_EX_FEA_XTSUP BIT(2)
#define AMDVI_EX_FEA_NXSUP BIT(3)
#define AMDVI_EX_FEA_GTSUP BIT(4)
#define AMDVI_EX_FEA_EFRW BIT(5)
#define AMDVI_EX_FEA_IASUP BIT(6)
#define AMDVI_EX_FEA_GASUP BIT(7)
#define AMDVI_EX_FEA_HESUP BIT(8)
#define AMDVI_EX_FEA_PCSUP BIT(9)
struct amdvi_dte {
uint32_t dt_valid:1;
uint32_t pt_valid:1;
uint16_t :7;
uint8_t pt_level:3;
uint64_t pt_base:40;
uint8_t :3;
uint8_t gv_valid:1;
uint8_t gv_level:2;
uint8_t gv_cr3_lsb:3;
uint8_t read_allow:1;
uint8_t write_allow:1;
uint8_t :1;
uint16_t domain_id:16;
uint16_t gv_cr3_lsb2:16;
uint8_t iotlb_enable:1;
uint8_t sup_second_io_fault:1;
uint8_t sup_all_io_fault:1;
uint8_t IOctl:2;
uint8_t iotlb_cache_disable:1;
uint8_t snoop_disable:1;
uint8_t allow_ex:1;
uint8_t sysmgmt:2;
uint8_t :1;
uint32_t gv_cr3_msb:21;
uint8_t intmap_valid:1;
uint8_t intmap_len:4;
uint8_t intmap_ign:1;
uint64_t intmap_base:46;
uint8_t :4;
uint8_t init_pass:1;
uint8_t extintr_pass:1;
uint8_t nmi_pass:1;
uint8_t :1;
uint8_t intr_ctrl:2;
uint8_t lint0_pass:1;
uint8_t lint1_pass:1;
uint64_t :64;
} __attribute__((__packed__));
CTASSERT(sizeof(struct amdvi_dte) == 32);
struct amdvi_cmd {
uint32_t word0;
uint32_t word1:28;
uint8_t opcode:4;
uint64_t addr;
} __attribute__((__packed__));
#define AMDVI_CMP_WAIT_OPCODE 0x1
#define AMDVI_INVD_DTE_OPCODE 0x2
#define AMDVI_INVD_PAGE_OPCODE 0x3
#define AMDVI_INVD_IOTLB_OPCODE 0x4
#define AMDVI_INVD_INTR_OPCODE 0x5
#define AMDVI_PREFETCH_PAGES_OPCODE 0x6
#define AMDVI_COMP_PPR_OPCODE 0x7
#define AMDVI_INV_ALL_OPCODE 0x8
#define AMDVI_CMP_WAIT_STORE BIT(0)
#define AMDVI_CMP_WAIT_INTR BIT(1)
#define AMDVI_CMP_WAIT_FLUSH BIT(2)
#define AMDVI_INVD_PAGE_S BIT(0)
#define AMDVI_INVD_PAGE_PDE BIT(1)
#define AMDVI_INVD_PAGE_GN_GVA BIT(2)
#define AMDVI_INVD_PAGE_ALL_ADDR (0x7FFFFFFFFFFFFULL << 12)
#define AMDVI_INVD_IOTLB_S BIT(0)
#define AMDVI_INVD_IOTLB_GN_GVA BIT(2)
#define AMDVI_INVD_IOTLB_ALL_ADDR (0x7FFFFFFFFFFFFULL << 12)
struct amdvi_event {
uint16_t devid;
uint16_t pasid_hi;
uint16_t pasid_domid;
uint16_t flag:12;
uint8_t opcode:4;
uint64_t addr;
} __attribute__((__packed__));
CTASSERT(sizeof(struct amdvi_event) == 16);
#define AMDVI_EVENT_INVALID_DTE 0x1
#define AMDVI_EVENT_PFAULT 0x2
#define AMDVI_EVENT_DTE_HW_ERROR 0x3
#define AMDVI_EVENT_PAGE_HW_ERROR 0x4
#define AMDVI_EVENT_ILLEGAL_CMD 0x5
#define AMDVI_EVENT_CMD_HW_ERROR 0x6
#define AMDVI_EVENT_IOTLB_TIMEOUT 0x7
#define AMDVI_EVENT_INVALID_DTE_REQ 0x8
#define AMDVI_EVENT_INVALID_PPR_REQ 0x9
#define AMDVI_EVENT_COUNTER_ZERO 0xA
#define AMDVI_EVENT_FLAG_MASK 0x1FF
#define AMDVI_EVENT_FLAG_TYPE(x) (((x) >> 9) & 0x3)
struct amdvi_ctrl {
struct {
uint16_t size:9;
uint16_t :3;
uint64_t base:40;
uint16_t :12;
} dte;
struct {
uint16_t :12;
uint64_t base:40;
uint8_t :4;
uint8_t len:4;
uint8_t :4;
} cmd;
struct {
uint16_t :12;
uint64_t base:40;
uint8_t :4;
uint8_t len:4;
uint8_t :4;
} event;
uint16_t control :13;
uint64_t :51;
struct {
uint8_t enable:1;
uint8_t allow:1;
uint16_t :10;
uint64_t base:40;
uint16_t :12;
uint16_t :12;
uint64_t limit:40;
uint16_t :12;
} excl;
uint64_t ex_feature;
struct {
uint16_t :12;
uint64_t base:40;
uint8_t :4;
uint8_t len:4;
uint8_t :4;
} ppr;
uint64_t first_event;
uint64_t second_event;
uint64_t event_status;
uint8_t pad1[0x1FA8];
uint32_t cmd_head:19;
uint64_t :45;
uint32_t cmd_tail:19;
uint64_t :45;
uint32_t evt_head:19;
uint64_t :45;
uint32_t evt_tail:19;
uint64_t :45;
uint32_t status:19;
uint64_t :45;
uint64_t pad2;
uint8_t :4;
uint16_t ppr_head:15;
uint64_t :45;
uint8_t :4;
uint16_t ppr_tail:15;
uint64_t :45;
uint8_t pad3[0x1FC0];
} __attribute__((__packed__));
CTASSERT(offsetof(struct amdvi_ctrl, pad1)== 0x58);
CTASSERT(offsetof(struct amdvi_ctrl, pad2)== 0x2028);
CTASSERT(offsetof(struct amdvi_ctrl, pad3)== 0x2040);
#define AMDVI_MMIO_V1_SIZE (4 * PAGE_SIZE)
#define AMDVI_MMIO_V2_SIZE (8 * PAGE_SIZE)
CTASSERT(sizeof(struct amdvi_ctrl) == 0x4000);
CTASSERT(sizeof(struct amdvi_ctrl) == AMDVI_MMIO_V1_SIZE);
#define IVHD_FLAG_HTT BIT(0)
#define IVHD_FLAG_PPW BIT(1)
#define IVHD_FLAG_RPPW BIT(2)
#define IVHD_FLAG_ISOC BIT(3)
#define IVHD_FLAG_IOTLB BIT(4)
#define IVHD_FLAG_COH BIT(5)
#define IVHD_FLAG_PFS BIT(6)
#define IVHD_FLAG_PPRS BIT(7)
#define IVHD_DEV_LINT0_PASS BIT(6)
#define IVHD_DEV_LINT1_PASS BIT(7)
#define IVHD_DEV_INIT_PASS BIT(0)
#define IVHD_DEV_EXTINTR_PASS BIT(1)
#define IVHD_DEV_NMI_PASS BIT(2)
#define IVHD_DEV_EXT_ATS_DISABLE BIT(31)
#define AMDVI_CTRL_EN BIT(0)
#define AMDVI_CTRL_HTT BIT(1)
#define AMDVI_CTRL_ELOG BIT(2)
#define AMDVI_CTRL_ELOGINT BIT(3)
#define AMDVI_CTRL_COMINT BIT(4)
#define AMDVI_CTRL_PPW BIT(8)
#define AMDVI_CTRL_RPPW BIT(9)
#define AMDVI_CTRL_COH BIT(10)
#define AMDVI_CTRL_ISOC BIT(11)
#define AMDVI_CTRL_CMD BIT(12)
#define AMDVI_CTRL_PPRLOG BIT(13)
#define AMDVI_CTRL_PPRINT BIT(14)
#define AMDVI_CTRL_PPREN BIT(15)
#define AMDVI_CTRL_GTE BIT(16)
#define AMDVI_CTRL_GAE BIT(17)
#define AMDVI_CTRL_INV_NO_TO 0
#define AMDVI_CTRL_INV_TO_1ms 1
#define AMDVI_CTRL_INV_TO_10ms 2
#define AMDVI_CTRL_INV_TO_100ms 3
#define AMDVI_CTRL_INV_TO_1S 4
#define AMDVI_CTRL_INV_TO_10S 5
#define AMDVI_CTRL_INV_TO_100S 6
#define PCI_NUM_DEV_MAX 0x10000
#define AMDVI_MAX_DOMAIN (BIT(16) - 1)
#define AMDVI_PT_PRESENT BIT(0)
#define AMDVI_PT_COHERENT BIT(60)
#define AMDVI_PT_READ BIT(61)
#define AMDVI_PT_WRITE BIT(62)
#define AMDVI_PT_RW (AMDVI_PT_READ | AMDVI_PT_WRITE)
#define AMDVI_PT_MASK 0xFFFFFFFFFF000UL
#define AMDVI_PD_LEVEL_SHIFT 9
#define AMDVI_PD_SUPER(x) (((x) >> AMDVI_PD_LEVEL_SHIFT) == 7)
#define AMDVI_STATUS_EV_OF BIT(0)
#define AMDVI_STATUS_EV_INTR BIT(1)
#define AMDVI_STATUS_CMP BIT(2)
#define IVRS_CTRL_RID 1
struct ivhd_dev_cfg {
uint32_t start_id;
uint32_t end_id;
uint8_t data;
bool enable_ats;
int ats_qlen;
};
struct amdvi_domain {
uint64_t *ptp;
int ptp_level;
u_int id;
SLIST_ENTRY (amdvi_domain) next;
};
enum IvrsType
{
IVRS_TYPE_HARDWARE_LEGACY = ACPI_IVRS_TYPE_HARDWARE1,
IVRS_TYPE_HARDWARE_EFR = ACPI_IVRS_TYPE_HARDWARE2,
IVRS_TYPE_HARDWARE_MIXED = 0x40,
};
struct amdvi_softc {
struct amdvi_ctrl *ctrl;
device_t dev;
device_t pci_dev;
enum IvrsType ivhd_type;
bool iotlb;
struct amdvi_cmd *cmd;
int cmd_max;
uint64_t cmp_data;
struct amdvi_event *event;
int event_max;
uint32_t ivhd_flag;
uint32_t ivhd_feature;
uint64_t ext_feature;
uint16_t cap_off;
uint8_t pci_cap;
uint16_t pci_seg;
uint16_t pci_rid;
struct ivhd_dev_cfg *dev_cfg;
int dev_cfg_cnt;
int dev_cfg_cap;
uint64_t event_intr_cnt;
uint64_t total_cmd;
};
int amdvi_setup_hw(struct amdvi_softc *softc);
int amdvi_teardown_hw(struct amdvi_softc *softc);
#endif