diff options
author | Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> | 2016-08-23 14:52:32 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-09-05 06:41:46 -0400 |
commit | 3928aa3f5775fc4e40117077e97d73d8526039c9 (patch) | |
tree | 4694f5be6a1013a1c159425f0df465b48034435b | |
parent | 29b4817d4018df78086157ea3a55c1d9424a7cfc (diff) |
iommu/amd: Detect and enable guest vAPIC support
This patch introduces a new IOMMU driver parameter, amd_iommu_guest_ir,
which can be used to specify different interrupt remapping mode for
passthrough devices to VM guest:
* legacy: Legacy interrupt remapping (w/ 32-bit IRTE)
* vapic : Guest vAPIC interrupt remapping (w/ GA mode 128-bit IRTE)
Note that in vapic mode, it can also supports legacy interrupt remapping
for non-passthrough devices with the 128-bit IRTE.
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | Documentation/kernel-parameters.txt | 9 | ||||
-rw-r--r-- | drivers/iommu/amd_iommu_init.c | 71 | ||||
-rw-r--r-- | drivers/iommu/amd_iommu_proto.h | 1 | ||||
-rw-r--r-- | drivers/iommu/amd_iommu_types.h | 24 |
4 files changed, 99 insertions, 6 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 46c030a49186..748ef7bdd64d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -460,6 +460,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
460 | driver will print ACPI tables for AMD IOMMU during | 460 | driver will print ACPI tables for AMD IOMMU during |
461 | IOMMU initialization. | 461 | IOMMU initialization. |
462 | 462 | ||
463 | amd_iommu_intr= [HW,X86-64] | ||
464 | Specifies one of the following AMD IOMMU interrupt | ||
465 | remapping modes: | ||
466 | legacy - Use legacy interrupt remapping mode. | ||
467 | vapic - Use virtual APIC mode, which allows IOMMU | ||
468 | to inject interrupts directly into guest. | ||
469 | This mode requires kvm-amd.avic=1. | ||
470 | (Default when IOMMU HW support is present.) | ||
471 | |||
463 | amijoy.map= [HW,JOY] Amiga joystick support | 472 | amijoy.map= [HW,JOY] Amiga joystick support |
464 | Map of devices attached to JOY0DAT and JOY1DAT | 473 | Map of devices attached to JOY0DAT and JOY1DAT |
465 | Format: <a>,<b> | 474 | Format: <a>,<b> |
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 59741ead7e15..c3afd8669bfb 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
@@ -145,6 +145,8 @@ struct ivmd_header { | |||
145 | bool amd_iommu_dump; | 145 | bool amd_iommu_dump; |
146 | bool amd_iommu_irq_remap __read_mostly; | 146 | bool amd_iommu_irq_remap __read_mostly; |
147 | 147 | ||
148 | int amd_iommu_guest_ir; | ||
149 | |||
148 | static bool amd_iommu_detected; | 150 | static bool amd_iommu_detected; |
149 | static bool __initdata amd_iommu_disabled; | 151 | static bool __initdata amd_iommu_disabled; |
150 | static int amd_iommu_target_ivhd_type; | 152 | static int amd_iommu_target_ivhd_type; |
@@ -1258,6 +1260,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | |||
1258 | iommu->mmio_phys_end = MMIO_REG_END_OFFSET; | 1260 | iommu->mmio_phys_end = MMIO_REG_END_OFFSET; |
1259 | else | 1261 | else |
1260 | iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; | 1262 | iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; |
1263 | if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0)) | ||
1264 | amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; | ||
1261 | break; | 1265 | break; |
1262 | case 0x11: | 1266 | case 0x11: |
1263 | case 0x40: | 1267 | case 0x40: |
@@ -1265,6 +1269,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | |||
1265 | iommu->mmio_phys_end = MMIO_REG_END_OFFSET; | 1269 | iommu->mmio_phys_end = MMIO_REG_END_OFFSET; |
1266 | else | 1270 | else |
1267 | iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; | 1271 | iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; |
1272 | if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) | ||
1273 | amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; | ||
1268 | break; | 1274 | break; |
1269 | default: | 1275 | default: |
1270 | return -EINVAL; | 1276 | return -EINVAL; |
@@ -1488,6 +1494,14 @@ static int iommu_init_pci(struct amd_iommu *iommu) | |||
1488 | if (iommu_feature(iommu, FEATURE_PPR) && alloc_ppr_log(iommu)) | 1494 | if (iommu_feature(iommu, FEATURE_PPR) && alloc_ppr_log(iommu)) |
1489 | return -ENOMEM; | 1495 | return -ENOMEM; |
1490 | 1496 | ||
1497 | /* Note: We have already checked GASup from IVRS table. | ||
1498 | * Now, we need to make sure that GAMSup is set. | ||
1499 | */ | ||
1500 | if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) && | ||
1501 | !iommu_feature(iommu, FEATURE_GAM_VAPIC)) | ||
1502 | amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY_GA; | ||
1503 | |||
1504 | |||
1491 | if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) | 1505 | if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) |
1492 | amd_iommu_np_cache = true; | 1506 | amd_iommu_np_cache = true; |
1493 | 1507 | ||
@@ -1545,16 +1559,24 @@ static void print_iommu_info(void) | |||
1545 | dev_name(&iommu->dev->dev), iommu->cap_ptr); | 1559 | dev_name(&iommu->dev->dev), iommu->cap_ptr); |
1546 | 1560 | ||
1547 | if (iommu->cap & (1 << IOMMU_CAP_EFR)) { | 1561 | if (iommu->cap & (1 << IOMMU_CAP_EFR)) { |
1548 | pr_info("AMD-Vi: Extended features: "); | 1562 | pr_info("AMD-Vi: Extended features (%#llx):\n", |
1563 | iommu->features); | ||
1549 | for (i = 0; i < ARRAY_SIZE(feat_str); ++i) { | 1564 | for (i = 0; i < ARRAY_SIZE(feat_str); ++i) { |
1550 | if (iommu_feature(iommu, (1ULL << i))) | 1565 | if (iommu_feature(iommu, (1ULL << i))) |
1551 | pr_cont(" %s", feat_str[i]); | 1566 | pr_cont(" %s", feat_str[i]); |
1552 | } | 1567 | } |
1568 | |||
1569 | if (iommu->features & FEATURE_GAM_VAPIC) | ||
1570 | pr_cont(" GA_vAPIC"); | ||
1571 | |||
1553 | pr_cont("\n"); | 1572 | pr_cont("\n"); |
1554 | } | 1573 | } |
1555 | } | 1574 | } |
1556 | if (irq_remapping_enabled) | 1575 | if (irq_remapping_enabled) { |
1557 | pr_info("AMD-Vi: Interrupt remapping enabled\n"); | 1576 | pr_info("AMD-Vi: Interrupt remapping enabled\n"); |
1577 | if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir)) | ||
1578 | pr_info("AMD-Vi: virtual APIC enabled\n"); | ||
1579 | } | ||
1558 | } | 1580 | } |
1559 | 1581 | ||
1560 | static int __init amd_iommu_init_pci(void) | 1582 | static int __init amd_iommu_init_pci(void) |
@@ -1862,6 +1884,22 @@ static void iommu_apply_resume_quirks(struct amd_iommu *iommu) | |||
1862 | iommu->stored_addr_lo | 1); | 1884 | iommu->stored_addr_lo | 1); |
1863 | } | 1885 | } |
1864 | 1886 | ||
1887 | static void iommu_enable_ga(struct amd_iommu *iommu) | ||
1888 | { | ||
1889 | #ifdef CONFIG_IRQ_REMAP | ||
1890 | switch (amd_iommu_guest_ir) { | ||
1891 | case AMD_IOMMU_GUEST_IR_VAPIC: | ||
1892 | iommu_feature_enable(iommu, CONTROL_GAM_EN); | ||
1893 | /* Fall through */ | ||
1894 | case AMD_IOMMU_GUEST_IR_LEGACY_GA: | ||
1895 | iommu_feature_enable(iommu, CONTROL_GA_EN); | ||
1896 | break; | ||
1897 | default: | ||
1898 | break; | ||
1899 | } | ||
1900 | #endif | ||
1901 | } | ||
1902 | |||
1865 | /* | 1903 | /* |
1866 | * This function finally enables all IOMMUs found in the system after | 1904 | * This function finally enables all IOMMUs found in the system after |
1867 | * they have been initialized | 1905 | * they have been initialized |
@@ -1877,6 +1915,7 @@ static void early_enable_iommus(void) | |||
1877 | iommu_enable_command_buffer(iommu); | 1915 | iommu_enable_command_buffer(iommu); |
1878 | iommu_enable_event_buffer(iommu); | 1916 | iommu_enable_event_buffer(iommu); |
1879 | iommu_set_exclusion_range(iommu); | 1917 | iommu_set_exclusion_range(iommu); |
1918 | iommu_enable_ga(iommu); | ||
1880 | iommu_enable(iommu); | 1919 | iommu_enable(iommu); |
1881 | iommu_flush_all_caches(iommu); | 1920 | iommu_flush_all_caches(iommu); |
1882 | } | 1921 | } |
@@ -2059,7 +2098,7 @@ static int __init early_amd_iommu_init(void) | |||
2059 | struct acpi_table_header *ivrs_base; | 2098 | struct acpi_table_header *ivrs_base; |
2060 | acpi_size ivrs_size; | 2099 | acpi_size ivrs_size; |
2061 | acpi_status status; | 2100 | acpi_status status; |
2062 | int i, ret = 0; | 2101 | int i, remap_cache_sz, ret = 0; |
2063 | 2102 | ||
2064 | if (!amd_iommu_detected) | 2103 | if (!amd_iommu_detected) |
2065 | return -ENODEV; | 2104 | return -ENODEV; |
@@ -2157,10 +2196,14 @@ static int __init early_amd_iommu_init(void) | |||
2157 | * remapping tables. | 2196 | * remapping tables. |
2158 | */ | 2197 | */ |
2159 | ret = -ENOMEM; | 2198 | ret = -ENOMEM; |
2199 | if (!AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir)) | ||
2200 | remap_cache_sz = MAX_IRQS_PER_TABLE * sizeof(u32); | ||
2201 | else | ||
2202 | remap_cache_sz = MAX_IRQS_PER_TABLE * (sizeof(u64) * 2); | ||
2160 | amd_iommu_irq_cache = kmem_cache_create("irq_remap_cache", | 2203 | amd_iommu_irq_cache = kmem_cache_create("irq_remap_cache", |
2161 | MAX_IRQS_PER_TABLE * sizeof(u32), | 2204 | remap_cache_sz, |
2162 | IRQ_TABLE_ALIGNMENT, | 2205 | IRQ_TABLE_ALIGNMENT, |
2163 | 0, NULL); | 2206 | 0, NULL); |
2164 | if (!amd_iommu_irq_cache) | 2207 | if (!amd_iommu_irq_cache) |
2165 | goto out; | 2208 | goto out; |
2166 | 2209 | ||
@@ -2413,6 +2456,21 @@ static int __init parse_amd_iommu_dump(char *str) | |||
2413 | return 1; | 2456 | return 1; |
2414 | } | 2457 | } |
2415 | 2458 | ||
2459 | static int __init parse_amd_iommu_intr(char *str) | ||
2460 | { | ||
2461 | for (; *str; ++str) { | ||
2462 | if (strncmp(str, "legacy", 6) == 0) { | ||
2463 | amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; | ||
2464 | break; | ||
2465 | } | ||
2466 | if (strncmp(str, "vapic", 5) == 0) { | ||
2467 | amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC; | ||
2468 | break; | ||
2469 | } | ||
2470 | } | ||
2471 | return 1; | ||
2472 | } | ||
2473 | |||
2416 | static int __init parse_amd_iommu_options(char *str) | 2474 | static int __init parse_amd_iommu_options(char *str) |
2417 | { | 2475 | { |
2418 | for (; *str; ++str) { | 2476 | for (; *str; ++str) { |
@@ -2521,6 +2579,7 @@ static int __init parse_ivrs_acpihid(char *str) | |||
2521 | 2579 | ||
2522 | __setup("amd_iommu_dump", parse_amd_iommu_dump); | 2580 | __setup("amd_iommu_dump", parse_amd_iommu_dump); |
2523 | __setup("amd_iommu=", parse_amd_iommu_options); | 2581 | __setup("amd_iommu=", parse_amd_iommu_options); |
2582 | __setup("amd_iommu_intr=", parse_amd_iommu_intr); | ||
2524 | __setup("ivrs_ioapic", parse_ivrs_ioapic); | 2583 | __setup("ivrs_ioapic", parse_ivrs_ioapic); |
2525 | __setup("ivrs_hpet", parse_ivrs_hpet); | 2584 | __setup("ivrs_hpet", parse_ivrs_hpet); |
2526 | __setup("ivrs_acpihid", parse_ivrs_acpihid); | 2585 | __setup("ivrs_acpihid", parse_ivrs_acpihid); |
diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h index 0bd9eb374462..faa3b4895cf0 100644 --- a/drivers/iommu/amd_iommu_proto.h +++ b/drivers/iommu/amd_iommu_proto.h | |||
@@ -38,6 +38,7 @@ extern int amd_iommu_enable(void); | |||
38 | extern void amd_iommu_disable(void); | 38 | extern void amd_iommu_disable(void); |
39 | extern int amd_iommu_reenable(int); | 39 | extern int amd_iommu_reenable(int); |
40 | extern int amd_iommu_enable_faulting(void); | 40 | extern int amd_iommu_enable_faulting(void); |
41 | extern int amd_iommu_guest_ir; | ||
41 | 42 | ||
42 | /* IOMMUv2 specific functions */ | 43 | /* IOMMUv2 specific functions */ |
43 | struct iommu_domain; | 44 | struct iommu_domain; |
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index caf5e3822715..3d1fc37b051b 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h | |||
@@ -92,6 +92,7 @@ | |||
92 | #define FEATURE_GA (1ULL<<7) | 92 | #define FEATURE_GA (1ULL<<7) |
93 | #define FEATURE_HE (1ULL<<8) | 93 | #define FEATURE_HE (1ULL<<8) |
94 | #define FEATURE_PC (1ULL<<9) | 94 | #define FEATURE_PC (1ULL<<9) |
95 | #define FEATURE_GAM_VAPIC (1ULL<<21) | ||
95 | 96 | ||
96 | #define FEATURE_PASID_SHIFT 32 | 97 | #define FEATURE_PASID_SHIFT 32 |
97 | #define FEATURE_PASID_MASK (0x1fULL << FEATURE_PASID_SHIFT) | 98 | #define FEATURE_PASID_MASK (0x1fULL << FEATURE_PASID_SHIFT) |
@@ -146,6 +147,8 @@ | |||
146 | #define CONTROL_PPFINT_EN 0x0eULL | 147 | #define CONTROL_PPFINT_EN 0x0eULL |
147 | #define CONTROL_PPR_EN 0x0fULL | 148 | #define CONTROL_PPR_EN 0x0fULL |
148 | #define CONTROL_GT_EN 0x10ULL | 149 | #define CONTROL_GT_EN 0x10ULL |
150 | #define CONTROL_GA_EN 0x11ULL | ||
151 | #define CONTROL_GAM_EN 0x19ULL | ||
149 | 152 | ||
150 | #define CTRL_INV_TO_MASK (7 << CONTROL_INV_TIMEOUT) | 153 | #define CTRL_INV_TO_MASK (7 << CONTROL_INV_TIMEOUT) |
151 | #define CTRL_INV_TO_NONE 0 | 154 | #define CTRL_INV_TO_NONE 0 |
@@ -329,6 +332,12 @@ | |||
329 | #define IOMMU_CAP_NPCACHE 26 | 332 | #define IOMMU_CAP_NPCACHE 26 |
330 | #define IOMMU_CAP_EFR 27 | 333 | #define IOMMU_CAP_EFR 27 |
331 | 334 | ||
335 | /* IOMMU Feature Reporting Field (for IVHD type 10h */ | ||
336 | #define IOMMU_FEAT_GASUP_SHIFT 6 | ||
337 | |||
338 | /* IOMMU Extended Feature Register (EFR) */ | ||
339 | #define IOMMU_EFR_GASUP_SHIFT 7 | ||
340 | |||
332 | #define MAX_DOMAIN_ID 65536 | 341 | #define MAX_DOMAIN_ID 65536 |
333 | 342 | ||
334 | /* Protection domain flags */ | 343 | /* Protection domain flags */ |
@@ -681,4 +690,19 @@ static inline int get_hpet_devid(int id) | |||
681 | return -EINVAL; | 690 | return -EINVAL; |
682 | } | 691 | } |
683 | 692 | ||
693 | enum amd_iommu_intr_mode_type { | ||
694 | AMD_IOMMU_GUEST_IR_LEGACY, | ||
695 | |||
696 | /* This mode is not visible to users. It is used when | ||
697 | * we cannot fully enable vAPIC and fallback to only support | ||
698 | * legacy interrupt remapping via 128-bit IRTE. | ||
699 | */ | ||
700 | AMD_IOMMU_GUEST_IR_LEGACY_GA, | ||
701 | AMD_IOMMU_GUEST_IR_VAPIC, | ||
702 | }; | ||
703 | |||
704 | #define AMD_IOMMU_GUEST_IR_GA(x) (x == AMD_IOMMU_GUEST_IR_VAPIC || \ | ||
705 | x == AMD_IOMMU_GUEST_IR_LEGACY_GA) | ||
706 | |||
707 | #define AMD_IOMMU_GUEST_IR_VAPIC(x) (x == AMD_IOMMU_GUEST_IR_VAPIC) | ||
684 | #endif /* _ASM_X86_AMD_IOMMU_TYPES_H */ | 708 | #endif /* _ASM_X86_AMD_IOMMU_TYPES_H */ |