diff options
author | Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> | 2016-08-23 14:52:39 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-09-05 06:41:46 -0400 |
commit | b9fc6b56f478b487dc8fc400da73d89ac9137201 (patch) | |
tree | f2bd018bb8dbb4a3c8e28bb3106293e221d3169c /drivers/iommu/amd_iommu.c | |
parent | 8dbea3fd7becd4af8ca882c3132be4b1a857e301 (diff) |
iommu/amd: Implements irq_set_vcpu_affinity() hook to setup vapic mode for pass-through devices
This patch implements irq_set_vcpu_affinity() function to set up interrupt
remapping table entry with vapic mode for pass-through devices.
In case requirements for vapic mode are not met, it falls back to set up
the IRTE in legacy mode.
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu/amd_iommu.c')
-rw-r--r-- | drivers/iommu/amd_iommu.c | 68 |
1 files changed, 64 insertions, 4 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 089e1ed4deec..69fc57e0b975 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -3718,7 +3718,8 @@ out: | |||
3718 | return index; | 3718 | return index; |
3719 | } | 3719 | } |
3720 | 3720 | ||
3721 | static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte) | 3721 | static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte, |
3722 | struct amd_ir_data *data) | ||
3722 | { | 3723 | { |
3723 | struct irq_remap_table *table; | 3724 | struct irq_remap_table *table; |
3724 | struct amd_iommu *iommu; | 3725 | struct amd_iommu *iommu; |
@@ -3741,6 +3742,8 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte) | |||
3741 | entry->hi.val = irte->hi.val; | 3742 | entry->hi.val = irte->hi.val; |
3742 | entry->lo.val = irte->lo.val; | 3743 | entry->lo.val = irte->lo.val; |
3743 | entry->lo.fields_remap.valid = 1; | 3744 | entry->lo.fields_remap.valid = 1; |
3745 | if (data) | ||
3746 | data->ref = entry; | ||
3744 | 3747 | ||
3745 | spin_unlock_irqrestore(&table->lock, flags); | 3748 | spin_unlock_irqrestore(&table->lock, flags); |
3746 | 3749 | ||
@@ -3839,7 +3842,7 @@ static void irte_ga_activate(void *entry, u16 devid, u16 index) | |||
3839 | struct irte_ga *irte = (struct irte_ga *) entry; | 3842 | struct irte_ga *irte = (struct irte_ga *) entry; |
3840 | 3843 | ||
3841 | irte->lo.fields_remap.valid = 1; | 3844 | irte->lo.fields_remap.valid = 1; |
3842 | modify_irte_ga(devid, index, irte); | 3845 | modify_irte_ga(devid, index, irte, NULL); |
3843 | } | 3846 | } |
3844 | 3847 | ||
3845 | static void irte_deactivate(void *entry, u16 devid, u16 index) | 3848 | static void irte_deactivate(void *entry, u16 devid, u16 index) |
@@ -3855,7 +3858,7 @@ static void irte_ga_deactivate(void *entry, u16 devid, u16 index) | |||
3855 | struct irte_ga *irte = (struct irte_ga *) entry; | 3858 | struct irte_ga *irte = (struct irte_ga *) entry; |
3856 | 3859 | ||
3857 | irte->lo.fields_remap.valid = 0; | 3860 | irte->lo.fields_remap.valid = 0; |
3858 | modify_irte_ga(devid, index, irte); | 3861 | modify_irte_ga(devid, index, irte, NULL); |
3859 | } | 3862 | } |
3860 | 3863 | ||
3861 | static void irte_set_affinity(void *entry, u16 devid, u16 index, | 3864 | static void irte_set_affinity(void *entry, u16 devid, u16 index, |
@@ -3876,7 +3879,7 @@ static void irte_ga_set_affinity(void *entry, u16 devid, u16 index, | |||
3876 | irte->hi.fields.vector = vector; | 3879 | irte->hi.fields.vector = vector; |
3877 | irte->lo.fields_remap.destination = dest_apicid; | 3880 | irte->lo.fields_remap.destination = dest_apicid; |
3878 | irte->lo.fields_remap.guest_mode = 0; | 3881 | irte->lo.fields_remap.guest_mode = 0; |
3879 | modify_irte_ga(devid, index, irte); | 3882 | modify_irte_ga(devid, index, irte, NULL); |
3880 | } | 3883 | } |
3881 | 3884 | ||
3882 | #define IRTE_ALLOCATED (~1U) | 3885 | #define IRTE_ALLOCATED (~1U) |
@@ -4211,6 +4214,62 @@ static struct irq_domain_ops amd_ir_domain_ops = { | |||
4211 | .deactivate = irq_remapping_deactivate, | 4214 | .deactivate = irq_remapping_deactivate, |
4212 | }; | 4215 | }; |
4213 | 4216 | ||
4217 | static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) | ||
4218 | { | ||
4219 | struct amd_iommu *iommu; | ||
4220 | struct amd_iommu_pi_data *pi_data = vcpu_info; | ||
4221 | struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data; | ||
4222 | struct amd_ir_data *ir_data = data->chip_data; | ||
4223 | struct irte_ga *irte = (struct irte_ga *) ir_data->entry; | ||
4224 | struct irq_2_irte *irte_info = &ir_data->irq_2_irte; | ||
4225 | |||
4226 | pi_data->ir_data = ir_data; | ||
4227 | |||
4228 | /* Note: | ||
4229 | * SVM tries to set up for VAPIC mode, but we are in | ||
4230 | * legacy mode. So, we force legacy mode instead. | ||
4231 | */ | ||
4232 | if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir)) { | ||
4233 | pr_debug("AMD-Vi: %s: Fall back to using intr legacy remap\n", | ||
4234 | __func__); | ||
4235 | pi_data->is_guest_mode = false; | ||
4236 | } | ||
4237 | |||
4238 | iommu = amd_iommu_rlookup_table[irte_info->devid]; | ||
4239 | if (iommu == NULL) | ||
4240 | return -EINVAL; | ||
4241 | |||
4242 | pi_data->prev_ga_tag = ir_data->cached_ga_tag; | ||
4243 | if (pi_data->is_guest_mode) { | ||
4244 | /* Setting */ | ||
4245 | irte->hi.fields.ga_root_ptr = (pi_data->base >> 12); | ||
4246 | irte->hi.fields.vector = vcpu_pi_info->vector; | ||
4247 | irte->lo.fields_vapic.guest_mode = 1; | ||
4248 | irte->lo.fields_vapic.ga_tag = pi_data->ga_tag; | ||
4249 | |||
4250 | ir_data->cached_ga_tag = pi_data->ga_tag; | ||
4251 | } else { | ||
4252 | /* Un-Setting */ | ||
4253 | struct irq_cfg *cfg = irqd_cfg(data); | ||
4254 | |||
4255 | irte->hi.val = 0; | ||
4256 | irte->lo.val = 0; | ||
4257 | irte->hi.fields.vector = cfg->vector; | ||
4258 | irte->lo.fields_remap.guest_mode = 0; | ||
4259 | irte->lo.fields_remap.destination = cfg->dest_apicid; | ||
4260 | irte->lo.fields_remap.int_type = apic->irq_delivery_mode; | ||
4261 | irte->lo.fields_remap.dm = apic->irq_dest_mode; | ||
4262 | |||
4263 | /* | ||
4264 | * This communicates the ga_tag back to the caller | ||
4265 | * so that it can do all the necessary clean up. | ||
4266 | */ | ||
4267 | ir_data->cached_ga_tag = 0; | ||
4268 | } | ||
4269 | |||
4270 | return modify_irte_ga(irte_info->devid, irte_info->index, irte, ir_data); | ||
4271 | } | ||
4272 | |||
4214 | static int amd_ir_set_affinity(struct irq_data *data, | 4273 | static int amd_ir_set_affinity(struct irq_data *data, |
4215 | const struct cpumask *mask, bool force) | 4274 | const struct cpumask *mask, bool force) |
4216 | { | 4275 | { |
@@ -4255,6 +4314,7 @@ static void ir_compose_msi_msg(struct irq_data *irq_data, struct msi_msg *msg) | |||
4255 | static struct irq_chip amd_ir_chip = { | 4314 | static struct irq_chip amd_ir_chip = { |
4256 | .irq_ack = ir_ack_apic_edge, | 4315 | .irq_ack = ir_ack_apic_edge, |
4257 | .irq_set_affinity = amd_ir_set_affinity, | 4316 | .irq_set_affinity = amd_ir_set_affinity, |
4317 | .irq_set_vcpu_affinity = amd_ir_set_vcpu_affinity, | ||
4258 | .irq_compose_msi_msg = ir_compose_msi_msg, | 4318 | .irq_compose_msi_msg = ir_compose_msi_msg, |
4259 | }; | 4319 | }; |
4260 | 4320 | ||