diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2012-06-26 05:17:32 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2012-09-28 11:43:51 -0400 |
commit | 5527de744da61f55aaa9b804873923f95272e793 (patch) | |
tree | e285dc54b58f7ab1198d44c9768c14e6b2345a37 /drivers/iommu/amd_iommu.c | |
parent | 2b324506341cb3baf65f3b6a0f950dd7648938ac (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.c | 126 |
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 | ||
4003 | static 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 | |||
4068 | static 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 | |||
4113 | static 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 |