diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2015-05-19 05:07:14 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-05-19 09:41:19 -0400 |
commit | 0a4377de305684c883bf90ad21e3cbdeead70f5c (patch) | |
tree | b1212a35515887f4505ba8d6407e02d357b13086 | |
parent | 5ebe6afaf0057ac3eaeb98defd5456894b446d22 (diff) |
genirq: Introduce irq_set_vcpu_affinity() to target an interrupt to a VCPU
With Posted-Interrupts support in Intel CPU and IOMMU, an external
interrupt from assigned-devices could be directly delivered to a
virtual CPU in a virtual machine. Instead of hacking KVM and Intel
IOMMU drivers, we propose a platform independent interface to target
an interrupt to a specific virtual CPU in a virtual machine, or set
virtual CPU affinity for an interrupt.
By adopting this new interface and the hierarchy irqdomain, we could
easily support posted-interrupts on Intel platforms, and also provide
flexible enough interfaces for other platforms to support similar
features.
Here is the usage scenario for this interface:
Guest update MSI/MSI-X interrupt configuration
-->QEMU and KVM handle this
-->KVM call this interface (passing posted interrupts descriptor
and guest vector)
-->irq core will transfer the control to IOMMU
-->IOMMU will do the real work of updating IRTE (IRTE has new
format for VT-d Posted-Interrupts)
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: Feng Wu <feng.wu@intel.com>
Link: http://lkml.kernel.org/r/1432026437-16560-2-git-send-email-feng.wu@intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | include/linux/irq.h | 6 | ||||
-rw-r--r-- | kernel/irq/chip.c | 14 | ||||
-rw-r--r-- | kernel/irq/manage.c | 31 |
3 files changed, 51 insertions, 0 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h index 62c6901cab55..48cb7d1aa58f 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -327,6 +327,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) | |||
327 | * @irq_write_msi_msg: optional to write message content for MSI | 327 | * @irq_write_msi_msg: optional to write message content for MSI |
328 | * @irq_get_irqchip_state: return the internal state of an interrupt | 328 | * @irq_get_irqchip_state: return the internal state of an interrupt |
329 | * @irq_set_irqchip_state: set the internal state of a interrupt | 329 | * @irq_set_irqchip_state: set the internal state of a interrupt |
330 | * @irq_set_vcpu_affinity: optional to target a vCPU in a virtual machine | ||
330 | * @flags: chip specific flags | 331 | * @flags: chip specific flags |
331 | */ | 332 | */ |
332 | struct irq_chip { | 333 | struct irq_chip { |
@@ -369,6 +370,8 @@ struct irq_chip { | |||
369 | int (*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state); | 370 | int (*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state); |
370 | int (*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state); | 371 | int (*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state); |
371 | 372 | ||
373 | int (*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info); | ||
374 | |||
372 | unsigned long flags; | 375 | unsigned long flags; |
373 | }; | 376 | }; |
374 | 377 | ||
@@ -422,6 +425,7 @@ extern void irq_cpu_online(void); | |||
422 | extern void irq_cpu_offline(void); | 425 | extern void irq_cpu_offline(void); |
423 | extern int irq_set_affinity_locked(struct irq_data *data, | 426 | extern int irq_set_affinity_locked(struct irq_data *data, |
424 | const struct cpumask *cpumask, bool force); | 427 | const struct cpumask *cpumask, bool force); |
428 | extern int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info); | ||
425 | 429 | ||
426 | #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) | 430 | #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) |
427 | void irq_move_irq(struct irq_data *data); | 431 | void irq_move_irq(struct irq_data *data); |
@@ -467,6 +471,8 @@ extern int irq_chip_set_affinity_parent(struct irq_data *data, | |||
467 | const struct cpumask *dest, | 471 | const struct cpumask *dest, |
468 | bool force); | 472 | bool force); |
469 | extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on); | 473 | extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on); |
474 | extern int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, | ||
475 | void *vcpu_info); | ||
470 | #endif | 476 | #endif |
471 | 477 | ||
472 | /* Handling of unhandled and spurious interrupts: */ | 478 | /* Handling of unhandled and spurious interrupts: */ |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index eb9a4ea394ab..55016b2151f3 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -950,6 +950,20 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data) | |||
950 | } | 950 | } |
951 | 951 | ||
952 | /** | 952 | /** |
953 | * irq_chip_set_vcpu_affinity_parent - Set vcpu affinity on the parent interrupt | ||
954 | * @data: Pointer to interrupt specific data | ||
955 | * @dest: The vcpu affinity information | ||
956 | */ | ||
957 | int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, void *vcpu_info) | ||
958 | { | ||
959 | data = data->parent_data; | ||
960 | if (data->chip->irq_set_vcpu_affinity) | ||
961 | return data->chip->irq_set_vcpu_affinity(data, vcpu_info); | ||
962 | |||
963 | return -ENOSYS; | ||
964 | } | ||
965 | |||
966 | /** | ||
953 | * irq_chip_set_wake_parent - Set/reset wake-up on the parent interrupt | 967 | * irq_chip_set_wake_parent - Set/reset wake-up on the parent interrupt |
954 | * @data: Pointer to interrupt specific data | 968 | * @data: Pointer to interrupt specific data |
955 | * @on: Whether to set or reset the wake-up capability of this irq | 969 | * @on: Whether to set or reset the wake-up capability of this irq |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index e68932bb308e..b1c7e8f46bfb 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -256,6 +256,37 @@ int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) | |||
256 | } | 256 | } |
257 | EXPORT_SYMBOL_GPL(irq_set_affinity_hint); | 257 | EXPORT_SYMBOL_GPL(irq_set_affinity_hint); |
258 | 258 | ||
259 | /** | ||
260 | * irq_set_vcpu_affinity - Set vcpu affinity for the interrupt | ||
261 | * @irq: interrupt number to set affinity | ||
262 | * @vcpu_info: vCPU specific data | ||
263 | * | ||
264 | * This function uses the vCPU specific data to set the vCPU | ||
265 | * affinity for an irq. The vCPU specific data is passed from | ||
266 | * outside, such as KVM. One example code path is as below: | ||
267 | * KVM -> IOMMU -> irq_set_vcpu_affinity(). | ||
268 | */ | ||
269 | int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info) | ||
270 | { | ||
271 | unsigned long flags; | ||
272 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); | ||
273 | struct irq_data *data; | ||
274 | struct irq_chip *chip; | ||
275 | int ret = -ENOSYS; | ||
276 | |||
277 | if (!desc) | ||
278 | return -EINVAL; | ||
279 | |||
280 | data = irq_desc_get_irq_data(desc); | ||
281 | chip = irq_data_get_irq_chip(data); | ||
282 | if (chip && chip->irq_set_vcpu_affinity) | ||
283 | ret = chip->irq_set_vcpu_affinity(data, vcpu_info); | ||
284 | irq_put_desc_unlock(desc, flags); | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | EXPORT_SYMBOL_GPL(irq_set_vcpu_affinity); | ||
289 | |||
259 | static void irq_affinity_notify(struct work_struct *work) | 290 | static void irq_affinity_notify(struct work_struct *work) |
260 | { | 291 | { |
261 | struct irq_affinity_notify *notify = | 292 | struct irq_affinity_notify *notify = |