xref: /openbsd-src/sys/dev/acpi/amd_iommu.h (revision 4b1a56afb1a28c97103da3911d326d1216798a6e)
196940271Sjordan /*
296940271Sjordan  * Copyright (c) 2019 Jordan Hargrave <jordan_hargrave@hotmail.com>
396940271Sjordan  *
496940271Sjordan  * Permission to use, copy, modify, and distribute this software for any
596940271Sjordan  * purpose with or without fee is hereby granted, provided that the above
696940271Sjordan  * copyright notice and this permission notice appear in all copies.
796940271Sjordan  *
896940271Sjordan  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
996940271Sjordan  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1096940271Sjordan  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1196940271Sjordan  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1296940271Sjordan  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1396940271Sjordan  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1496940271Sjordan  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1596940271Sjordan  */
1696940271Sjordan #ifndef __amd_iommu_h__
1796940271Sjordan #define __amd_iommu_h__
1896940271Sjordan 
1996940271Sjordan #define DEV_TAB_BASE_REG	0x0000
2096940271Sjordan #define CMD_BASE_REG		0x0008
2196940271Sjordan #define EVT_BASE_REG		0x0010
2296940271Sjordan 
2396940271Sjordan #define EXCL_BASE_REG		0x0020
2496940271Sjordan #define EXCL_LIMIT_REG		0x0028
2596940271Sjordan 
2696940271Sjordan /* Extended Feature Register */
2796940271Sjordan #define EXTFEAT_REG		0x0030
2896940271Sjordan #define  EFR_PREFSUP		(1L << 0)
2996940271Sjordan #define  EFR_PPRSUP		(1L << 1)
3096940271Sjordan #define  EFR_NXSUP		(1L << 3)
3196940271Sjordan #define  EFR_GTSUP		(1L << 4)
3296940271Sjordan #define  EFR_IASUP		(1L << 6)
3396940271Sjordan #define  EFR_GASUP		(1L << 7)
3496940271Sjordan #define  EFR_HESUP		(1L << 8)
3596940271Sjordan #define  EFR_PCSUP		(1L << 9)
3696940271Sjordan #define  EFR_HATS_SHIFT		10
3796940271Sjordan #define  EFR_HATS_MASK		0x3
3896940271Sjordan #define  EFR_GATS_SHIFT		12
3996940271Sjordan #define  EFR_GATS_MASK		0x3
4096940271Sjordan #define  EFR_GLXSUP_SHIFT	14
4196940271Sjordan #define  EFR_GLXSUP_MASK	0x3
4296940271Sjordan #define  EFR_SMIFSUP_SHIFT	16
4396940271Sjordan #define  EFR_SMIFSUP_MASK	0x3
4496940271Sjordan #define  EFR_SMIFRC_SHIFT	18
4596940271Sjordan #define  EFR_SMIFRC_MASK	0x7
4696940271Sjordan #define  EFR_GAMSUP_SHIFT	21
4796940271Sjordan #define  EFR_GAMSUP_MASK	0x7
4896940271Sjordan 
4996940271Sjordan #define CMD_HEAD_REG		0x2000
5096940271Sjordan #define CMD_TAIL_REG		0x2008
5196940271Sjordan #define EVT_HEAD_REG		0x2010
5296940271Sjordan #define EVT_TAIL_REG		0x2018
5396940271Sjordan 
5496940271Sjordan #define IOMMUSTS_REG		0x2020
5596940271Sjordan 
5696940271Sjordan #define DEV_TAB_MASK		0x000FFFFFFFFFF000LL
5796940271Sjordan #define DEV_TAB_LEN		0x1FF
5896940271Sjordan 
5996940271Sjordan /* IOMMU Control */
6096940271Sjordan #define IOMMUCTL_REG		0x0018
6196940271Sjordan #define  CTL_IOMMUEN		(1L << 0)
6296940271Sjordan #define  CTL_HTTUNEN		(1L << 1)
6396940271Sjordan #define  CTL_EVENTLOGEN		(1L << 2)
6496940271Sjordan #define  CTL_EVENTINTEN		(1L << 3)
6596940271Sjordan #define  CTL_COMWAITINTEN	(1L << 4)
6696940271Sjordan #define  CTL_INVTIMEOUT_SHIFT	5
6796940271Sjordan #define  CTL_INVTIMEOUT_MASK	0x7
6896940271Sjordan #define  CTL_INVTIMEOUT_NONE	0
6996940271Sjordan #define  CTL_INVTIMEOUT_1MS     1
7096940271Sjordan #define  CTL_INVTIMEOUT_10MS    2
7196940271Sjordan #define  CTL_INVTIMEOUT_100MS   3
7296940271Sjordan #define  CTL_INVTIMEOUT_1S      4
7396940271Sjordan #define  CTL_INVTIMEOUT_10S     5
7496940271Sjordan #define  CTL_INVTIMEOUT_100S    6
7596940271Sjordan #define  CTL_PASSPW		(1L << 8)
7696940271Sjordan #define  CTL_RESPASSPW		(1L << 9)
7796940271Sjordan #define  CTL_COHERENT		(1L << 10)
7896940271Sjordan #define  CTL_ISOC		(1L << 11)
7996940271Sjordan #define  CTL_CMDBUFEN		(1L << 12)
8096940271Sjordan #define  CTL_PPRLOGEN		(1L << 13)
8196940271Sjordan #define  CTL_PPRINTEN		(1L << 14)
8296940271Sjordan #define  CTL_PPREN		(1L << 15)
8396940271Sjordan #define  CTL_GTEN		(1L << 16)
8496940271Sjordan #define  CTL_GAEN		(1L << 17)
8596940271Sjordan #define  CTL_CRW_SHIFT		18
8696940271Sjordan #define  CTL_CRW_MASK		0xF
8796940271Sjordan #define  CTL_SMIFEN		(1L << 22)
8896940271Sjordan #define  CTL_SLFWBDIS		(1L << 23)
8996940271Sjordan #define  CTL_SMIFLOGEN		(1L << 24)
9096940271Sjordan #define  CTL_GAMEN_SHIFT	25
9196940271Sjordan #define  CTL_GAMEN_MASK		0x7
9296940271Sjordan #define  CTL_GALOGEN		(1L << 28)
9396940271Sjordan #define  CTL_GAINTEN		(1L << 29)
9496940271Sjordan #define  CTL_DUALPPRLOGEN_SHIFT	30
9596940271Sjordan #define  CTL_DUALPPRLOGEN_MASK	0x3
9696940271Sjordan #define  CTL_DUALEVTLOGEN_SHIFT	32
9796940271Sjordan #define  CTL_DUALEVTLOGEN_MASK	0x3
9896940271Sjordan #define  CTL_DEVTBLSEGEN_SHIFT	34
9996940271Sjordan #define  CTL_DEVTBLSEGEN_MASK	0x7
10096940271Sjordan #define  CTL_PRIVABRTEN_SHIFT	37
10196940271Sjordan #define  CTL_PRIVABRTEN_MASK	0x3
10296940271Sjordan #define  CTL_PPRAUTORSPEN	(1LL << 39)
10396940271Sjordan #define  CTL_MARCEN		(1LL << 40)
10496940271Sjordan #define  CTL_BLKSTOPMRKEN	(1LL << 41)
10596940271Sjordan #define  CTL_PPRAUTOSPAON	(1LL << 42)
10696940271Sjordan #define  CTL_DOMAINIDPNE	(1LL << 43)
10796940271Sjordan 
10896940271Sjordan #define CMD_BASE_MASK		0x000FFFFFFFFFF000LL
10996940271Sjordan #define CMD_TBL_SIZE		4096
11096940271Sjordan #define CMD_TBL_LEN_4K		(8LL << 56)
11196940271Sjordan #define CMD_TBL_LEN_8K		(9lL << 56)
11296940271Sjordan 
11396940271Sjordan #define EVT_BASE_MASK		0x000FFFFFFFFFF000LL
11496940271Sjordan #define EVT_TBL_SIZE		4096
11596940271Sjordan #define EVT_TBL_LEN_4K		(8LL << 56)
11696940271Sjordan #define EVT_TBL_LEN_8K		(9LL << 56)
11796940271Sjordan 
11896940271Sjordan /*========================
11996940271Sjordan  * DEVICE TABLE ENTRY
12096940271Sjordan  * Contains mapping of bus-device-function
12196940271Sjordan  *
12296940271Sjordan  *  0       Valid (V)
12396940271Sjordan  *  1       Translation Valid (TV)
12496940271Sjordan  *  7:8     Host Address Dirty (HAD)
12596940271Sjordan  *  9:11    Page Table Depth (usually 4)
12696940271Sjordan  *  12:51   Page Table Physical Address
12796940271Sjordan  *  52      PPR Enable
12896940271Sjordan  *  53      GPRP
12996940271Sjordan  *  54      Guest I/O Protection Valid (GIoV)
13096940271Sjordan  *  55      Guest Translation Valid (GV)
13196940271Sjordan  *  56:57   Guest Levels translated (GLX)
13296940271Sjordan  *  58:60   Guest CR3 bits 12:14 (GCR3TRP)
13396940271Sjordan  *  61      I/O Read Permission (IR)
13496940271Sjordan  *  62      I/O Write Permission (IW)
13596940271Sjordan  *  64:79   Domain ID
13696940271Sjordan  *  80:95   Guest CR3 bits 15:30 (GCR3TRP)
13796940271Sjordan  *  96      IOTLB Enable (I)
13896940271Sjordan  *  97      Suppress multiple I/O page faults (I)
139*4b1a56afSjsg  *  98      Suppress all I/O page faults (SA)
14096940271Sjordan  *  99:100  Port I/O Control (IoCTL)
14196940271Sjordan  *  101     Cache IOTLB Hint
14296940271Sjordan  *  102     Snoop Disable (SD)
14396940271Sjordan  *  103     Allow Exclusion (EX)
14496940271Sjordan  *  104:105 System Management Message (SysMgt)
14596940271Sjordan  *  107:127 Guest CR3 bits 31:51 (GCR3TRP)
14696940271Sjordan  *  128     Interrupt Map Valid (IV)
14796940271Sjordan  *  129:132 Interrupt Table Length (IntTabLen)
14896940271Sjordan  *========================*/
14996940271Sjordan struct ivhd_dte {
15096940271Sjordan 	uint32_t dw0;
15196940271Sjordan 	uint32_t dw1;
15296940271Sjordan 	uint32_t dw2;
15396940271Sjordan 	uint32_t dw3;
15496940271Sjordan 	uint32_t dw4;
15596940271Sjordan 	uint32_t dw5;
15696940271Sjordan 	uint32_t dw6;
15796940271Sjordan 	uint32_t dw7;
15896940271Sjordan } __packed;
15996940271Sjordan 
16096940271Sjordan #define HWDTE_SIZE (65536 * sizeof(struct ivhd_dte))
16196940271Sjordan 
16296940271Sjordan #define DTE_V			(1L << 0)			/* dw0 */
16396940271Sjordan #define DTE_TV			(1L << 1)			/* dw0 */
16496940271Sjordan #define DTE_LEVEL_SHIFT		9				/* dw0 */
16596940271Sjordan #define DTE_LEVEL_MASK		0x7				/* dw0 */
16696940271Sjordan #define DTE_HPTRP_MASK		0x000FFFFFFFFFF000LL		/* dw0,1 */
16796940271Sjordan 
16896940271Sjordan #define DTE_PPR			(1L << 20)			/* dw1 */
16996940271Sjordan #define DTE_GPRP		(1L << 21)			/* dw1 */
17096940271Sjordan #define DTE_GIOV		(1L << 22)			/* dw1 */
17196940271Sjordan #define DTE_GV			(1L << 23)			/* dw1 */
17296940271Sjordan #define DTE_IR			(1L << 29)			/* dw1 */
17396940271Sjordan #define DTE_IW			(1L << 30)			/* dw1 */
17496940271Sjordan 
17596940271Sjordan #define DTE_DID_MASK		0xFFFF				/* dw2 */
17696940271Sjordan 
17796940271Sjordan #define DTE_IV			(1L << 0)			/* dw3 */
17896940271Sjordan #define DTE_SE			(1L << 1)
17996940271Sjordan #define DTE_SA			(1L << 2)
18096940271Sjordan #define DTE_INTTABLEN_SHIFT	1
18196940271Sjordan #define DTE_INTTABLEN_MASK	0xF
18296940271Sjordan #define DTE_IRTP_MASK		0x000FFFFFFFFFFFC0LL
18396940271Sjordan 
18496940271Sjordan #define PTE_LVL5                48
18596940271Sjordan #define PTE_LVL4                39
18696940271Sjordan #define PTE_LVL3                30
18796940271Sjordan #define PTE_LVL2                21
18896940271Sjordan #define PTE_LVL1                12
18996940271Sjordan 
19096940271Sjordan #define PTE_NXTLVL(x)           (((x) & 0x7) << 9)
19196940271Sjordan #define PTE_PADDR_MASK		0x000FFFFFFFFFF000LL
19296940271Sjordan #define PTE_IR                  (1LL << 61)
19396940271Sjordan #define PTE_IW                  (1LL << 62)
19496940271Sjordan 
19596940271Sjordan #define DTE_GCR312_MASK		0x3
19696940271Sjordan #define DTE_GCR312_SHIFT	24
19796940271Sjordan 
19896940271Sjordan #define DTE_GCR315_MASK		0xFFFF
19996940271Sjordan #define DTE_GCR315_SHIFT	16
20096940271Sjordan 
20196940271Sjordan #define DTE_GCR331_MASK		0xFFFFF
20296940271Sjordan #define DTE_GCR331_SHIFT	12
20396940271Sjordan 
20496940271Sjordan #define _get64(x)   *(uint64_t *)(x)
20596940271Sjordan #define _put64(x,v) *(uint64_t *)(x) = (v)
20696940271Sjordan 
20796940271Sjordan /* Set Guest CR3 address */
20896940271Sjordan static inline void
dte_set_guest_cr3(struct ivhd_dte * dte,paddr_t paddr)20996940271Sjordan dte_set_guest_cr3(struct ivhd_dte *dte, paddr_t paddr)
21096940271Sjordan {
21196940271Sjordan 	iommu_rmw32(&dte->dw1, DTE_GCR312_MASK, DTE_GCR312_SHIFT, paddr >> 12);
21296940271Sjordan 	iommu_rmw32(&dte->dw2, DTE_GCR315_MASK, DTE_GCR315_SHIFT, paddr >> 15);
21396940271Sjordan 	iommu_rmw32(&dte->dw3, DTE_GCR331_MASK, DTE_GCR331_SHIFT, paddr >> 31);
21496940271Sjordan }
21596940271Sjordan 
21696940271Sjordan /* Set Interrupt Remapping Root Pointer */
21796940271Sjordan static inline void
dte_set_interrupt_table_root_ptr(struct ivhd_dte * dte,paddr_t paddr)21896940271Sjordan dte_set_interrupt_table_root_ptr(struct ivhd_dte *dte, paddr_t paddr)
21996940271Sjordan {
22096940271Sjordan 	uint64_t ov = _get64(&dte->dw4);
22196940271Sjordan 	_put64(&dte->dw4, (ov & ~DTE_IRTP_MASK) | (paddr & DTE_IRTP_MASK));
22296940271Sjordan }
22396940271Sjordan 
22496940271Sjordan /* Set Interrupt Remapping Table length */
22596940271Sjordan static inline void
dte_set_interrupt_table_length(struct ivhd_dte * dte,int nEnt)22696940271Sjordan dte_set_interrupt_table_length(struct ivhd_dte *dte, int nEnt)
22796940271Sjordan {
22896940271Sjordan 	iommu_rmw32(&dte->dw4, DTE_INTTABLEN_MASK, DTE_INTTABLEN_SHIFT, nEnt);
22996940271Sjordan }
23096940271Sjordan 
23196940271Sjordan /* Set Interrupt Remapping Valid */
23296940271Sjordan static inline void
dte_set_interrupt_valid(struct ivhd_dte * dte)23396940271Sjordan dte_set_interrupt_valid(struct ivhd_dte *dte)
23496940271Sjordan {
23596940271Sjordan 	dte->dw4 |= DTE_IV;
23696940271Sjordan }
23796940271Sjordan 
23896940271Sjordan /* Set Domain ID in Device Table Entry */
23996940271Sjordan static inline void
dte_set_domain(struct ivhd_dte * dte,uint16_t did)24096940271Sjordan dte_set_domain(struct ivhd_dte *dte, uint16_t did)
24196940271Sjordan {
24296940271Sjordan 	dte->dw2 = (dte->dw2 & ~DTE_DID_MASK) | (did & DTE_DID_MASK);
24396940271Sjordan }
24496940271Sjordan 
24596940271Sjordan /* Set Page Table Pointer for device */
24696940271Sjordan static inline void
dte_set_host_page_table_root_ptr(struct ivhd_dte * dte,paddr_t paddr)24796940271Sjordan dte_set_host_page_table_root_ptr(struct ivhd_dte *dte, paddr_t paddr)
24896940271Sjordan {
24996940271Sjordan 	uint64_t ov;
25096940271Sjordan 
25196940271Sjordan 	ov = _get64(&dte->dw0) & ~DTE_HPTRP_MASK;
25296940271Sjordan 	ov |= (paddr & DTE_HPTRP_MASK) | PTE_IW | PTE_IR;
25396940271Sjordan 
25496940271Sjordan 	_put64(&dte->dw0, ov);
25596940271Sjordan }
25696940271Sjordan 
25796940271Sjordan /* Set Page Table Levels Mask */
25896940271Sjordan static inline void
dte_set_mode(struct ivhd_dte * dte,int mode)25996940271Sjordan dte_set_mode(struct ivhd_dte *dte, int mode)
26096940271Sjordan {
26196940271Sjordan 	iommu_rmw32(&dte->dw0, DTE_LEVEL_MASK, DTE_LEVEL_SHIFT, mode);
26296940271Sjordan }
26396940271Sjordan 
26496940271Sjordan static inline void
dte_set_tv(struct ivhd_dte * dte)26596940271Sjordan dte_set_tv(struct ivhd_dte *dte)
26696940271Sjordan {
26796940271Sjordan 	dte->dw0 |= DTE_TV;
26896940271Sjordan }
26996940271Sjordan 
27096940271Sjordan /* Set Device Table Entry valid.
27196940271Sjordan  * Domain/Level/Mode/PageTable should already be set
27296940271Sjordan  */
27396940271Sjordan static inline void
dte_set_valid(struct ivhd_dte * dte)27496940271Sjordan dte_set_valid(struct ivhd_dte *dte)
27596940271Sjordan {
27696940271Sjordan 	dte->dw0 |= DTE_V;
27796940271Sjordan }
27896940271Sjordan 
27996940271Sjordan /* Check if Device Table Entry is valid */
28096940271Sjordan static inline int
dte_is_valid(struct ivhd_dte * dte)28196940271Sjordan dte_is_valid(struct ivhd_dte *dte)
28296940271Sjordan {
28396940271Sjordan 	return (dte->dw0 & DTE_V);
28496940271Sjordan }
28596940271Sjordan 
28696940271Sjordan /*=========================================
28796940271Sjordan  * COMMAND
28896940271Sjordan  *=========================================*/
28996940271Sjordan struct ivhd_command {
29096940271Sjordan 	uint32_t dw0;
29196940271Sjordan 	uint32_t dw1;
29296940271Sjordan 	uint32_t dw2;
29396940271Sjordan 	uint32_t dw3;
29496940271Sjordan } __packed;
29596940271Sjordan 
29696940271Sjordan #define CMD_SHIFT 28
29796940271Sjordan 
29896940271Sjordan enum {
29996940271Sjordan 	COMPLETION_WAIT			= 0x01,
30096940271Sjordan 	INVALIDATE_DEVTAB_ENTRY		= 0x02,
30196940271Sjordan 	INVALIDATE_IOMMU_PAGES		= 0x03,
30296940271Sjordan 	INVALIDATE_IOTLB_PAGES		= 0x04,
30396940271Sjordan 	INVALIDATE_INTERRUPT_TABLE	= 0x05,
30496940271Sjordan 	PREFETCH_IOMMU_PAGES		= 0x06,
30596940271Sjordan 	COMPLETE_PPR_REQUEST		= 0x07,
30696940271Sjordan 	INVALIDATE_IOMMU_ALL		= 0x08,
30796940271Sjordan };
30896940271Sjordan 
30996940271Sjordan /*=========================================
31096940271Sjordan  * EVENT
31196940271Sjordan  *=========================================*/
31296940271Sjordan struct ivhd_event {
31396940271Sjordan 	uint32_t dw0;
31496940271Sjordan 	uint32_t dw1;
31596940271Sjordan 	uint32_t dw2;
31696940271Sjordan 	uint32_t dw3;
31796940271Sjordan } __packed;
31896940271Sjordan 
31996940271Sjordan #define EVT_TYPE_SHIFT		28
32096940271Sjordan #define EVT_TYPE_MASK		0xF
32196940271Sjordan #define EVT_SID_SHIFT		0
32296940271Sjordan #define EVT_SID_MASK		0xFFFF
32396940271Sjordan #define EVT_DID_SHIFT		0
32496940271Sjordan #define EVT_DID_MASK		0xFFFF
32596940271Sjordan #define EVT_FLAG_SHIFT		16
32696940271Sjordan #define EVT_FLAG_MASK		0xFFF
32796940271Sjordan 
32896940271Sjordan /* IOMMU Fault reasons */
32996940271Sjordan enum {
33096940271Sjordan 	ILLEGAL_DEV_TABLE_ENTRY		= 0x1,
33196940271Sjordan 	IO_PAGE_FAULT			= 0x2,
33296940271Sjordan 	DEV_TAB_HARDWARE_ERROR		= 0x3,
33396940271Sjordan 	PAGE_TAB_HARDWARE_ERROR		= 0x4,
33496940271Sjordan 	ILLEGAL_COMMAND_ERROR		= 0x5,
33596940271Sjordan 	COMMAND_HARDWARE_ERROR		= 0x6,
33696940271Sjordan 	IOTLB_INV_TIMEOUT		= 0x7,
33796940271Sjordan 	INVALID_DEVICE_REQUEST		= 0x8,
33896940271Sjordan };
33996940271Sjordan 
34096940271Sjordan #define EVT_GN			(1L << 16)
34196940271Sjordan #define EVT_NX			(1L << 17)
34296940271Sjordan #define EVT_US			(1L << 18)
34396940271Sjordan #define EVT_I			(1L << 19)
34496940271Sjordan #define EVT_PR			(1L << 20)
34596940271Sjordan #define EVT_RW			(1L << 21)
34696940271Sjordan #define EVT_PE			(1L << 22)
34796940271Sjordan #define EVT_RZ			(1L << 23)
34896940271Sjordan #define EVT_TR			(1L << 24)
34996940271Sjordan 
35096940271Sjordan struct iommu_softc;
35196940271Sjordan 
35296940271Sjordan int	ivhd_flush_devtab(struct iommu_softc *, int);
35396940271Sjordan int	ivhd_invalidate_iommu_all(struct iommu_softc *);
35496940271Sjordan int	ivhd_invalidate_interrupt_table(struct iommu_softc *, int);
35596940271Sjordan int	ivhd_issue_command(struct iommu_softc *, const struct ivhd_command *, int);
35696940271Sjordan int	ivhd_invalidate_domain(struct iommu_softc *, int);
35796940271Sjordan 
35896940271Sjordan void	_dumppte(struct pte_entry *, int, vaddr_t);
35996940271Sjordan 
36096940271Sjordan #endif
361