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); |
