diff options
author | Yu Zhao <yu.zhao@intel.com> | 2009-05-18 01:51:34 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-05-18 09:45:09 -0400 |
commit | aa5d2b515b6fca5f8a56eac84f7fa0a68c1ce9b7 (patch) | |
tree | c98753254dfe2f3e54a4c38c9191ab5f4afb4c39 | |
parent | e277d2fc79d6abb86fafadb58dca0b9c498a9aa7 (diff) |
VT-d: parse ATSR in DMA Remapping Reporting Structure
Parse the Root Port ATS Capability Reporting Structure in the DMA
Remapping Reporting Structure ACPI table.
Signed-off-by: Yu Zhao <yu.zhao@intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r-- | drivers/pci/dmar.c | 112 | ||||
-rw-r--r-- | include/linux/dmar.h | 9 | ||||
-rw-r--r-- | include/linux/intel-iommu.h | 1 |
3 files changed, 116 insertions, 6 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index f23460a5d106..6d7f9619b8a9 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -267,6 +267,84 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) | |||
267 | } | 267 | } |
268 | return ret; | 268 | return ret; |
269 | } | 269 | } |
270 | |||
271 | static LIST_HEAD(dmar_atsr_units); | ||
272 | |||
273 | static int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr) | ||
274 | { | ||
275 | struct acpi_dmar_atsr *atsr; | ||
276 | struct dmar_atsr_unit *atsru; | ||
277 | |||
278 | atsr = container_of(hdr, struct acpi_dmar_atsr, header); | ||
279 | atsru = kzalloc(sizeof(*atsru), GFP_KERNEL); | ||
280 | if (!atsru) | ||
281 | return -ENOMEM; | ||
282 | |||
283 | atsru->hdr = hdr; | ||
284 | atsru->include_all = atsr->flags & 0x1; | ||
285 | |||
286 | list_add(&atsru->list, &dmar_atsr_units); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) | ||
292 | { | ||
293 | int rc; | ||
294 | struct acpi_dmar_atsr *atsr; | ||
295 | |||
296 | if (atsru->include_all) | ||
297 | return 0; | ||
298 | |||
299 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); | ||
300 | rc = dmar_parse_dev_scope((void *)(atsr + 1), | ||
301 | (void *)atsr + atsr->header.length, | ||
302 | &atsru->devices_cnt, &atsru->devices, | ||
303 | atsr->segment); | ||
304 | if (rc || !atsru->devices_cnt) { | ||
305 | list_del(&atsru->list); | ||
306 | kfree(atsru); | ||
307 | } | ||
308 | |||
309 | return rc; | ||
310 | } | ||
311 | |||
312 | int dmar_find_matched_atsr_unit(struct pci_dev *dev) | ||
313 | { | ||
314 | int i; | ||
315 | struct pci_bus *bus; | ||
316 | struct acpi_dmar_atsr *atsr; | ||
317 | struct dmar_atsr_unit *atsru; | ||
318 | |||
319 | list_for_each_entry(atsru, &dmar_atsr_units, list) { | ||
320 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); | ||
321 | if (atsr->segment == pci_domain_nr(dev->bus)) | ||
322 | goto found; | ||
323 | } | ||
324 | |||
325 | return 0; | ||
326 | |||
327 | found: | ||
328 | for (bus = dev->bus; bus; bus = bus->parent) { | ||
329 | struct pci_dev *bridge = bus->self; | ||
330 | |||
331 | if (!bridge || !bridge->is_pcie || | ||
332 | bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) | ||
333 | return 0; | ||
334 | |||
335 | if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { | ||
336 | for (i = 0; i < atsru->devices_cnt; i++) | ||
337 | if (atsru->devices[i] == bridge) | ||
338 | return 1; | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | if (atsru->include_all) | ||
344 | return 1; | ||
345 | |||
346 | return 0; | ||
347 | } | ||
270 | #endif | 348 | #endif |
271 | 349 | ||
272 | static void __init | 350 | static void __init |
@@ -274,22 +352,28 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | |||
274 | { | 352 | { |
275 | struct acpi_dmar_hardware_unit *drhd; | 353 | struct acpi_dmar_hardware_unit *drhd; |
276 | struct acpi_dmar_reserved_memory *rmrr; | 354 | struct acpi_dmar_reserved_memory *rmrr; |
355 | struct acpi_dmar_atsr *atsr; | ||
277 | 356 | ||
278 | switch (header->type) { | 357 | switch (header->type) { |
279 | case ACPI_DMAR_TYPE_HARDWARE_UNIT: | 358 | case ACPI_DMAR_TYPE_HARDWARE_UNIT: |
280 | drhd = (struct acpi_dmar_hardware_unit *)header; | 359 | drhd = container_of(header, struct acpi_dmar_hardware_unit, |
360 | header); | ||
281 | printk (KERN_INFO PREFIX | 361 | printk (KERN_INFO PREFIX |
282 | "DRHD (flags: 0x%08x)base: 0x%016Lx\n", | 362 | "DRHD base: %#016Lx flags: %#x\n", |
283 | drhd->flags, (unsigned long long)drhd->address); | 363 | (unsigned long long)drhd->address, drhd->flags); |
284 | break; | 364 | break; |
285 | case ACPI_DMAR_TYPE_RESERVED_MEMORY: | 365 | case ACPI_DMAR_TYPE_RESERVED_MEMORY: |
286 | rmrr = (struct acpi_dmar_reserved_memory *)header; | 366 | rmrr = container_of(header, struct acpi_dmar_reserved_memory, |
287 | 367 | header); | |
288 | printk (KERN_INFO PREFIX | 368 | printk (KERN_INFO PREFIX |
289 | "RMRR base: 0x%016Lx end: 0x%016Lx\n", | 369 | "RMRR base: %#016Lx end: %#016Lx\n", |
290 | (unsigned long long)rmrr->base_address, | 370 | (unsigned long long)rmrr->base_address, |
291 | (unsigned long long)rmrr->end_address); | 371 | (unsigned long long)rmrr->end_address); |
292 | break; | 372 | break; |
373 | case ACPI_DMAR_TYPE_ATSR: | ||
374 | atsr = container_of(header, struct acpi_dmar_atsr, header); | ||
375 | printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); | ||
376 | break; | ||
293 | } | 377 | } |
294 | } | 378 | } |
295 | 379 | ||
@@ -363,6 +447,11 @@ parse_dmar_table(void) | |||
363 | ret = dmar_parse_one_rmrr(entry_header); | 447 | ret = dmar_parse_one_rmrr(entry_header); |
364 | #endif | 448 | #endif |
365 | break; | 449 | break; |
450 | case ACPI_DMAR_TYPE_ATSR: | ||
451 | #ifdef CONFIG_DMAR | ||
452 | ret = dmar_parse_one_atsr(entry_header); | ||
453 | #endif | ||
454 | break; | ||
366 | default: | 455 | default: |
367 | printk(KERN_WARNING PREFIX | 456 | printk(KERN_WARNING PREFIX |
368 | "Unknown DMAR structure type\n"); | 457 | "Unknown DMAR structure type\n"); |
@@ -431,11 +520,19 @@ int __init dmar_dev_scope_init(void) | |||
431 | #ifdef CONFIG_DMAR | 520 | #ifdef CONFIG_DMAR |
432 | { | 521 | { |
433 | struct dmar_rmrr_unit *rmrr, *rmrr_n; | 522 | struct dmar_rmrr_unit *rmrr, *rmrr_n; |
523 | struct dmar_atsr_unit *atsr, *atsr_n; | ||
524 | |||
434 | list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) { | 525 | list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) { |
435 | ret = rmrr_parse_dev(rmrr); | 526 | ret = rmrr_parse_dev(rmrr); |
436 | if (ret) | 527 | if (ret) |
437 | return ret; | 528 | return ret; |
438 | } | 529 | } |
530 | |||
531 | list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) { | ||
532 | ret = atsr_parse_dev(atsr); | ||
533 | if (ret) | ||
534 | return ret; | ||
535 | } | ||
439 | } | 536 | } |
440 | #endif | 537 | #endif |
441 | 538 | ||
@@ -468,6 +565,9 @@ int __init dmar_table_init(void) | |||
468 | #ifdef CONFIG_DMAR | 565 | #ifdef CONFIG_DMAR |
469 | if (list_empty(&dmar_rmrr_units)) | 566 | if (list_empty(&dmar_rmrr_units)) |
470 | printk(KERN_INFO PREFIX "No RMRR found\n"); | 567 | printk(KERN_INFO PREFIX "No RMRR found\n"); |
568 | |||
569 | if (list_empty(&dmar_atsr_units)) | ||
570 | printk(KERN_INFO PREFIX "No ATSR found\n"); | ||
471 | #endif | 571 | #endif |
472 | 572 | ||
473 | #ifdef CONFIG_INTR_REMAP | 573 | #ifdef CONFIG_INTR_REMAP |
diff --git a/include/linux/dmar.h b/include/linux/dmar.h index e397dc342cda..7c9a207e5da6 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h | |||
@@ -185,6 +185,15 @@ struct dmar_rmrr_unit { | |||
185 | 185 | ||
186 | #define for_each_rmrr_units(rmrr) \ | 186 | #define for_each_rmrr_units(rmrr) \ |
187 | list_for_each_entry(rmrr, &dmar_rmrr_units, list) | 187 | list_for_each_entry(rmrr, &dmar_rmrr_units, list) |
188 | |||
189 | struct dmar_atsr_unit { | ||
190 | struct list_head list; /* list of ATSR units */ | ||
191 | struct acpi_dmar_header *hdr; /* ACPI header */ | ||
192 | struct pci_dev **devices; /* target devices */ | ||
193 | int devices_cnt; /* target device count */ | ||
194 | u8 include_all:1; /* include all ports */ | ||
195 | }; | ||
196 | |||
188 | /* Intel DMAR initialization functions */ | 197 | /* Intel DMAR initialization functions */ |
189 | extern int intel_iommu_init(void); | 198 | extern int intel_iommu_init(void); |
190 | #else | 199 | #else |
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index 29e05a034c09..0a1939f200fc 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h | |||
@@ -331,6 +331,7 @@ static inline void __iommu_flush_cache( | |||
331 | } | 331 | } |
332 | 332 | ||
333 | extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); | 333 | extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); |
334 | extern int dmar_find_matched_atsr_unit(struct pci_dev *dev); | ||
334 | 335 | ||
335 | extern int alloc_iommu(struct dmar_drhd_unit *drhd); | 336 | extern int alloc_iommu(struct dmar_drhd_unit *drhd); |
336 | extern void free_iommu(struct intel_iommu *iommu); | 337 | extern void free_iommu(struct intel_iommu *iommu); |