iommu/amd: Introduce interrupt remapping ops structure
Currently, IOMMU support two interrupt remapping table entry formats, 32-bit (legacy) and 128-bit (GA). The spec also implies that it might support additional modes/formats in the future. So, this patch introduces the new struct amd_irte_ops, which allows the same code to work with different irte formats by providing hooks for various operations on an interrupt remapping table entry. Suggested-by: Joerg Roedel <joro@8bytes.org> Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
a38180bd36
commit
880ac60e25
|
@ -3644,7 +3644,39 @@ out:
|
|||
return index;
|
||||
}
|
||||
|
||||
static int modify_irte(u16 devid, int index, union irte irte)
|
||||
static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte)
|
||||
{
|
||||
struct irq_remap_table *table;
|
||||
struct amd_iommu *iommu;
|
||||
unsigned long flags;
|
||||
struct irte_ga *entry;
|
||||
|
||||
iommu = amd_iommu_rlookup_table[devid];
|
||||
if (iommu == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
table = get_irq_table(devid, false);
|
||||
if (!table)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&table->lock, flags);
|
||||
|
||||
entry = (struct irte_ga *)table->table;
|
||||
entry = &entry[index];
|
||||
entry->lo.fields_remap.valid = 0;
|
||||
entry->hi.val = irte->hi.val;
|
||||
entry->lo.val = irte->lo.val;
|
||||
entry->lo.fields_remap.valid = 1;
|
||||
|
||||
spin_unlock_irqrestore(&table->lock, flags);
|
||||
|
||||
iommu_flush_irt(iommu, devid);
|
||||
iommu_completion_wait(iommu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int modify_irte(u16 devid, int index, union irte *irte)
|
||||
{
|
||||
struct irq_remap_table *table;
|
||||
struct amd_iommu *iommu;
|
||||
|
@ -3659,7 +3691,7 @@ static int modify_irte(u16 devid, int index, union irte irte)
|
|||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&table->lock, flags);
|
||||
table->table[index] = irte.val;
|
||||
table->table[index] = irte->val;
|
||||
spin_unlock_irqrestore(&table->lock, flags);
|
||||
|
||||
iommu_flush_irt(iommu, devid);
|
||||
|
@ -3690,6 +3722,134 @@ static void free_irte(u16 devid, int index)
|
|||
iommu_completion_wait(iommu);
|
||||
}
|
||||
|
||||
static void irte_prepare(void *entry,
|
||||
u32 delivery_mode, u32 dest_mode,
|
||||
u8 vector, u32 dest_apicid)
|
||||
{
|
||||
union irte *irte = (union irte *) entry;
|
||||
|
||||
irte->val = 0;
|
||||
irte->fields.vector = vector;
|
||||
irte->fields.int_type = delivery_mode;
|
||||
irte->fields.destination = dest_apicid;
|
||||
irte->fields.dm = dest_mode;
|
||||
irte->fields.valid = 1;
|
||||
}
|
||||
|
||||
static void irte_ga_prepare(void *entry,
|
||||
u32 delivery_mode, u32 dest_mode,
|
||||
u8 vector, u32 dest_apicid)
|
||||
{
|
||||
struct irte_ga *irte = (struct irte_ga *) entry;
|
||||
|
||||
irte->lo.val = 0;
|
||||
irte->hi.val = 0;
|
||||
irte->lo.fields_remap.guest_mode = 0;
|
||||
irte->lo.fields_remap.int_type = delivery_mode;
|
||||
irte->lo.fields_remap.dm = dest_mode;
|
||||
irte->hi.fields.vector = vector;
|
||||
irte->lo.fields_remap.destination = dest_apicid;
|
||||
irte->lo.fields_remap.valid = 1;
|
||||
}
|
||||
|
||||
static void irte_activate(void *entry, u16 devid, u16 index)
|
||||
{
|
||||
union irte *irte = (union irte *) entry;
|
||||
|
||||
irte->fields.valid = 1;
|
||||
modify_irte(devid, index, irte);
|
||||
}
|
||||
|
||||
static void irte_ga_activate(void *entry, u16 devid, u16 index)
|
||||
{
|
||||
struct irte_ga *irte = (struct irte_ga *) entry;
|
||||
|
||||
irte->lo.fields_remap.valid = 1;
|
||||
modify_irte_ga(devid, index, irte);
|
||||
}
|
||||
|
||||
static void irte_deactivate(void *entry, u16 devid, u16 index)
|
||||
{
|
||||
union irte *irte = (union irte *) entry;
|
||||
|
||||
irte->fields.valid = 0;
|
||||
modify_irte(devid, index, irte);
|
||||
}
|
||||
|
||||
static void irte_ga_deactivate(void *entry, u16 devid, u16 index)
|
||||
{
|
||||
struct irte_ga *irte = (struct irte_ga *) entry;
|
||||
|
||||
irte->lo.fields_remap.valid = 0;
|
||||
modify_irte_ga(devid, index, irte);
|
||||
}
|
||||
|
||||
static void irte_set_affinity(void *entry, u16 devid, u16 index,
|
||||
u8 vector, u32 dest_apicid)
|
||||
{
|
||||
union irte *irte = (union irte *) entry;
|
||||
|
||||
irte->fields.vector = vector;
|
||||
irte->fields.destination = dest_apicid;
|
||||
modify_irte(devid, index, irte);
|
||||
}
|
||||
|
||||
static void irte_ga_set_affinity(void *entry, u16 devid, u16 index,
|
||||
u8 vector, u32 dest_apicid)
|
||||
{
|
||||
struct irte_ga *irte = (struct irte_ga *) entry;
|
||||
|
||||
irte->hi.fields.vector = vector;
|
||||
irte->lo.fields_remap.destination = dest_apicid;
|
||||
irte->lo.fields_remap.guest_mode = 0;
|
||||
modify_irte_ga(devid, index, irte);
|
||||
}
|
||||
|
||||
static void irte_set_allocated(struct irq_remap_table *table, int index)
|
||||
{
|
||||
table->table[index] = IRTE_ALLOCATED;
|
||||
}
|
||||
|
||||
static void irte_ga_set_allocated(struct irq_remap_table *table, int index)
|
||||
{
|
||||
struct irte_ga *ptr = (struct irte_ga *)table->table;
|
||||
struct irte_ga *irte = &ptr[index];
|
||||
|
||||
memset(&irte->lo.val, 0, sizeof(u64));
|
||||
memset(&irte->hi.val, 0, sizeof(u64));
|
||||
irte->hi.fields.vector = 0xff;
|
||||
}
|
||||
|
||||
static bool irte_is_allocated(struct irq_remap_table *table, int index)
|
||||
{
|
||||
union irte *ptr = (union irte *)table->table;
|
||||
union irte *irte = &ptr[index];
|
||||
|
||||
return irte->val != 0;
|
||||
}
|
||||
|
||||
static bool irte_ga_is_allocated(struct irq_remap_table *table, int index)
|
||||
{
|
||||
struct irte_ga *ptr = (struct irte_ga *)table->table;
|
||||
struct irte_ga *irte = &ptr[index];
|
||||
|
||||
return irte->hi.fields.vector != 0;
|
||||
}
|
||||
|
||||
static void irte_clear_allocated(struct irq_remap_table *table, int index)
|
||||
{
|
||||
table->table[index] = 0;
|
||||
}
|
||||
|
||||
static void irte_ga_clear_allocated(struct irq_remap_table *table, int index)
|
||||
{
|
||||
struct irte_ga *ptr = (struct irte_ga *)table->table;
|
||||
struct irte_ga *irte = &ptr[index];
|
||||
|
||||
memset(&irte->lo.val, 0, sizeof(u64));
|
||||
memset(&irte->hi.val, 0, sizeof(u64));
|
||||
}
|
||||
|
||||
static int get_devid(struct irq_alloc_info *info)
|
||||
{
|
||||
int devid = -1;
|
||||
|
@ -3817,6 +3977,26 @@ static void irq_remapping_prepare_irte(struct amd_ir_data *data,
|
|||
}
|
||||
}
|
||||
|
||||
struct amd_irte_ops irte_32_ops = {
|
||||
.prepare = irte_prepare,
|
||||
.activate = irte_activate,
|
||||
.deactivate = irte_deactivate,
|
||||
.set_affinity = irte_set_affinity,
|
||||
.set_allocated = irte_set_allocated,
|
||||
.is_allocated = irte_is_allocated,
|
||||
.clear_allocated = irte_clear_allocated,
|
||||
};
|
||||
|
||||
struct amd_irte_ops irte_128_ops = {
|
||||
.prepare = irte_ga_prepare,
|
||||
.activate = irte_ga_activate,
|
||||
.deactivate = irte_ga_deactivate,
|
||||
.set_affinity = irte_ga_set_affinity,
|
||||
.set_allocated = irte_ga_set_allocated,
|
||||
.is_allocated = irte_ga_is_allocated,
|
||||
.clear_allocated = irte_ga_clear_allocated,
|
||||
};
|
||||
|
||||
static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
|
@ -3922,7 +4102,7 @@ static void irq_remapping_activate(struct irq_domain *domain,
|
|||
struct amd_ir_data *data = irq_data->chip_data;
|
||||
struct irq_2_irte *irte_info = &data->irq_2_irte;
|
||||
|
||||
modify_irte(irte_info->devid, irte_info->index, data->irte_entry);
|
||||
modify_irte(irte_info->devid, irte_info->index, &data->irte_entry);
|
||||
}
|
||||
|
||||
static void irq_remapping_deactivate(struct irq_domain *domain,
|
||||
|
@ -3933,7 +4113,7 @@ static void irq_remapping_deactivate(struct irq_domain *domain,
|
|||
union irte entry;
|
||||
|
||||
entry.val = 0;
|
||||
modify_irte(irte_info->devid, irte_info->index, data->irte_entry);
|
||||
modify_irte(irte_info->devid, irte_info->index, &data->irte_entry);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops amd_ir_domain_ops = {
|
||||
|
@ -3962,7 +4142,7 @@ static int amd_ir_set_affinity(struct irq_data *data,
|
|||
*/
|
||||
ir_data->irte_entry.fields.vector = cfg->vector;
|
||||
ir_data->irte_entry.fields.destination = cfg->dest_apicid;
|
||||
modify_irte(irte_info->devid, irte_info->index, ir_data->irte_entry);
|
||||
modify_irte(irte_info->devid, irte_info->index, &ir_data->irte_entry);
|
||||
|
||||
/*
|
||||
* After this point, all the interrupts will start arriving
|
||||
|
|
|
@ -410,6 +410,7 @@ struct amd_iommu_fault {
|
|||
|
||||
struct iommu_domain;
|
||||
struct irq_domain;
|
||||
struct amd_irte_ops;
|
||||
|
||||
/*
|
||||
* This structure contains generic data for IOMMU protection domains
|
||||
|
@ -533,6 +534,8 @@ struct amd_iommu {
|
|||
#ifdef CONFIG_IRQ_REMAP
|
||||
struct irq_domain *ir_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
|
||||
struct amd_irte_ops *irte_ops;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -779,6 +782,23 @@ struct amd_ir_data {
|
|||
struct irq_2_irte irq_2_irte;
|
||||
union irte irte_entry;
|
||||
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);
|
||||
void (*deactivate)(void *, u16, u16);
|
||||
void (*set_affinity)(void *, u16, u16, u8, u32);
|
||||
void *(*get)(struct irq_remap_table *, int);
|
||||
void (*set_allocated)(struct irq_remap_table *, int);
|
||||
bool (*is_allocated)(struct irq_remap_table *, int);
|
||||
void (*clear_allocated)(struct irq_remap_table *, int);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
extern struct amd_irte_ops irte_32_ops;
|
||||
extern struct amd_irte_ops irte_128_ops;
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_AMD_IOMMU_TYPES_H */
|
||||
|
|
Loading…
Reference in New Issue