Lines 49-54
Link Here
|
49 |
* Architecture Spec, September 2008. |
49 |
* Architecture Spec, September 2008. |
50 |
*/ |
50 |
*/ |
51 |
|
51 |
|
|
|
52 |
#define VTD_DRHD_INCLUDE_PCI_ALL(Flags) (((Flags) >> 0) & 0x1) |
53 |
|
52 |
/* Section 10.4 "Register Descriptions" */ |
54 |
/* Section 10.4 "Register Descriptions" */ |
53 |
struct vtdmap { |
55 |
struct vtdmap { |
54 |
volatile uint32_t version; |
56 |
volatile uint32_t version; |
Lines 114-123
Link Here
|
114 |
static SLIST_HEAD(, domain) domhead; |
116 |
static SLIST_HEAD(, domain) domhead; |
115 |
|
117 |
|
116 |
#define DRHD_MAX_UNITS 8 |
118 |
#define DRHD_MAX_UNITS 8 |
117 |
static int drhd_num; |
119 |
static ACPI_DMAR_HARDWARE_UNIT *drhds[DRHD_MAX_UNITS]; |
118 |
static struct vtdmap *vtdmaps[DRHD_MAX_UNITS]; |
120 |
static int drhd_num; |
119 |
static int max_domains; |
121 |
static struct vtdmap *vtdmaps[DRHD_MAX_UNITS]; |
120 |
typedef int (*drhd_ident_func_t)(void); |
122 |
static int max_domains; |
|
|
123 |
typedef int (*drhd_ident_func_t)(void); |
121 |
|
124 |
|
122 |
static uint64_t root_table[PAGE_SIZE / sizeof(uint64_t)] __aligned(4096); |
125 |
static uint64_t root_table[PAGE_SIZE / sizeof(uint64_t)] __aligned(4096); |
123 |
static uint64_t ctx_tables[256][PAGE_SIZE / sizeof(uint64_t)] __aligned(4096); |
126 |
static uint64_t ctx_tables[256][PAGE_SIZE / sizeof(uint64_t)] __aligned(4096); |
Lines 173-178
Link Here
|
173 |
return (id); |
176 |
return (id); |
174 |
} |
177 |
} |
175 |
|
178 |
|
|
|
179 |
static struct vtdmap * |
180 |
vtd_device_scope(uint16_t rid) |
181 |
{ |
182 |
int i, remaining, pathremaining; |
183 |
char *end, *pathend; |
184 |
struct vtdmap *vtdmap; |
185 |
ACPI_DMAR_HARDWARE_UNIT *drhd; |
186 |
ACPI_DMAR_DEVICE_SCOPE *device_scope; |
187 |
ACPI_DMAR_PCI_PATH *path; |
188 |
|
189 |
for (i = 0; i < drhd_num; i++) { |
190 |
drhd = drhds[i]; |
191 |
|
192 |
if (VTD_DRHD_INCLUDE_PCI_ALL(drhd->Flags)) { |
193 |
/* |
194 |
* From Intel VT-d arch spec, version 3.0: |
195 |
* If a DRHD structure with INCLUDE_PCI_ALL flag Set is reported |
196 |
* for a Segment, it must be enumerated by BIOS after all other |
197 |
* DRHD structures for the same Segment. |
198 |
*/ |
199 |
vtdmap = vtdmaps[i]; |
200 |
return(vtdmap); |
201 |
} |
202 |
|
203 |
end = (char *)drhd + drhd->Header.Length; |
204 |
remaining = drhd->Header.Length - sizeof(ACPI_DMAR_HARDWARE_UNIT); |
205 |
while (remaining > sizeof(ACPI_DMAR_DEVICE_SCOPE)) { |
206 |
device_scope = (ACPI_DMAR_DEVICE_SCOPE *)(end - remaining); |
207 |
remaining -= device_scope->Length; |
208 |
|
209 |
switch (device_scope->EntryType){ |
210 |
/* 0x01 and 0x02 are PCI device entries */ |
211 |
case 0x01: |
212 |
case 0x02: |
213 |
break; |
214 |
default: |
215 |
continue; |
216 |
} |
217 |
|
218 |
if (PCI_RID2BUS(rid) != device_scope->Bus) |
219 |
continue; |
220 |
|
221 |
pathend = (char *)device_scope + device_scope->Length; |
222 |
pathremaining = device_scope->Length - sizeof(ACPI_DMAR_DEVICE_SCOPE); |
223 |
while (pathremaining >= sizeof(ACPI_DMAR_PCI_PATH)) { |
224 |
path = (ACPI_DMAR_PCI_PATH *)(pathend - pathremaining); |
225 |
pathremaining -= sizeof(ACPI_DMAR_PCI_PATH); |
226 |
|
227 |
if (PCI_RID2SLOT(rid) != path->Device) |
228 |
continue; |
229 |
if (PCI_RID2FUNC(rid) != path->Function) |
230 |
continue; |
231 |
|
232 |
vtdmap = vtdmaps[i]; |
233 |
return (vtdmap); |
234 |
} |
235 |
} |
236 |
} |
237 |
|
238 |
/* No matching scope */ |
239 |
return (NULL); |
240 |
} |
241 |
|
176 |
static void |
242 |
static void |
177 |
vtd_wbflush(struct vtdmap *vtdmap) |
243 |
vtd_wbflush(struct vtdmap *vtdmap) |
178 |
{ |
244 |
{ |
Lines 238-244
Link Here
|
238 |
static int |
304 |
static int |
239 |
vtd_init(void) |
305 |
vtd_init(void) |
240 |
{ |
306 |
{ |
241 |
int i, units, remaining; |
307 |
int i, units, remaining, tmp; |
242 |
struct vtdmap *vtdmap; |
308 |
struct vtdmap *vtdmap; |
243 |
vm_paddr_t ctx_paddr; |
309 |
vm_paddr_t ctx_paddr; |
244 |
char *end, envname[32]; |
310 |
char *end, envname[32]; |
Lines 289-296
Link Here
|
289 |
break; |
355 |
break; |
290 |
|
356 |
|
291 |
drhd = (ACPI_DMAR_HARDWARE_UNIT *)hdr; |
357 |
drhd = (ACPI_DMAR_HARDWARE_UNIT *)hdr; |
292 |
vtdmaps[units++] = (struct vtdmap *)PHYS_TO_DMAP(drhd->Address); |
358 |
drhds[units] = drhd; |
293 |
if (units >= DRHD_MAX_UNITS) |
359 |
vtdmaps[units] = (struct vtdmap *)PHYS_TO_DMAP(drhd->Address); |
|
|
360 |
if (++units >= DRHD_MAX_UNITS) |
294 |
break; |
361 |
break; |
295 |
remaining -= hdr->Length; |
362 |
remaining -= hdr->Length; |
296 |
} |
363 |
} |
Lines 300-311
Link Here
|
300 |
|
367 |
|
301 |
skip_dmar: |
368 |
skip_dmar: |
302 |
drhd_num = units; |
369 |
drhd_num = units; |
303 |
vtdmap = vtdmaps[0]; |
|
|
304 |
|
370 |
|
305 |
if (VTD_CAP_CM(vtdmap->cap) != 0) |
371 |
max_domains = 64 * 1024; /* maximum valid value */ |
306 |
panic("vtd_init: invalid caching mode"); |
372 |
for (i = 0; i < drhd_num; i++){ |
|
|
373 |
vtdmap = vtdmaps[i]; |
374 |
|
375 |
if (VTD_CAP_CM(vtdmap->cap) != 0) |
376 |
panic("vtd_init: invalid caching mode"); |
307 |
|
377 |
|
308 |
max_domains = vtd_max_domains(vtdmap); |
378 |
/* take most compatible (minimum) value */ |
|
|
379 |
if ((tmp = vtd_max_domains(vtdmap)) < max_domains) |
380 |
max_domains = tmp; |
381 |
} |
309 |
|
382 |
|
310 |
/* |
383 |
/* |
311 |
* Set up the root-table to point to the context-entry tables |
384 |
* Set up the root-table to point to the context-entry tables |
Lines 371-377
Link Here
|
371 |
struct vtdmap *vtdmap; |
444 |
struct vtdmap *vtdmap; |
372 |
uint8_t bus; |
445 |
uint8_t bus; |
373 |
|
446 |
|
374 |
vtdmap = vtdmaps[0]; |
|
|
375 |
bus = PCI_RID2BUS(rid); |
447 |
bus = PCI_RID2BUS(rid); |
376 |
ctxp = ctx_tables[bus]; |
448 |
ctxp = ctx_tables[bus]; |
377 |
pt_paddr = vtophys(dom->ptp); |
449 |
pt_paddr = vtophys(dom->ptp); |
Lines 383-388
Link Here
|
383 |
(uint16_t)(ctxp[idx + 1] >> 8)); |
455 |
(uint16_t)(ctxp[idx + 1] >> 8)); |
384 |
} |
456 |
} |
385 |
|
457 |
|
|
|
458 |
if ((vtdmap = vtd_device_scope(rid)) == NULL) |
459 |
panic("vtd_add_device: device %x is not in scope for " |
460 |
"any DMA remapping unit", rid); |
461 |
|
386 |
/* |
462 |
/* |
387 |
* Order is important. The 'present' bit is set only after all fields |
463 |
* Order is important. The 'present' bit is set only after all fields |
388 |
* of the context pointer are initialized. |
464 |
* of the context pointer are initialized. |
Lines 566-573
Link Here
|
566 |
if (drhd_num <= 0) |
642 |
if (drhd_num <= 0) |
567 |
panic("vtd_create_domain: no dma remapping hardware available"); |
643 |
panic("vtd_create_domain: no dma remapping hardware available"); |
568 |
|
644 |
|
569 |
vtdmap = vtdmaps[0]; |
|
|
570 |
|
571 |
/* |
645 |
/* |
572 |
* Calculate AGAW. |
646 |
* Calculate AGAW. |
573 |
* Section 3.4.2 "Adjusted Guest Address Width", Architecture Spec. |
647 |
* Section 3.4.2 "Adjusted Guest Address Width", Architecture Spec. |
Lines 592-598
Link Here
|
592 |
pt_levels = 2; |
666 |
pt_levels = 2; |
593 |
sagaw = 30; |
667 |
sagaw = 30; |
594 |
addrwidth = 0; |
668 |
addrwidth = 0; |
595 |
tmp = VTD_CAP_SAGAW(vtdmap->cap); |
669 |
|
|
|
670 |
tmp = ~0; |
671 |
for (i = 0; i < drhd_num; i++) { |
672 |
vtdmap = vtdmaps[i]; |
673 |
/* take most compatible value */ |
674 |
tmp &= VTD_CAP_SAGAW(vtdmap->cap); |
675 |
} |
676 |
|
596 |
for (i = 0; i < 5; i++) { |
677 |
for (i = 0; i < 5; i++) { |
597 |
if ((tmp & (1 << i)) != 0 && sagaw >= agaw) |
678 |
if ((tmp & (1 << i)) != 0 && sagaw >= agaw) |
598 |
break; |
679 |
break; |
Lines 604-611
Link Here
|
604 |
} |
685 |
} |
605 |
|
686 |
|
606 |
if (i >= 5) { |
687 |
if (i >= 5) { |
607 |
panic("vtd_create_domain: SAGAW 0x%lx does not support AGAW %d", |
688 |
panic("vtd_create_domain: SAGAW 0x%x does not support AGAW %d", |
608 |
VTD_CAP_SAGAW(vtdmap->cap), agaw); |
689 |
tmp, agaw); |
609 |
} |
690 |
} |
610 |
|
691 |
|
611 |
dom = malloc(sizeof(struct domain), M_VTD, M_ZERO | M_WAITOK); |
692 |
dom = malloc(sizeof(struct domain), M_VTD, M_ZERO | M_WAITOK); |
Lines 632-638
Link Here
|
632 |
* There is not any code to deal with the demotion at the moment |
713 |
* There is not any code to deal with the demotion at the moment |
633 |
* so we disable superpage mappings altogether. |
714 |
* so we disable superpage mappings altogether. |
634 |
*/ |
715 |
*/ |
635 |
dom->spsmask = VTD_CAP_SPS(vtdmap->cap); |
716 |
dom->spsmask = ~0; |
|
|
717 |
for (i = 0; i < drhd_num; i++) { |
718 |
vtdmap = vtdmaps[i]; |
719 |
/* take most compatible value */ |
720 |
dom->spsmask &= VTD_CAP_SPS(vtdmap->cap); |
721 |
} |
636 |
#endif |
722 |
#endif |
637 |
|
723 |
|
638 |
SLIST_INSERT_HEAD(&domhead, dom, next); |
724 |
SLIST_INSERT_HEAD(&domhead, dom, next); |