diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-10-20 15:16:53 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-10-20 15:19:36 -0400 |
commit | b364776ad1208a71f0c53578c84619a395412a8d (patch) | |
tree | d6050e5db6298095324ccb8af7d477684485d52e /drivers/pci/dmar.c | |
parent | 6da0b38f4433fb0f24615449d7966471b6e5eae0 (diff) | |
parent | 6c8909b42fee1be67647bcd2518161a0fa8ca533 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/pci/intel-iommu.c
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r-- | drivers/pci/dmar.c | 119 |
1 files changed, 87 insertions, 32 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index e842e756308a..7b3751136e63 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -188,12 +188,11 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header) | |||
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
190 | 190 | ||
191 | static int __init | 191 | static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) |
192 | dmar_parse_dev(struct dmar_drhd_unit *dmaru) | ||
193 | { | 192 | { |
194 | struct acpi_dmar_hardware_unit *drhd; | 193 | struct acpi_dmar_hardware_unit *drhd; |
195 | static int include_all; | 194 | static int include_all; |
196 | int ret; | 195 | int ret = 0; |
197 | 196 | ||
198 | drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; | 197 | drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; |
199 | 198 | ||
@@ -277,14 +276,15 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | |||
277 | drhd = (struct acpi_dmar_hardware_unit *)header; | 276 | drhd = (struct acpi_dmar_hardware_unit *)header; |
278 | printk (KERN_INFO PREFIX | 277 | printk (KERN_INFO PREFIX |
279 | "DRHD (flags: 0x%08x)base: 0x%016Lx\n", | 278 | "DRHD (flags: 0x%08x)base: 0x%016Lx\n", |
280 | drhd->flags, drhd->address); | 279 | drhd->flags, (unsigned long long)drhd->address); |
281 | break; | 280 | break; |
282 | case ACPI_DMAR_TYPE_RESERVED_MEMORY: | 281 | case ACPI_DMAR_TYPE_RESERVED_MEMORY: |
283 | rmrr = (struct acpi_dmar_reserved_memory *)header; | 282 | rmrr = (struct acpi_dmar_reserved_memory *)header; |
284 | 283 | ||
285 | printk (KERN_INFO PREFIX | 284 | printk (KERN_INFO PREFIX |
286 | "RMRR base: 0x%016Lx end: 0x%016Lx\n", | 285 | "RMRR base: 0x%016Lx end: 0x%016Lx\n", |
287 | rmrr->base_address, rmrr->end_address); | 286 | (unsigned long long)rmrr->base_address, |
287 | (unsigned long long)rmrr->end_address); | ||
288 | break; | 288 | break; |
289 | } | 289 | } |
290 | } | 290 | } |
@@ -304,7 +304,7 @@ parse_dmar_table(void) | |||
304 | if (!dmar) | 304 | if (!dmar) |
305 | return -ENODEV; | 305 | return -ENODEV; |
306 | 306 | ||
307 | if (dmar->width < PAGE_SHIFT_4K - 1) { | 307 | if (dmar->width < PAGE_SHIFT - 1) { |
308 | printk(KERN_WARNING PREFIX "Invalid DMAR haw\n"); | 308 | printk(KERN_WARNING PREFIX "Invalid DMAR haw\n"); |
309 | return -EINVAL; | 309 | return -EINVAL; |
310 | } | 310 | } |
@@ -455,8 +455,8 @@ void __init detect_intel_iommu(void) | |||
455 | 455 | ||
456 | ret = early_dmar_detect(); | 456 | ret = early_dmar_detect(); |
457 | 457 | ||
458 | #ifdef CONFIG_DMAR | ||
459 | { | 458 | { |
459 | #ifdef CONFIG_INTR_REMAP | ||
460 | struct acpi_table_dmar *dmar; | 460 | struct acpi_table_dmar *dmar; |
461 | /* | 461 | /* |
462 | * for now we will disable dma-remapping when interrupt | 462 | * for now we will disable dma-remapping when interrupt |
@@ -465,28 +465,18 @@ void __init detect_intel_iommu(void) | |||
465 | * is added, we will not need this any more. | 465 | * is added, we will not need this any more. |
466 | */ | 466 | */ |
467 | dmar = (struct acpi_table_dmar *) dmar_tbl; | 467 | dmar = (struct acpi_table_dmar *) dmar_tbl; |
468 | if (ret && cpu_has_x2apic && dmar->flags & 0x1) { | 468 | if (ret && cpu_has_x2apic && dmar->flags & 0x1) |
469 | printk(KERN_INFO | 469 | printk(KERN_INFO |
470 | "Queued invalidation will be enabled to support " | 470 | "Queued invalidation will be enabled to support " |
471 | "x2apic and Intr-remapping.\n"); | 471 | "x2apic and Intr-remapping.\n"); |
472 | printk(KERN_INFO | 472 | #endif |
473 | "Disabling IOMMU detection, because of missing " | ||
474 | "queued invalidation support for IOTLB " | ||
475 | "invalidation\n"); | ||
476 | printk(KERN_INFO | ||
477 | "Use \"nox2apic\", if you want to use Intel " | ||
478 | " IOMMU for DMA-remapping and don't care about " | ||
479 | " x2apic support\n"); | ||
480 | |||
481 | dmar_disabled = 1; | ||
482 | return; | ||
483 | } | ||
484 | 473 | ||
474 | #ifdef CONFIG_DMAR | ||
485 | if (ret && !no_iommu && !iommu_detected && !swiotlb && | 475 | if (ret && !no_iommu && !iommu_detected && !swiotlb && |
486 | !dmar_disabled) | 476 | !dmar_disabled) |
487 | iommu_detected = 1; | 477 | iommu_detected = 1; |
488 | } | ||
489 | #endif | 478 | #endif |
479 | } | ||
490 | } | 480 | } |
491 | 481 | ||
492 | 482 | ||
@@ -503,7 +493,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
503 | 493 | ||
504 | iommu->seq_id = iommu_allocated++; | 494 | iommu->seq_id = iommu_allocated++; |
505 | 495 | ||
506 | iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K); | 496 | iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE); |
507 | if (!iommu->reg) { | 497 | if (!iommu->reg) { |
508 | printk(KERN_ERR "IOMMU: can't map the region\n"); | 498 | printk(KERN_ERR "IOMMU: can't map the region\n"); |
509 | goto error; | 499 | goto error; |
@@ -514,8 +504,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
514 | /* the registers might be more than one page */ | 504 | /* the registers might be more than one page */ |
515 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), | 505 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), |
516 | cap_max_fault_reg_offset(iommu->cap)); | 506 | cap_max_fault_reg_offset(iommu->cap)); |
517 | map_size = PAGE_ALIGN_4K(map_size); | 507 | map_size = VTD_PAGE_ALIGN(map_size); |
518 | if (map_size > PAGE_SIZE_4K) { | 508 | if (map_size > VTD_PAGE_SIZE) { |
519 | iounmap(iommu->reg); | 509 | iounmap(iommu->reg); |
520 | iommu->reg = ioremap(drhd->reg_base_addr, map_size); | 510 | iommu->reg = ioremap(drhd->reg_base_addr, map_size); |
521 | if (!iommu->reg) { | 511 | if (!iommu->reg) { |
@@ -526,8 +516,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
526 | 516 | ||
527 | ver = readl(iommu->reg + DMAR_VER_REG); | 517 | ver = readl(iommu->reg + DMAR_VER_REG); |
528 | pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n", | 518 | pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n", |
529 | drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver), | 519 | (unsigned long long)drhd->reg_base_addr, |
530 | iommu->cap, iommu->ecap); | 520 | DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver), |
521 | (unsigned long long)iommu->cap, | ||
522 | (unsigned long long)iommu->ecap); | ||
531 | 523 | ||
532 | spin_lock_init(&iommu->register_lock); | 524 | spin_lock_init(&iommu->register_lock); |
533 | 525 | ||
@@ -580,11 +572,11 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) | |||
580 | 572 | ||
581 | hw = qi->desc; | 573 | hw = qi->desc; |
582 | 574 | ||
583 | spin_lock(&qi->q_lock); | 575 | spin_lock_irqsave(&qi->q_lock, flags); |
584 | while (qi->free_cnt < 3) { | 576 | while (qi->free_cnt < 3) { |
585 | spin_unlock(&qi->q_lock); | 577 | spin_unlock_irqrestore(&qi->q_lock, flags); |
586 | cpu_relax(); | 578 | cpu_relax(); |
587 | spin_lock(&qi->q_lock); | 579 | spin_lock_irqsave(&qi->q_lock, flags); |
588 | } | 580 | } |
589 | 581 | ||
590 | index = qi->free_head; | 582 | index = qi->free_head; |
@@ -605,15 +597,22 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) | |||
605 | qi->free_head = (qi->free_head + 2) % QI_LENGTH; | 597 | qi->free_head = (qi->free_head + 2) % QI_LENGTH; |
606 | qi->free_cnt -= 2; | 598 | qi->free_cnt -= 2; |
607 | 599 | ||
608 | spin_lock_irqsave(&iommu->register_lock, flags); | 600 | spin_lock(&iommu->register_lock); |
609 | /* | 601 | /* |
610 | * update the HW tail register indicating the presence of | 602 | * update the HW tail register indicating the presence of |
611 | * new descriptors. | 603 | * new descriptors. |
612 | */ | 604 | */ |
613 | writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG); | 605 | writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG); |
614 | spin_unlock_irqrestore(&iommu->register_lock, flags); | 606 | spin_unlock(&iommu->register_lock); |
615 | 607 | ||
616 | while (qi->desc_status[wait_index] != QI_DONE) { | 608 | while (qi->desc_status[wait_index] != QI_DONE) { |
609 | /* | ||
610 | * We will leave the interrupts disabled, to prevent interrupt | ||
611 | * context to queue another cmd while a cmd is already submitted | ||
612 | * and waiting for completion on this cpu. This is to avoid | ||
613 | * a deadlock where the interrupt context can wait indefinitely | ||
614 | * for free slots in the queue. | ||
615 | */ | ||
617 | spin_unlock(&qi->q_lock); | 616 | spin_unlock(&qi->q_lock); |
618 | cpu_relax(); | 617 | cpu_relax(); |
619 | spin_lock(&qi->q_lock); | 618 | spin_lock(&qi->q_lock); |
@@ -622,7 +621,7 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) | |||
622 | qi->desc_status[index] = QI_DONE; | 621 | qi->desc_status[index] = QI_DONE; |
623 | 622 | ||
624 | reclaim_free_desc(qi); | 623 | reclaim_free_desc(qi); |
625 | spin_unlock(&qi->q_lock); | 624 | spin_unlock_irqrestore(&qi->q_lock, flags); |
626 | } | 625 | } |
627 | 626 | ||
628 | /* | 627 | /* |
@@ -638,6 +637,62 @@ void qi_global_iec(struct intel_iommu *iommu) | |||
638 | qi_submit_sync(&desc, iommu); | 637 | qi_submit_sync(&desc, iommu); |
639 | } | 638 | } |
640 | 639 | ||
640 | int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm, | ||
641 | u64 type, int non_present_entry_flush) | ||
642 | { | ||
643 | |||
644 | struct qi_desc desc; | ||
645 | |||
646 | if (non_present_entry_flush) { | ||
647 | if (!cap_caching_mode(iommu->cap)) | ||
648 | return 1; | ||
649 | else | ||
650 | did = 0; | ||
651 | } | ||
652 | |||
653 | desc.low = QI_CC_FM(fm) | QI_CC_SID(sid) | QI_CC_DID(did) | ||
654 | | QI_CC_GRAN(type) | QI_CC_TYPE; | ||
655 | desc.high = 0; | ||
656 | |||
657 | qi_submit_sync(&desc, iommu); | ||
658 | |||
659 | return 0; | ||
660 | |||
661 | } | ||
662 | |||
663 | int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, | ||
664 | unsigned int size_order, u64 type, | ||
665 | int non_present_entry_flush) | ||
666 | { | ||
667 | u8 dw = 0, dr = 0; | ||
668 | |||
669 | struct qi_desc desc; | ||
670 | int ih = 0; | ||
671 | |||
672 | if (non_present_entry_flush) { | ||
673 | if (!cap_caching_mode(iommu->cap)) | ||
674 | return 1; | ||
675 | else | ||
676 | did = 0; | ||
677 | } | ||
678 | |||
679 | if (cap_write_drain(iommu->cap)) | ||
680 | dw = 1; | ||
681 | |||
682 | if (cap_read_drain(iommu->cap)) | ||
683 | dr = 1; | ||
684 | |||
685 | desc.low = QI_IOTLB_DID(did) | QI_IOTLB_DR(dr) | QI_IOTLB_DW(dw) | ||
686 | | QI_IOTLB_GRAN(type) | QI_IOTLB_TYPE; | ||
687 | desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih) | ||
688 | | QI_IOTLB_AM(size_order); | ||
689 | |||
690 | qi_submit_sync(&desc, iommu); | ||
691 | |||
692 | return 0; | ||
693 | |||
694 | } | ||
695 | |||
641 | /* | 696 | /* |
642 | * Enable Queued Invalidation interface. This is a must to support | 697 | * Enable Queued Invalidation interface. This is a must to support |
643 | * interrupt-remapping. Also used by DMA-remapping, which replaces | 698 | * interrupt-remapping. Also used by DMA-remapping, which replaces |