From: Greg Kroah-Hartman Date: Tue, 6 Jan 2026 14:26:36 +0000 (+0100) Subject: 6.12-stable patches X-Git-Tag: v6.12.64~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=befa45d99c9615115477828b43acaf7831ea0e6a;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches added patches: asoc-qcom-sdw-fix-memory-leak-for-sdw_stream_runtime.patch asoc-renesas-rz-ssi-fix-channel-swap-issue-in-full-duplex-mode.patch asoc-renesas-rz-ssi-fix-rz_ssi_priv-hw_params_cache-sample_width.patch block-handle-zone-management-operations-completions.patch gve-defer-interrupt-enabling-until-napi-registration.patch media-amphion-add-a-frame-flush-mode-for-decoder.patch media-amphion-make-some-vpu_v4l2-functions-static.patch media-amphion-remove-vpu_vb_is_codecconfig.patch media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch pci-brcmstb-fix-disabling-l0s-capability.patch pci-brcmstb-reuse-pcie_cfg_data-structure.patch pci-brcmstb-set-mlw-based-on-num-lanes-dt-property-if-present.patch powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch soundwire-stream-extend-sdw_alloc_stream-to-take-type-parameter.patch vfio-pci-disable-qword-access-to-the-pci-rom-bar.patch --- diff --git a/queue-6.12/asoc-qcom-sdw-fix-memory-leak-for-sdw_stream_runtime.patch b/queue-6.12/asoc-qcom-sdw-fix-memory-leak-for-sdw_stream_runtime.patch new file mode 100644 index 0000000000..9252d2e636 --- /dev/null +++ b/queue-6.12/asoc-qcom-sdw-fix-memory-leak-for-sdw_stream_runtime.patch @@ -0,0 +1,249 @@ +From stable+bounces-204828-greg=kroah.com@vger.kernel.org Mon Jan 5 16:15:00 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:10:08 -0500 +Subject: ASoC: qcom: sdw: fix memory leak for sdw_stream_runtime +To: stable@vger.kernel.org +Cc: Srinivas Kandagatla , Krzysztof Kozlowski , Stable@vger.kernel.org, Steev Klimaszewski , Mark Brown , Sasha Levin +Message-ID: <20260105151008.2624877-2-sashal@kernel.org> + +From: Srinivas Kandagatla + +[ Upstream commit bcba17279327c6e85dee6a97014dc642e2dc93cc ] + +For some reason we endedup allocating sdw_stream_runtime for every cpu dai, +this has two issues. +1. we never set snd_soc_dai_set_stream for non soundwire dai, which + means there is no way that we can free this, resulting in memory leak +2. startup and shutdown callbacks can be called without + hw_params callback called. This combination results in memory leak +because machine driver sruntime array pointer is only set in hw_params +callback. + +Fix this by + 1. adding a helper function to get sdw_runtime for substream +which can be used by shutdown callback to get hold of sruntime to free. + 2. only allocate sdw_runtime for soundwire dais. + +Fixes: d32bac9cb09c ("ASoC: qcom: Add helper for allocating Soundwire stream runtime") +Cc: Krzysztof Kozlowski +Cc: Stable@vger.kernel.org +Signed-off-by: Srinivas Kandagatla +Tested-by: Steev Klimaszewski # Thinkpad X13s +Link: https://patch.msgid.link/20251022143349.1081513-2-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/qcom/sc7280.c | 2 + sound/soc/qcom/sc8280xp.c | 2 + sound/soc/qcom/sdw.c | 105 +++++++++++++++++++++++++--------------------- + sound/soc/qcom/sdw.h | 1 + sound/soc/qcom/sm8250.c | 2 + sound/soc/qcom/x1e80100.c | 2 + 6 files changed, 64 insertions(+), 50 deletions(-) + +--- a/sound/soc/qcom/sc7280.c ++++ b/sound/soc/qcom/sc7280.c +@@ -317,7 +317,7 @@ static void sc7280_snd_shutdown(struct s + struct snd_soc_card *card = rtd->card; + struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); +- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; ++ struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); + + switch (cpu_dai->id) { + case MI2S_PRIMARY: +--- a/sound/soc/qcom/sc8280xp.c ++++ b/sound/soc/qcom/sc8280xp.c +@@ -69,7 +69,7 @@ static void sc8280xp_snd_shutdown(struct + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); +- struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id]; ++ struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); + + pdata->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); +--- a/sound/soc/qcom/sdw.c ++++ b/sound/soc/qcom/sdw.c +@@ -7,6 +7,37 @@ + #include + #include "sdw.h" + ++static bool qcom_snd_is_sdw_dai(int id) ++{ ++ switch (id) { ++ case WSA_CODEC_DMA_RX_0: ++ case WSA_CODEC_DMA_TX_0: ++ case WSA_CODEC_DMA_RX_1: ++ case WSA_CODEC_DMA_TX_1: ++ case WSA_CODEC_DMA_TX_2: ++ case RX_CODEC_DMA_RX_0: ++ case TX_CODEC_DMA_TX_0: ++ case RX_CODEC_DMA_RX_1: ++ case TX_CODEC_DMA_TX_1: ++ case RX_CODEC_DMA_RX_2: ++ case TX_CODEC_DMA_TX_2: ++ case RX_CODEC_DMA_RX_3: ++ case TX_CODEC_DMA_TX_3: ++ case RX_CODEC_DMA_RX_4: ++ case TX_CODEC_DMA_TX_4: ++ case RX_CODEC_DMA_RX_5: ++ case TX_CODEC_DMA_TX_5: ++ case RX_CODEC_DMA_RX_6: ++ case RX_CODEC_DMA_RX_7: ++ case SLIMBUS_0_RX...SLIMBUS_6_TX: ++ return true; ++ default: ++ break; ++ } ++ ++ return false; ++} ++ + /** + * qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card + * @substream: The PCM substream from audio, as passed to snd_soc_ops->startup() +@@ -27,6 +58,9 @@ int qcom_snd_sdw_startup(struct snd_pcm_ + struct snd_soc_dai *codec_dai; + int ret, i; + ++ if (!qcom_snd_is_sdw_dai(cpu_dai->id)) ++ return 0; ++ + sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM); + if (!sruntime) + return -ENOMEM; +@@ -61,19 +95,8 @@ int qcom_snd_sdw_prepare(struct snd_pcm_ + if (!sruntime) + return 0; + +- switch (cpu_dai->id) { +- case WSA_CODEC_DMA_RX_0: +- case WSA_CODEC_DMA_RX_1: +- case RX_CODEC_DMA_RX_0: +- case RX_CODEC_DMA_RX_1: +- case TX_CODEC_DMA_TX_0: +- case TX_CODEC_DMA_TX_1: +- case TX_CODEC_DMA_TX_2: +- case TX_CODEC_DMA_TX_3: +- break; +- default: ++ if (!qcom_snd_is_sdw_dai(cpu_dai->id)) + return 0; +- } + + if (*stream_prepared) + return 0; +@@ -101,9 +124,7 @@ int qcom_snd_sdw_prepare(struct snd_pcm_ + } + EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare); + +-int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, +- struct snd_pcm_hw_params *params, +- struct sdw_stream_runtime **psruntime) ++struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *substream) + { + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; +@@ -111,21 +132,23 @@ int qcom_snd_sdw_hw_params(struct snd_pc + struct sdw_stream_runtime *sruntime; + int i; + +- switch (cpu_dai->id) { +- case WSA_CODEC_DMA_RX_0: +- case RX_CODEC_DMA_RX_0: +- case RX_CODEC_DMA_RX_1: +- case TX_CODEC_DMA_TX_0: +- case TX_CODEC_DMA_TX_1: +- case TX_CODEC_DMA_TX_2: +- case TX_CODEC_DMA_TX_3: +- for_each_rtd_codec_dais(rtd, i, codec_dai) { +- sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream); +- if (sruntime != ERR_PTR(-ENOTSUPP)) +- *psruntime = sruntime; +- } +- break; ++ if (!qcom_snd_is_sdw_dai(cpu_dai->id)) ++ return NULL; ++ ++ for_each_rtd_codec_dais(rtd, i, codec_dai) { ++ sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream); ++ if (sruntime != ERR_PTR(-ENOTSUPP)) ++ return sruntime; + } ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(qcom_snd_sdw_get_stream); ++ ++int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct sdw_stream_runtime **psruntime) ++{ ++ *psruntime = qcom_snd_sdw_get_stream(substream); + + return 0; + +@@ -138,23 +161,13 @@ int qcom_snd_sdw_hw_free(struct snd_pcm_ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + +- switch (cpu_dai->id) { +- case WSA_CODEC_DMA_RX_0: +- case WSA_CODEC_DMA_RX_1: +- case RX_CODEC_DMA_RX_0: +- case RX_CODEC_DMA_RX_1: +- case TX_CODEC_DMA_TX_0: +- case TX_CODEC_DMA_TX_1: +- case TX_CODEC_DMA_TX_2: +- case TX_CODEC_DMA_TX_3: +- if (sruntime && *stream_prepared) { +- sdw_disable_stream(sruntime); +- sdw_deprepare_stream(sruntime); +- *stream_prepared = false; +- } +- break; +- default: +- break; ++ if (!qcom_snd_is_sdw_dai(cpu_dai->id)) ++ return 0; ++ ++ if (sruntime && *stream_prepared) { ++ sdw_disable_stream(sruntime); ++ sdw_deprepare_stream(sruntime); ++ *stream_prepared = false; + } + + return 0; +--- a/sound/soc/qcom/sdw.h ++++ b/sound/soc/qcom/sdw.h +@@ -10,6 +10,7 @@ int qcom_snd_sdw_startup(struct snd_pcm_ + int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *runtime, + bool *stream_prepared); ++struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *stream); + int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sdw_stream_runtime **psruntime); +--- a/sound/soc/qcom/sm8250.c ++++ b/sound/soc/qcom/sm8250.c +@@ -86,7 +86,7 @@ static void sm2450_snd_shutdown(struct s + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); +- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; ++ struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); + + data->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); +--- a/sound/soc/qcom/x1e80100.c ++++ b/sound/soc/qcom/x1e80100.c +@@ -55,7 +55,7 @@ static void x1e80100_snd_shutdown(struct + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); +- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; ++ struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream); + + data->sruntime[cpu_dai->id] = NULL; + sdw_release_stream(sruntime); diff --git a/queue-6.12/asoc-renesas-rz-ssi-fix-channel-swap-issue-in-full-duplex-mode.patch b/queue-6.12/asoc-renesas-rz-ssi-fix-channel-swap-issue-in-full-duplex-mode.patch new file mode 100644 index 0000000000..57a245ce84 --- /dev/null +++ b/queue-6.12/asoc-renesas-rz-ssi-fix-channel-swap-issue-in-full-duplex-mode.patch @@ -0,0 +1,126 @@ +From stable+bounces-204839-greg=kroah.com@vger.kernel.org Mon Jan 5 17:15:20 2026 +From: Biju +Date: Mon, 5 Jan 2026 15:33:04 +0000 +Subject: ASoC: renesas: rz-ssi: Fix channel swap issue in full duplex mode +To: stable@vger.kernel.org +Cc: Biju Das , stable@kernel.org, Tony Tang , Kuninori Morimoto , Mark Brown +Message-ID: <20260105153304.252300-1-biju.das.jz@bp.renesas.com> + +From: Biju Das + +[ Upstream commit 52a525011cb8e293799a085436f026f2958403f9 ] + +The full duplex audio starts with half duplex mode and then switch to +full duplex mode (another FIFO reset) when both playback/capture +streams available leading to random audio left/right channel swap +issue. Fix this channel swap issue by detecting the full duplex +condition by populating struct dup variable in startup() callback +and synchronize starting both the play and capture at the same time +in rz_ssi_start(). + +Cc: stable@kernel.org +Fixes: 4f8cd05a4305 ("ASoC: sh: rz-ssi: Add full duplex support") +Co-developed-by: Tony Tang +Signed-off-by: Tony Tang +Reviewed-by: Kuninori Morimoto +Signed-off-by: Biju Das +Link: https://patch.msgid.link/20251114073709.4376-2-biju.das.jz@bp.renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/sh/rz-ssi.c | 51 ++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 43 insertions(+), 8 deletions(-) + +--- a/sound/soc/sh/rz-ssi.c ++++ b/sound/soc/sh/rz-ssi.c +@@ -132,6 +132,12 @@ struct rz_ssi_priv { + bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */ + bool dma_rt; + ++ struct { ++ bool tx_active; ++ bool rx_active; ++ bool one_stream_triggered; ++ } dup; ++ + /* Full duplex communication support */ + struct { + unsigned int rate; +@@ -352,13 +358,12 @@ static int rz_ssi_start(struct rz_ssi_pr + bool is_full_duplex; + u32 ssicr, ssifcr; + +- is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) || +- rz_ssi_is_stream_running(&ssi->capture); ++ is_full_duplex = ssi->dup.tx_active && ssi->dup.rx_active; + ssicr = rz_ssi_reg_readl(ssi, SSICR); + ssifcr = rz_ssi_reg_readl(ssi, SSIFCR); + if (!is_full_duplex) { + ssifcr &= ~0xF; +- } else { ++ } else if (ssi->dup.one_stream_triggered) { + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); + rz_ssi_set_idle(ssi); + ssifcr &= ~SSIFCR_FIFO_RST; +@@ -394,12 +399,16 @@ static int rz_ssi_start(struct rz_ssi_pr + SSISR_RUIRQ), 0); + + strm->running = 1; +- if (is_full_duplex) +- ssicr |= SSICR_TEN | SSICR_REN; +- else ++ if (!is_full_duplex) { + ssicr |= is_play ? SSICR_TEN : SSICR_REN; +- +- rz_ssi_reg_writel(ssi, SSICR, ssicr); ++ rz_ssi_reg_writel(ssi, SSICR, ssicr); ++ } else if (ssi->dup.one_stream_triggered) { ++ ssicr |= SSICR_TEN | SSICR_REN; ++ rz_ssi_reg_writel(ssi, SSICR, ssicr); ++ ssi->dup.one_stream_triggered = false; ++ } else { ++ ssi->dup.one_stream_triggered = true; ++ } + + return 0; + } +@@ -897,6 +906,30 @@ static int rz_ssi_dai_set_fmt(struct snd + return 0; + } + ++static int rz_ssi_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ ssi->dup.tx_active = true; ++ else ++ ssi->dup.rx_active = true; ++ ++ return 0; ++} ++ ++static void rz_ssi_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ ssi->dup.tx_active = false; ++ else ++ ssi->dup.rx_active = false; ++} ++ + static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels, + unsigned int sample_width, +@@ -962,6 +995,8 @@ static int rz_ssi_dai_hw_params(struct s + } + + static const struct snd_soc_dai_ops rz_ssi_dai_ops = { ++ .startup = rz_ssi_startup, ++ .shutdown = rz_ssi_shutdown, + .trigger = rz_ssi_dai_trigger, + .set_fmt = rz_ssi_dai_set_fmt, + .hw_params = rz_ssi_dai_hw_params, diff --git a/queue-6.12/asoc-renesas-rz-ssi-fix-rz_ssi_priv-hw_params_cache-sample_width.patch b/queue-6.12/asoc-renesas-rz-ssi-fix-rz_ssi_priv-hw_params_cache-sample_width.patch new file mode 100644 index 0000000000..fe00e804b6 --- /dev/null +++ b/queue-6.12/asoc-renesas-rz-ssi-fix-rz_ssi_priv-hw_params_cache-sample_width.patch @@ -0,0 +1,89 @@ +From stable+bounces-204816-greg=kroah.com@vger.kernel.org Mon Jan 5 15:54:31 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 09:47:43 -0500 +Subject: ASoC: renesas: rz-ssi: Fix rz_ssi_priv::hw_params_cache::sample_width +To: stable@vger.kernel.org +Cc: Biju Das , stable@kernel.org, Kuninori Morimoto , Mark Brown , Sasha Levin +Message-ID: <20260105144743.2610088-1-sashal@kernel.org> + +From: Biju Das + +[ Upstream commit 2bae7beda19f3b2dc6ab2062c94df19c27923712 ] + +The strm->sample_width is not filled during rz_ssi_dai_hw_params(). This +wrong value is used for caching sample_width in struct hw_params_cache. +Fix this issue by replacing 'strm->sample_width'->'params_width(params)' +in rz_ssi_dai_hw_params(). After this drop the variable sample_width +from struct rz_ssi_stream as it is unused. + +Cc: stable@kernel.org +Fixes: 4f8cd05a4305 ("ASoC: sh: rz-ssi: Add full duplex support") +Reviewed-by: Kuninori Morimoto +Signed-off-by: Biju Das +Link: https://patch.msgid.link/20251114073709.4376-3-biju.das.jz@bp.renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/sh/rz-ssi.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +--- a/sound/soc/sh/rz-ssi.c ++++ b/sound/soc/sh/rz-ssi.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + + /* REGISTER OFFSET */ +@@ -85,7 +86,6 @@ struct rz_ssi_stream { + int fifo_sample_size; /* sample capacity of SSI FIFO */ + int dma_buffer_pos; /* The address for the next DMA descriptor */ + int period_counter; /* for keeping track of periods transferred */ +- int sample_width; + int buffer_pos; /* current frame position in the buffer */ + int running; /* 0=stopped, 1=running */ + +@@ -231,10 +231,7 @@ static inline bool rz_ssi_is_stream_runn + static void rz_ssi_stream_init(struct rz_ssi_stream *strm, + struct snd_pcm_substream *substream) + { +- struct snd_pcm_runtime *runtime = substream->runtime; +- + rz_ssi_set_substream(strm, substream); +- strm->sample_width = samples_to_bytes(runtime, 1); + strm->dma_buffer_pos = 0; + strm->period_counter = 0; + strm->buffer_pos = 0; +@@ -960,9 +957,9 @@ static int rz_ssi_dai_hw_params(struct s + struct snd_soc_dai *dai) + { + struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); +- struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); + unsigned int sample_bits = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; ++ unsigned int sample_width = params_width(params); + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + +@@ -980,16 +977,14 @@ static int rz_ssi_dai_hw_params(struct s + + if (rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture)) { +- if (rz_ssi_is_valid_hw_params(ssi, rate, channels, +- strm->sample_width, sample_bits)) ++ if (rz_ssi_is_valid_hw_params(ssi, rate, channels, sample_width, sample_bits)) + return 0; + + dev_err(ssi->dev, "Full duplex needs same HW params\n"); + return -EINVAL; + } + +- rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, +- sample_bits); ++ rz_ssi_cache_hw_params(ssi, rate, channels, sample_width, sample_bits); + + return rz_ssi_clk_setup(ssi, rate, channels); + } diff --git a/queue-6.12/block-handle-zone-management-operations-completions.patch b/queue-6.12/block-handle-zone-management-operations-completions.patch new file mode 100644 index 0000000000..10db360757 --- /dev/null +++ b/queue-6.12/block-handle-zone-management-operations-completions.patch @@ -0,0 +1,277 @@ +From stable+bounces-204835-greg=kroah.com@vger.kernel.org Mon Jan 5 16:17:14 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:11:02 -0500 +Subject: block: handle zone management operations completions +To: stable@vger.kernel.org +Cc: Damien Le Moal , Christoph Hellwig , Johannes Thumshirn , Chaitanya Kulkarni , Hannes Reinecke , "Martin K. Petersen" , Jens Axboe , Sasha Levin +Message-ID: <20260105151102.2626035-1-sashal@kernel.org> + +From: Damien Le Moal + +[ Upstream commit efae226c2ef19528ffd81d29ba0eecf1b0896ca2 ] + +The functions blk_zone_wplug_handle_reset_or_finish() and +blk_zone_wplug_handle_reset_all() both modify the zone write pointer +offset of zone write plugs that are the target of a reset, reset all or +finish zone management operation. However, these functions do this +modification before the BIO is executed. So if the zone operation fails, +the modified zone write pointer offsets become invalid. + +Avoid this by modifying the zone write pointer offset of a zone write +plug that is the target of a zone management operation when the +operation completes. To do so, modify blk_zone_bio_endio() to call the +new function blk_zone_mgmt_bio_endio() which in turn calls the functions +blk_zone_reset_all_bio_endio(), blk_zone_reset_bio_endio() or +blk_zone_finish_bio_endio() depending on the operation of the completed +BIO, to modify a zone write plug write pointer offset accordingly. +These functions are called only if the BIO execution was successful. + +Fixes: dd291d77cc90 ("block: Introduce zone write plugging") +Cc: stable@vger.kernel.org +Signed-off-by: Damien Le Moal +Reviewed-by: Christoph Hellwig +Reviewed-by: Johannes Thumshirn +Reviewed-by: Chaitanya Kulkarni +Reviewed-by: Hannes Reinecke +Reviewed-by: Martin K. Petersen +Signed-off-by: Jens Axboe +[ adapted bdev_zone_is_seq() check to disk_zone_is_conv() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + block/blk-zoned.c | 141 +++++++++++++++++++++++++++++++++++------------------- + block/blk.h | 14 +++++ + 2 files changed, 106 insertions(+), 49 deletions(-) + +--- a/block/blk-zoned.c ++++ b/block/blk-zoned.c +@@ -73,6 +73,11 @@ struct blk_zone_wplug { + struct gendisk *disk; + }; + ++static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) ++{ ++ return 1U << disk->zone_wplugs_hash_bits; ++} ++ + /* + * Zone write plug flags bits: + * - BLK_ZONE_WPLUG_PLUGGED: Indicates that the zone write plug is plugged, +@@ -712,71 +717,91 @@ static int disk_zone_sync_wp_offset(stru + disk_report_zones_cb, &args); + } + +-static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, +- unsigned int wp_offset) ++static void blk_zone_reset_bio_endio(struct bio *bio) + { + struct gendisk *disk = bio->bi_bdev->bd_disk; +- sector_t sector = bio->bi_iter.bi_sector; + struct blk_zone_wplug *zwplug; +- unsigned long flags; +- +- /* Conventional zones cannot be reset nor finished. */ +- if (disk_zone_is_conv(disk, sector)) { +- bio_io_error(bio); +- return true; +- } +- +- /* +- * No-wait reset or finish BIOs do not make much sense as the callers +- * issue these as blocking operations in most cases. To avoid issues +- * the BIO execution potentially failing with BLK_STS_AGAIN, warn about +- * REQ_NOWAIT being set and ignore that flag. +- */ +- if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT)) +- bio->bi_opf &= ~REQ_NOWAIT; + + /* +- * If we have a zone write plug, set its write pointer offset to 0 +- * (reset case) or to the zone size (finish case). This will abort all +- * BIOs plugged for the target zone. It is fine as resetting or +- * finishing zones while writes are still in-flight will result in the ++ * If we have a zone write plug, set its write pointer offset to 0. ++ * This will abort all BIOs plugged for the target zone. It is fine as ++ * resetting zones while writes are still in-flight will result in the + * writes failing anyway. + */ +- zwplug = disk_get_zone_wplug(disk, sector); ++ zwplug = disk_get_zone_wplug(disk, bio->bi_iter.bi_sector); + if (zwplug) { ++ unsigned long flags; ++ + spin_lock_irqsave(&zwplug->lock, flags); +- disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset); ++ disk_zone_wplug_set_wp_offset(disk, zwplug, 0); + spin_unlock_irqrestore(&zwplug->lock, flags); + disk_put_zone_wplug(zwplug); + } +- +- return false; + } + +-static bool blk_zone_wplug_handle_reset_all(struct bio *bio) ++static void blk_zone_reset_all_bio_endio(struct bio *bio) + { + struct gendisk *disk = bio->bi_bdev->bd_disk; + struct blk_zone_wplug *zwplug; + unsigned long flags; +- sector_t sector; ++ unsigned int i; + +- /* +- * Set the write pointer offset of all zone write plugs to 0. This will +- * abort all plugged BIOs. It is fine as resetting zones while writes +- * are still in-flight will result in the writes failing anyway. +- */ +- for (sector = 0; sector < get_capacity(disk); +- sector += disk->queue->limits.chunk_sectors) { +- zwplug = disk_get_zone_wplug(disk, sector); +- if (zwplug) { ++ /* Update the condition of all zone write plugs. */ ++ rcu_read_lock(); ++ for (i = 0; i < disk_zone_wplugs_hash_size(disk); i++) { ++ hlist_for_each_entry_rcu(zwplug, &disk->zone_wplugs_hash[i], ++ node) { + spin_lock_irqsave(&zwplug->lock, flags); + disk_zone_wplug_set_wp_offset(disk, zwplug, 0); + spin_unlock_irqrestore(&zwplug->lock, flags); +- disk_put_zone_wplug(zwplug); + } + } ++ rcu_read_unlock(); ++} + +- return false; ++static void blk_zone_finish_bio_endio(struct bio *bio) ++{ ++ struct block_device *bdev = bio->bi_bdev; ++ struct gendisk *disk = bdev->bd_disk; ++ struct blk_zone_wplug *zwplug; ++ ++ /* ++ * If we have a zone write plug, set its write pointer offset to the ++ * zone size. This will abort all BIOs plugged for the target zone. It ++ * is fine as resetting zones while writes are still in-flight will ++ * result in the writes failing anyway. ++ */ ++ zwplug = disk_get_zone_wplug(disk, bio->bi_iter.bi_sector); ++ if (zwplug) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&zwplug->lock, flags); ++ disk_zone_wplug_set_wp_offset(disk, zwplug, ++ bdev_zone_sectors(bdev)); ++ spin_unlock_irqrestore(&zwplug->lock, flags); ++ disk_put_zone_wplug(zwplug); ++ } ++} ++ ++void blk_zone_mgmt_bio_endio(struct bio *bio) ++{ ++ /* If the BIO failed, we have nothing to do. */ ++ if (bio->bi_status != BLK_STS_OK) ++ return; ++ ++ switch (bio_op(bio)) { ++ case REQ_OP_ZONE_RESET: ++ blk_zone_reset_bio_endio(bio); ++ return; ++ case REQ_OP_ZONE_RESET_ALL: ++ blk_zone_reset_all_bio_endio(bio); ++ return; ++ case REQ_OP_ZONE_FINISH: ++ blk_zone_finish_bio_endio(bio); ++ return; ++ default: ++ return; ++ } + } + + static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, +@@ -1119,6 +1144,32 @@ static void blk_zone_wplug_handle_native + disk_put_zone_wplug(zwplug); + } + ++static bool blk_zone_wplug_handle_zone_mgmt(struct bio *bio) ++{ ++ struct gendisk *disk = bio->bi_bdev->bd_disk; ++ ++ if (bio_op(bio) != REQ_OP_ZONE_RESET_ALL && ++ disk_zone_is_conv(disk, bio->bi_iter.bi_sector)) { ++ /* ++ * Zone reset and zone finish operations do not apply to ++ * conventional zones. ++ */ ++ bio_io_error(bio); ++ return true; ++ } ++ ++ /* ++ * No-wait zone management BIOs do not make much sense as the callers ++ * issue these as blocking operations in most cases. To avoid issues ++ * with the BIO execution potentially failing with BLK_STS_AGAIN, warn ++ * about REQ_NOWAIT being set and ignore that flag. ++ */ ++ if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT)) ++ bio->bi_opf &= ~REQ_NOWAIT; ++ ++ return false; ++} ++ + /** + * blk_zone_plug_bio - Handle a zone write BIO with zone write plugging + * @bio: The BIO being submitted +@@ -1166,12 +1217,9 @@ bool blk_zone_plug_bio(struct bio *bio, + case REQ_OP_WRITE_ZEROES: + return blk_zone_wplug_handle_write(bio, nr_segs); + case REQ_OP_ZONE_RESET: +- return blk_zone_wplug_handle_reset_or_finish(bio, 0); + case REQ_OP_ZONE_FINISH: +- return blk_zone_wplug_handle_reset_or_finish(bio, +- bdev_zone_sectors(bdev)); + case REQ_OP_ZONE_RESET_ALL: +- return blk_zone_wplug_handle_reset_all(bio); ++ return blk_zone_wplug_handle_zone_mgmt(bio); + default: + return false; + } +@@ -1328,11 +1376,6 @@ put_zwplug: + disk_put_zone_wplug(zwplug); + } + +-static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) +-{ +- return 1U << disk->zone_wplugs_hash_bits; +-} +- + void disk_init_zone_resources(struct gendisk *disk) + { + spin_lock_init(&disk->zone_wplugs_lock); +--- a/block/blk.h ++++ b/block/blk.h +@@ -486,10 +486,24 @@ static inline void blk_zone_update_reque + bio_flagged(bio, BIO_EMULATES_ZONE_APPEND)) + bio->bi_iter.bi_sector = rq->__sector; + } ++void blk_zone_mgmt_bio_endio(struct bio *bio); + void blk_zone_write_plug_bio_endio(struct bio *bio); + static inline void blk_zone_bio_endio(struct bio *bio) + { + /* ++ * Zone management BIOs may impact zone write plugs (e.g. a zone reset ++ * changes a zone write plug zone write pointer offset), but these ++ * operation do not go through zone write plugging as they may operate ++ * on zones that do not have a zone write ++ * plug. blk_zone_mgmt_bio_endio() handles the potential changes to zone ++ * write plugs that are present. ++ */ ++ if (op_is_zone_mgmt(bio_op(bio))) { ++ blk_zone_mgmt_bio_endio(bio); ++ return; ++ } ++ ++ /* + * For write BIOs to zoned devices, signal the completion of the BIO so + * that the next write BIO can be submitted by zone write plugging. + */ diff --git a/queue-6.12/gve-defer-interrupt-enabling-until-napi-registration.patch b/queue-6.12/gve-defer-interrupt-enabling-until-napi-registration.patch new file mode 100644 index 0000000000..b602052e5b --- /dev/null +++ b/queue-6.12/gve-defer-interrupt-enabling-until-napi-registration.patch @@ -0,0 +1,74 @@ +From 3d970eda003441f66551a91fda16478ac0711617 Mon Sep 17 00:00:00 2001 +From: Ankit Garg +Date: Fri, 19 Dec 2025 10:29:45 +0000 +Subject: gve: defer interrupt enabling until NAPI registration + +From: Ankit Garg + +commit 3d970eda003441f66551a91fda16478ac0711617 upstream. + +Currently, interrupts are automatically enabled immediately upon +request. This allows interrupt to fire before the associated NAPI +context is fully initialized and cause failures like below: + +[ 0.946369] Call Trace: +[ 0.946369] +[ 0.946369] __napi_poll+0x2a/0x1e0 +[ 0.946369] net_rx_action+0x2f9/0x3f0 +[ 0.946369] handle_softirqs+0xd6/0x2c0 +[ 0.946369] ? handle_edge_irq+0xc1/0x1b0 +[ 0.946369] __irq_exit_rcu+0xc3/0xe0 +[ 0.946369] common_interrupt+0x81/0xa0 +[ 0.946369] +[ 0.946369] +[ 0.946369] asm_common_interrupt+0x22/0x40 +[ 0.946369] RIP: 0010:pv_native_safe_halt+0xb/0x10 + +Use the `IRQF_NO_AUTOEN` flag when requesting interrupts to prevent auto +enablement and explicitly enable the interrupt in NAPI initialization +path (and disable it during NAPI teardown). + +This ensures that interrupt lifecycle is strictly coupled with +readiness of NAPI context. + +Cc: stable@vger.kernel.org +Fixes: 1dfc2e46117e ("gve: Refactor napi add and remove functions") +Signed-off-by: Ankit Garg +Reviewed-by: Jordan Rhee +Reviewed-by: Joshua Washington +Signed-off-by: Harshitha Ramamurthy +Link: https://patch.msgid.link/20251219102945.2193617-1-hramamurthy@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/google/gve/gve_main.c | 2 +- + drivers/net/ethernet/google/gve/gve_utils.c | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -500,7 +500,7 @@ static int gve_alloc_notify_blocks(struc + block->priv = priv; + err = request_irq(priv->msix_vectors[msix_idx].vector, + gve_is_gqi(priv) ? gve_intr : gve_intr_dqo, +- 0, block->name, block); ++ IRQF_NO_AUTOEN, block->name, block); + if (err) { + dev_err(&priv->pdev->dev, + "Failed to receive msix vector %d\n", i); +--- a/drivers/net/ethernet/google/gve/gve_utils.c ++++ b/drivers/net/ethernet/google/gve/gve_utils.c +@@ -111,11 +111,13 @@ void gve_add_napi(struct gve_priv *priv, + struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + + netif_napi_add(priv->dev, &block->napi, gve_poll); ++ enable_irq(block->irq); + } + + void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) + { + struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + ++ disable_irq(block->irq); + netif_napi_del(&block->napi); + } diff --git a/queue-6.12/media-amphion-add-a-frame-flush-mode-for-decoder.patch b/queue-6.12/media-amphion-add-a-frame-flush-mode-for-decoder.patch new file mode 100644 index 0000000000..9e3b6d5712 --- /dev/null +++ b/queue-6.12/media-amphion-add-a-frame-flush-mode-for-decoder.patch @@ -0,0 +1,64 @@ +From stable+bounces-204925-greg=kroah.com@vger.kernel.org Mon Jan 5 22:05:38 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:05:30 -0500 +Subject: media: amphion: Add a frame flush mode for decoder +To: stable@vger.kernel.org +Cc: Ming Qian , Nicolas Dufresne , Sebastian Fricke , Hans Verkuil , Sasha Levin +Message-ID: <20260105210532.2800255-1-sashal@kernel.org> + +From: Ming Qian + +[ Upstream commit 9ea16ba6eaf93f25f61855751f71e2e701709ddf ] + +By default the amphion decoder will pre-parse 3 frames before starting +to decode the first frame. Alternatively, a block of flush padding data +can be appended to the frame, which will ensure that the decoder can +start decoding immediately after parsing the flush padding data, thus +potentially reducing decoding latency. + +This mode was previously only enabled, when the display delay was set to +0. Allow the user to manually toggle the use of that mode via a module +parameter called low_latency, which enables the mode without +changing the display order. + +Signed-off-by: Ming Qian +Reviewed-by: Nicolas Dufresne +Signed-off-by: Sebastian Fricke +Signed-off-by: Hans Verkuil +Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_malone.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/amphion/vpu_malone.c ++++ b/drivers/media/platform/amphion/vpu_malone.c +@@ -25,6 +25,10 @@ + #include "vpu_imx8q.h" + #include "vpu_malone.h" + ++static bool low_latency; ++module_param(low_latency, bool, 0644); ++MODULE_PARM_DESC(low_latency, "Set low latency frame flush mode: 0 (disable) or 1 (enable)"); ++ + #define CMD_SIZE 25600 + #define MSG_SIZE 25600 + #define CODEC_SIZE 0x1000 +@@ -1562,7 +1566,15 @@ static int vpu_malone_input_frame_data(s + + vpu_malone_update_wptr(str_buf, wptr); + +- if (disp_imm && !vpu_vb_is_codecconfig(vbuf)) { ++ /* ++ * Enable the low latency flush mode if display delay is set to 0 ++ * or the low latency frame flush mode if it is set to 1. ++ * The low latency flush mode requires some padding data to be appended to each frame, ++ * but there must not be any padding data between the sequence header and the frame. ++ * This module is currently only supported for the H264 and HEVC formats, ++ * for other formats, vpu_malone_add_scode() will return 0. ++ */ ++ if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { + ret = vpu_malone_add_scode(inst->core->iface, + inst->id, + &inst->stream_buffer, diff --git a/queue-6.12/media-amphion-make-some-vpu_v4l2-functions-static.patch b/queue-6.12/media-amphion-make-some-vpu_v4l2-functions-static.patch new file mode 100644 index 0000000000..863f65fe94 --- /dev/null +++ b/queue-6.12/media-amphion-make-some-vpu_v4l2-functions-static.patch @@ -0,0 +1,98 @@ +From stable+bounces-204926-greg=kroah.com@vger.kernel.org Mon Jan 5 22:05:39 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:05:31 -0500 +Subject: media: amphion: Make some vpu_v4l2 functions static +To: stable@vger.kernel.org +Cc: Laurent Pinchart , Ming Qian , Hans Verkuil , Sasha Levin +Message-ID: <20260105210532.2800255-2-sashal@kernel.org> + +From: Laurent Pinchart + +[ Upstream commit 5d1e54bb4dc6741284a3ed587e994308ddee2f16 ] + +Some functions defined in vpu_v4l2.c are never used outside of that +compilation unit. Make them static. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Ming Qian +Signed-off-by: Hans Verkuil +Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_v4l2.c | 12 +++++++++--- + drivers/media/platform/amphion/vpu_v4l2.h | 8 -------- + 2 files changed, 9 insertions(+), 11 deletions(-) + +--- a/drivers/media/platform/amphion/vpu_v4l2.c ++++ b/drivers/media/platform/amphion/vpu_v4l2.c +@@ -24,6 +24,11 @@ + #include "vpu_msgs.h" + #include "vpu_helpers.h" + ++static char *vpu_type_name(u32 type) ++{ ++ return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; ++} ++ + void vpu_inst_lock(struct vpu_inst *inst) + { + mutex_lock(&inst->lock); +@@ -42,7 +47,7 @@ dma_addr_t vpu_get_vb_phy_addr(struct vb + vb->planes[plane_no].data_offset; + } + +-unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) ++static unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) + { + if (plane_no >= vb->num_planes) + return 0; +@@ -81,7 +86,7 @@ void vpu_v4l2_set_error(struct vpu_inst + vpu_inst_unlock(inst); + } + +-int vpu_notify_eos(struct vpu_inst *inst) ++static int vpu_notify_eos(struct vpu_inst *inst) + { + static const struct v4l2_event ev = { + .id = 0, +@@ -562,7 +567,8 @@ static void vpu_vb2_buf_finish(struct vb + call_void_vop(inst, on_queue_empty, q->type); + } + +-void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state) ++static void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, ++ enum vb2_buffer_state state) + { + struct vb2_v4l2_buffer *buf; + +--- a/drivers/media/platform/amphion/vpu_v4l2.h ++++ b/drivers/media/platform/amphion/vpu_v4l2.h +@@ -26,15 +26,12 @@ void vpu_skip_frame(struct vpu_inst *ins + struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence); + struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx); + void vpu_v4l2_set_error(struct vpu_inst *inst); +-int vpu_notify_eos(struct vpu_inst *inst); + int vpu_notify_source_change(struct vpu_inst *inst); + int vpu_set_last_buffer_dequeued(struct vpu_inst *inst, bool eos); +-void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state); + int vpu_get_num_buffers(struct vpu_inst *inst, u32 type); + bool vpu_is_source_empty(struct vpu_inst *inst); + + dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no); +-unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no); + static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) + { + if (V4L2_TYPE_IS_OUTPUT(type)) +@@ -43,11 +40,6 @@ static inline struct vpu_format *vpu_get + return &inst->cap_format; + } + +-static inline char *vpu_type_name(u32 type) +-{ +- return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; +-} +- + static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) + { + #ifdef V4L2_BUF_FLAG_CODECCONFIG diff --git a/queue-6.12/media-amphion-remove-vpu_vb_is_codecconfig.patch b/queue-6.12/media-amphion-remove-vpu_vb_is_codecconfig.patch new file mode 100644 index 0000000000..3c50d467ac --- /dev/null +++ b/queue-6.12/media-amphion-remove-vpu_vb_is_codecconfig.patch @@ -0,0 +1,142 @@ +From stable+bounces-204927-greg=kroah.com@vger.kernel.org Mon Jan 5 22:05:38 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:05:32 -0500 +Subject: media: amphion: Remove vpu_vb_is_codecconfig +To: stable@vger.kernel.org +Cc: Ming Qian , Nicolas Dufresne , Hans Verkuil , Sasha Levin +Message-ID: <20260105210532.2800255-3-sashal@kernel.org> + +From: Ming Qian + +[ Upstream commit 634c2cd17bd021487c57b95973bddb14be8002ff ] + +Currently the function vpu_vb_is_codecconfig() always returns 0. +Delete it and its related code. + +Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support") +Cc: stable@vger.kernel.org +Signed-off-by: Ming Qian +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_malone.c | 23 +++-------------------- + drivers/media/platform/amphion/vpu_v4l2.c | 10 ---------- + drivers/media/platform/amphion/vpu_v4l2.h | 10 ---------- + 3 files changed, 3 insertions(+), 40 deletions(-) + +--- a/drivers/media/platform/amphion/vpu_malone.c ++++ b/drivers/media/platform/amphion/vpu_malone.c +@@ -1315,22 +1315,18 @@ static int vpu_malone_insert_scode_vc1_g + { + if (!scode->inst->total_input_count) + return 0; +- if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) +- scode->need_data = 0; + return 0; + } + + static int vpu_malone_insert_scode_vc1_g_pic(struct malone_scode_t *scode) + { +- struct vb2_v4l2_buffer *vbuf; + u8 nal_hdr[MALONE_VC1_NAL_HEADER_LEN]; + u32 *data = NULL; + int ret; + +- vbuf = to_vb2_v4l2_buffer(scode->vb); + data = vb2_plane_vaddr(scode->vb, 0); + +- if (scode->inst->total_input_count == 0 || vpu_vb_is_codecconfig(vbuf)) ++ if (scode->inst->total_input_count == 0) + return 0; + if (MALONE_VC1_CONTAIN_NAL(*data)) + return 0; +@@ -1351,8 +1347,6 @@ static int vpu_malone_insert_scode_vc1_l + int size = 0; + u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN]; + +- if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) +- scode->need_data = 0; + if (scode->inst->total_input_count) + return 0; + scode->need_data = 0; +@@ -1538,7 +1532,7 @@ static int vpu_malone_input_frame_data(s + scode.vb = vb; + scode.wptr = wptr; + scode.need_data = 1; +- if (vbuf->sequence == 0 || vpu_vb_is_codecconfig(vbuf)) ++ if (vbuf->sequence == 0) + ret = vpu_malone_insert_scode(&scode, SCODE_SEQUENCE); + + if (ret < 0) +@@ -1574,7 +1568,7 @@ static int vpu_malone_input_frame_data(s + * This module is currently only supported for the H264 and HEVC formats, + * for other formats, vpu_malone_add_scode() will return 0. + */ +- if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { ++ if (disp_imm || low_latency) { + ret = vpu_malone_add_scode(inst->core->iface, + inst->id, + &inst->stream_buffer, +@@ -1621,7 +1615,6 @@ int vpu_malone_input_frame(struct vpu_sh + struct vpu_inst *inst, struct vb2_buffer *vb) + { + struct vpu_dec_ctrl *hc = shared->priv; +- struct vb2_v4l2_buffer *vbuf; + struct vpu_malone_str_buffer __iomem *str_buf = hc->str_buf[inst->id]; + u32 disp_imm = hc->codec_param[inst->id].disp_imm; + u32 size; +@@ -1635,16 +1628,6 @@ int vpu_malone_input_frame(struct vpu_sh + return ret; + size = ret; + +- /* +- * if buffer only contain codec data, and the timestamp is invalid, +- * don't put the invalid timestamp to resync +- * merge the data to next frame +- */ +- vbuf = to_vb2_v4l2_buffer(vb); +- if (vpu_vb_is_codecconfig(vbuf)) { +- inst->extra_size += size; +- return 0; +- } + if (inst->extra_size) { + size += inst->extra_size; + inst->extra_size = 0; +--- a/drivers/media/platform/amphion/vpu_v4l2.c ++++ b/drivers/media/platform/amphion/vpu_v4l2.c +@@ -349,16 +349,6 @@ struct vb2_v4l2_buffer *vpu_next_src_buf + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return NULL; + +- while (vpu_vb_is_codecconfig(src_buf)) { +- v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); +- vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); +- v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); +- +- src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); +- if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) +- return NULL; +- } +- + return src_buf; + } + +--- a/drivers/media/platform/amphion/vpu_v4l2.h ++++ b/drivers/media/platform/amphion/vpu_v4l2.h +@@ -39,14 +39,4 @@ static inline struct vpu_format *vpu_get + else + return &inst->cap_format; + } +- +-static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) +-{ +-#ifdef V4L2_BUF_FLAG_CODECCONFIG +- return (vbuf->flags & V4L2_BUF_FLAG_CODECCONFIG) ? 1 : 0; +-#else +- return 0; +-#endif +-} +- + #endif diff --git a/queue-6.12/media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch b/queue-6.12/media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch new file mode 100644 index 0000000000..852df224b4 --- /dev/null +++ b/queue-6.12/media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch @@ -0,0 +1,256 @@ +From stable+bounces-204957-greg=kroah.com@vger.kernel.org Tue Jan 6 00:33:25 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 18:31:58 -0500 +Subject: media: mediatek: vcodec: Use spinlock for context list protection lock +To: stable@vger.kernel.org +Cc: Chen-Yu Tsai , Yunfei Dong , Fei Shao , Tomasz Figa , Nicolas Dufresne , Hans Verkuil , Sasha Levin +Message-ID: <20260105233158.2846053-1-sashal@kernel.org> + +From: Chen-Yu Tsai + +[ Upstream commit a5844227e0f030d2af2d85d4aed10c5eca6ca176 ] + +Previously a mutex was added to protect the encoder and decoder context +lists from unexpected changes originating from the SCP IP block, causing +the context pointer to go invalid, resulting in a NULL pointer +dereference in the IPI handler. + +Turns out on the MT8173, the VPU IPI handler is called from hard IRQ +context. This causes a big warning from the scheduler. This was first +reported downstream on the ChromeOS kernels, but is also reproducible +on mainline using Fluster with the FFmpeg v4l2m2m decoders. Even though +the actual capture format is not supported, the affected code paths +are triggered. + +Since this lock just protects the context list and operations on it are +very fast, it should be OK to switch to a spinlock. + +Fixes: 6467cda18c9f ("media: mediatek: vcodec: adding lock to protect decoder context list") +Fixes: afaaf3a0f647 ("media: mediatek: vcodec: adding lock to protect encoder context list") +Cc: Yunfei Dong +Cc: stable@vger.kernel.org +Signed-off-by: Chen-Yu Tsai +Reviewed-by: Fei Shao +Reviewed-by: Tomasz Figa +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +[ adapted file_to_dec_ctx() and file_to_enc_ctx() helper calls to equivalent fh_to_dec_ctx(file->private_data) and fh_to_enc_ctx(file->private_data) pattern ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c | 10 +++++--- + drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c | 12 +++++----- + drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h | 2 - + drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c | 5 ++-- + drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c | 12 +++++----- + drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h | 2 - + drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c | 5 ++-- + 7 files changed, 28 insertions(+), 20 deletions(-) + +--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c ++++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +@@ -47,30 +47,32 @@ static void mtk_vcodec_vpu_reset_dec_han + { + struct mtk_vcodec_dec_dev *dev = priv; + struct mtk_vcodec_dec_ctx *ctx; ++ unsigned long flags; + + dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &dev->ctx_list, list) { + ctx->state = MTK_STATE_ABORT; + mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); + } +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + } + + static void mtk_vcodec_vpu_reset_enc_handler(void *priv) + { + struct mtk_vcodec_enc_dev *dev = priv; + struct mtk_vcodec_enc_ctx *ctx; ++ unsigned long flags; + + dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &dev->ctx_list, list) { + ctx->state = MTK_STATE_ABORT; + mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); + } +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + } + + static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = { +--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c ++++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +@@ -198,6 +198,7 @@ static int fops_vcodec_open(struct file + struct mtk_vcodec_dec_ctx *ctx = NULL; + int ret = 0, i, hw_count; + struct vb2_queue *src_vq; ++ unsigned long flags; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) +@@ -268,9 +269,9 @@ static int fops_vcodec_open(struct file + + ctx->dev->vdec_pdata->init_vdec_params(ctx); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_add(&ctx->list, &dev->ctx_list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + mtk_vcodec_dbgfs_create(ctx); + + mutex_unlock(&dev->dev_mutex); +@@ -295,6 +296,7 @@ static int fops_vcodec_release(struct fi + { + struct mtk_vcodec_dec_dev *dev = video_drvdata(file); + struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(file->private_data); ++ unsigned long flags; + + mtk_v4l2_vdec_dbg(0, ctx, "[%d] decoder", ctx->id); + mutex_lock(&dev->dev_mutex); +@@ -313,9 +315,9 @@ static int fops_vcodec_release(struct fi + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + + mtk_vcodec_dbgfs_remove(dev, ctx->id); +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_del_init(&ctx->list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + return 0; +@@ -408,7 +410,7 @@ static int mtk_vcodec_probe(struct platf + for (i = 0; i < MTK_VDEC_HW_MAX; i++) + mutex_init(&dev->dec_mutex[i]); + mutex_init(&dev->dev_mutex); +- mutex_init(&dev->dev_ctx_lock); ++ spin_lock_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->irqlock); + + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", +--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h ++++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +@@ -283,7 +283,7 @@ struct mtk_vcodec_dec_dev { + /* decoder hardware mutex lock */ + struct mutex dec_mutex[MTK_VDEC_HW_MAX]; + struct mutex dev_mutex; +- struct mutex dev_ctx_lock; ++ spinlock_t dev_ctx_lock; + struct workqueue_struct *decode_workqueue; + + spinlock_t irqlock; +--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c ++++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c +@@ -75,16 +75,17 @@ static void handle_get_param_msg_ack(con + static bool vpu_dec_check_ap_inst(struct mtk_vcodec_dec_dev *dec_dev, struct vdec_vpu_inst *vpu) + { + struct mtk_vcodec_dec_ctx *ctx; ++ unsigned long flags; + int ret = false; + +- mutex_lock(&dec_dev->dev_ctx_lock); ++ spin_lock_irqsave(&dec_dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &dec_dev->ctx_list, list) { + if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { + ret = true; + break; + } + } +- mutex_unlock(&dec_dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dec_dev->dev_ctx_lock, flags); + + return ret; + } +--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +@@ -117,6 +117,7 @@ static int fops_vcodec_open(struct file + struct mtk_vcodec_enc_ctx *ctx = NULL; + int ret = 0; + struct vb2_queue *src_vq; ++ unsigned long flags; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) +@@ -177,9 +178,9 @@ static int fops_vcodec_open(struct file + mtk_v4l2_venc_dbg(2, ctx, "Create instance [%d]@%p m2m_ctx=%p ", + ctx->id, ctx, ctx->m2m_ctx); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_add(&ctx->list, &dev->ctx_list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + + mutex_unlock(&dev->dev_mutex); + mtk_v4l2_venc_dbg(0, ctx, "%s encoder [%d]", dev_name(&dev->plat_dev->dev), +@@ -204,6 +205,7 @@ static int fops_vcodec_release(struct fi + { + struct mtk_vcodec_enc_dev *dev = video_drvdata(file); + struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(file->private_data); ++ unsigned long flags; + + mtk_v4l2_venc_dbg(1, ctx, "[%d] encoder", ctx->id); + mutex_lock(&dev->dev_mutex); +@@ -214,9 +216,9 @@ static int fops_vcodec_release(struct fi + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + +- mutex_lock(&dev->dev_ctx_lock); ++ spin_lock_irqsave(&dev->dev_ctx_lock, flags); + list_del_init(&ctx->list); +- mutex_unlock(&dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + return 0; +@@ -298,7 +300,7 @@ static int mtk_vcodec_probe(struct platf + + mutex_init(&dev->enc_mutex); + mutex_init(&dev->dev_mutex); +- mutex_init(&dev->dev_ctx_lock); ++ spin_lock_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->irqlock); + + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", +--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h ++++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h +@@ -206,7 +206,7 @@ struct mtk_vcodec_enc_dev { + /* encoder hardware mutex lock */ + struct mutex enc_mutex; + struct mutex dev_mutex; +- struct mutex dev_ctx_lock; ++ spinlock_t dev_ctx_lock; + struct workqueue_struct *encode_workqueue; + + int enc_irq; +--- a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c ++++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c +@@ -45,16 +45,17 @@ static void handle_enc_encode_msg(struct + static bool vpu_enc_check_ap_inst(struct mtk_vcodec_enc_dev *enc_dev, struct venc_vpu_inst *vpu) + { + struct mtk_vcodec_enc_ctx *ctx; ++ unsigned long flags; + int ret = false; + +- mutex_lock(&enc_dev->dev_ctx_lock); ++ spin_lock_irqsave(&enc_dev->dev_ctx_lock, flags); + list_for_each_entry(ctx, &enc_dev->ctx_list, list) { + if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { + ret = true; + break; + } + } +- mutex_unlock(&enc_dev->dev_ctx_lock); ++ spin_unlock_irqrestore(&enc_dev->dev_ctx_lock, flags); + + return ret; + } diff --git a/queue-6.12/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch b/queue-6.12/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch new file mode 100644 index 0000000000..c279b3ffbe --- /dev/null +++ b/queue-6.12/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch @@ -0,0 +1,225 @@ +From sashal@kernel.org Mon Jan 5 18:42:17 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:42:04 -0500 +Subject: mm/balloon_compaction: convert balloon_page_delete() to balloon_page_finalize() +To: stable@vger.kernel.org +Cc: "David Hildenbrand" , "Lorenzo Stoakes" , "Alistair Popple" , "Al Viro" , "Arnd Bergmann" , "Brendan Jackman" , "Byungchul Park" , "Chengming Zhou" , "Christian Brauner" , "Christophe Leroy" , "Eugenio Pé rez" , "Greg Kroah-Hartman" , "Gregory Price" , "Harry Yoo" , "Huang, Ying" , "Jan Kara" , "Jason Gunthorpe" , "Jason Wang" , "Jerrin Shaji George" , "Johannes Weiner" , "John Hubbard" , "Jonathan Corbet" , "Joshua Hahn" , "Liam Howlett" , "Madhavan Srinivasan" , "Mathew Brost" , "Matthew Wilcox (Oracle)" , "Miaohe Lin" , "Michael Ellerman" , "Michael S. Tsirkin" , "Michal Hocko" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Nicholas Piggin" , "Oscar Salvador" , "Peter Xu" , "Qi Zheng" , "Rakie Kim" , "Rik van Riel" , "Sergey Senozhatsky" , "Shakeel Butt" , "Suren Baghdasaryan" , "Vlastimil Babka" , "Xuan Zhuo" , "xu xin" , "Zi Yan" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260105174205.2697666-2-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 15504b1163007bbfbd9a63460d5c14737c16e96d ] + +Let's move the removal of the page from the balloon list into the single +caller, to remove the dependency on the PG_isolated flag and clarify +locking requirements. + +Note that for now, balloon_page_delete() was used on two paths: + +(1) Removing a page from the balloon for deflation through + balloon_page_list_dequeue() +(2) Removing an isolated page from the balloon for migration in the + per-driver migration handlers. Isolated pages were already removed from + the balloon list during isolation. + +So instead of relying on the flag, we can just distinguish both cases +directly and handle it accordingly in the caller. + +We'll shuffle the operations a bit such that they logically make more +sense (e.g., remove from the list before clearing flags). + +In balloon migration functions we can now move the balloon_page_finalize() +out of the balloon lock and perform the finalization just before dropping +the balloon reference. + +Document that the page lock is currently required when modifying the +movability aspects of a page; hopefully we can soon decouple this from the +page lock. + +Link: https://lkml.kernel.org/r/20250704102524.326966-3-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Lorenzo Stoakes +Cc: Alistair Popple +Cc: Al Viro +Cc: Arnd Bergmann +Cc: Brendan Jackman +Cc: Byungchul Park +Cc: Chengming Zhou +Cc: Christian Brauner +Cc: Christophe Leroy +Cc: Eugenio Pé rez +Cc: Greg Kroah-Hartman +Cc: Gregory Price +Cc: Harry Yoo +Cc: "Huang, Ying" +Cc: Jan Kara +Cc: Jason Gunthorpe +Cc: Jason Wang +Cc: Jerrin Shaji George +Cc: Johannes Weiner +Cc: John Hubbard +Cc: Jonathan Corbet +Cc: Joshua Hahn +Cc: Liam Howlett +Cc: Madhavan Srinivasan +Cc: Mathew Brost +Cc: Matthew Wilcox (Oracle) +Cc: Miaohe Lin +Cc: Michael Ellerman +Cc: "Michael S. Tsirkin" +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Nicholas Piggin +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Qi Zheng +Cc: Rakie Kim +Cc: Rik van Riel +Cc: Sergey Senozhatsky +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Xuan Zhuo +Cc: xu xin +Cc: Zi Yan +Signed-off-by: Andrew Morton +Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/pseries/cmm.c | 2 - + drivers/misc/vmw_balloon.c | 3 -- + drivers/virtio/virtio_balloon.c | 4 --- + include/linux/balloon_compaction.h | 43 +++++++++++++---------------------- + mm/balloon_compaction.c | 3 +- + 5 files changed, 21 insertions(+), 34 deletions(-) + +--- a/arch/powerpc/platforms/pseries/cmm.c ++++ b/arch/powerpc/platforms/pseries/cmm.c +@@ -532,7 +532,6 @@ static int cmm_migratepage(struct balloo + + spin_lock_irqsave(&b_dev_info->pages_lock, flags); + balloon_page_insert(b_dev_info, newpage); +- balloon_page_delete(page); + b_dev_info->isolated_pages--; + spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); + +@@ -542,6 +541,7 @@ static int cmm_migratepage(struct balloo + */ + plpar_page_set_active(page); + ++ balloon_page_finalize(page); + /* balloon page list reference */ + put_page(page); + +--- a/drivers/misc/vmw_balloon.c ++++ b/drivers/misc/vmw_balloon.c +@@ -1778,8 +1778,7 @@ static int vmballoon_migratepage(struct + * @pages_lock . We keep holding @comm_lock since we will need it in a + * second. + */ +- balloon_page_delete(page); +- ++ balloon_page_finalize(page); + put_page(page); + + /* Inflate */ +--- a/drivers/virtio/virtio_balloon.c ++++ b/drivers/virtio/virtio_balloon.c +@@ -866,15 +866,13 @@ static int virtballoon_migratepage(struc + tell_host(vb, vb->inflate_vq); + + /* balloon's page migration 2nd step -- deflate "page" */ +- spin_lock_irqsave(&vb_dev_info->pages_lock, flags); +- balloon_page_delete(page); +- spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags); + vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE; + set_page_pfns(vb, vb->pfns, page); + tell_host(vb, vb->deflate_vq); + + mutex_unlock(&vb->balloon_lock); + ++ balloon_page_finalize(page); + put_page(page); /* balloon reference */ + + return MIGRATEPAGE_SUCCESS; +--- a/include/linux/balloon_compaction.h ++++ b/include/linux/balloon_compaction.h +@@ -98,27 +98,6 @@ static inline void balloon_page_insert(s + } + + /* +- * balloon_page_delete - delete a page from balloon's page list and clear +- * the page->private assignement accordingly. +- * @page : page to be released from balloon's page list +- * +- * Caller must ensure the page is locked and the spin_lock protecting balloon +- * pages list is held before deleting a page from the balloon device. +- */ +-static inline void balloon_page_delete(struct page *page) +-{ +- __ClearPageOffline(page); +- __ClearPageMovable(page); +- set_page_private(page, 0); +- /* +- * No touch page.lru field once @page has been isolated +- * because VM is using the field. +- */ +- if (!PageIsolated(page)) +- list_del(&page->lru); +-} +- +-/* + * balloon_page_device - get the b_dev_info descriptor for the balloon device + * that enqueues the given page. + */ +@@ -141,12 +120,6 @@ static inline void balloon_page_insert(s + list_add(&page->lru, &balloon->pages); + } + +-static inline void balloon_page_delete(struct page *page) +-{ +- __ClearPageOffline(page); +- list_del(&page->lru); +-} +- + static inline gfp_t balloon_mapping_gfp_mask(void) + { + return GFP_HIGHUSER; +@@ -155,6 +128,22 @@ static inline gfp_t balloon_mapping_gfp_ + #endif /* CONFIG_BALLOON_COMPACTION */ + + /* ++ * balloon_page_finalize - prepare a balloon page that was removed from the ++ * balloon list for release to the page allocator ++ * @page: page to be released to the page allocator ++ * ++ * Caller must ensure that the page is locked. ++ */ ++static inline void balloon_page_finalize(struct page *page) ++{ ++ if (IS_ENABLED(CONFIG_BALLOON_COMPACTION)) { ++ __ClearPageMovable(page); ++ set_page_private(page, 0); ++ } ++ __ClearPageOffline(page); ++} ++ ++/* + * balloon_page_push - insert a page into a page list. + * @head : pointer to list + * @page : page to be added +--- a/mm/balloon_compaction.c ++++ b/mm/balloon_compaction.c +@@ -93,7 +93,8 @@ size_t balloon_page_list_dequeue(struct + if (!trylock_page(page)) + continue; + +- balloon_page_delete(page); ++ list_del(&page->lru); ++ balloon_page_finalize(page); + __count_vm_event(BALLOON_DEFLATE); + list_add(&page->lru, pages); + unlock_page(page); diff --git a/queue-6.12/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch b/queue-6.12/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch new file mode 100644 index 0000000000..a5953da0e4 --- /dev/null +++ b/queue-6.12/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch @@ -0,0 +1,109 @@ +From stable+bounces-204876-greg=kroah.com@vger.kernel.org Mon Jan 5 18:42:15 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:42:03 -0500 +Subject: mm/balloon_compaction: we cannot have isolated pages in the balloon list +To: stable@vger.kernel.org +Cc: "David Hildenbrand" , "Zi Yan" , "Lorenzo Stoakes" , "Alistair Popple" , "Al Viro" , "Arnd Bergmann" , "Brendan Jackman" , "Byungchul Park" , "Chengming Zhou" , "Christian Brauner" , "Christophe Leroy" , "Eugenio Pé rez" , "Greg Kroah-Hartman" , "Gregory Price" , "Huang, Ying" , "Jan Kara" , "Jason Gunthorpe" , "Jason Wang" , "Jerrin Shaji George" , "Johannes Weiner" , "John Hubbard" , "Jonathan Corbet" , "Joshua Hahn" , "Liam Howlett" , "Madhavan Srinivasan" , "Mathew Brost" , "Matthew Wilcox (Oracle)" , "Miaohe Lin" , "Michael Ellerman" , "Michael S. Tsirkin" , "Michal Hocko" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Nicholas Piggin" , "Oscar Salvador" , "Peter Xu" , "Qi Zheng" , "Rakie Kim" , "Rik van Riel" , "Sergey Senozhatsky" , "Shakeel Butt" , "Suren Baghdasaryan" , "Vlastimil Babka" , "Xuan Zhuo" , "xu xin" , "Harry Yoo" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260105174205.2697666-1-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit fb05f992b6bbb4702307d96f00703ee637b24dbf ] + +Patch series "mm/migration: rework movable_ops page migration (part 1)", +v2. + +In the future, as we decouple "struct page" from "struct folio", pages +that support "non-lru page migration" -- movable_ops page migration such +as memory balloons and zsmalloc -- will no longer be folios. They will +not have ->mapping, ->lru, and likely no refcount and no page lock. But +they will have a type and flags 🙂 + +This is the first part (other parts not written yet) of decoupling +movable_ops page migration from folio migration. + +In this series, we get rid of the ->mapping usage, and start cleaning up +the code + separating it from folio migration. + +Migration core will have to be further reworked to not treat movable_ops +pages like folios. This is the first step into that direction. + +This patch (of 29): + +The core will set PG_isolated only after mops->isolate_page() was called. +In case of the balloon, that is where we will remove it from the balloon +list. So we cannot have isolated pages in the balloon list. + +Let's drop this unnecessary check. + +Link: https://lkml.kernel.org/r/20250704102524.326966-2-david@redhat.com +Signed-off-by: David Hildenbrand +Acked-by: Zi Yan +Reviewed-by: Lorenzo Stoakes +Cc: Alistair Popple +Cc: Al Viro +Cc: Arnd Bergmann +Cc: Brendan Jackman +Cc: Byungchul Park +Cc: Chengming Zhou +Cc: Christian Brauner +Cc: Christophe Leroy +Cc: Eugenio Pé rez +Cc: Greg Kroah-Hartman +Cc: Gregory Price +Cc: "Huang, Ying" +Cc: Jan Kara +Cc: Jason Gunthorpe +Cc: Jason Wang +Cc: Jerrin Shaji George +Cc: Johannes Weiner +Cc: John Hubbard +Cc: Jonathan Corbet +Cc: Joshua Hahn +Cc: Liam Howlett +Cc: Madhavan Srinivasan +Cc: Mathew Brost +Cc: Matthew Wilcox (Oracle) +Cc: Miaohe Lin +Cc: Michael Ellerman +Cc: "Michael S. Tsirkin" +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Nicholas Piggin +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Qi Zheng +Cc: Rakie Kim +Cc: Rik van Riel +Cc: Sergey Senozhatsky +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Xuan Zhuo +Cc: xu xin +Cc: Harry Yoo +Signed-off-by: Andrew Morton +Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/balloon_compaction.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/mm/balloon_compaction.c ++++ b/mm/balloon_compaction.c +@@ -93,12 +93,6 @@ size_t balloon_page_list_dequeue(struct + if (!trylock_page(page)) + continue; + +- if (IS_ENABLED(CONFIG_BALLOON_COMPACTION) && +- PageIsolated(page)) { +- /* raced with isolation */ +- unlock_page(page); +- continue; +- } + balloon_page_delete(page); + __count_vm_event(BALLOON_DEFLATE); + list_add(&page->lru, pages); diff --git a/queue-6.12/pci-brcmstb-fix-disabling-l0s-capability.patch b/queue-6.12/pci-brcmstb-fix-disabling-l0s-capability.patch new file mode 100644 index 0000000000..f2c542ca6e --- /dev/null +++ b/queue-6.12/pci-brcmstb-fix-disabling-l0s-capability.patch @@ -0,0 +1,78 @@ +From stable+bounces-204872-greg=kroah.com@vger.kernel.org Mon Jan 5 18:42:14 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:34:20 -0500 +Subject: PCI: brcmstb: Fix disabling L0s capability +To: stable@vger.kernel.org +Cc: Jim Quinlan , Bjorn Helgaas , Manivannan Sadhasivam , Florian Fainelli , Sasha Levin +Message-ID: <20260105173420.2692565-3-sashal@kernel.org> + +From: Jim Quinlan + +[ Upstream commit 9583f9d22991d2cfb5cc59a2552040c4ae98d998 ] + +caab002d5069 ("PCI: brcmstb: Disable L0s component of ASPM if requested") +set PCI_EXP_LNKCAP_ASPM_L1 and (optionally) PCI_EXP_LNKCAP_ASPM_L0S in +PCI_EXP_LNKCAP (aka PCIE_RC_CFG_PRIV1_LINK_CAPABILITY in brcmstb). + +But instead of using PCI_EXP_LNKCAP_ASPM_L1 and PCI_EXP_LNKCAP_ASPM_L0S +directly, it used PCIE_LINK_STATE_L1 and PCIE_LINK_STATE_L0S, which are +Linux-created values that only coincidentally matched the PCIe spec. +b478e162f227 ("PCI/ASPM: Consolidate link state defines") later changed +them so they no longer matched the PCIe spec, so the bits ended up in the +wrong place in PCI_EXP_LNKCAP. + +Use PCI_EXP_LNKCAP_ASPM_L0S to clear L0s support when there's an +'aspm-no-l0s' property. Rely on brcmstb hardware to advertise L0s and/or +L1 support otherwise. + +Fixes: caab002d5069 ("PCI: brcmstb: Disable L0s component of ASPM if requested") +Reported-by: Bjorn Helgaas +Closes: https://lore.kernel.org/linux-pci/20250925194424.GA2197200@bhelgaas +Signed-off-by: Jim Quinlan +[mani: reworded subject and description, added closes tag and CCed stable] +Signed-off-by: Manivannan Sadhasivam +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Florian Fainelli +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20251003170436.1446030-1-james.quinlan@broadcom.com +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/controller/pcie-brcmstb.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -47,7 +47,6 @@ + + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK 0x1f0 +-#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 + + #define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8 + #define PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK 0xf8 +@@ -1029,7 +1028,7 @@ static int brcm_pcie_setup(struct brcm_p + void __iomem *base = pcie->base; + struct pci_host_bridge *bridge; + struct resource_entry *entry; +- u32 tmp, burst, aspm_support, num_lanes, num_lanes_cap; ++ u32 tmp, burst, num_lanes, num_lanes_cap; + u8 num_out_wins = 0; + int num_inbound_wins = 0; + int memc, ret; +@@ -1129,12 +1128,9 @@ static int brcm_pcie_setup(struct brcm_p + + + /* Don't advertise L0s capability if 'aspm-no-l0s' */ +- aspm_support = PCIE_LINK_STATE_L1; +- if (!of_property_read_bool(pcie->np, "aspm-no-l0s")) +- aspm_support |= PCIE_LINK_STATE_L0S; + tmp = readl(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); +- u32p_replace_bits(&tmp, aspm_support, +- PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); ++ if (of_property_read_bool(pcie->np, "aspm-no-l0s")) ++ tmp &= ~PCI_EXP_LNKCAP_ASPM_L0S; + writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); + + /* 'tmp' still holds the contents of PRIV1_LINK_CAPABILITY */ diff --git a/queue-6.12/pci-brcmstb-reuse-pcie_cfg_data-structure.patch b/queue-6.12/pci-brcmstb-reuse-pcie_cfg_data-structure.patch new file mode 100644 index 0000000000..ec0ebafcdf --- /dev/null +++ b/queue-6.12/pci-brcmstb-reuse-pcie_cfg_data-structure.patch @@ -0,0 +1,261 @@ +From stable+bounces-204870-greg=kroah.com@vger.kernel.org Mon Jan 5 18:41:47 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:34:18 -0500 +Subject: PCI: brcmstb: Reuse pcie_cfg_data structure +To: stable@vger.kernel.org +Cc: "Stanimir Varbanov" , "Florian Fainelil" , "Jim Quinlan" , "Ivan T. Ivanov" , "Krzysztof Wilczyński" , "Sasha Levin" +Message-ID: <20260105173420.2692565-1-sashal@kernel.org> + +From: Stanimir Varbanov + +[ Upstream commit 10dbedad3c8188ce8b68559d43b7aaee7dafba25 ] + +Instead of copying fields from the pcie_cfg_data structure to +brcm_pcie, reference it directly. + +Signed-off-by: Stanimir Varbanov +Reviewed-by: Florian Fainelil +Reviewed-by: Jim Quinlan +Tested-by: Ivan T. Ivanov +Link: https://lore.kernel.org/r/20250224083559.47645-6-svarbanov@suse.de +[kwilczynski: commit log] +Signed-off-by: Krzysztof Wilczyński +Stable-dep-of: 9583f9d22991 ("PCI: brcmstb: Fix disabling L0s capability") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/controller/pcie-brcmstb.c | 72 +++++++++++++++------------------- + 1 file changed, 32 insertions(+), 40 deletions(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -191,11 +191,11 @@ + #define SSC_STATUS_PLL_LOCK_MASK 0x800 + #define PCIE_BRCM_MAX_MEMC 3 + +-#define IDX_ADDR(pcie) ((pcie)->reg_offsets[EXT_CFG_INDEX]) +-#define DATA_ADDR(pcie) ((pcie)->reg_offsets[EXT_CFG_DATA]) +-#define PCIE_RGR1_SW_INIT_1(pcie) ((pcie)->reg_offsets[RGR1_SW_INIT_1]) +-#define HARD_DEBUG(pcie) ((pcie)->reg_offsets[PCIE_HARD_DEBUG]) +-#define INTR2_CPU_BASE(pcie) ((pcie)->reg_offsets[PCIE_INTR2_CPU_BASE]) ++#define IDX_ADDR(pcie) ((pcie)->cfg->offsets[EXT_CFG_INDEX]) ++#define DATA_ADDR(pcie) ((pcie)->cfg->offsets[EXT_CFG_DATA]) ++#define PCIE_RGR1_SW_INIT_1(pcie) ((pcie)->cfg->offsets[RGR1_SW_INIT_1]) ++#define HARD_DEBUG(pcie) ((pcie)->cfg->offsets[PCIE_HARD_DEBUG]) ++#define INTR2_CPU_BASE(pcie) ((pcie)->cfg->offsets[PCIE_INTR2_CPU_BASE]) + + /* Rescal registers */ + #define PCIE_DVT_PMU_PCIE_PHY_CTRL 0xc700 +@@ -276,8 +276,6 @@ struct brcm_pcie { + int gen; + u64 msi_target_addr; + struct brcm_msi *msi; +- const int *reg_offsets; +- enum pcie_soc_base soc_base; + struct reset_control *rescal; + struct reset_control *perst_reset; + struct reset_control *bridge_reset; +@@ -285,17 +283,14 @@ struct brcm_pcie { + int num_memc; + u64 memc_size[PCIE_BRCM_MAX_MEMC]; + u32 hw_rev; +- int (*perst_set)(struct brcm_pcie *pcie, u32 val); +- int (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); + struct subdev_regulators *sr; + bool ep_wakeup_capable; +- bool has_phy; +- u8 num_inbound_wins; ++ const struct pcie_cfg_data *cfg; + }; + + static inline bool is_bmips(const struct brcm_pcie *pcie) + { +- return pcie->soc_base == BCM7435 || pcie->soc_base == BCM7425; ++ return pcie->cfg->soc_base == BCM7435 || pcie->cfg->soc_base == BCM7425; + } + + /* +@@ -855,7 +850,7 @@ static int brcm_pcie_get_inbound_wins(st + * security considerations, and is not implemented in our modern + * SoCs. + */ +- if (pcie->soc_base != BCM7712) ++ if (pcie->cfg->soc_base != BCM7712) + add_inbound_win(b++, &n, 0, 0, 0); + + resource_list_for_each_entry(entry, &bridge->dma_ranges) { +@@ -872,10 +867,10 @@ static int brcm_pcie_get_inbound_wins(st + * That being said, each BARs size must still be a power of + * two. + */ +- if (pcie->soc_base == BCM7712) ++ if (pcie->cfg->soc_base == BCM7712) + add_inbound_win(b++, &n, size, cpu_start, pcie_start); + +- if (n > pcie->num_inbound_wins) ++ if (n > pcie->cfg->num_inbound_wins) + break; + } + +@@ -889,7 +884,7 @@ static int brcm_pcie_get_inbound_wins(st + * that enables multiple memory controllers. As such, it can return + * now w/o doing special configuration. + */ +- if (pcie->soc_base == BCM7712) ++ if (pcie->cfg->soc_base == BCM7712) + return n; + + ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1, +@@ -1012,7 +1007,7 @@ static void set_inbound_win_registers(st + * 7712: + * All of their BARs need to be set. + */ +- if (pcie->soc_base == BCM7712) { ++ if (pcie->cfg->soc_base == BCM7712) { + /* BUS remap register settings */ + reg_offset = brcm_ubus_reg_offset(i); + tmp = lower_32_bits(cpu_addr) & ~0xfff; +@@ -1036,15 +1031,15 @@ static int brcm_pcie_setup(struct brcm_p + int memc, ret; + + /* Reset the bridge */ +- ret = pcie->bridge_sw_init_set(pcie, 1); ++ ret = pcie->cfg->bridge_sw_init_set(pcie, 1); + if (ret) + return ret; + + /* Ensure that PERST# is asserted; some bootloaders may deassert it. */ +- if (pcie->soc_base == BCM2711) { +- ret = pcie->perst_set(pcie, 1); ++ if (pcie->cfg->soc_base == BCM2711) { ++ ret = pcie->cfg->perst_set(pcie, 1); + if (ret) { +- pcie->bridge_sw_init_set(pcie, 0); ++ pcie->cfg->bridge_sw_init_set(pcie, 0); + return ret; + } + } +@@ -1052,7 +1047,7 @@ static int brcm_pcie_setup(struct brcm_p + usleep_range(100, 200); + + /* Take the bridge out of reset */ +- ret = pcie->bridge_sw_init_set(pcie, 0); ++ ret = pcie->cfg->bridge_sw_init_set(pcie, 0); + if (ret) + return ret; + +@@ -1072,9 +1067,9 @@ static int brcm_pcie_setup(struct brcm_p + */ + if (is_bmips(pcie)) + burst = 0x1; /* 256 bytes */ +- else if (pcie->soc_base == BCM2711) ++ else if (pcie->cfg->soc_base == BCM2711) + burst = 0x0; /* 128 bytes */ +- else if (pcie->soc_base == BCM7278) ++ else if (pcie->cfg->soc_base == BCM7278) + burst = 0x3; /* 512 bytes */ + else + burst = 0x2; /* 512 bytes */ +@@ -1199,7 +1194,7 @@ static void brcm_extend_rbus_timeout(str + u32 timeout_us = 4000000; /* 4 seconds, our setting for L1SS */ + + /* 7712 does not have this (RGR1) timer */ +- if (pcie->soc_base == BCM7712) ++ if (pcie->cfg->soc_base == BCM7712) + return; + + /* Each unit in timeout register is 1/216,000,000 seconds */ +@@ -1281,7 +1276,7 @@ static int brcm_pcie_start_link(struct b + brcm_pcie_set_gen(pcie, pcie->gen); + + /* Unassert the fundamental reset */ +- ret = pcie->perst_set(pcie, 0); ++ ret = pcie->cfg->perst_set(pcie, 0); + if (ret) + return ret; + +@@ -1465,12 +1460,12 @@ static int brcm_phy_cntl(struct brcm_pci + + static inline int brcm_phy_start(struct brcm_pcie *pcie) + { +- return pcie->has_phy ? brcm_phy_cntl(pcie, 1) : 0; ++ return pcie->cfg->has_phy ? brcm_phy_cntl(pcie, 1) : 0; + } + + static inline int brcm_phy_stop(struct brcm_pcie *pcie) + { +- return pcie->has_phy ? brcm_phy_cntl(pcie, 0) : 0; ++ return pcie->cfg->has_phy ? brcm_phy_cntl(pcie, 0) : 0; + } + + static int brcm_pcie_turn_off(struct brcm_pcie *pcie) +@@ -1481,7 +1476,7 @@ static int brcm_pcie_turn_off(struct brc + if (brcm_pcie_link_up(pcie)) + brcm_pcie_enter_l23(pcie); + /* Assert fundamental reset */ +- ret = pcie->perst_set(pcie, 1); ++ ret = pcie->cfg->perst_set(pcie, 1); + if (ret) + return ret; + +@@ -1496,7 +1491,7 @@ static int brcm_pcie_turn_off(struct brc + writel(tmp, base + HARD_DEBUG(pcie)); + + /* Shutdown PCIe bridge */ +- ret = pcie->bridge_sw_init_set(pcie, 1); ++ ret = pcie->cfg->bridge_sw_init_set(pcie, 1); + + return ret; + } +@@ -1584,7 +1579,7 @@ static int brcm_pcie_resume_noirq(struct + goto err_reset; + + /* Take bridge out of reset so we can access the SERDES reg */ +- pcie->bridge_sw_init_set(pcie, 0); ++ pcie->cfg->bridge_sw_init_set(pcie, 0); + + /* SERDES_IDDQ = 0 */ + tmp = readl(base + HARD_DEBUG(pcie)); +@@ -1805,12 +1800,7 @@ static int brcm_pcie_probe(struct platfo + pcie = pci_host_bridge_priv(bridge); + pcie->dev = &pdev->dev; + pcie->np = np; +- pcie->reg_offsets = data->offsets; +- pcie->soc_base = data->soc_base; +- pcie->perst_set = data->perst_set; +- pcie->bridge_sw_init_set = data->bridge_sw_init_set; +- pcie->has_phy = data->has_phy; +- pcie->num_inbound_wins = data->num_inbound_wins; ++ pcie->cfg = data; + + pcie->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pcie->base)) +@@ -1845,7 +1835,7 @@ static int brcm_pcie_probe(struct platfo + if (ret) + return dev_err_probe(&pdev->dev, ret, "could not enable clock\n"); + +- pcie->bridge_sw_init_set(pcie, 0); ++ pcie->cfg->bridge_sw_init_set(pcie, 0); + + if (pcie->swinit_reset) { + ret = reset_control_assert(pcie->swinit_reset); +@@ -1884,7 +1874,8 @@ static int brcm_pcie_probe(struct platfo + goto fail; + + pcie->hw_rev = readl(pcie->base + PCIE_MISC_REVISION); +- if (pcie->soc_base == BCM4908 && pcie->hw_rev >= BRCM_PCIE_HW_REV_3_20) { ++ if (pcie->cfg->soc_base == BCM4908 && ++ pcie->hw_rev >= BRCM_PCIE_HW_REV_3_20) { + dev_err(pcie->dev, "hardware revision with unsupported PERST# setup\n"); + ret = -ENODEV; + goto fail; +@@ -1904,7 +1895,8 @@ static int brcm_pcie_probe(struct platfo + } + } + +- bridge->ops = pcie->soc_base == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops; ++ bridge->ops = pcie->cfg->soc_base == BCM7425 ? ++ &brcm7425_pcie_ops : &brcm_pcie_ops; + bridge->sysdata = pcie; + + platform_set_drvdata(pdev, pcie); diff --git a/queue-6.12/pci-brcmstb-set-mlw-based-on-num-lanes-dt-property-if-present.patch b/queue-6.12/pci-brcmstb-set-mlw-based-on-num-lanes-dt-property-if-present.patch new file mode 100644 index 0000000000..a92d05e3bf --- /dev/null +++ b/queue-6.12/pci-brcmstb-set-mlw-based-on-num-lanes-dt-property-if-present.patch @@ -0,0 +1,86 @@ +From stable+bounces-204871-greg=kroah.com@vger.kernel.org Mon Jan 5 18:34:28 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:34:19 -0500 +Subject: PCI: brcmstb: Set MLW based on "num-lanes" DT property if present +To: stable@vger.kernel.org +Cc: Jim Quinlan , Manivannan Sadhasivam , Florian Fainelli , Sasha Levin +Message-ID: <20260105173420.2692565-2-sashal@kernel.org> + +From: Jim Quinlan + +[ Upstream commit a364d10ffe361fb34c3838d33604da493045de1e ] + +By default, the driver relies on the default hardware defined value for the +Max Link Width (MLW) capability. But if the "num-lanes" DT property is +present, assume that the chip's default capability information is incorrect +or undesired, and use the specified value instead. + +Signed-off-by: Jim Quinlan +[mani: reworded the description and comments] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250530224035.41886-3-james.quinlan@broadcom.com +Stable-dep-of: 9583f9d22991 ("PCI: brcmstb: Fix disabling L0s capability") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/controller/pcie-brcmstb.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -46,6 +46,7 @@ + #define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff + + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc ++#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK 0x1f0 + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 + + #define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8 +@@ -55,6 +56,9 @@ + #define PCIE_RC_DL_MDIO_WR_DATA 0x1104 + #define PCIE_RC_DL_MDIO_RD_DATA 0x1108 + ++#define PCIE_RC_PL_REG_PHY_CTL_1 0x1804 ++#define PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK 0x8 ++ + #define PCIE_MISC_MISC_CTRL 0x4008 + #define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80 + #define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400 +@@ -1025,7 +1029,7 @@ static int brcm_pcie_setup(struct brcm_p + void __iomem *base = pcie->base; + struct pci_host_bridge *bridge; + struct resource_entry *entry; +- u32 tmp, burst, aspm_support; ++ u32 tmp, burst, aspm_support, num_lanes, num_lanes_cap; + u8 num_out_wins = 0; + int num_inbound_wins = 0; + int memc, ret; +@@ -1133,6 +1137,27 @@ static int brcm_pcie_setup(struct brcm_p + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); + writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); + ++ /* 'tmp' still holds the contents of PRIV1_LINK_CAPABILITY */ ++ num_lanes_cap = u32_get_bits(tmp, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK); ++ num_lanes = 0; ++ ++ /* ++ * Use hardware negotiated Max Link Width value by default. If the ++ * "num-lanes" DT property is present, assume that the chip's default ++ * link width capability information is incorrect/undesired and use the ++ * specified value instead. ++ */ ++ if (!of_property_read_u32(pcie->np, "num-lanes", &num_lanes) && ++ num_lanes && num_lanes <= 4 && num_lanes_cap != num_lanes) { ++ u32p_replace_bits(&tmp, num_lanes, ++ PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK); ++ writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); ++ tmp = readl(base + PCIE_RC_PL_REG_PHY_CTL_1); ++ u32p_replace_bits(&tmp, 1, ++ PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK); ++ writel(tmp, base + PCIE_RC_PL_REG_PHY_CTL_1); ++ } ++ + /* + * For config space accesses on the RC, show the right class for + * a PCIe-PCIe bridge (the default setting is to be EP mode). diff --git a/queue-6.12/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch b/queue-6.12/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch new file mode 100644 index 0000000000..853807b661 --- /dev/null +++ b/queue-6.12/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch @@ -0,0 +1,45 @@ +From stable+bounces-204878-greg=kroah.com@vger.kernel.org Mon Jan 5 18:47:39 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:42:05 -0500 +Subject: powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages +To: stable@vger.kernel.org +Cc: David Hildenbrand , "Ritesh Harjani (IBM)" , Christophe Leroy , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , Andrew Morton , Sasha Levin +Message-ID: <20260105174205.2697666-3-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 0da2ba35c0d532ca0fe7af698b17d74c4d084b9a ] + +Let's properly adjust BALLOON_MIGRATE like the other drivers. + +Note that the INFLATE/DEFLATE events are triggered from the core when +enqueueing/dequeueing pages. + +This was found by code inspection. + +Link: https://lkml.kernel.org/r/20251021100606.148294-3-david@redhat.com +Fixes: fe030c9b85e6 ("powerpc/pseries/cmm: Implement balloon compaction") +Signed-off-by: David Hildenbrand +Reviewed-by: Ritesh Harjani (IBM) +Cc: Christophe Leroy +Cc: Madhavan Srinivasan +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/pseries/cmm.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/powerpc/platforms/pseries/cmm.c ++++ b/arch/powerpc/platforms/pseries/cmm.c +@@ -532,6 +532,7 @@ static int cmm_migratepage(struct balloo + + spin_lock_irqsave(&b_dev_info->pages_lock, flags); + balloon_page_insert(b_dev_info, newpage); ++ __count_vm_event(BALLOON_MIGRATE); + b_dev_info->isolated_pages--; + spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); + diff --git a/queue-6.12/series b/queue-6.12/series index b7ce9717f3..eaaa2f2185 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -544,3 +544,20 @@ idpf-replace-flow-scheduling-buffer-ring-with-buffer-pool.patch idpf-stop-tx-if-there-are-insufficient-buffer-resources.patch idpf-remove-obsolete-stashing-code.patch hrtimers-make-hrtimer_update_function-less-expensive.patch +gve-defer-interrupt-enabling-until-napi-registration.patch +asoc-renesas-rz-ssi-fix-channel-swap-issue-in-full-duplex-mode.patch +block-handle-zone-management-operations-completions.patch +soundwire-stream-extend-sdw_alloc_stream-to-take-type-parameter.patch +asoc-qcom-sdw-fix-memory-leak-for-sdw_stream_runtime.patch +asoc-renesas-rz-ssi-fix-rz_ssi_priv-hw_params_cache-sample_width.patch +pci-brcmstb-reuse-pcie_cfg_data-structure.patch +pci-brcmstb-set-mlw-based-on-num-lanes-dt-property-if-present.patch +pci-brcmstb-fix-disabling-l0s-capability.patch +mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch +mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch +powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch +media-mediatek-vcodec-use-spinlock-for-context-list-protection-lock.patch +media-amphion-add-a-frame-flush-mode-for-decoder.patch +media-amphion-make-some-vpu_v4l2-functions-static.patch +media-amphion-remove-vpu_vb_is_codecconfig.patch +vfio-pci-disable-qword-access-to-the-pci-rom-bar.patch diff --git a/queue-6.12/soundwire-stream-extend-sdw_alloc_stream-to-take-type-parameter.patch b/queue-6.12/soundwire-stream-extend-sdw_alloc_stream-to-take-type-parameter.patch new file mode 100644 index 0000000000..3b114a459b --- /dev/null +++ b/queue-6.12/soundwire-stream-extend-sdw_alloc_stream-to-take-type-parameter.patch @@ -0,0 +1,103 @@ +From stable+bounces-204827-greg=kroah.com@vger.kernel.org Mon Jan 5 16:14:58 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:10:07 -0500 +Subject: soundwire: stream: extend sdw_alloc_stream() to take 'type' parameter +To: stable@vger.kernel.org +Cc: "Pierre-Louis Bossart" , "Bard Liao" , "Péter Ujfalusi" , "Liam Girdwood" , "Ranjani Sridharan" , shumingf@realtek.com, "Vinod Koul" , "Sasha Levin" +Message-ID: <20260105151008.2624877-1-sashal@kernel.org> + +From: Pierre-Louis Bossart + +[ Upstream commit dc90bbefa792031d89fe2af9ad4a6febd6be96a9 ] + +In the existing definition of sdw_stream_runtime, the 'type' member is +never set and defaults to PCM. To prepare for the BPT/BRA support, we +need to special-case streams and make use of the 'type'. + +No functional change for now, the implicit PCM type is now explicit. + +Signed-off-by: Pierre-Louis Bossart +Signed-off-by: Bard Liao +Reviewed-by: Péter Ujfalusi +Reviewed-by: Liam Girdwood +Reviewed-by: Ranjani Sridharan +Tested-by: shumingf@realtek.com +Link: https://lore.kernel.org/r/20250227140615.8147-5-yung-chuan.liao@linux.intel.com +Signed-off-by: Vinod Koul +Stable-dep-of: bcba17279327 ("ASoC: qcom: sdw: fix memory leak for sdw_stream_runtime") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/driver-api/soundwire/stream.rst | 2 +- + drivers/soundwire/stream.c | 6 ++++-- + include/linux/soundwire/sdw.h | 2 +- + sound/soc/qcom/sdw.c | 2 +- + 4 files changed, 7 insertions(+), 5 deletions(-) + +--- a/Documentation/driver-api/soundwire/stream.rst ++++ b/Documentation/driver-api/soundwire/stream.rst +@@ -291,7 +291,7 @@ per stream. From ASoC DPCM framework, th + + .. code-block:: c + +- int sdw_alloc_stream(char * stream_name); ++ int sdw_alloc_stream(char * stream_name, enum sdw_stream_type type); + + The SoundWire core provides a sdw_startup_stream() helper function, + typically called during a dailink .startup() callback, which performs +--- a/drivers/soundwire/stream.c ++++ b/drivers/soundwire/stream.c +@@ -1744,12 +1744,13 @@ static int set_stream(struct snd_pcm_sub + * sdw_alloc_stream() - Allocate and return stream runtime + * + * @stream_name: SoundWire stream name ++ * @type: stream type (could be PCM ,PDM or BPT) + * + * Allocates a SoundWire stream runtime instance. + * sdw_alloc_stream should be called only once per stream. Typically + * invoked from ALSA/ASoC machine/platform driver. + */ +-struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name) ++struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name, enum sdw_stream_type type) + { + struct sdw_stream_runtime *stream; + +@@ -1761,6 +1762,7 @@ struct sdw_stream_runtime *sdw_alloc_str + INIT_LIST_HEAD(&stream->master_list); + stream->state = SDW_STREAM_ALLOCATED; + stream->m_rt_count = 0; ++ stream->type = type; + + return stream; + } +@@ -1789,7 +1791,7 @@ int sdw_startup_stream(void *sdw_substre + if (!name) + return -ENOMEM; + +- sdw_stream = sdw_alloc_stream(name); ++ sdw_stream = sdw_alloc_stream(name, SDW_STREAM_PCM); + if (!sdw_stream) { + dev_err(rtd->dev, "alloc stream failed for substream DAI %s\n", substream->name); + ret = -ENOMEM; +--- a/include/linux/soundwire/sdw.h ++++ b/include/linux/soundwire/sdw.h +@@ -1024,7 +1024,7 @@ struct sdw_stream_runtime { + int m_rt_count; + }; + +-struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name); ++struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name, enum sdw_stream_type type); + void sdw_release_stream(struct sdw_stream_runtime *stream); + + int sdw_compute_params(struct sdw_bus *bus); +--- a/sound/soc/qcom/sdw.c ++++ b/sound/soc/qcom/sdw.c +@@ -27,7 +27,7 @@ int qcom_snd_sdw_startup(struct snd_pcm_ + struct snd_soc_dai *codec_dai; + int ret, i; + +- sruntime = sdw_alloc_stream(cpu_dai->name); ++ sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM); + if (!sruntime) + return -ENOMEM; + diff --git a/queue-6.12/vfio-pci-disable-qword-access-to-the-pci-rom-bar.patch b/queue-6.12/vfio-pci-disable-qword-access-to-the-pci-rom-bar.patch new file mode 100644 index 0000000000..92992484f6 --- /dev/null +++ b/queue-6.12/vfio-pci-disable-qword-access-to-the-pci-rom-bar.patch @@ -0,0 +1,167 @@ +From stable+bounces-205024-greg=kroah.com@vger.kernel.org Tue Jan 6 03:41:16 2026 +From: Kevin Tian +Date: Tue, 6 Jan 2026 02:44:28 +0000 +Subject: vfio/pci: Disable qword access to the PCI ROM bar +To: stable@vger.kernel.org +Cc: Kevin Tian , Farrah Chen , Alex Williamson +Message-ID: <20260106024428.1334406-1-kevin.tian@intel.com> + +From: Kevin Tian + +[ Upstream commit dc85a46928c41423ad89869baf05a589e2975575 ] + +Commit 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio +pci") enables qword access to the PCI bar resources. However certain +devices (e.g. Intel X710) are observed with problem upon qword accesses +to the rom bar, e.g. triggering PCI aer errors. + +This is triggered by Qemu which caches the rom content by simply does a +pread() of the remaining size until it gets the full contents. The other +bars would only perform operations at the same access width as their +guest drivers. + +Instead of trying to identify all broken devices, universally disable +qword access to the rom bar i.e. going back to the old way which worked +reliably for years. + +Reported-by: Farrah Chen +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220740 +Fixes: 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio pci") +Cc: stable@vger.kernel.org +Signed-off-by: Kevin Tian +Tested-by: Farrah Chen +Link: https://lore.kernel.org/r/20251218081650.555015-2-kevin.tian@intel.com +Signed-off-by: Alex Williamson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vfio/pci/nvgrace-gpu/main.c | 4 ++-- + drivers/vfio/pci/vfio_pci_rdwr.c | 24 ++++++++++++++++++------ + include/linux/vfio_pci_core.h | 10 +++++++++- + 3 files changed, 29 insertions(+), 9 deletions(-) + +--- a/drivers/vfio/pci/nvgrace-gpu/main.c ++++ b/drivers/vfio/pci/nvgrace-gpu/main.c +@@ -482,7 +482,7 @@ nvgrace_gpu_map_and_read(struct nvgrace_ + ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, + nvdev->resmem.ioaddr, + buf, offset, mem_count, +- 0, 0, false); ++ 0, 0, false, VFIO_PCI_IO_WIDTH_8); + } + + return ret; +@@ -600,7 +600,7 @@ nvgrace_gpu_map_and_write(struct nvgrace + ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, + nvdev->resmem.ioaddr, + (char __user *)buf, pos, mem_count, +- 0, 0, true); ++ 0, 0, true, VFIO_PCI_IO_WIDTH_8); + } + + return ret; +--- a/drivers/vfio/pci/vfio_pci_rdwr.c ++++ b/drivers/vfio/pci/vfio_pci_rdwr.c +@@ -141,7 +141,8 @@ VFIO_IORDWR(64) + ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, + void __iomem *io, char __user *buf, + loff_t off, size_t count, size_t x_start, +- size_t x_end, bool iswrite) ++ size_t x_end, bool iswrite, ++ enum vfio_pci_io_width max_width) + { + ssize_t done = 0; + int ret; +@@ -157,7 +158,7 @@ ssize_t vfio_pci_core_do_io_rw(struct vf + fillable = 0; + + #if defined(ioread64) && defined(iowrite64) +- if (fillable >= 8 && !(off % 8)) { ++ if (fillable >= 8 && !(off % 8) && max_width >= 8) { + ret = vfio_pci_iordwr64(vdev, iswrite, test_mem, + io, buf, off, &filled); + if (ret) +@@ -165,13 +166,13 @@ ssize_t vfio_pci_core_do_io_rw(struct vf + + } else + #endif +- if (fillable >= 4 && !(off % 4)) { ++ if (fillable >= 4 && !(off % 4) && max_width >= 4) { + ret = vfio_pci_iordwr32(vdev, iswrite, test_mem, + io, buf, off, &filled); + if (ret) + return ret; + +- } else if (fillable >= 2 && !(off % 2)) { ++ } else if (fillable >= 2 && !(off % 2) && max_width >= 2) { + ret = vfio_pci_iordwr16(vdev, iswrite, test_mem, + io, buf, off, &filled); + if (ret) +@@ -242,6 +243,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_ + void __iomem *io; + struct resource *res = &vdev->pdev->resource[bar]; + ssize_t done; ++ enum vfio_pci_io_width max_width = VFIO_PCI_IO_WIDTH_8; + + if (pci_resource_start(pdev, bar)) + end = pci_resource_len(pdev, bar); +@@ -268,6 +270,16 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_ + goto out; + } + x_end = end; ++ ++ /* ++ * Certain devices (e.g. Intel X710) don't support qword ++ * access to the ROM bar. Otherwise PCI AER errors might be ++ * triggered. ++ * ++ * Disable qword access to the ROM bar universally, which ++ * worked reliably for years before qword access is enabled. ++ */ ++ max_width = VFIO_PCI_IO_WIDTH_4; + } else { + int ret = vfio_pci_core_setup_barmap(vdev, bar); + if (ret) { +@@ -284,7 +296,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_ + } + + done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos, +- count, x_start, x_end, iswrite); ++ count, x_start, x_end, iswrite, max_width); + + if (done >= 0) + *ppos += done; +@@ -353,7 +365,7 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_ + * to the memory enable bit in the command register. + */ + done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count, +- 0, 0, iswrite); ++ 0, 0, iswrite, VFIO_PCI_IO_WIDTH_8); + + vga_put(vdev->pdev, rsrc); + +--- a/include/linux/vfio_pci_core.h ++++ b/include/linux/vfio_pci_core.h +@@ -102,6 +102,13 @@ struct vfio_pci_core_device { + struct rw_semaphore memory_lock; + }; + ++enum vfio_pci_io_width { ++ VFIO_PCI_IO_WIDTH_1 = 1, ++ VFIO_PCI_IO_WIDTH_2 = 2, ++ VFIO_PCI_IO_WIDTH_4 = 4, ++ VFIO_PCI_IO_WIDTH_8 = 8, ++}; ++ + /* Will be exported for vfio pci drivers usage */ + int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev, + unsigned int type, unsigned int subtype, +@@ -137,7 +144,8 @@ pci_ers_result_t vfio_pci_core_aer_err_d + ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, + void __iomem *io, char __user *buf, + loff_t off, size_t count, size_t x_start, +- size_t x_end, bool iswrite); ++ size_t x_end, bool iswrite, ++ enum vfio_pci_io_width max_width); + bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt, + loff_t reg_start, size_t reg_cnt, + loff_t *buf_offset,