aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/amd_iommu.c
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2012-06-26 05:17:32 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-09-28 11:43:51 -0400
commit5527de744da61f55aaa9b804873923f95272e793 (patch)
treee285dc54b58f7ab1198d44c9768c14e6b2345a37 /drivers/iommu/amd_iommu.c
parent2b324506341cb3baf65f3b6a0f950dd7648938ac (diff)
iommu/amd: Add IOAPIC remapping routines
Add the routine to setup interrupt remapping for ioapic interrupts. Also add a routine to change the affinity of an irq and to free an irq allocation for interrupt remapping. The last two functions will also be used for MSI interrupts. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu/amd_iommu.c')
-rw-r--r--drivers/iommu/amd_iommu.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 4e429e781333..886b4c7fba72 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4000,4 +4000,130 @@ static void free_irte(u16 devid, int index)
4000 iommu_completion_wait(iommu); 4000 iommu_completion_wait(iommu);
4001} 4001}
4002 4002
4003static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
4004 unsigned int destination, int vector,
4005 struct io_apic_irq_attr *attr)
4006{
4007 struct irq_remap_table *table;
4008 struct irq_2_iommu *irte_info;
4009 struct irq_cfg *cfg;
4010 union irte irte;
4011 int ioapic_id;
4012 int index;
4013 int devid;
4014 int ret;
4015
4016 cfg = irq_get_chip_data(irq);
4017 if (!cfg)
4018 return -EINVAL;
4019
4020 irte_info = &cfg->irq_2_iommu;
4021 ioapic_id = mpc_ioapic_id(attr->ioapic);
4022 devid = get_ioapic_devid(ioapic_id);
4023
4024 if (devid < 0)
4025 return devid;
4026
4027 table = get_irq_table(devid, true);
4028 if (table == NULL)
4029 return -ENOMEM;
4030
4031 index = attr->ioapic_pin;
4032
4033 /* Setup IRQ remapping info */
4034 irte_info->sub_handle = devid;
4035 irte_info->irte_index = index;
4036 irte_info->iommu = (void *)cfg;
4037
4038 /* Setup IRTE for IOMMU */
4039 irte.val = 0;
4040 irte.fields.vector = vector;
4041 irte.fields.int_type = apic->irq_delivery_mode;
4042 irte.fields.destination = destination;
4043 irte.fields.dm = apic->irq_dest_mode;
4044 irte.fields.valid = 1;
4045
4046 ret = modify_irte(devid, index, irte);
4047 if (ret)
4048 return ret;
4049
4050 /* Setup IOAPIC entry */
4051 memset(entry, 0, sizeof(*entry));
4052
4053 entry->vector = index;
4054 entry->mask = 0;
4055 entry->trigger = attr->trigger;
4056 entry->polarity = attr->polarity;
4057
4058 /*
4059 * Mask level triggered irqs.
4060 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
4061 */
4062 if (attr->trigger)
4063 entry->mask = 1;
4064
4065 return 0;
4066}
4067
4068static int set_affinity(struct irq_data *data, const struct cpumask *mask,
4069 bool force)
4070{
4071 struct irq_2_iommu *irte_info;
4072 unsigned int dest, irq;
4073 struct irq_cfg *cfg;
4074 union irte irte;
4075 int err;
4076
4077 if (!config_enabled(CONFIG_SMP))
4078 return -1;
4079
4080 cfg = data->chip_data;
4081 irq = data->irq;
4082 irte_info = &cfg->irq_2_iommu;
4083
4084 if (!cpumask_intersects(mask, cpu_online_mask))
4085 return -EINVAL;
4086
4087 if (get_irte(irte_info->sub_handle, irte_info->irte_index, &irte))
4088 return -EBUSY;
4089
4090 if (assign_irq_vector(irq, cfg, mask))
4091 return -EBUSY;
4092
4093 err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest);
4094 if (err) {
4095 if (assign_irq_vector(irq, cfg, data->affinity))
4096 pr_err("AMD-Vi: Failed to recover vector for irq %d\n", irq);
4097 return err;
4098 }
4099
4100 irte.fields.vector = cfg->vector;
4101 irte.fields.destination = dest;
4102
4103 modify_irte(irte_info->sub_handle, irte_info->irte_index, irte);
4104
4105 if (cfg->move_in_progress)
4106 send_cleanup_vector(cfg);
4107
4108 cpumask_copy(data->affinity, mask);
4109
4110 return 0;
4111}
4112
4113static int free_irq(int irq)
4114{
4115 struct irq_2_iommu *irte_info;
4116 struct irq_cfg *cfg;
4117
4118 cfg = irq_get_chip_data(irq);
4119 if (!cfg)
4120 return -EINVAL;
4121
4122 irte_info = &cfg->irq_2_iommu;
4123
4124 free_irte(irte_info->sub_handle, irte_info->irte_index);
4125
4126 return 0;
4127}
4128
4003#endif 4129#endif