RE: [EXTERNAL] [PATCH 3/3] PCI: hv: fix interrupt affinity change on the nested root partition

From: Long Li

Date: Tue Aug 25 2026 - 16:34:05 EST


>
> From: Wei Liu <wei.liu@xxxxxxxxxx>
>
> hv_compose_msi_msg() sends PCI_CREATE_INTERRUPT carrying
> int_desc.vector, and the vPCI backend programs the device with the
> address/data it returns for it.
>
> An affinity change only ran irq_chip_set_affinity_parent(), which re-allocates
> the x86 vector and nothing else, and hv_arch_irq_unmask() then issued
> MAP_DEVICE_INTERRUPT for the new (VP, vector). Nothing re-composed the
> interrupt, so the device kept signalling the vector it was created with and the
> new mapping was never used. This led to loss of interrupts.
>
> Do the re-target where the vector is known and the interrupt is quiescent. If
> the vector changed, re-compose the VMBus interrupt for it, write the
> resulting message to the device, and only then map the new (vp, vector); the
> old mapping is destroyed as the new message is composed.
>
> Signed-off-by: Wei Liu <wei.liu@xxxxxxxxxx>
> ---
> drivers/pci/controller/pci-hyperv.c | 41 +++++++++++++++++++++++++++--
> 1 file changed, 39 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-
> hyperv.c
> index 5a36382742bf..5acb8e41567e 100644
> --- a/drivers/pci/controller/pci-hyperv.c
> +++ b/drivers/pci/controller/pci-hyperv.c
> @@ -294,6 +294,7 @@ struct tran_int_desc { struct hv_msi_int_entry {
> struct tran_int_desc int_desc;
> struct hv_interrupt_entry hv_entry;
> + unsigned int mapped_vector;
> };
>
> /* chip_data is passed around as a struct tran_int_desc *, so it must be first.
> */ @@ -742,6 +743,8 @@ static void hv_irq_retarget_interrupt(struct
> irq_data *data)
> "%s() failed: %#llx", __func__, res); }
>
> +static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg
> +*msg);
> +
> static void hv_arch_irq_unmask(struct irq_data *data) {
> if (hv_root_partition()) {
> @@ -752,9 +755,17 @@ static void hv_arch_irq_unmask(struct irq_data
> *data)
> * RETARGET_INTERRUPT.
> *
> * Keep the returned entry so the mapping can be removed
> again
> - * when the interrupt is torn down.
> + * when the interrupt is re-targeted or torn down.
> + *
> + * This is also the re-target point. The core calls us from
> + * __irq_move_irq() with the interrupt masked once the new
> + * vector has been assigned, so if the vector changed the
> vmbus
> + * interrupt is re-composed for it first --
> PCI_CREATE_INTERRUPT
> + * carries the vector, so the device would otherwise keep
> + * signalling the one it was created with.
> */
> struct hv_msi_int_entry *ie = data->chip_data;
> + unsigned int vec = hv_msi_get_int_vector(data);
>
> /*
> * A NULL chip_data means hv_compose_msi_msg() failed
> and the @@ -763,8 +774,29 @@ static void hv_arch_irq_unmask(struct
> irq_data *data)
> if (!ie)
> return;
>
> - if (hv_map_msi_interrupt(data, &ie->hv_entry))
> + /* Already mapped for this vector, nothing changed. */
> + if (ie->mapped_vector == vec && ie->hv_entry.source)
> + return;
> +
> + if (ie->mapped_vector && ie->mapped_vector != vec) {
> + struct msi_msg msg;
> +
> + hv_compose_msi_msg(data, &msg);
> +
> + ie = data->chip_data;
> + if (!ie)
> + return;
> +
> + if (data->chip->irq_write_msi_msg)
> + data->chip->irq_write_msi_msg(data, &msg);

I don't see the function irq_write_msi_msg defined in hv_msi_irq_chip, maybe not looking at the right place. Is this function ever getting called?