#ifndef _DEV_ACPI_DMARREG_H_
#define _DEV_ACPI_DMARREG_H_
#define VTD_STRIDE_MASK 0x1FF
#define VTD_STRIDE_SIZE 9
#define VTD_PAGE_SIZE 4096
#define VTD_PAGE_MASK 0xFFF
#define VTD_PTE_MASK 0x0000FFFFFFFFF000LL
#define VTD_LEVEL0 12
#define VTD_LEVEL1 21
#define VTD_LEVEL2 30
#define VTD_LEVEL3 39
#define VTD_LEVEL4 48
#define VTD_LEVEL5 57
#define _xbit(x,y) (((x)>> (y)) & 1)
#define _xfld(x,y) (uint32_t)(((x)>> y##_SHIFT) & y##_MASK)
#define VTD_AWTOLEVEL(x) (((x) - 30) / VTD_STRIDE_SIZE)
#define VTD_LEVELTOAW(x) (((x) * VTD_STRIDE_SIZE) + 30)
#define DMAR_VER_REG 0x00
#define DMAR_RTADDR_REG 0x20
#define DMAR_FEDATA_REG 0x3c
#define DMAR_FEADDR_REG 0x40
#define DMAR_FEUADDR_REG 0x44
#define DMAR_AFLOG_REG 0x58
#define DMAR_PMEN_REG 0x64
#define DMAR_PLMBASE_REG 0x68
#define DMAR_PLMLIMIT_REG 0x6c
#define DMAR_PHMBASE_REG 0x70
#define DMAR_PHMLIMIT_REG 0x78
#define DMAR_ICS_REG 0x9C
#define DMAR_IECTL_REG 0xa0
#define DMAR_IEDATA_REG 0xa4
#define DMAR_IEADDR_REG 0xa8
#define DMAR_IEUADDR_REG 0xac
#define DMAR_IRTA_REG 0xb8
#define DMAR_CAP_REG 0x08
#define CAP_PI (1LL << 59)
#define CAP_FL1GP (1LL << 56)
#define CAP_DRD (1LL << 55)
#define CAP_DWD (1LL << 54)
#define CAP_MAMV_MASK 0x3F
#define CAP_MAMV_SHIFT 48LL
#define cap_mamv(x) _xfld(x,CAP_MAMV)
#define CAP_NFR_MASK 0xFF
#define CAP_NFR_SHIFT 40LL
#define cap_nfr(x) (_xfld(x,CAP_NFR) + 1)
#define CAP_PSI (1LL << 39)
#define CAP_SLLPS_MASK 0xF
#define CAP_SLLPS_SHIFT 34LL
#define cap_sllps(x) _xfld(x,CAP_SLLPS)
#define CAP_FRO_MASK 0x3FF
#define CAP_FRO_SHIFT 24LL
#define cap_fro(x) (_xfld(x,CAP_FRO) * 16)
#define CAP_ZLR (1LL << 22)
#define CAP_MGAW_MASK 0x3F
#define CAP_MGAW_SHIFT 16LL
#define cap_mgaw(x) (_xfld(x,CAP_MGAW) + 1)
#define CAP_SAGAW_MASK 0x1F
#define CAP_SAGAW_SHIFT 8LL
#define cap_sagaw(x) _xfld(x,CAP_SAGAW)
#define CAP_CM (1LL << 7)
#define CAP_PHMR (1LL << 6)
#define CAP_PLMR (1LL << 5)
#define CAP_RWBF (1LL << 4)
#define CAP_AFL (1LL << 3)
#define CAP_ND_MASK 0x7
#define CAP_ND_SHIFT 0x00
#define cap_nd(x) (16 << (((x) & CAP_ND_MASK) << 1))
#define DMAR_ECAP_REG 0x10
#define ECAP_PSS_MASK 0x1F
#define ECAP_PSS_SHIFT 35
#define ECAP_EAFS (1LL << 34)
#define ECAP_NWFS (1LL << 33)
#define ECAP_SRS (1LL << 31)
#define ECAP_ERS (1LL << 30)
#define ECAP_PRS (1LL << 29)
#define ECAP_PASID (1LL << 28)
#define ECAP_DIS (1LL << 27)
#define ECAP_NEST (1LL << 26)
#define ECAP_MTS (1LL << 25)
#define ECAP_ECS (1LL << 24)
#define ECAP_MHMV_MASK 0xF
#define ECAP_MHMV_SHIFT 0x20
#define ecap_mhmv(x) _xfld(x,ECAP_MHMV)
#define ECAP_IRO_MASK 0x3FF
#define ECAP_IRO_SHIFT 0x8
#define ecap_iro(x) (_xfld(x,ECAP_IRO) * 16)
#define ECAP_SC (1LL << 7)
#define ECAP_PT (1LL << 6)
#define ECAP_EIM (1LL << 4)
#define ECAP_IR (1LL << 3)
#define ECAP_DT (1LL << 2)
#define ECAP_QI (1LL << 1)
#define ECAP_C (1LL << 0)
#define DMAR_GCMD_REG 0x18
#define GCMD_TE (1LL << 31)
#define GCMD_SRTP (1LL << 30)
#define GCMD_SFL (1LL << 29)
#define GCMD_EAFL (1LL << 28)
#define GCMD_WBF (1LL << 27)
#define GCMD_QIE (1LL << 26)
#define GCMD_IRE (1LL << 25)
#define GCMD_SIRTP (1LL << 24)
#define GCMD_CFI (1LL << 23)
#define DMAR_GSTS_REG 0x1c
#define GSTS_TES (1LL << 31)
#define GSTS_RTPS (1LL << 30)
#define GSTS_FLS (1LL << 29)
#define GSTS_AFLS (1LL << 28)
#define GSTS_WBFS (1LL << 27)
#define GSTS_QIES (1LL << 26)
#define GSTS_IRES (1LL << 25)
#define GSTS_IRTPS (1LL << 24)
#define GSTS_CFIS (1LL << 23)
#define DMAR_CCMD_REG 0x28
#define CCMD_ICC (1LL << 63)
#define CCMD_CIRG_MASK 0x3
#define CCMD_CIRG_SHIFT 61
#define CCMD_CIRG(x) ((uint64_t)(x) << CCMD_CIRG_SHIFT)
#define CCMD_CAIG_MASK 0x3
#define CCMD_CAIG_SHIFT 59
#define CCMD_FM_MASK 0x3
#define CCMD_FM_SHIFT 32
#define CCMD_FM(x) (((uint64_t)(x) << CCMD_FM_SHIFT))
#define CCMD_SID_MASK 0xFFFF
#define CCMD_SID_SHIFT 8
#define CCMD_SID(x) (((x) << CCMD_SID_SHIFT))
#define CCMD_DID_MASK 0xFFFF
#define CCMD_DID_SHIFT 0
#define CCMD_DID(x) (((x) << CCMD_DID_SHIFT))
#define CIG_GLOBAL CCMD_CIRG(CTX_GLOBAL)
#define CIG_DOMAIN CCMD_CIRG(CTX_DOMAIN)
#define CIG_DEVICE CCMD_CIRG(CTX_DEVICE)
#define DMAR_FSTS_REG 0x34
#define FSTS_FRI_MASK 0xFF
#define FSTS_FRI_SHIFT 8
#define FSTS_PRO (1LL << 7)
#define FSTS_ITE (1LL << 6)
#define FSTS_ICE (1LL << 5)
#define FSTS_IQE (1LL << 4)
#define FSTS_APF (1LL << 3)
#define FSTS_APO (1LL << 2)
#define FSTS_PPF (1LL << 1)
#define FSTS_PFO (1LL << 0)
#define DMAR_FECTL_REG 0x38
#define FECTL_IM (1LL << 31)
#define FECTL_IP (1LL << 30)
#define FRCD_HI_F (1LL << (127-64))
#define FRCD_HI_T (1LL << (126-64))
#define FRCD_HI_AT_MASK 0x3
#define FRCD_HI_AT_SHIFT (124-64)
#define FRCD_HI_PV_MASK 0xFFFFF
#define FRCD_HI_PV_SHIFT (104-64)
#define FRCD_HI_FR_MASK 0xFF
#define FRCD_HI_FR_SHIFT (96-64)
#define FRCD_HI_PP (1LL << (95-64))
#define FRCD_HI_SID_MASK 0xFF
#define FRCD_HI_SID_SHIFT 0
#define FRCD_HI_BUS_SHIFT 8
#define FRCD_HI_BUS_MASK 0xFF
#define FRCD_HI_DEV_SHIFT 3
#define FRCD_HI_DEV_MASK 0x1F
#define FRCD_HI_FUN_SHIFT 0
#define FRCD_HI_FUN_MASK 0x7
#define DMAR_IOTLB_REG(x) (ecap_iro((x)->ecap) + 8)
#define DMAR_IVA_REG(x) (ecap_iro((x)->ecap) + 0)
#define DMAR_FRIH_REG(x,i) (cap_fro((x)->cap) + 16*(i) + 8)
#define DMAR_FRIL_REG(x,i) (cap_fro((x)->cap) + 16*(i) + 0)
#define IOTLB_IVT (1LL << 63)
#define IOTLB_IIRG_MASK 0x3
#define IOTLB_IIRG_SHIFT 60
#define IOTLB_IIRG(x) ((uint64_t)(x) << IOTLB_IIRG_SHIFT)
#define IOTLB_IAIG_MASK 0x3
#define IOTLB_IAIG_SHIFT 57
#define IOTLB_DR (1LL << 49)
#define IOTLB_DW (1LL << 48)
#define IOTLB_DID_MASK 0xFFFF
#define IOTLB_DID_SHIFT 32
#define IOTLB_DID(x) ((uint64_t)(x) << IOTLB_DID_SHIFT)
#define IIG_GLOBAL IOTLB_IIRG(IOTLB_GLOBAL)
#define IIG_DOMAIN IOTLB_IIRG(IOTLB_DOMAIN)
#define IIG_PAGE IOTLB_IIRG(IOTLB_PAGE)
#define DMAR_IQH_REG 0x80
#define DMAR_IQT_REG 0x88
#define DMAR_IQA_REG 0x90
#define IQA_QS_256 0
#define IQA_QS_512 1
#define IQA_QS_1K 2
#define IQA_QS_2K 3
#define IQA_QS_4K 4
#define IQA_QS_8K 5
#define IQA_QS_16K 6
#define IQA_QS_32K 7
static inline void
iommu_rmw32(void *ov, uint32_t mask, uint32_t shift, uint32_t nv)
{
*(uint32_t *)ov &= ~(mask << shift);
*(uint32_t *)ov |= (nv & mask) << shift;
}
static inline void
iommu_rmw64(void *ov, uint32_t mask, uint32_t shift, uint64_t nv)
{
*(uint64_t *)ov &= ~(mask << shift);
*(uint64_t *)ov |= (nv & mask) << shift;
}
#define ROOT_P (1L << 0)
struct root_entry {
uint64_t lo;
uint64_t hi;
};
static inline bool
root_entry_is_valid(struct root_entry *re)
{
return (re->lo & ROOT_P);
}
#define CTX_P (1L << 0)
#define CTX_FPD (1L << 1)
#define CTX_T_MASK 0x3
#define CTX_T_SHIFT 2
enum {
CTX_T_MULTI,
CTX_T_IOTLB,
CTX_T_PASSTHRU
};
#define CTX_H_AW_MASK 0x7
#define CTX_H_AW_SHIFT 0
#define CTX_H_USER_MASK 0xF
#define CTX_H_USER_SHIFT 3
#define CTX_H_DID_MASK 0xFFFF
#define CTX_H_DID_SHIFT 8
struct context_entry {
uint64_t lo;
uint64_t hi;
};
static inline void
context_set_fpd(struct context_entry *ce, int enable)
{
ce->lo &= ~CTX_FPD;
if (enable)
ce->lo |= CTX_FPD;
}
static inline void
context_set_present(struct context_entry *ce)
{
ce->lo |= CTX_P;
}
static inline void
context_set_slpte(struct context_entry *ce, paddr_t slpte)
{
ce->lo &= VTD_PAGE_MASK;
ce->lo |= (slpte & ~VTD_PAGE_MASK);
}
static inline void
context_set_translation_type(struct context_entry *ce, int tt)
{
ce->lo &= ~(CTX_T_MASK << CTX_T_SHIFT);
ce->lo |= ((tt & CTX_T_MASK) << CTX_T_SHIFT);
}
static inline void
context_set_address_width(struct context_entry *ce, int lvl)
{
ce->hi &= ~(CTX_H_AW_MASK << CTX_H_AW_SHIFT);
ce->hi |= ((lvl & CTX_H_AW_MASK) << CTX_H_AW_SHIFT);
}
static inline void
context_set_domain_id(struct context_entry *ce, int did)
{
ce->hi &= ~(CTX_H_DID_MASK << CTX_H_DID_SHIFT);
ce->hi |= ((did & CTX_H_DID_MASK) << CTX_H_DID_SHIFT);
}
static inline uint64_t
context_pte(struct context_entry *ce)
{
return (ce->lo & ~VTD_PAGE_MASK);
}
static inline int
context_translation_type(struct context_entry *ce)
{
return (ce->lo >> CTX_T_SHIFT) & CTX_T_MASK;
}
static inline int
context_domain_id(struct context_entry *ce)
{
return (ce->hi >> CTX_H_DID_SHIFT) & CTX_H_DID_MASK;
}
static inline int
context_address_width(struct context_entry *ce)
{
return VTD_LEVELTOAW((ce->hi >> CTX_H_AW_SHIFT) & CTX_H_AW_MASK);
}
static inline bool
context_entry_is_valid(struct context_entry *ce)
{
return (ce->lo & CTX_P);
}
static inline int
context_user(struct context_entry *ce)
{
return (ce->hi >> CTX_H_USER_SHIFT) & CTX_H_USER_MASK;
}
static inline void
context_set_user(struct context_entry *ce, int v)
{
ce->hi &= ~(CTX_H_USER_MASK << CTX_H_USER_SHIFT);
ce->hi |= ((v & CTX_H_USER_MASK) << CTX_H_USER_SHIFT);
}
struct fault_entry {
uint64_t lo;
uint64_t hi;
};
#define PTE_P (1L << 0)
#define PTE_R 0x00
#define PTE_W (1L << 1)
#define PTE_US (1L << 2)
#define PTE_PWT (1L << 3)
#define PTE_PCD (1L << 4)
#define PTE_A (1L << 5)
#define PTE_D (1L << 6)
#define PTE_PAT (1L << 7)
#define PTE_G (1L << 8)
#define PTE_EA (1L << 10)
#define PTE_XD (1LL << 63)
#define PTE_PS (1L << 7)
struct pte_entry {
uint64_t val;
};
#define QI_CTX_DID_MASK 0xFFFF
#define QI_CTX_DID_SHIFT 16
#define QI_CTX_SID_MASK 0xFFFF
#define QI_CTX_SID_SHIFT 32
#define QI_CTX_FM_MASK 0x3
#define QI_CTX_FM_SHIFT 48
#define QI_CTX_IG_MASK 0x3
#define QI_CTX_IG_SHIFT 4
#define QI_CTX_DID(x) (((uint64_t)(x) << QI_CTX_DID_SHIFT))
#define QI_CTX_SID(x) (((uint64_t)(x) << QI_CTX_SID_SHIFT))
#define QI_CTX_FM(x) (((uint64_t)(x) << QI_CTX_FM_SHIFT))
#define QI_CTX_IG_GLOBAL (CTX_GLOBAL << QI_CTX_IG_SHIFT)
#define QI_CTX_IG_DOMAIN (CTX_DOMAIN << QI_CTX_IG_SHIFT)
#define QI_CTX_IG_DEVICE (CTX_DEVICE << QI_CTX_IG_SHIFT)
#define QI_IOTLB_DID_MASK 0xFFFF
#define QI_IOTLB_DID_SHIFT 16
#define QI_IOTLB_IG_MASK 0x3
#define QI_IOTLB_IG_SHIFT 4
#define QI_IOTLB_DR (1LL << 6)
#define QI_IOTLB_DW (1LL << 5)
#define QI_IOTLB_DID(x) (((uint64_t)(x) << QI_IOTLB_DID_SHIFT))
#define QI_IOTLB_IG_GLOBAL (1 << QI_IOTLB_IG_SHIFT)
#define QI_IOTLB_IG_DOMAIN (2 << QI_IOTLB_IG_SHIFT)
#define QI_IOTLB_IG_PAGE (3 << QI_IOTLB_IG_SHIFT)
#define QI_CTX 0x1
#define QI_IOTLB 0x2
#define QI_DEVTLB 0x3
#define QI_INTR 0x4
#define QI_WAIT 0x5
#define QI_EXTTLB 0x6
#define QI_PAS 0x7
#define QI_EXTDEV 0x8
struct qi_entry {
uint64_t lo;
uint64_t hi;
};
enum {
CTX_GLOBAL = 1,
CTX_DOMAIN,
CTX_DEVICE,
IOTLB_GLOBAL = 1,
IOTLB_DOMAIN,
IOTLB_PAGE,
};
enum {
VTD_FAULT_ROOT_P = 0x1,
VTD_FAULT_CTX_P = 0x2,
VTD_FAULT_CTX_INVAL = 0x3,
VTD_FAULT_LIMIT = 0x4,
VTD_FAULT_WRITE = 0x5,
VTD_FAULT_READ = 0x6,
VTD_FAULT_PTE_INVAL = 0x7,
VTD_FAULT_ROOT_INVAL = 0x8,
VTD_FAULT_CTX_TBL_INVAL = 0x9,
VTD_FAULT_ROOT_RESERVED = 0xa,
VTD_FAULT_CTX_RESERVED = 0xb,
VTD_FAULT_PTE_RESERVED = 0xc,
VTD_FAULT_CTX_TT = 0xd,
};
#endif
void acpidmar_pci_hook(pci_chipset_tag_t, struct pci_attach_args *);
void dmar_ptmap(bus_dma_tag_t, bus_addr_t);
#define __EXTRACT(v,m) (((v) >> m##_SHIFT) & m##_MASK)