Skip to content

Commit 3928aa3

Browse files
ssuthiku-amdjoergroedel
authored andcommitted
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 <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent 29b4817 commit 3928aa3

File tree

4 files changed

+99
-6
lines changed

4 files changed

+99
-6
lines changed

Documentation/kernel-parameters.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
460460
driver will print ACPI tables for AMD IOMMU during
461461
IOMMU initialization.
462462

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+
463472
amijoy.map= [HW,JOY] Amiga joystick support
464473
Map of devices attached to JOY0DAT and JOY1DAT
465474
Format: <a>,<b>

drivers/iommu/amd_iommu_init.c

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ struct ivmd_header {
145145
bool amd_iommu_dump;
146146
bool amd_iommu_irq_remap __read_mostly;
147147

148+
int amd_iommu_guest_ir;
149+
148150
static bool amd_iommu_detected;
149151
static bool __initdata amd_iommu_disabled;
150152
static int amd_iommu_target_ivhd_type;
@@ -1258,13 +1260,17 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
12581260
iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
12591261
else
12601262
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;
12611265
break;
12621266
case 0x11:
12631267
case 0x40:
12641268
if (h->efr_reg & (1 << 9))
12651269
iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
12661270
else
12671271
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;
12681274
break;
12691275
default:
12701276
return -EINVAL;
@@ -1488,6 +1494,14 @@ static int iommu_init_pci(struct amd_iommu *iommu)
14881494
if (iommu_feature(iommu, FEATURE_PPR) && alloc_ppr_log(iommu))
14891495
return -ENOMEM;
14901496

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+
14911505
if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE))
14921506
amd_iommu_np_cache = true;
14931507

@@ -1545,16 +1559,24 @@ static void print_iommu_info(void)
15451559
dev_name(&iommu->dev->dev), iommu->cap_ptr);
15461560

15471561
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);
15491564
for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
15501565
if (iommu_feature(iommu, (1ULL << i)))
15511566
pr_cont(" %s", feat_str[i]);
15521567
}
1568+
1569+
if (iommu->features & FEATURE_GAM_VAPIC)
1570+
pr_cont(" GA_vAPIC");
1571+
15531572
pr_cont("\n");
15541573
}
15551574
}
1556-
if (irq_remapping_enabled)
1575+
if (irq_remapping_enabled) {
15571576
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+
}
15581580
}
15591581

15601582
static int __init amd_iommu_init_pci(void)
@@ -1862,6 +1884,22 @@ static void iommu_apply_resume_quirks(struct amd_iommu *iommu)
18621884
iommu->stored_addr_lo | 1);
18631885
}
18641886

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+
18651903
/*
18661904
* This function finally enables all IOMMUs found in the system after
18671905
* they have been initialized
@@ -1877,6 +1915,7 @@ static void early_enable_iommus(void)
18771915
iommu_enable_command_buffer(iommu);
18781916
iommu_enable_event_buffer(iommu);
18791917
iommu_set_exclusion_range(iommu);
1918+
iommu_enable_ga(iommu);
18801919
iommu_enable(iommu);
18811920
iommu_flush_all_caches(iommu);
18821921
}
@@ -2059,7 +2098,7 @@ static int __init early_amd_iommu_init(void)
20592098
struct acpi_table_header *ivrs_base;
20602099
acpi_size ivrs_size;
20612100
acpi_status status;
2062-
int i, ret = 0;
2101+
int i, remap_cache_sz, ret = 0;
20632102

20642103
if (!amd_iommu_detected)
20652104
return -ENODEV;
@@ -2157,10 +2196,14 @@ static int __init early_amd_iommu_init(void)
21572196
* remapping tables.
21582197
*/
21592198
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);
21602203
amd_iommu_irq_cache = kmem_cache_create("irq_remap_cache",
2161-
MAX_IRQS_PER_TABLE * sizeof(u32),
2162-
IRQ_TABLE_ALIGNMENT,
2163-
0, NULL);
2204+
remap_cache_sz,
2205+
IRQ_TABLE_ALIGNMENT,
2206+
0, NULL);
21642207
if (!amd_iommu_irq_cache)
21652208
goto out;
21662209

@@ -2413,6 +2456,21 @@ static int __init parse_amd_iommu_dump(char *str)
24132456
return 1;
24142457
}
24152458

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+
24162474
static int __init parse_amd_iommu_options(char *str)
24172475
{
24182476
for (; *str; ++str) {
@@ -2521,6 +2579,7 @@ static int __init parse_ivrs_acpihid(char *str)
25212579

25222580
__setup("amd_iommu_dump", parse_amd_iommu_dump);
25232581
__setup("amd_iommu=", parse_amd_iommu_options);
2582+
__setup("amd_iommu_intr=", parse_amd_iommu_intr);
25242583
__setup("ivrs_ioapic", parse_ivrs_ioapic);
25252584
__setup("ivrs_hpet", parse_ivrs_hpet);
25262585
__setup("ivrs_acpihid", parse_ivrs_acpihid);

drivers/iommu/amd_iommu_proto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern int amd_iommu_enable(void);
3838
extern void amd_iommu_disable(void);
3939
extern int amd_iommu_reenable(int);
4040
extern int amd_iommu_enable_faulting(void);
41+
extern int amd_iommu_guest_ir;
4142

4243
/* IOMMUv2 specific functions */
4344
struct iommu_domain;

drivers/iommu/amd_iommu_types.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
#define FEATURE_GA (1ULL<<7)
9393
#define FEATURE_HE (1ULL<<8)
9494
#define FEATURE_PC (1ULL<<9)
95+
#define FEATURE_GAM_VAPIC (1ULL<<21)
9596

9697
#define FEATURE_PASID_SHIFT 32
9798
#define FEATURE_PASID_MASK (0x1fULL << FEATURE_PASID_SHIFT)
@@ -146,6 +147,8 @@
146147
#define CONTROL_PPFINT_EN 0x0eULL
147148
#define CONTROL_PPR_EN 0x0fULL
148149
#define CONTROL_GT_EN 0x10ULL
150+
#define CONTROL_GA_EN 0x11ULL
151+
#define CONTROL_GAM_EN 0x19ULL
149152

150153
#define CTRL_INV_TO_MASK (7 << CONTROL_INV_TIMEOUT)
151154
#define CTRL_INV_TO_NONE 0
@@ -329,6 +332,12 @@
329332
#define IOMMU_CAP_NPCACHE 26
330333
#define IOMMU_CAP_EFR 27
331334

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+
332341
#define MAX_DOMAIN_ID 65536
333342

334343
/* Protection domain flags */
@@ -681,4 +690,19 @@ static inline int get_hpet_devid(int id)
681690
return -EINVAL;
682691
}
683692

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)
684708
#endif /* _ASM_X86_AMD_IOMMU_TYPES_H */

0 commit comments

Comments
 (0)