From aa8e17989453909df2dce77fd917a5346e19957e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Oct 2025 16:17:46 +0200 Subject: [PATCH] 5.15-stable patches added patches: media-pci-ivtv-add-missing-check-after-dma-map.patch media-pci-ivtv-switch-from-pci_-to-dma_-api.patch xen-events-update-virq_to_irq-on-migration.patch --- ...ivtv-add-missing-check-after-dma-map.patch | 63 +++ ...ci-ivtv-switch-from-pci_-to-dma_-api.patch | 393 ++++++++++++++++++ queue-5.15/series | 3 + ...ents-update-virq_to_irq-on-migration.patch | 64 +++ 4 files changed, 523 insertions(+) create mode 100644 queue-5.15/media-pci-ivtv-add-missing-check-after-dma-map.patch create mode 100644 queue-5.15/media-pci-ivtv-switch-from-pci_-to-dma_-api.patch create mode 100644 queue-5.15/xen-events-update-virq_to_irq-on-migration.patch diff --git a/queue-5.15/media-pci-ivtv-add-missing-check-after-dma-map.patch b/queue-5.15/media-pci-ivtv-add-missing-check-after-dma-map.patch new file mode 100644 index 0000000000..e5d6df2ba9 --- /dev/null +++ b/queue-5.15/media-pci-ivtv-add-missing-check-after-dma-map.patch @@ -0,0 +1,63 @@ +From stable+bounces-186330-greg=kroah.com@vger.kernel.org Fri Oct 17 15:59:41 2025 +From: Sasha Levin +Date: Fri, 17 Oct 2025 09:59:32 -0400 +Subject: media: pci: ivtv: Add missing check after DMA map +To: stable@vger.kernel.org +Cc: Thomas Fourier , Hans Verkuil , Sasha Levin +Message-ID: <20251017135932.3966607-2-sashal@kernel.org> + +From: Thomas Fourier + +[ Upstream commit 1069a4fe637d0e3e4c163e3f8df9be306cc299b4 ] + +The DMA map functions can fail and should be tested for errors. +If the mapping fails, free blanking_ptr and set it to 0. As 0 is a +valid DMA address, use blanking_ptr to test if the DMA address +is set. + +Fixes: 1a0adaf37c30 ("V4L/DVB (5345): ivtv driver for Conexant cx23416/cx23415 MPEG encoder/decoder") +Cc: stable@vger.kernel.org +Signed-off-by: Thomas Fourier +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/pci/ivtv/ivtv-irq.c | 2 +- + drivers/media/pci/ivtv/ivtv-yuv.c | 8 +++++++- + 2 files changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/media/pci/ivtv/ivtv-irq.c ++++ b/drivers/media/pci/ivtv/ivtv-irq.c +@@ -351,7 +351,7 @@ void ivtv_dma_stream_dec_prepare(struct + + /* Insert buffer block for YUV if needed */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { +- if (yi->blanking_dmaptr) { ++ if (yi->blanking_ptr) { + s->sg_pending[idx].src = yi->blanking_dmaptr; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = 720 * 16; +--- a/drivers/media/pci/ivtv/ivtv-yuv.c ++++ b/drivers/media/pci/ivtv/ivtv-yuv.c +@@ -120,7 +120,7 @@ static int ivtv_yuv_prep_user_dma(struct + ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); + + /* If we've offset the y plane, ensure top area is blanked */ +- if (f->offset_y && yi->blanking_dmaptr) { ++ if (f->offset_y && yi->blanking_ptr) { + dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); + dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); +@@ -924,6 +924,12 @@ static void ivtv_yuv_init(struct ivtv *i + yi->blanking_dmaptr = dma_map_single(&itv->pdev->dev, + yi->blanking_ptr, + 720 * 16, DMA_TO_DEVICE); ++ if (dma_mapping_error(&itv->pdev->dev, yi->blanking_dmaptr)) { ++ kfree(yi->blanking_ptr); ++ yi->blanking_ptr = NULL; ++ yi->blanking_dmaptr = 0; ++ IVTV_DEBUG_WARN("Failed to dma_map yuv blanking buffer\n"); ++ } + } else { + yi->blanking_dmaptr = 0; + IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); diff --git a/queue-5.15/media-pci-ivtv-switch-from-pci_-to-dma_-api.patch b/queue-5.15/media-pci-ivtv-switch-from-pci_-to-dma_-api.patch new file mode 100644 index 0000000000..ab21d88972 --- /dev/null +++ b/queue-5.15/media-pci-ivtv-switch-from-pci_-to-dma_-api.patch @@ -0,0 +1,393 @@ +From stable+bounces-186329-greg=kroah.com@vger.kernel.org Fri Oct 17 15:59:40 2025 +From: Sasha Levin +Date: Fri, 17 Oct 2025 09:59:31 -0400 +Subject: media: pci/ivtv: switch from 'pci_' to 'dma_' API +To: stable@vger.kernel.org +Cc: Christophe JAILLET , Hans Verkuil , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <20251017135932.3966607-1-sashal@kernel.org> + +From: Christophe JAILLET + +[ Upstream commit 1932dc2f4cf6ac23e48e5fcc24d21adbe35691d1 ] + +The wrappers in include/linux/pci-dma-compat.h should go away. + +The patch has been generated with the coccinelle script below. +It has been compile tested. + +No memory allocation in involved in this patch, so no GFP_ tweak is needed. + +@@ @@ +- PCI_DMA_BIDIRECTIONAL ++ DMA_BIDIRECTIONAL + +@@ @@ +- PCI_DMA_TODEVICE ++ DMA_TO_DEVICE + +@@ @@ +- PCI_DMA_FROMDEVICE ++ DMA_FROM_DEVICE + +@@ @@ +- PCI_DMA_NONE ++ DMA_NONE + +@@ +expression e1, e2, e3; +@@ +- pci_alloc_consistent(e1, e2, e3) ++ dma_alloc_coherent(&e1->dev, e2, e3, GFP_) + +@@ +expression e1, e2, e3; +@@ +- pci_zalloc_consistent(e1, e2, e3) ++ dma_alloc_coherent(&e1->dev, e2, e3, GFP_) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_free_consistent(e1, e2, e3, e4) ++ dma_free_coherent(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_map_single(e1, e2, e3, e4) ++ dma_map_single(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_unmap_single(e1, e2, e3, e4) ++ dma_unmap_single(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4, e5; +@@ +- pci_map_page(e1, e2, e3, e4, e5) ++ dma_map_page(&e1->dev, e2, e3, e4, e5) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_unmap_page(e1, e2, e3, e4) ++ dma_unmap_page(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_map_sg(e1, e2, e3, e4) ++ dma_map_sg(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_unmap_sg(e1, e2, e3, e4) ++ dma_unmap_sg(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_dma_sync_single_for_cpu(e1, e2, e3, e4) ++ dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_dma_sync_single_for_device(e1, e2, e3, e4) ++ dma_sync_single_for_device(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) ++ dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2, e3, e4; +@@ +- pci_dma_sync_sg_for_device(e1, e2, e3, e4) ++ dma_sync_sg_for_device(&e1->dev, e2, e3, e4) + +@@ +expression e1, e2; +@@ +- pci_dma_mapping_error(e1, e2) ++ dma_mapping_error(&e1->dev, e2) + +@@ +expression e1, e2; +@@ +- pci_set_dma_mask(e1, e2) ++ dma_set_mask(&e1->dev, e2) + +@@ +expression e1, e2; +@@ +- pci_set_consistent_dma_mask(e1, e2) ++ dma_set_coherent_mask(&e1->dev, e2) + +Signed-off-by: Christophe JAILLET +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Stable-dep-of: 1069a4fe637d ("media: pci: ivtv: Add missing check after DMA map") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/pci/ivtv/ivtv-driver.c | 2 +- + drivers/media/pci/ivtv/ivtv-queue.c | 18 ++++++++++-------- + drivers/media/pci/ivtv/ivtv-streams.c | 22 +++++++++++----------- + drivers/media/pci/ivtv/ivtv-udma.c | 19 ++++++++++++------- + drivers/media/pci/ivtv/ivtv-yuv.c | 10 +++++++--- + 5 files changed, 41 insertions(+), 30 deletions(-) + +--- a/drivers/media/pci/ivtv/ivtv-driver.c ++++ b/drivers/media/pci/ivtv/ivtv-driver.c +@@ -837,7 +837,7 @@ static int ivtv_setup_pci(struct ivtv *i + IVTV_ERR("Can't enable device!\n"); + return -EIO; + } +- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { ++ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { + IVTV_ERR("No suitable DMA available.\n"); + return -EIO; + } +--- a/drivers/media/pci/ivtv/ivtv-queue.c ++++ b/drivers/media/pci/ivtv/ivtv-queue.c +@@ -188,7 +188,7 @@ int ivtv_stream_alloc(struct ivtv_stream + return 0; + + IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", +- s->dma != PCI_DMA_NONE ? "DMA " : "", ++ s->dma != DMA_NONE ? "DMA " : "", + s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); + + s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); +@@ -218,8 +218,9 @@ int ivtv_stream_alloc(struct ivtv_stream + return -ENOMEM; + } + if (ivtv_might_use_dma(s)) { +- s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, +- sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); ++ s->sg_handle = dma_map_single(&itv->pdev->dev, s->sg_dma, ++ sizeof(struct ivtv_sg_element), ++ DMA_TO_DEVICE); + ivtv_stream_sync_for_cpu(s); + } + +@@ -237,7 +238,7 @@ int ivtv_stream_alloc(struct ivtv_stream + } + INIT_LIST_HEAD(&buf->list); + if (ivtv_might_use_dma(s)) { +- buf->dma_handle = pci_map_single(s->itv->pdev, ++ buf->dma_handle = dma_map_single(&s->itv->pdev->dev, + buf->buf, s->buf_size + 256, s->dma); + ivtv_buf_sync_for_cpu(s, buf); + } +@@ -260,8 +261,8 @@ void ivtv_stream_free(struct ivtv_stream + /* empty q_free */ + while ((buf = ivtv_dequeue(s, &s->q_free))) { + if (ivtv_might_use_dma(s)) +- pci_unmap_single(s->itv->pdev, buf->dma_handle, +- s->buf_size + 256, s->dma); ++ dma_unmap_single(&s->itv->pdev->dev, buf->dma_handle, ++ s->buf_size + 256, s->dma); + kfree(buf->buf); + kfree(buf); + } +@@ -269,8 +270,9 @@ void ivtv_stream_free(struct ivtv_stream + /* Free SG Array/Lists */ + if (s->sg_dma != NULL) { + if (s->sg_handle != IVTV_DMA_UNMAPPED) { +- pci_unmap_single(s->itv->pdev, s->sg_handle, +- sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); ++ dma_unmap_single(&s->itv->pdev->dev, s->sg_handle, ++ sizeof(struct ivtv_sg_element), ++ DMA_TO_DEVICE); + s->sg_handle = IVTV_DMA_UNMAPPED; + } + kfree(s->sg_pending); +--- a/drivers/media/pci/ivtv/ivtv-streams.c ++++ b/drivers/media/pci/ivtv/ivtv-streams.c +@@ -100,7 +100,7 @@ static struct { + { /* IVTV_ENC_STREAM_TYPE_MPG */ + "encoder MPG", + VFL_TYPE_VIDEO, 0, +- PCI_DMA_FROMDEVICE, 0, ++ DMA_FROM_DEVICE, 0, + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops +@@ -108,7 +108,7 @@ static struct { + { /* IVTV_ENC_STREAM_TYPE_YUV */ + "encoder YUV", + VFL_TYPE_VIDEO, IVTV_V4L2_ENC_YUV_OFFSET, +- PCI_DMA_FROMDEVICE, 0, ++ DMA_FROM_DEVICE, 0, + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops +@@ -116,7 +116,7 @@ static struct { + { /* IVTV_ENC_STREAM_TYPE_VBI */ + "encoder VBI", + VFL_TYPE_VBI, 0, +- PCI_DMA_FROMDEVICE, 0, ++ DMA_FROM_DEVICE, 0, + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops +@@ -124,42 +124,42 @@ static struct { + { /* IVTV_ENC_STREAM_TYPE_PCM */ + "encoder PCM", + VFL_TYPE_VIDEO, IVTV_V4L2_ENC_PCM_OFFSET, +- PCI_DMA_FROMDEVICE, 0, ++ DMA_FROM_DEVICE, 0, + V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_RAD */ + "encoder radio", + VFL_TYPE_RADIO, 0, +- PCI_DMA_NONE, 1, ++ DMA_NONE, 1, + V4L2_CAP_RADIO | V4L2_CAP_TUNER, + &ivtv_v4l2_radio_fops + }, + { /* IVTV_DEC_STREAM_TYPE_MPG */ + "decoder MPG", + VFL_TYPE_VIDEO, IVTV_V4L2_DEC_MPG_OFFSET, +- PCI_DMA_TODEVICE, 0, ++ DMA_TO_DEVICE, 0, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_dec_fops + }, + { /* IVTV_DEC_STREAM_TYPE_VBI */ + "decoder VBI", + VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, +- PCI_DMA_NONE, 1, ++ DMA_NONE, 1, + V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_DEC_STREAM_TYPE_VOUT */ + "decoder VOUT", + VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, +- PCI_DMA_NONE, 1, ++ DMA_NONE, 1, + V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_dec_fops + }, + { /* IVTV_DEC_STREAM_TYPE_YUV */ + "decoder YUV", + VFL_TYPE_VIDEO, IVTV_V4L2_DEC_YUV_OFFSET, +- PCI_DMA_TODEVICE, 0, ++ DMA_TO_DEVICE, 0, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_dec_fops + } +@@ -179,7 +179,7 @@ static void ivtv_stream_init(struct ivtv + s->vdev.device_caps = ivtv_stream_info[type].v4l2_caps; + + if (ivtv_stream_info[type].pio) +- s->dma = PCI_DMA_NONE; ++ s->dma = DMA_NONE; + else + s->dma = ivtv_stream_info[type].dma; + s->buf_size = itv->stream_buf_size[type]; +@@ -217,7 +217,7 @@ static int ivtv_prep_dev(struct ivtv *it + + /* User explicitly selected 0 buffers for these streams, so don't + create them. */ +- if (ivtv_stream_info[type].dma != PCI_DMA_NONE && ++ if (ivtv_stream_info[type].dma != DMA_NONE && + itv->options.kilobytes[type] == 0) { + IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); + return 0; +--- a/drivers/media/pci/ivtv/ivtv-udma.c ++++ b/drivers/media/pci/ivtv/ivtv-udma.c +@@ -81,8 +81,10 @@ void ivtv_udma_alloc(struct ivtv *itv) + { + if (itv->udma.SG_handle == 0) { + /* Map DMA Page Array Buffer */ +- itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray, +- sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); ++ itv->udma.SG_handle = dma_map_single(&itv->pdev->dev, ++ itv->udma.SGarray, ++ sizeof(itv->udma.SGarray), ++ DMA_TO_DEVICE); + ivtv_udma_sync_for_cpu(itv); + } + } +@@ -135,7 +137,8 @@ int ivtv_udma_setup(struct ivtv *itv, un + } + + /* Map SG List */ +- dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); ++ dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, ++ dma->page_count, DMA_TO_DEVICE); + + /* Fill SG Array with new values */ + ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); +@@ -159,7 +162,8 @@ void ivtv_udma_unmap(struct ivtv *itv) + + /* Unmap Scatterlist */ + if (dma->SG_length) { +- pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); ++ dma_unmap_sg(&itv->pdev->dev, dma->SGlist, dma->page_count, ++ DMA_TO_DEVICE); + dma->SG_length = 0; + } + /* sync DMA */ +@@ -175,13 +179,14 @@ void ivtv_udma_free(struct ivtv *itv) + + /* Unmap SG Array */ + if (itv->udma.SG_handle) { +- pci_unmap_single(itv->pdev, itv->udma.SG_handle, +- sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); ++ dma_unmap_single(&itv->pdev->dev, itv->udma.SG_handle, ++ sizeof(itv->udma.SGarray), DMA_TO_DEVICE); + } + + /* Unmap Scatterlist */ + if (itv->udma.SG_length) { +- pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); ++ dma_unmap_sg(&itv->pdev->dev, itv->udma.SGlist, ++ itv->udma.page_count, DMA_TO_DEVICE); + } + + for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { +--- a/drivers/media/pci/ivtv/ivtv-yuv.c ++++ b/drivers/media/pci/ivtv/ivtv-yuv.c +@@ -113,7 +113,8 @@ static int ivtv_yuv_prep_user_dma(struct + dma->page_count = 0; + return -ENOMEM; + } +- dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); ++ dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, ++ dma->page_count, DMA_TO_DEVICE); + + /* Fill SG Array with new values */ + ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); +@@ -920,7 +921,9 @@ static void ivtv_yuv_init(struct ivtv *i + /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ + yi->blanking_ptr = kzalloc(720 * 16, GFP_ATOMIC|__GFP_NOWARN); + if (yi->blanking_ptr) { +- yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); ++ yi->blanking_dmaptr = dma_map_single(&itv->pdev->dev, ++ yi->blanking_ptr, ++ 720 * 16, DMA_TO_DEVICE); + } else { + yi->blanking_dmaptr = 0; + IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); +@@ -1264,7 +1267,8 @@ void ivtv_yuv_close(struct ivtv *itv) + if (yi->blanking_ptr) { + kfree(yi->blanking_ptr); + yi->blanking_ptr = NULL; +- pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); ++ dma_unmap_single(&itv->pdev->dev, yi->blanking_dmaptr, ++ 720 * 16, DMA_TO_DEVICE); + } + + /* Invalidate the old dimension information */ diff --git a/queue-5.15/series b/queue-5.15/series index c6d0895c88..30606ee7fe 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -267,3 +267,6 @@ writeback-avoid-excessively-long-inode-switching-tim.patch media-switch-from-pci_-to-dma_-api.patch media-cx18-add-missing-check-after-dma-map.patch arm64-mte-do-not-flag-the-zero-page-as-pg_mte_tagged.patch +media-pci-ivtv-switch-from-pci_-to-dma_-api.patch +media-pci-ivtv-add-missing-check-after-dma-map.patch +xen-events-update-virq_to_irq-on-migration.patch diff --git a/queue-5.15/xen-events-update-virq_to_irq-on-migration.patch b/queue-5.15/xen-events-update-virq_to_irq-on-migration.patch new file mode 100644 index 0000000000..86108da06b --- /dev/null +++ b/queue-5.15/xen-events-update-virq_to_irq-on-migration.patch @@ -0,0 +1,64 @@ +From stable+bounces-186328-greg=kroah.com@vger.kernel.org Fri Oct 17 15:55:49 2025 +From: Sasha Levin +Date: Fri, 17 Oct 2025 09:55:42 -0400 +Subject: xen/events: Update virq_to_irq on migration +To: stable@vger.kernel.org +Cc: Jason Andryuk , Juergen Gross , Sasha Levin +Message-ID: <20251017135542.3964097-1-sashal@kernel.org> + +From: Jason Andryuk + +[ Upstream commit 3fcc8e146935415d69ffabb5df40ecf50e106131 ] + +VIRQs come in 3 flavors, per-VPU, per-domain, and global, and the VIRQs +are tracked in per-cpu virq_to_irq arrays. + +Per-domain and global VIRQs must be bound on CPU 0, and +bind_virq_to_irq() sets the per_cpu virq_to_irq at registration time +Later, the interrupt can migrate, and info->cpu is updated. When +calling __unbind_from_irq(), the per-cpu virq_to_irq is cleared for a +different cpu. If bind_virq_to_irq() is called again with CPU 0, the +stale irq is returned. There won't be any irq_info for the irq, so +things break. + +Make xen_rebind_evtchn_to_cpu() update the per_cpu virq_to_irq mappings +to keep them update to date with the current cpu. This ensures the +correct virq_to_irq is cleared in __unbind_from_irq(). + +Fixes: e46cdb66c8fc ("xen: event channels") +Cc: stable@vger.kernel.org +Signed-off-by: Jason Andryuk +Reviewed-by: Juergen Gross +Signed-off-by: Juergen Gross +Message-ID: <20250828003604.8949-4-jason.andryuk@amd.com> +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/xen/events/events_base.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/xen/events/events_base.c ++++ b/drivers/xen/events/events_base.c +@@ -1820,9 +1820,20 @@ static int xen_rebind_evtchn_to_cpu(stru + * virq or IPI channel, which don't actually need to be rebound. Ignore + * it, but don't do the xenlinux-level rebind in that case. + */ +- if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0) ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0) { ++ int old_cpu = info->cpu; ++ + bind_evtchn_to_cpu(evtchn, tcpu, false); + ++ if (info->type == IRQT_VIRQ) { ++ int virq = info->u.virq; ++ int irq = per_cpu(virq_to_irq, old_cpu)[virq]; ++ ++ per_cpu(virq_to_irq, old_cpu)[virq] = -1; ++ per_cpu(virq_to_irq, tcpu)[virq] = irq; ++ } ++ } ++ + do_unmask(info, EVT_MASK_REASON_TEMPORARY); + + return 0; -- 2.47.3