Introduces a new IOMMU API, amd_iommu_update_ga(), which allows KVM (SVM) to update existing posted interrupt IOMMU IRTE when load/unload vcpu. Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@xxxxxxx> --- drivers/iommu/amd_iommu.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/iommu/amd_iommu_types.h | 11 ----------- include/linux/amd-iommu.h | 22 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index fd5ceff..8bb85ca 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -4454,4 +4454,44 @@ int amd_iommu_create_irq_domain(struct amd_iommu *iommu) return 0; } + +int amd_iommu_update_ga(u32 cpu, u64 base, bool is_run, + struct amd_ir_data *ir_data) +{ + unsigned long flags; + struct amd_iommu *iommu; + struct irq_remap_table *irt; + int devid = ir_data->irq_2_irte.devid; + struct irte_ga *entry = (struct irte_ga *) ir_data->entry; + struct irte_ga *ref = (struct irte_ga *) ir_data->ref; + + if ((!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir)) || + (!entry->lo.fields_vapic.guest_mode)) + return 0; + + iommu = amd_iommu_rlookup_table[devid]; + if (!iommu) + return -ENODEV; + + irt = get_irq_table(devid, false); + if (!irt) + return -ENODEV; + + spin_lock_irqsave(&irt->lock, flags); + + if (ref->lo.fields_vapic.guest_mode) { + ref->hi.fields.ga_root_ptr = (base >> 12); + if (cpu >= 0) + ref->lo.fields_vapic.destination = cpu; + ref->lo.fields_vapic.is_run = is_run; + barrier(); + } + + spin_unlock_irqrestore(&irt->lock, flags); + + iommu_flush_irt(iommu, devid); + iommu_completion_wait(iommu); + return 0; +} +EXPORT_SYMBOL(amd_iommu_update_ga); #endif diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index a3b6e22..71d1d0e 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -802,17 +802,6 @@ struct irte_ga { union irte_ga_hi hi; }; -struct irq_2_irte { - u16 devid; /* Device ID for IRTE table */ - u16 index; /* Index into IRTE table*/ -}; - -struct amd_ir_data { - struct irq_2_irte irq_2_irte; - struct msi_msg msi_entry; - void *entry; /* Pointer to union irte or struct irte_ga */ -}; - struct amd_irte_ops { void (*prepare)(void *, u32, u32, u8, u32); void (*activate)(void *, u16, u16); diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h index 465d096..dfd3bc4 100644 --- a/include/linux/amd-iommu.h +++ b/include/linux/amd-iommu.h @@ -21,6 +21,19 @@ #define _ASM_X86_AMD_IOMMU_H #include <linux/types.h> +#include <linux/msi.h> + +struct irq_2_irte { + u16 devid; /* Device ID for IRTE table */ + u16 index; /* Index into IRTE table*/ +}; + +struct amd_ir_data { + struct irq_2_irte irq_2_irte; + struct msi_msg msi_entry; + void *entry; /* Pointer to union irte or struct irte_ga */ + void *ref; /* Pointer to the actual irte */ +}; #ifdef CONFIG_AMD_IOMMU @@ -179,6 +192,9 @@ static inline int amd_iommu_detect(void) { return -ENODEV; } /* IOMMU AVIC Function */ extern int amd_iommu_register_ga_log_notifier(int (*notifier)(u32)); +extern int +amd_iommu_update_ga(u32 cpu, u64 base, bool is_run, struct amd_ir_data *ir_data); + #else /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */ static inline int @@ -187,6 +203,12 @@ amd_iommu_register_ga_log_notifier(int (*notifier)(u32)) return 0; } +static inline int +amd_iommu_update_ga(u32 cpu, u64 base, bool is_run, struct amd_ir_data *ir_data); +{ + return 0; +} + #endif /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */ #endif /* _ASM_X86_AMD_IOMMU_H */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html