diff options
Diffstat (limited to 'drivers/pci/intr_remapping.c')
-rw-r--r-- | drivers/pci/intr_remapping.c | 222 |
1 files changed, 177 insertions, 45 deletions
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index f5e0ea724a6f..4f5b8712931f 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
@@ -10,11 +10,21 @@ | |||
10 | #include <linux/intel-iommu.h> | 10 | #include <linux/intel-iommu.h> |
11 | #include "intr_remapping.h" | 11 | #include "intr_remapping.h" |
12 | #include <acpi/acpi.h> | 12 | #include <acpi/acpi.h> |
13 | #include <asm/pci-direct.h> | ||
14 | #include "pci.h" | ||
13 | 15 | ||
14 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; | 16 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; |
15 | static int ir_ioapic_num; | 17 | static int ir_ioapic_num; |
16 | int intr_remapping_enabled; | 18 | int intr_remapping_enabled; |
17 | 19 | ||
20 | static int disable_intremap; | ||
21 | static __init int setup_nointremap(char *str) | ||
22 | { | ||
23 | disable_intremap = 1; | ||
24 | return 0; | ||
25 | } | ||
26 | early_param("nointremap", setup_nointremap); | ||
27 | |||
18 | struct irq_2_iommu { | 28 | struct irq_2_iommu { |
19 | struct intel_iommu *iommu; | 29 | struct intel_iommu *iommu; |
20 | u16 irte_index; | 30 | u16 irte_index; |
@@ -23,15 +33,12 @@ struct irq_2_iommu { | |||
23 | }; | 33 | }; |
24 | 34 | ||
25 | #ifdef CONFIG_GENERIC_HARDIRQS | 35 | #ifdef CONFIG_GENERIC_HARDIRQS |
26 | static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu) | 36 | static struct irq_2_iommu *get_one_free_irq_2_iommu(int node) |
27 | { | 37 | { |
28 | struct irq_2_iommu *iommu; | 38 | struct irq_2_iommu *iommu; |
29 | int node; | ||
30 | |||
31 | node = cpu_to_node(cpu); | ||
32 | 39 | ||
33 | iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node); | 40 | iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node); |
34 | printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node); | 41 | printk(KERN_DEBUG "alloc irq_2_iommu on node %d\n", node); |
35 | 42 | ||
36 | return iommu; | 43 | return iommu; |
37 | } | 44 | } |
@@ -48,7 +55,7 @@ static struct irq_2_iommu *irq_2_iommu(unsigned int irq) | |||
48 | return desc->irq_2_iommu; | 55 | return desc->irq_2_iommu; |
49 | } | 56 | } |
50 | 57 | ||
51 | static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) | 58 | static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node) |
52 | { | 59 | { |
53 | struct irq_desc *desc; | 60 | struct irq_desc *desc; |
54 | struct irq_2_iommu *irq_iommu; | 61 | struct irq_2_iommu *irq_iommu; |
@@ -56,7 +63,7 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) | |||
56 | /* | 63 | /* |
57 | * alloc irq desc if not allocated already. | 64 | * alloc irq desc if not allocated already. |
58 | */ | 65 | */ |
59 | desc = irq_to_desc_alloc_cpu(irq, cpu); | 66 | desc = irq_to_desc_alloc_node(irq, node); |
60 | if (!desc) { | 67 | if (!desc) { |
61 | printk(KERN_INFO "can not get irq_desc for %d\n", irq); | 68 | printk(KERN_INFO "can not get irq_desc for %d\n", irq); |
62 | return NULL; | 69 | return NULL; |
@@ -65,14 +72,14 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) | |||
65 | irq_iommu = desc->irq_2_iommu; | 72 | irq_iommu = desc->irq_2_iommu; |
66 | 73 | ||
67 | if (!irq_iommu) | 74 | if (!irq_iommu) |
68 | desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu); | 75 | desc->irq_2_iommu = get_one_free_irq_2_iommu(node); |
69 | 76 | ||
70 | return desc->irq_2_iommu; | 77 | return desc->irq_2_iommu; |
71 | } | 78 | } |
72 | 79 | ||
73 | static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) | 80 | static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) |
74 | { | 81 | { |
75 | return irq_2_iommu_alloc_cpu(irq, boot_cpu_id); | 82 | return irq_2_iommu_alloc_node(irq, cpu_to_node(boot_cpu_id)); |
76 | } | 83 | } |
77 | 84 | ||
78 | #else /* !CONFIG_SPARSE_IRQ */ | 85 | #else /* !CONFIG_SPARSE_IRQ */ |
@@ -309,7 +316,8 @@ int modify_irte(int irq, struct irte *irte_modified) | |||
309 | index = irq_iommu->irte_index + irq_iommu->sub_handle; | 316 | index = irq_iommu->irte_index + irq_iommu->sub_handle; |
310 | irte = &iommu->ir_table->base[index]; | 317 | irte = &iommu->ir_table->base[index]; |
311 | 318 | ||
312 | set_64bit((unsigned long *)irte, irte_modified->low); | 319 | set_64bit((unsigned long *)&irte->low, irte_modified->low); |
320 | set_64bit((unsigned long *)&irte->high, irte_modified->high); | ||
313 | __iommu_flush_cache(iommu, irte, sizeof(*irte)); | 321 | __iommu_flush_cache(iommu, irte, sizeof(*irte)); |
314 | 322 | ||
315 | rc = qi_flush_iec(iommu, index, 0); | 323 | rc = qi_flush_iec(iommu, index, 0); |
@@ -364,12 +372,32 @@ struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) | |||
364 | return drhd->iommu; | 372 | return drhd->iommu; |
365 | } | 373 | } |
366 | 374 | ||
375 | static int clear_entries(struct irq_2_iommu *irq_iommu) | ||
376 | { | ||
377 | struct irte *start, *entry, *end; | ||
378 | struct intel_iommu *iommu; | ||
379 | int index; | ||
380 | |||
381 | if (irq_iommu->sub_handle) | ||
382 | return 0; | ||
383 | |||
384 | iommu = irq_iommu->iommu; | ||
385 | index = irq_iommu->irte_index + irq_iommu->sub_handle; | ||
386 | |||
387 | start = iommu->ir_table->base + index; | ||
388 | end = start + (1 << irq_iommu->irte_mask); | ||
389 | |||
390 | for (entry = start; entry < end; entry++) { | ||
391 | set_64bit((unsigned long *)&entry->low, 0); | ||
392 | set_64bit((unsigned long *)&entry->high, 0); | ||
393 | } | ||
394 | |||
395 | return qi_flush_iec(iommu, index, irq_iommu->irte_mask); | ||
396 | } | ||
397 | |||
367 | int free_irte(int irq) | 398 | int free_irte(int irq) |
368 | { | 399 | { |
369 | int rc = 0; | 400 | int rc = 0; |
370 | int index, i; | ||
371 | struct irte *irte; | ||
372 | struct intel_iommu *iommu; | ||
373 | struct irq_2_iommu *irq_iommu; | 401 | struct irq_2_iommu *irq_iommu; |
374 | unsigned long flags; | 402 | unsigned long flags; |
375 | 403 | ||
@@ -380,16 +408,7 @@ int free_irte(int irq) | |||
380 | return -1; | 408 | return -1; |
381 | } | 409 | } |
382 | 410 | ||
383 | iommu = irq_iommu->iommu; | 411 | rc = clear_entries(irq_iommu); |
384 | |||
385 | index = irq_iommu->irte_index + irq_iommu->sub_handle; | ||
386 | irte = &iommu->ir_table->base[index]; | ||
387 | |||
388 | if (!irq_iommu->sub_handle) { | ||
389 | for (i = 0; i < (1 << irq_iommu->irte_mask); i++) | ||
390 | set_64bit((unsigned long *)(irte + i), 0); | ||
391 | rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask); | ||
392 | } | ||
393 | 412 | ||
394 | irq_iommu->iommu = NULL; | 413 | irq_iommu->iommu = NULL; |
395 | irq_iommu->irte_index = 0; | 414 | irq_iommu->irte_index = 0; |
@@ -401,10 +420,95 @@ int free_irte(int irq) | |||
401 | return rc; | 420 | return rc; |
402 | } | 421 | } |
403 | 422 | ||
423 | /* | ||
424 | * source validation type | ||
425 | */ | ||
426 | #define SVT_NO_VERIFY 0x0 /* no verification is required */ | ||
427 | #define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fiels */ | ||
428 | #define SVT_VERIFY_BUS 0x2 /* verify bus of request-id */ | ||
429 | |||
430 | /* | ||
431 | * source-id qualifier | ||
432 | */ | ||
433 | #define SQ_ALL_16 0x0 /* verify all 16 bits of request-id */ | ||
434 | #define SQ_13_IGNORE_1 0x1 /* verify most significant 13 bits, ignore | ||
435 | * the third least significant bit | ||
436 | */ | ||
437 | #define SQ_13_IGNORE_2 0x2 /* verify most significant 13 bits, ignore | ||
438 | * the second and third least significant bits | ||
439 | */ | ||
440 | #define SQ_13_IGNORE_3 0x3 /* verify most significant 13 bits, ignore | ||
441 | * the least three significant bits | ||
442 | */ | ||
443 | |||
444 | /* | ||
445 | * set SVT, SQ and SID fields of irte to verify | ||
446 | * source ids of interrupt requests | ||
447 | */ | ||
448 | static void set_irte_sid(struct irte *irte, unsigned int svt, | ||
449 | unsigned int sq, unsigned int sid) | ||
450 | { | ||
451 | irte->svt = svt; | ||
452 | irte->sq = sq; | ||
453 | irte->sid = sid; | ||
454 | } | ||
455 | |||
456 | int set_ioapic_sid(struct irte *irte, int apic) | ||
457 | { | ||
458 | int i; | ||
459 | u16 sid = 0; | ||
460 | |||
461 | if (!irte) | ||
462 | return -1; | ||
463 | |||
464 | for (i = 0; i < MAX_IO_APICS; i++) { | ||
465 | if (ir_ioapic[i].id == apic) { | ||
466 | sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn; | ||
467 | break; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | if (sid == 0) { | ||
472 | pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic); | ||
473 | return -1; | ||
474 | } | ||
475 | |||
476 | set_irte_sid(irte, 1, 0, sid); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) | ||
482 | { | ||
483 | struct pci_dev *bridge; | ||
484 | |||
485 | if (!irte || !dev) | ||
486 | return -1; | ||
487 | |||
488 | /* PCIe device or Root Complex integrated PCI device */ | ||
489 | if (dev->is_pcie || !dev->bus->parent) { | ||
490 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, | ||
491 | (dev->bus->number << 8) | dev->devfn); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | bridge = pci_find_upstream_pcie_bridge(dev); | ||
496 | if (bridge) { | ||
497 | if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */ | ||
498 | set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, | ||
499 | (bridge->bus->number << 8) | dev->bus->number); | ||
500 | else /* this is a legacy PCI bridge */ | ||
501 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, | ||
502 | (bridge->bus->number << 8) | bridge->devfn); | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
404 | static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) | 508 | static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) |
405 | { | 509 | { |
406 | u64 addr; | 510 | u64 addr; |
407 | u32 cmd, sts; | 511 | u32 sts; |
408 | unsigned long flags; | 512 | unsigned long flags; |
409 | 513 | ||
410 | addr = virt_to_phys((void *)iommu->ir_table->base); | 514 | addr = virt_to_phys((void *)iommu->ir_table->base); |
@@ -415,28 +519,13 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) | |||
415 | (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE); | 519 | (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE); |
416 | 520 | ||
417 | /* Set interrupt-remapping table pointer */ | 521 | /* Set interrupt-remapping table pointer */ |
418 | cmd = iommu->gcmd | DMA_GCMD_SIRTP; | ||
419 | iommu->gcmd |= DMA_GCMD_SIRTP; | 522 | iommu->gcmd |= DMA_GCMD_SIRTP; |
420 | writel(cmd, iommu->reg + DMAR_GCMD_REG); | 523 | writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); |
421 | 524 | ||
422 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, | 525 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, |
423 | readl, (sts & DMA_GSTS_IRTPS), sts); | 526 | readl, (sts & DMA_GSTS_IRTPS), sts); |
424 | spin_unlock_irqrestore(&iommu->register_lock, flags); | 527 | spin_unlock_irqrestore(&iommu->register_lock, flags); |
425 | 528 | ||
426 | if (mode == 0) { | ||
427 | spin_lock_irqsave(&iommu->register_lock, flags); | ||
428 | |||
429 | /* enable comaptiblity format interrupt pass through */ | ||
430 | cmd = iommu->gcmd | DMA_GCMD_CFI; | ||
431 | iommu->gcmd |= DMA_GCMD_CFI; | ||
432 | writel(cmd, iommu->reg + DMAR_GCMD_REG); | ||
433 | |||
434 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, | ||
435 | readl, (sts & DMA_GSTS_CFIS), sts); | ||
436 | |||
437 | spin_unlock_irqrestore(&iommu->register_lock, flags); | ||
438 | } | ||
439 | |||
440 | /* | 529 | /* |
441 | * global invalidation of interrupt entry cache before enabling | 530 | * global invalidation of interrupt entry cache before enabling |
442 | * interrupt-remapping. | 531 | * interrupt-remapping. |
@@ -446,9 +535,8 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) | |||
446 | spin_lock_irqsave(&iommu->register_lock, flags); | 535 | spin_lock_irqsave(&iommu->register_lock, flags); |
447 | 536 | ||
448 | /* Enable interrupt-remapping */ | 537 | /* Enable interrupt-remapping */ |
449 | cmd = iommu->gcmd | DMA_GCMD_IRE; | ||
450 | iommu->gcmd |= DMA_GCMD_IRE; | 538 | iommu->gcmd |= DMA_GCMD_IRE; |
451 | writel(cmd, iommu->reg + DMAR_GCMD_REG); | 539 | writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); |
452 | 540 | ||
453 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, | 541 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, |
454 | readl, (sts & DMA_GSTS_IRES), sts); | 542 | readl, (sts & DMA_GSTS_IRES), sts); |
@@ -516,6 +604,23 @@ end: | |||
516 | spin_unlock_irqrestore(&iommu->register_lock, flags); | 604 | spin_unlock_irqrestore(&iommu->register_lock, flags); |
517 | } | 605 | } |
518 | 606 | ||
607 | int __init intr_remapping_supported(void) | ||
608 | { | ||
609 | struct dmar_drhd_unit *drhd; | ||
610 | |||
611 | if (disable_intremap) | ||
612 | return 0; | ||
613 | |||
614 | for_each_drhd_unit(drhd) { | ||
615 | struct intel_iommu *iommu = drhd->iommu; | ||
616 | |||
617 | if (!ecap_ir_support(iommu->ecap)) | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | return 1; | ||
622 | } | ||
623 | |||
519 | int __init enable_intr_remapping(int eim) | 624 | int __init enable_intr_remapping(int eim) |
520 | { | 625 | { |
521 | struct dmar_drhd_unit *drhd; | 626 | struct dmar_drhd_unit *drhd; |
@@ -606,6 +711,35 @@ error: | |||
606 | return -1; | 711 | return -1; |
607 | } | 712 | } |
608 | 713 | ||
714 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, | ||
715 | struct intel_iommu *iommu) | ||
716 | { | ||
717 | struct acpi_dmar_pci_path *path; | ||
718 | u8 bus; | ||
719 | int count; | ||
720 | |||
721 | bus = scope->bus; | ||
722 | path = (struct acpi_dmar_pci_path *)(scope + 1); | ||
723 | count = (scope->length - sizeof(struct acpi_dmar_device_scope)) | ||
724 | / sizeof(struct acpi_dmar_pci_path); | ||
725 | |||
726 | while (--count > 0) { | ||
727 | /* | ||
728 | * Access PCI directly due to the PCI | ||
729 | * subsystem isn't initialized yet. | ||
730 | */ | ||
731 | bus = read_pci_config_byte(bus, path->dev, path->fn, | ||
732 | PCI_SECONDARY_BUS); | ||
733 | path++; | ||
734 | } | ||
735 | |||
736 | ir_ioapic[ir_ioapic_num].bus = bus; | ||
737 | ir_ioapic[ir_ioapic_num].devfn = PCI_DEVFN(path->dev, path->fn); | ||
738 | ir_ioapic[ir_ioapic_num].iommu = iommu; | ||
739 | ir_ioapic[ir_ioapic_num].id = scope->enumeration_id; | ||
740 | ir_ioapic_num++; | ||
741 | } | ||
742 | |||
609 | static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | 743 | static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, |
610 | struct intel_iommu *iommu) | 744 | struct intel_iommu *iommu) |
611 | { | 745 | { |
@@ -630,9 +764,7 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | |||
630 | " 0x%Lx\n", scope->enumeration_id, | 764 | " 0x%Lx\n", scope->enumeration_id, |
631 | drhd->address); | 765 | drhd->address); |
632 | 766 | ||
633 | ir_ioapic[ir_ioapic_num].iommu = iommu; | 767 | ir_parse_one_ioapic_scope(scope, iommu); |
634 | ir_ioapic[ir_ioapic_num].id = scope->enumeration_id; | ||
635 | ir_ioapic_num++; | ||
636 | } | 768 | } |
637 | start += scope->length; | 769 | start += scope->length; |
638 | } | 770 | } |