Commit | Line | Data |
---|---|---|
56283174 LB |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | |
02f3effd | 3 | * pasid.h - PASID idr, table and entry header |
56283174 LB |
4 | * |
5 | * Copyright (C) 2018 Intel Corporation | |
6 | * | |
7 | * Author: Lu Baolu <baolu.lu@linux.intel.com> | |
8 | */ | |
9 | ||
10 | #ifndef __INTEL_PASID_H | |
11 | #define __INTEL_PASID_H | |
12 | ||
0bbeb01a LB |
13 | #define PASID_MAX 0x100000 |
14 | #define PASID_PTE_MASK 0x3F | |
15 | #define PASID_PTE_PRESENT 1 | |
37e91bd4 | 16 | #define PASID_PTE_FPD 2 |
0bbeb01a LB |
17 | #define PDE_PFN_MASK PAGE_MASK |
18 | #define PASID_PDE_SHIFT 6 | |
7373a8cc | 19 | #define MAX_NR_PASID_BITS 20 |
cdd3a249 SPP |
20 | #define PASID_TBL_ENTRIES BIT(PASID_PDE_SHIFT) |
21 | ||
22 | #define is_pasid_enabled(entry) (((entry)->lo >> 3) & 0x1) | |
23 | #define get_pasid_dir_size(entry) (1 << ((((entry)->lo >> 9) & 0x7) + 7)) | |
56283174 | 24 | |
3b33d4ab LB |
25 | /* |
26 | * Domain ID reserved for pasid entries programmed for first-level | |
27 | * only and pass-through transfer modes. | |
28 | */ | |
29 | #define FLPT_DEFAULT_DID 1 | |
98f7b0db | 30 | #define NUM_RESERVED_DID 2 |
3b33d4ab | 31 | |
b0d1f874 | 32 | #define PASID_FLAG_NESTED BIT(1) |
6c00612d | 33 | #define PASID_FLAG_PAGE_SNOOP BIT(2) |
437f35e1 | 34 | |
87208f22 LB |
35 | /* |
36 | * The PASID_FLAG_FL5LP flag Indicates using 5-level paging for first- | |
37 | * level translation, otherwise, 4-level paging will be used. | |
38 | */ | |
39 | #define PASID_FLAG_FL5LP BIT(1) | |
40 | ||
0bbeb01a | 41 | struct pasid_dir_entry { |
cc580e41 LB |
42 | u64 val; |
43 | }; | |
44 | ||
0bbeb01a LB |
45 | struct pasid_entry { |
46 | u64 val[8]; | |
47 | }; | |
48 | ||
b0d1f874 JP |
49 | #define PASID_ENTRY_PGTT_FL_ONLY (1) |
50 | #define PASID_ENTRY_PGTT_SL_ONLY (2) | |
51 | #define PASID_ENTRY_PGTT_NESTED (3) | |
52 | #define PASID_ENTRY_PGTT_PT (4) | |
53 | ||
cc580e41 LB |
54 | /* The representative of a PASID table */ |
55 | struct pasid_table { | |
56 | void *table; /* pasid table pointer */ | |
57 | int order; /* page order of pasid table */ | |
c7b6bac9 | 58 | u32 max_pasid; /* max pasid */ |
cc580e41 LB |
59 | }; |
60 | ||
cdd3a249 SPP |
61 | /* Get PRESENT bit of a PASID directory entry. */ |
62 | static inline bool pasid_pde_is_present(struct pasid_dir_entry *pde) | |
63 | { | |
64 | return READ_ONCE(pde->val) & PASID_PTE_PRESENT; | |
65 | } | |
66 | ||
67 | /* Get PASID table from a PASID directory entry. */ | |
68 | static inline struct pasid_entry * | |
69 | get_pasid_table_from_pde(struct pasid_dir_entry *pde) | |
70 | { | |
71 | if (!pasid_pde_is_present(pde)) | |
72 | return NULL; | |
73 | ||
74 | return phys_to_virt(READ_ONCE(pde->val) & PDE_PFN_MASK); | |
75 | } | |
76 | ||
77 | /* Get PRESENT bit of a PASID table entry. */ | |
78 | static inline bool pasid_pte_is_present(struct pasid_entry *pte) | |
79 | { | |
80 | return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT; | |
81 | } | |
82 | ||
8798d364 LY |
83 | /* Get PGTT field of a PASID table entry */ |
84 | static inline u16 pasid_pte_get_pgtt(struct pasid_entry *pte) | |
85 | { | |
86 | return (u16)((READ_ONCE(pte->val[0]) >> 6) & 0x7); | |
87 | } | |
88 | ||
80b79e14 LB |
89 | static inline void pasid_clear_entry(struct pasid_entry *pe) |
90 | { | |
91 | WRITE_ONCE(pe->val[0], 0); | |
92 | WRITE_ONCE(pe->val[1], 0); | |
93 | WRITE_ONCE(pe->val[2], 0); | |
94 | WRITE_ONCE(pe->val[3], 0); | |
95 | WRITE_ONCE(pe->val[4], 0); | |
96 | WRITE_ONCE(pe->val[5], 0); | |
97 | WRITE_ONCE(pe->val[6], 0); | |
98 | WRITE_ONCE(pe->val[7], 0); | |
99 | } | |
100 | ||
101 | static inline void pasid_clear_entry_with_fpd(struct pasid_entry *pe) | |
102 | { | |
103 | WRITE_ONCE(pe->val[0], PASID_PTE_FPD); | |
104 | WRITE_ONCE(pe->val[1], 0); | |
105 | WRITE_ONCE(pe->val[2], 0); | |
106 | WRITE_ONCE(pe->val[3], 0); | |
107 | WRITE_ONCE(pe->val[4], 0); | |
108 | WRITE_ONCE(pe->val[5], 0); | |
109 | WRITE_ONCE(pe->val[6], 0); | |
110 | WRITE_ONCE(pe->val[7], 0); | |
111 | } | |
112 | ||
113 | static inline void pasid_set_bits(u64 *ptr, u64 mask, u64 bits) | |
114 | { | |
115 | u64 old; | |
116 | ||
117 | old = READ_ONCE(*ptr); | |
118 | WRITE_ONCE(*ptr, (old & ~mask) | bits); | |
119 | } | |
120 | ||
121 | static inline u64 pasid_get_bits(u64 *ptr) | |
122 | { | |
123 | return READ_ONCE(*ptr); | |
124 | } | |
125 | ||
126 | /* | |
127 | * Setup the DID(Domain Identifier) field (Bit 64~79) of scalable mode | |
128 | * PASID entry. | |
129 | */ | |
130 | static inline void | |
131 | pasid_set_domain_id(struct pasid_entry *pe, u64 value) | |
132 | { | |
133 | pasid_set_bits(&pe->val[1], GENMASK_ULL(15, 0), value); | |
134 | } | |
135 | ||
136 | /* | |
137 | * Get domain ID value of a scalable mode PASID entry. | |
138 | */ | |
139 | static inline u16 | |
140 | pasid_get_domain_id(struct pasid_entry *pe) | |
141 | { | |
142 | return (u16)(READ_ONCE(pe->val[1]) & GENMASK_ULL(15, 0)); | |
143 | } | |
144 | ||
145 | /* | |
146 | * Setup the SLPTPTR(Second Level Page Table Pointer) field (Bit 12~63) | |
147 | * of a scalable mode PASID entry. | |
148 | */ | |
149 | static inline void | |
150 | pasid_set_slptr(struct pasid_entry *pe, u64 value) | |
151 | { | |
152 | pasid_set_bits(&pe->val[0], VTD_PAGE_MASK, value); | |
153 | } | |
154 | ||
155 | /* | |
156 | * Setup the AW(Address Width) field (Bit 2~4) of a scalable mode PASID | |
157 | * entry. | |
158 | */ | |
159 | static inline void | |
160 | pasid_set_address_width(struct pasid_entry *pe, u64 value) | |
161 | { | |
162 | pasid_set_bits(&pe->val[0], GENMASK_ULL(4, 2), value << 2); | |
163 | } | |
164 | ||
165 | /* | |
166 | * Setup the PGTT(PASID Granular Translation Type) field (Bit 6~8) | |
167 | * of a scalable mode PASID entry. | |
168 | */ | |
169 | static inline void | |
170 | pasid_set_translation_type(struct pasid_entry *pe, u64 value) | |
171 | { | |
172 | pasid_set_bits(&pe->val[0], GENMASK_ULL(8, 6), value << 6); | |
173 | } | |
174 | ||
175 | /* | |
176 | * Enable fault processing by clearing the FPD(Fault Processing | |
177 | * Disable) field (Bit 1) of a scalable mode PASID entry. | |
178 | */ | |
179 | static inline void pasid_set_fault_enable(struct pasid_entry *pe) | |
180 | { | |
181 | pasid_set_bits(&pe->val[0], 1 << 1, 0); | |
182 | } | |
183 | ||
184 | /* | |
185 | * Enable second level A/D bits by setting the SLADE (Second Level | |
186 | * Access Dirty Enable) field (Bit 9) of a scalable mode PASID | |
187 | * entry. | |
188 | */ | |
189 | static inline void pasid_set_ssade(struct pasid_entry *pe) | |
190 | { | |
191 | pasid_set_bits(&pe->val[0], 1 << 9, 1 << 9); | |
192 | } | |
193 | ||
194 | /* | |
195 | * Disable second level A/D bits by clearing the SLADE (Second Level | |
196 | * Access Dirty Enable) field (Bit 9) of a scalable mode PASID | |
197 | * entry. | |
198 | */ | |
199 | static inline void pasid_clear_ssade(struct pasid_entry *pe) | |
200 | { | |
201 | pasid_set_bits(&pe->val[0], 1 << 9, 0); | |
202 | } | |
203 | ||
204 | /* | |
205 | * Checks if second level A/D bits specifically the SLADE (Second Level | |
206 | * Access Dirty Enable) field (Bit 9) of a scalable mode PASID | |
207 | * entry is set. | |
208 | */ | |
209 | static inline bool pasid_get_ssade(struct pasid_entry *pe) | |
210 | { | |
211 | return pasid_get_bits(&pe->val[0]) & (1 << 9); | |
212 | } | |
213 | ||
214 | /* | |
215 | * Setup the SRE(Supervisor Request Enable) field (Bit 128) of a | |
216 | * scalable mode PASID entry. | |
217 | */ | |
218 | static inline void pasid_set_sre(struct pasid_entry *pe) | |
219 | { | |
220 | pasid_set_bits(&pe->val[2], 1 << 0, 1); | |
221 | } | |
222 | ||
223 | /* | |
224 | * Setup the WPE(Write Protect Enable) field (Bit 132) of a | |
225 | * scalable mode PASID entry. | |
226 | */ | |
227 | static inline void pasid_set_wpe(struct pasid_entry *pe) | |
228 | { | |
229 | pasid_set_bits(&pe->val[2], 1 << 4, 1 << 4); | |
230 | } | |
231 | ||
232 | /* | |
233 | * Setup the P(Present) field (Bit 0) of a scalable mode PASID | |
234 | * entry. | |
235 | */ | |
236 | static inline void pasid_set_present(struct pasid_entry *pe) | |
237 | { | |
238 | pasid_set_bits(&pe->val[0], 1 << 0, 1); | |
239 | } | |
240 | ||
241 | /* | |
242 | * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID | |
243 | * entry. | |
244 | */ | |
245 | static inline void pasid_set_page_snoop(struct pasid_entry *pe, bool value) | |
246 | { | |
247 | pasid_set_bits(&pe->val[1], 1 << 23, value << 23); | |
248 | } | |
249 | ||
250 | /* | |
251 | * Setup No Execute Enable bit (Bit 133) of a scalable mode PASID | |
252 | * entry. It is required when XD bit of the first level page table | |
253 | * entry is about to be set. | |
254 | */ | |
255 | static inline void pasid_set_nxe(struct pasid_entry *pe) | |
256 | { | |
257 | pasid_set_bits(&pe->val[2], 1 << 5, 1 << 5); | |
258 | } | |
259 | ||
260 | /* | |
261 | * Setup the Page Snoop (PGSNP) field (Bit 88) of a scalable mode | |
262 | * PASID entry. | |
263 | */ | |
264 | static inline void | |
265 | pasid_set_pgsnp(struct pasid_entry *pe) | |
266 | { | |
267 | pasid_set_bits(&pe->val[1], 1ULL << 24, 1ULL << 24); | |
268 | } | |
269 | ||
270 | /* | |
271 | * Setup the First Level Page table Pointer field (Bit 140~191) | |
272 | * of a scalable mode PASID entry. | |
273 | */ | |
274 | static inline void | |
275 | pasid_set_flptr(struct pasid_entry *pe, u64 value) | |
276 | { | |
277 | pasid_set_bits(&pe->val[2], VTD_PAGE_MASK, value); | |
278 | } | |
279 | ||
280 | /* | |
281 | * Setup the First Level Paging Mode field (Bit 130~131) of a | |
282 | * scalable mode PASID entry. | |
283 | */ | |
284 | static inline void | |
285 | pasid_set_flpm(struct pasid_entry *pe, u64 value) | |
286 | { | |
287 | pasid_set_bits(&pe->val[2], GENMASK_ULL(3, 2), value << 2); | |
288 | } | |
289 | ||
290 | /* | |
291 | * Setup the Extended Access Flag Enable (EAFE) field (Bit 135) | |
292 | * of a scalable mode PASID entry. | |
293 | */ | |
294 | static inline void pasid_set_eafe(struct pasid_entry *pe) | |
295 | { | |
296 | pasid_set_bits(&pe->val[2], 1 << 7, 1 << 7); | |
297 | } | |
298 | ||
c7b6bac9 | 299 | extern unsigned int intel_pasid_max_id; |
cc580e41 LB |
300 | int intel_pasid_alloc_table(struct device *dev); |
301 | void intel_pasid_free_table(struct device *dev); | |
302 | struct pasid_table *intel_pasid_get_table(struct device *dev); | |
437f35e1 LB |
303 | int intel_pasid_setup_first_level(struct intel_iommu *iommu, |
304 | struct device *dev, pgd_t *pgd, | |
c7b6bac9 | 305 | u32 pasid, u16 did, int flags); |
6f7db75e LB |
306 | int intel_pasid_setup_second_level(struct intel_iommu *iommu, |
307 | struct dmar_domain *domain, | |
c7b6bac9 | 308 | struct device *dev, u32 pasid); |
f35f22cc JM |
309 | int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu, |
310 | struct dmar_domain *domain, | |
311 | struct device *dev, u32 pasid, | |
312 | bool enabled); | |
6f7db75e | 313 | int intel_pasid_setup_pass_through(struct intel_iommu *iommu, |
c7b6bac9 | 314 | struct device *dev, u32 pasid); |
111bf85c LB |
315 | int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev, |
316 | u32 pasid, struct dmar_domain *domain); | |
6f7db75e | 317 | void intel_pasid_tear_down_entry(struct intel_iommu *iommu, |
c7b6bac9 | 318 | struct device *dev, u32 pasid, |
37e91bd4 | 319 | bool fault_ignore); |
fc0051cb LB |
320 | void intel_pasid_setup_page_snoop_control(struct intel_iommu *iommu, |
321 | struct device *dev, u32 pasid); | |
56283174 | 322 | #endif /* __INTEL_PASID_H */ |