From: Sasha Levin Date: Sat, 26 Apr 2025 13:23:09 +0000 (-0400) Subject: Fixes for 6.6 X-Git-Tag: v5.4.293~89 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=390521cbe12f3f72d378a57a0a186de388e1c8c5;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.6 Signed-off-by: Sasha Levin --- diff --git a/queue-6.6/arm64-tegra-remove-the-orin-nx-nano-suspend-key.patch b/queue-6.6/arm64-tegra-remove-the-orin-nx-nano-suspend-key.patch new file mode 100644 index 0000000000..57ab3c5b37 --- /dev/null +++ b/queue-6.6/arm64-tegra-remove-the-orin-nx-nano-suspend-key.patch @@ -0,0 +1,50 @@ +From 41b69992d0010f57001c2bd8465cc301c6f2e53d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Feb 2025 22:40:34 +0000 +Subject: arm64: tegra: Remove the Orin NX/Nano suspend key + +From: Ninad Malwade + +[ Upstream commit bb8a3ad25f098b6ea9b1d0f522427b4ad53a7bba ] + +As per the Orin Nano Dev Kit schematic, GPIO_G.02 is not available +on this device family. It should not be used at all on Orin NX/Nano. +Having this unused pin mapped as the suspend key can lead to +unpredictable behavior for low power modes. + +Orin NX/Nano uses GPIO_EE.04 as both a "power" button and a "suspend" +button. However, we cannot have two gpio-keys mapped to the same +GPIO. Therefore remove the "suspend" key. + +Cc: stable@vger.kernel.org +Fixes: e63472eda5ea ("arm64: tegra: Support Jetson Orin NX reference platform") +Signed-off-by: Ninad Malwade +Signed-off-by: Ivy Huang +Link: https://lore.kernel.org/r/20250206224034.3691397-1-yijuh@nvidia.com +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi +index 39110c1232e0d..db10b4b46cca9 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3768-0000.dtsi +@@ -196,13 +196,6 @@ key-power { + wakeup-event-action = ; + wakeup-source; + }; +- +- key-suspend { +- label = "Suspend"; +- gpios = <&gpio TEGRA234_MAIN_GPIO(G, 2) GPIO_ACTIVE_LOW>; +- linux,input-type = ; +- linux,code = ; +- }; + }; + + fan: pwm-fan { +-- +2.39.5 + diff --git a/queue-6.6/asoc-q6apm-dai-make-use-of-q6apm_get_hw_pointer.patch b/queue-6.6/asoc-q6apm-dai-make-use-of-q6apm_get_hw_pointer.patch new file mode 100644 index 0000000000..1d0852c752 --- /dev/null +++ b/queue-6.6/asoc-q6apm-dai-make-use-of-q6apm_get_hw_pointer.patch @@ -0,0 +1,106 @@ +From d933556fe7d4117d9a187a9724b11af377152e9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Mar 2025 17:47:58 +0000 +Subject: ASoC: q6apm-dai: make use of q6apm_get_hw_pointer + +From: Srinivas Kandagatla + +[ Upstream commit a93dad6f4e6a04a5943f6ee5686585f24abf7063 ] + +With the existing code, the buffer position is only reset in pointer +callback, which leaves the possiblity of it going over the size of +buffer size and reporting incorrect position to userspace. + +Without this patch, its possible to see errors like: +snd-x1e80100 sound: invalid position: pcmC0D0p:0, pos = 12288, buffer size = 12288, period size = 1536 +snd-x1e80100 sound: invalid position: pcmC0D0p:0, pos = 12288, buffer size = 12288, period size = 1536 + +Fixes: 9b4fe0f1cd791 ("ASoC: qdsp6: audioreach: add q6apm-dai support") +Cc: stable@vger.kernel.org +Signed-off-by: Srinivas Kandagatla +Tested-by: Krzysztof Kozlowski +Tested-by: Johan Hovold +Link: https://patch.msgid.link/20250314174800.10142-4-srinivas.kandagatla@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/q6apm-dai.c | 23 ++++------------------- + 1 file changed, 4 insertions(+), 19 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c +index a52304bef9d92..179f4f7386dd0 100644 +--- a/sound/soc/qcom/qdsp6/q6apm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6apm-dai.c +@@ -64,7 +64,6 @@ struct q6apm_dai_rtd { + phys_addr_t phys; + unsigned int pcm_size; + unsigned int pcm_count; +- unsigned int pos; /* Buffer position */ + unsigned int periods; + unsigned int bytes_sent; + unsigned int bytes_received; +@@ -124,23 +123,16 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo + { + struct q6apm_dai_rtd *prtd = priv; + struct snd_pcm_substream *substream = prtd->substream; +- unsigned long flags; + + switch (opcode) { + case APM_CLIENT_EVENT_CMD_EOS_DONE: + prtd->state = Q6APM_STREAM_STOPPED; + break; + case APM_CLIENT_EVENT_DATA_WRITE_DONE: +- spin_lock_irqsave(&prtd->lock, flags); +- prtd->pos += prtd->pcm_count; +- spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); + + break; + case APM_CLIENT_EVENT_DATA_READ_DONE: +- spin_lock_irqsave(&prtd->lock, flags); +- prtd->pos += prtd->pcm_count; +- spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); + if (prtd->state == Q6APM_STREAM_RUNNING) + q6apm_read(prtd->graph); +@@ -246,7 +238,6 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, + } + + prtd->pcm_count = snd_pcm_lib_period_bytes(substream); +- prtd->pos = 0; + /* rate and channels are sent to audio driver */ + ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); + if (ret < 0) { +@@ -445,16 +436,12 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component, + struct snd_pcm_runtime *runtime = substream->runtime; + struct q6apm_dai_rtd *prtd = runtime->private_data; + snd_pcm_uframes_t ptr; +- unsigned long flags; + +- spin_lock_irqsave(&prtd->lock, flags); +- if (prtd->pos == prtd->pcm_size) +- prtd->pos = 0; +- +- ptr = bytes_to_frames(runtime, prtd->pos); +- spin_unlock_irqrestore(&prtd->lock, flags); ++ ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size; ++ if (ptr) ++ return ptr - 1; + +- return ptr; ++ return 0; + } + + static int q6apm_dai_hw_params(struct snd_soc_component *component, +@@ -669,8 +656,6 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component, + prtd->pcm_size = runtime->fragments * runtime->fragment_size; + prtd->bits_per_sample = 16; + +- prtd->pos = 0; +- + if (prtd->next_track != true) { + memcpy(&prtd->codec, codec, sizeof(*codec)); + +-- +2.39.5 + diff --git a/queue-6.6/asoc-q6apm-dai-schedule-all-available-frames-to-avoi.patch b/queue-6.6/asoc-q6apm-dai-schedule-all-available-frames-to-avoi.patch new file mode 100644 index 0000000000..6e01d5dd55 --- /dev/null +++ b/queue-6.6/asoc-q6apm-dai-schedule-all-available-frames-to-avoi.patch @@ -0,0 +1,101 @@ +From a96ad67ff2025a363b96450fd290f95ad0b598f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Mar 2025 17:47:56 +0000 +Subject: ASoC: q6apm-dai: schedule all available frames to avoid dsp + under-runs + +From: Srinivas Kandagatla + +[ Upstream commit 3d4a4411aa8bbc3653ff22a1ff0432eb93d22ae0 ] + +With the existing code, we are only setting up one period at a time, in a +ping-pong buffer style. This triggers lot of underruns in the dsp +leading to jitter noise during audio playback. + +Fix this by scheduling all available periods, this will ensure that the dsp +has enough buffer feed and ultimatley fixing the underruns and audio +distortion. + +Fixes: 9b4fe0f1cd79 ("ASoC: qdsp6: audioreach: add q6apm-dai support") +Cc: stable@vger.kernel.org +Reported-by: Krzysztof Kozlowski +Signed-off-by: Srinivas Kandagatla +Tested-by: Krzysztof Kozlowski +Tested-by: Johan Hovold +Link: https://patch.msgid.link/20250314174800.10142-2-srinivas.kandagatla@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/q6apm-dai.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c +index 5573802e480ba..f188d00825c03 100644 +--- a/sound/soc/qcom/qdsp6/q6apm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6apm-dai.c +@@ -70,6 +70,7 @@ struct q6apm_dai_rtd { + unsigned int bytes_received; + unsigned int copied_total; + uint16_t bits_per_sample; ++ snd_pcm_uframes_t queue_ptr; + bool next_track; + enum stream_state state; + struct q6apm_graph *graph; +@@ -134,8 +135,6 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo + prtd->pos += prtd->pcm_count; + spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); +- if (prtd->state == Q6APM_STREAM_RUNNING) +- q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); + + break; + case APM_CLIENT_EVENT_DATA_READ_DONE: +@@ -293,6 +292,27 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, + return 0; + } + ++static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct q6apm_dai_rtd *prtd = runtime->private_data; ++ int i, ret = 0, avail_periods; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size; ++ for (i = 0; i < avail_periods; i++) { ++ ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP); ++ if (ret < 0) { ++ dev_err(component->dev, "Error queuing playback buffer %d\n", ret); ++ return ret; ++ } ++ prtd->queue_ptr += runtime->period_size; ++ } ++ } ++ ++ return ret; ++} ++ + static int q6apm_dai_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) + { +@@ -304,9 +324,6 @@ static int q6apm_dai_trigger(struct snd_soc_component *component, + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +- /* start writing buffers for playback only as we already queued capture buffers */ +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +- ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); + break; + case SNDRV_PCM_TRIGGER_STOP: + /* TODO support be handled via SoftPause Module */ +@@ -834,6 +851,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = { + .hw_params = q6apm_dai_hw_params, + .pointer = q6apm_dai_pointer, + .trigger = q6apm_dai_trigger, ++ .ack = q6apm_dai_ack, + .compress_ops = &q6apm_dai_compress_ops, + .use_dai_pcm_id = true, + }; +-- +2.39.5 + diff --git a/queue-6.6/asoc-qcom-fix-trivial-code-style-issues.patch b/queue-6.6/asoc-qcom-fix-trivial-code-style-issues.patch new file mode 100644 index 0000000000..b49e1a5ca0 --- /dev/null +++ b/queue-6.6/asoc-qcom-fix-trivial-code-style-issues.patch @@ -0,0 +1,309 @@ +From 6de6666884340b22f57e5cd7dfb6d7c5bea859d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Dec 2023 11:00:48 +0100 +Subject: ASoC: qcom: Fix trivial code style issues + +From: Krzysztof Kozlowski + +[ Upstream commit bb3392453d3ba44e60b85381e3bfa3c551a44e5d ] + +Fix few trivial code style issues, pointed out by checkpatch, so they do +not get copied to new code (when old code is used as template): + + WARNING: Prefer "GPL" over "GPL v2" - see commit bf7fbeeae6db ("module: Cure the MODULE_LICENSE "GPL" vs. "GPL v2" bogosity") + WARNING: function definition argument 'struct platform_device *' should also have an identifier name + ERROR: code indent should use tabs where possible + WARNING: please, no spaces at the start of a line + WARNING: Missing a blank line after declarations + WARNING: unnecessary whitespace before a quoted newline + +Signed-off-by: Krzysztof Kozlowski +Link: https://msgid.link/r/20231204100048.211800-1-krzysztof.kozlowski@linaro.org +Signed-off-by: Mark Brown +Stable-dep-of: a93dad6f4e6a ("ASoC: q6apm-dai: make use of q6apm_get_hw_pointer") +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/apq8016_sbc.c | 2 +- + sound/soc/qcom/apq8096.c | 2 +- + sound/soc/qcom/common.c | 2 +- + sound/soc/qcom/lpass-apq8016.c | 2 +- + sound/soc/qcom/lpass-cpu.c | 2 +- + sound/soc/qcom/lpass-hdmi.c | 2 +- + sound/soc/qcom/lpass-ipq806x.c | 2 +- + sound/soc/qcom/lpass-platform.c | 2 +- + sound/soc/qcom/lpass-sc7180.c | 2 +- + sound/soc/qcom/lpass.h | 2 +- + sound/soc/qcom/qdsp6/q6afe.c | 8 ++++---- + sound/soc/qcom/qdsp6/q6apm-dai.c | 4 ++-- + sound/soc/qcom/qdsp6/q6asm.h | 20 ++++++++++---------- + sound/soc/qcom/qdsp6/topology.c | 3 ++- + sound/soc/qcom/sc7180.c | 2 +- + sound/soc/qcom/sc8280xp.c | 2 +- + sound/soc/qcom/sdm845.c | 2 +- + sound/soc/qcom/sdw.c | 2 +- + sound/soc/qcom/sm8250.c | 2 +- + sound/soc/qcom/storm.c | 2 +- + 20 files changed, 34 insertions(+), 33 deletions(-) + +diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c +index ff9f6a1c95df1..40b6a837f66bb 100644 +--- a/sound/soc/qcom/apq8016_sbc.c ++++ b/sound/soc/qcom/apq8016_sbc.c +@@ -343,4 +343,4 @@ module_platform_driver(apq8016_sbc_platform_driver); + + MODULE_AUTHOR("Srinivas Kandagatla state = Q6APM_STREAM_STOPPED; + break; + case APM_CLIENT_EVENT_DATA_WRITE_DONE: +- spin_lock_irqsave(&prtd->lock, flags); ++ spin_lock_irqsave(&prtd->lock, flags); + prtd->pos += prtd->pcm_count; + spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); + + break; + case APM_CLIENT_EVENT_DATA_READ_DONE: +- spin_lock_irqsave(&prtd->lock, flags); ++ spin_lock_irqsave(&prtd->lock, flags); + prtd->pos += prtd->pcm_count; + spin_unlock_irqrestore(&prtd->lock, flags); + snd_pcm_period_elapsed(substream); +diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h +index 394604c349432..a33d92c7bd6bf 100644 +--- a/sound/soc/qcom/qdsp6/q6asm.h ++++ b/sound/soc/qcom/qdsp6/q6asm.h +@@ -36,16 +36,16 @@ enum { + #define ASM_LAST_BUFFER_FLAG BIT(30) + + struct q6asm_flac_cfg { +- u32 sample_rate; +- u32 ext_sample_rate; +- u32 min_frame_size; +- u32 max_frame_size; +- u16 stream_info_present; +- u16 min_blk_size; +- u16 max_blk_size; +- u16 ch_cfg; +- u16 sample_size; +- u16 md5_sum; ++ u32 sample_rate; ++ u32 ext_sample_rate; ++ u32 min_frame_size; ++ u32 max_frame_size; ++ u16 stream_info_present; ++ u16 min_blk_size; ++ u16 max_blk_size; ++ u16 ch_cfg; ++ u16 sample_size; ++ u16 md5_sum; + }; + + struct q6asm_wma_cfg { +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index 130b22a34fb3b..70572c83e1017 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -545,6 +545,7 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap + + if (mod) { + int pn, id = 0; ++ + mod->module_id = module_id; + mod->max_ip_port = max_ip_port; + mod->max_op_port = max_op_port; +@@ -1271,7 +1272,7 @@ int audioreach_tplg_init(struct snd_soc_component *component) + + ret = request_firmware(&fw, tplg_fw_name, dev); + if (ret < 0) { +- dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); ++ dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret); + goto err; + } + +diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c +index d1fd40e3f7a9d..1367752f2b63a 100644 +--- a/sound/soc/qcom/sc7180.c ++++ b/sound/soc/qcom/sc7180.c +@@ -428,4 +428,4 @@ static struct platform_driver sc7180_snd_driver = { + module_platform_driver(sc7180_snd_driver); + + MODULE_DESCRIPTION("sc7180 ASoC Machine Driver"); +-MODULE_LICENSE("GPL v2"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c +index 6e5f194bc34b0..d5cc967992d16 100644 +--- a/sound/soc/qcom/sc8280xp.c ++++ b/sound/soc/qcom/sc8280xp.c +@@ -174,4 +174,4 @@ static struct platform_driver snd_sc8280xp_driver = { + module_platform_driver(snd_sc8280xp_driver); + MODULE_AUTHOR("Srinivas Kandagatla +Date: Sat, 14 Oct 2023 00:19:52 +0200 +Subject: ASoC: qcom: lpass: Make asoc_qcom_lpass_cpu_platform_remove() return + void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit d0cc676c426d1958989fac2a0d45179fb9992f0a ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +asoc_qcom_lpass_cpu_platform_remove() returned zero unconditionally. +Make it return void instead and convert all users to struct +platform_device::remove_new(). + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20231013221945.1489203-15-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: a93dad6f4e6a ("ASoC: q6apm-dai: make use of q6apm_get_hw_pointer") +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/lpass-apq8016.c | 2 +- + sound/soc/qcom/lpass-cpu.c | 5 +---- + sound/soc/qcom/lpass-ipq806x.c | 2 +- + sound/soc/qcom/lpass-sc7180.c | 2 +- + sound/soc/qcom/lpass-sc7280.c | 2 +- + sound/soc/qcom/lpass.h | 2 +- + 6 files changed, 6 insertions(+), 9 deletions(-) + +diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c +index f919d46e18caa..06a4faae50875 100644 +--- a/sound/soc/qcom/lpass-apq8016.c ++++ b/sound/soc/qcom/lpass-apq8016.c +@@ -300,7 +300,7 @@ static struct platform_driver apq8016_lpass_cpu_platform_driver = { + .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id), + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + }; + module_platform_driver(apq8016_lpass_cpu_platform_driver); + +diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c +index e587455dc40a0..92316768011ae 100644 +--- a/sound/soc/qcom/lpass-cpu.c ++++ b/sound/soc/qcom/lpass-cpu.c +@@ -1284,15 +1284,12 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) + } + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe); + +-int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) ++void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) + { + struct lpass_data *drvdata = platform_get_drvdata(pdev); + + if (drvdata->variant->exit) + drvdata->variant->exit(pdev); +- +- +- return 0; + } + EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); + +diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c +index 2c97f295e3940..10f7e2639c423 100644 +--- a/sound/soc/qcom/lpass-ipq806x.c ++++ b/sound/soc/qcom/lpass-ipq806x.c +@@ -172,7 +172,7 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = { + .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id), + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + }; + module_platform_driver(ipq806x_lpass_cpu_platform_driver); + +diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c +index d16c0d83aaad9..62e49a0d27ba2 100644 +--- a/sound/soc/qcom/lpass-sc7180.c ++++ b/sound/soc/qcom/lpass-sc7180.c +@@ -315,7 +315,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = { + .pm = &sc7180_lpass_pm_ops, + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, + }; + +diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c +index 6b2eb25ed9390..97b9053ed3b02 100644 +--- a/sound/soc/qcom/lpass-sc7280.c ++++ b/sound/soc/qcom/lpass-sc7280.c +@@ -445,7 +445,7 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = { + .pm = &sc7280_lpass_pm_ops, + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, +- .remove = asoc_qcom_lpass_cpu_platform_remove, ++ .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, + }; + +diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h +index ea12f02eca55f..f821271a11467 100644 +--- a/sound/soc/qcom/lpass.h ++++ b/sound/soc/qcom/lpass.h +@@ -400,7 +400,7 @@ struct lpass_pcm_data { + + /* register the platform driver from the CPU DAI driver */ + int asoc_qcom_lpass_platform_register(struct platform_device *); +-int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); ++void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); + void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); + int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); + extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; +-- +2.39.5 + diff --git a/queue-6.6/asoc-qcom-q6apm-dai-drop-unused-q6apm_dai_rtd-fields.patch b/queue-6.6/asoc-qcom-q6apm-dai-drop-unused-q6apm_dai_rtd-fields.patch new file mode 100644 index 0000000000..aa79719883 --- /dev/null +++ b/queue-6.6/asoc-qcom-q6apm-dai-drop-unused-q6apm_dai_rtd-fields.patch @@ -0,0 +1,59 @@ +From 223fad1b693f6885fafce892a3df5188c3999529 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Apr 2024 16:09:54 +0200 +Subject: ASoC: qcom: q6apm-dai: drop unused 'q6apm_dai_rtd' fields + +From: Krzysztof Kozlowski + +[ Upstream commit bd381c9d151467e784988bbacf22bd7ca02455d6 ] + +Remove few unused fields from 'struct q6apm_dai_rtd'. + +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20240430140954.328127-1-krzysztof.kozlowski@linaro.org +Signed-off-by: Mark Brown +Stable-dep-of: 3d4a4411aa8b ("ASoC: q6apm-dai: schedule all available frames to avoid dsp under-runs") +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/q6apm-dai.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c +index def05ce58d176..5573802e480ba 100644 +--- a/sound/soc/qcom/qdsp6/q6apm-dai.c ++++ b/sound/soc/qcom/qdsp6/q6apm-dai.c +@@ -70,14 +70,10 @@ struct q6apm_dai_rtd { + unsigned int bytes_received; + unsigned int copied_total; + uint16_t bits_per_sample; +- uint16_t source; /* Encoding source bit mask */ +- uint16_t session_id; + bool next_track; + enum stream_state state; + struct q6apm_graph *graph; + spinlock_t lock; +- uint32_t initial_samples_drop; +- uint32_t trailing_samples_drop; + bool notify_on_drain; + }; + +@@ -721,14 +717,12 @@ static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component, + + switch (metadata->key) { + case SNDRV_COMPRESS_ENCODER_PADDING: +- prtd->trailing_samples_drop = metadata->value[0]; + q6apm_remove_trailing_silence(component->dev, prtd->graph, +- prtd->trailing_samples_drop); ++ metadata->value[0]); + break; + case SNDRV_COMPRESS_ENCODER_DELAY: +- prtd->initial_samples_drop = metadata->value[0]; + q6apm_remove_initial_silence(component->dev, prtd->graph, +- prtd->initial_samples_drop); ++ metadata->value[0]); + break; + default: + ret = -EINVAL; +-- +2.39.5 + diff --git a/queue-6.6/auxdisplay-hd44780-convert-to-platform-remove-callba.patch b/queue-6.6/auxdisplay-hd44780-convert-to-platform-remove-callba.patch new file mode 100644 index 0000000000..aded7eceac --- /dev/null +++ b/queue-6.6/auxdisplay-hd44780-convert-to-platform-remove-callba.patch @@ -0,0 +1,68 @@ +From 0c87d45b50512aa513998bffbe79fd79f46f299b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Mar 2024 22:59:23 +0100 +Subject: auxdisplay: hd44780: Convert to platform remove callback returning + void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 9ea02f7cc39d484d16e8a14f3713fefcd33407c0 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. + +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new(), which already returns void. Eventually after all drivers +are converted, .remove_new() will be renamed to .remove(). + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Stable-dep-of: 9b98a7d2e5f4 ("auxdisplay: hd44780: Fix an API misuse in hd44780.c") +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/hd44780.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c +index d56a5d508ccd7..7ac0b1b1d5482 100644 +--- a/drivers/auxdisplay/hd44780.c ++++ b/drivers/auxdisplay/hd44780.c +@@ -319,7 +319,7 @@ static int hd44780_probe(struct platform_device *pdev) + return ret; + } + +-static int hd44780_remove(struct platform_device *pdev) ++static void hd44780_remove(struct platform_device *pdev) + { + struct charlcd *lcd = platform_get_drvdata(pdev); + struct hd44780_common *hdc = lcd->drvdata; +@@ -329,7 +329,6 @@ static int hd44780_remove(struct platform_device *pdev) + kfree(lcd->drvdata); + + kfree(lcd); +- return 0; + } + + static const struct of_device_id hd44780_of_match[] = { +@@ -340,7 +339,7 @@ MODULE_DEVICE_TABLE(of, hd44780_of_match); + + static struct platform_driver hd44780_driver = { + .probe = hd44780_probe, +- .remove = hd44780_remove, ++ .remove_new = hd44780_remove, + .driver = { + .name = "hd44780", + .of_match_table = hd44780_of_match, +-- +2.39.5 + diff --git a/queue-6.6/auxdisplay-hd44780-fix-an-api-misuse-in-hd44780.c.patch b/queue-6.6/auxdisplay-hd44780-fix-an-api-misuse-in-hd44780.c.patch new file mode 100644 index 0000000000..8ff13f1f32 --- /dev/null +++ b/queue-6.6/auxdisplay-hd44780-fix-an-api-misuse-in-hd44780.c.patch @@ -0,0 +1,48 @@ +From 5d94c54b7fa06a21c2931fb347571cca3ba3f7fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Feb 2025 18:15:27 +0800 +Subject: auxdisplay: hd44780: Fix an API misuse in hd44780.c + +From: Haoxiang Li + +[ Upstream commit 9b98a7d2e5f4e2beeff88f6571da0cdc5883c7fb ] + +Variable allocated by charlcd_alloc() should be released +by charlcd_free(). The following patch changed kfree() to +charlcd_free() to fix an API misuse. + +Fixes: 718e05ed92ec ("auxdisplay: Introduce hd44780_common.[ch]") +Cc: stable@vger.kernel.org +Signed-off-by: Haoxiang Li +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + drivers/auxdisplay/hd44780.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c +index 7ac0b1b1d5482..8b690f59df27d 100644 +--- a/drivers/auxdisplay/hd44780.c ++++ b/drivers/auxdisplay/hd44780.c +@@ -313,7 +313,7 @@ static int hd44780_probe(struct platform_device *pdev) + fail3: + kfree(hd); + fail2: +- kfree(lcd); ++ charlcd_free(lcd); + fail1: + kfree(hdc); + return ret; +@@ -328,7 +328,7 @@ static void hd44780_remove(struct platform_device *pdev) + kfree(hdc->hd44780); + kfree(lcd->drvdata); + +- kfree(lcd); ++ charlcd_free(lcd); + } + + static const struct of_device_id hd44780_of_match[] = { +-- +2.39.5 + diff --git a/queue-6.6/clk-renesas-r9a07g04-34-fix-typo-for-sel_shdi-variab.patch b/queue-6.6/clk-renesas-r9a07g04-34-fix-typo-for-sel_shdi-variab.patch new file mode 100644 index 0000000000..7047db7c6b --- /dev/null +++ b/queue-6.6/clk-renesas-r9a07g04-34-fix-typo-for-sel_shdi-variab.patch @@ -0,0 +1,75 @@ +From 9d40353865c599c49c9074e6b12d77bab44d12f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Jan 2024 12:29:30 +0200 +Subject: clk: renesas: r9a07g04[34]: Fix typo for sel_shdi variable + +From: Claudiu Beznea + +[ Upstream commit 46fb5dd9ca289953fa791b2bb060dac7f8002ae0 ] + +Fix typo for sel_shdi variable. + +Signed-off-by: Claudiu Beznea +Reviewed-by: Geert Uytterhoeven +Link: https://lore.kernel.org/r/20240131102930.1841901-3-claudiu.beznea.uj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 7f22a298d926 ("clk: renesas: r9a07g043: Fix HP clock source for RZ/Five") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a07g043-cpg.c | 6 +++--- + drivers/clk/renesas/r9a07g044-cpg.c | 6 +++--- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 9ad7ceb3ab1ba..3a717dcecba56 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -87,7 +87,7 @@ static const struct clk_div_table dtable_1_32[] = { + /* Mux clock tables */ + static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; +-static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++static const char * const sel_sdhi[] = { ".clk_533", ".clk_400", ".clk_266" }; + + static const u32 mtable_sdhi[] = { 1, 2, 3 }; + +@@ -136,9 +136,9 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + DEF_MUX("HP", R9A07G043_CLK_HP, SEL_PLL6_2, sel_pll6_2), + DEF_FIXED("SPI0", R9A07G043_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, ++ DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_sdhi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), +- DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_shdi, ++ DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index bc822b9fd7ce6..48404cafea3f5 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -106,7 +106,7 @@ static const struct clk_div_table dtable_16_128[] = { + static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; + static const char * const sel_pll5_4[] = { ".pll5_foutpostdiv", ".pll5_fout1ph0" }; + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; +-static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; ++static const char * const sel_sdhi[] = { ".clk_533", ".clk_400", ".clk_266" }; + static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" }; + + static const u32 mtable_sdhi[] = { 1, 2, 3 }; +@@ -176,9 +176,9 @@ static const struct { + DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, sel_pll6_2), + DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, ++ DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_sdhi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), +- DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_shdi, ++ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), +-- +2.39.5 + diff --git a/queue-6.6/clk-renesas-r9a07g04-34-use-sel_sdhi1_sts-status-con.patch b/queue-6.6/clk-renesas-r9a07g04-34-use-sel_sdhi1_sts-status-con.patch new file mode 100644 index 0000000000..5ec556043f --- /dev/null +++ b/queue-6.6/clk-renesas-r9a07g04-34-use-sel_sdhi1_sts-status-con.patch @@ -0,0 +1,54 @@ +From 858f7fb5ed155ed2a5d614fa73526b139d68a5c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Jan 2024 12:29:29 +0200 +Subject: clk: renesas: r9a07g04[34]: Use SEL_SDHI1_STS status configuration + for SD1 mux + +From: Claudiu Beznea + +[ Upstream commit 9b2a11c83859c06233049b134bd8ee974b284559 ] + +The status configuration for SD1 mux clock is SEL_SDHI1_STS. Fix it. + +Fixes: 16b86e5c03c5 ("clk: renesas: rzg2l: Refactor SD mux driver") +Reported-by: Hien Huynh +Signed-off-by: Claudiu Beznea +Reviewed-by: Geert Uytterhoeven +Link: https://lore.kernel.org/r/20240131102930.1841901-2-claudiu.beznea.uj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 7f22a298d926 ("clk: renesas: r9a07g043: Fix HP clock source for RZ/Five") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a07g043-cpg.c | 2 +- + drivers/clk/renesas/r9a07g044-cpg.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 55c58b9a9b804..9ad7ceb3ab1ba 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -138,7 +138,7 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), + DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), +- DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, ++ DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index 1047278c9079a..bc822b9fd7ce6 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -178,7 +178,7 @@ static const struct { + DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), + DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), +- DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, ++ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), +-- +2.39.5 + diff --git a/queue-6.6/clk-renesas-r9a07g043-fix-hp-clock-source-for-rz-fiv.patch b/queue-6.6/clk-renesas-r9a07g043-fix-hp-clock-source-for-rz-fiv.patch new file mode 100644 index 0000000000..e3373941f3 --- /dev/null +++ b/queue-6.6/clk-renesas-r9a07g043-fix-hp-clock-source-for-rz-fiv.patch @@ -0,0 +1,59 @@ +From bac26a05796cebd5ca41ee5bd29bd0381a81a4f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jan 2025 17:31:59 +0000 +Subject: clk: renesas: r9a07g043: Fix HP clock source for RZ/Five + +From: Lad Prabhakar + +[ Upstream commit 7f22a298d926664b51fcfe2f8ea5feb7f8b79952 ] + +According to the Rev.1.20 hardware manual for the RZ/Five SoC, the clock +source for HP is derived from PLL6 divided by 2. Correct the +implementation by configuring HP as a fixed clock source instead of a +MUX. + +The `CPG_PL6_ETH_SSEL' register, which is available on the RZ/G2UL SoC, +is not present on the RZ/Five SoC, necessitating this change. + +Fixes: 95d48d270305ad2c ("clk: renesas: r9a07g043: Add support for RZ/Five SoC") +Cc: stable@vger.kernel.org +Reported-by: Hien Huynh +Signed-off-by: Lad Prabhakar +Reviewed-by: Geert Uytterhoeven +Link: https://lore.kernel.org/20250127173159.34572-1-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a07g043-cpg.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 3a717dcecba56..865d47800791b 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -86,7 +86,9 @@ static const struct clk_div_table dtable_1_32[] = { + + /* Mux clock tables */ + static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; ++#ifdef CONFIG_ARM64 + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; ++#endif + static const char * const sel_sdhi[] = { ".clk_533", ".clk_400", ".clk_266" }; + + static const u32 mtable_sdhi[] = { 1, 2, 3 }; +@@ -133,7 +135,12 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + DEF_DIV("P2", R9A07G043_CLK_P2, CLK_PLL3_DIV2_4_2, DIVPL3A, dtable_1_32), + DEF_FIXED("M0", R9A07G043_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), + DEF_FIXED("ZT", R9A07G043_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1), ++#ifdef CONFIG_ARM64 + DEF_MUX("HP", R9A07G043_CLK_HP, SEL_PLL6_2, sel_pll6_2), ++#endif ++#ifdef CONFIG_RISCV ++ DEF_FIXED("HP", R9A07G043_CLK_HP, CLK_PLL6_250, 1, 1), ++#endif + DEF_FIXED("SPI0", R9A07G043_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), + DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_sdhi, +-- +2.39.5 + diff --git a/queue-6.6/clk-renesas-rzg2l-add-struct-clk_hw_data.patch b/queue-6.6/clk-renesas-rzg2l-add-struct-clk_hw_data.patch new file mode 100644 index 0000000000..908089585c --- /dev/null +++ b/queue-6.6/clk-renesas-rzg2l-add-struct-clk_hw_data.patch @@ -0,0 +1,137 @@ +From 25f99f7d19c9237677792a2cc640d9e7fe5ba0c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Sep 2023 08:38:55 +0300 +Subject: clk: renesas: rzg2l: Add struct clk_hw_data + +From: Claudiu Beznea + +[ Upstream commit 97c1c4ccda76d2919775d748cf223637cf0e82ae ] + +Add clk_hw_data struct that keeps the core part of the clock data. +sd_hw_data embeds a member of type struct clk_hw_data along with other +members (in the next commits). This commit prepares the field for +refactoring the SD MUX clock driver. + +Signed-off-by: Claudiu Beznea +Reviewed-by: Geert Uytterhoeven +Link: https://lore.kernel.org/r/20230929053915.1530607-9-claudiu.beznea@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 7f22a298d926 ("clk: renesas: r9a07g043: Fix HP clock source for RZ/Five") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/rzg2l-cpg.c | 52 +++++++++++++++++++++------------ + 1 file changed, 34 insertions(+), 18 deletions(-) + +diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c +index f8dbb092b9f1b..280d61f1e174c 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.c ++++ b/drivers/clk/renesas/rzg2l-cpg.c +@@ -58,13 +58,29 @@ + + #define MAX_VCLK_FREQ (148500000) + +-struct sd_hw_data { ++/** ++ * struct clk_hw_data - clock hardware data ++ * @hw: clock hw ++ * @conf: clock configuration (register offset, shift, width) ++ * @priv: CPG private data structure ++ */ ++struct clk_hw_data { + struct clk_hw hw; + u32 conf; + struct rzg2l_cpg_priv *priv; + }; + +-#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw) ++#define to_clk_hw_data(_hw) container_of(_hw, struct clk_hw_data, hw) ++ ++/** ++ * struct sd_hw_data - SD clock hardware data ++ * @hw_data: clock hw data ++ */ ++struct sd_hw_data { ++ struct clk_hw_data hw_data; ++}; ++ ++#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw_data) + + struct rzg2l_pll5_param { + u32 pl5_fracin; +@@ -183,10 +199,10 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, + + static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + { +- struct sd_hw_data *hwdata = to_sd_hw_data(hw); +- struct rzg2l_cpg_priv *priv = hwdata->priv; +- u32 off = GET_REG_OFFSET(hwdata->conf); +- u32 shift = GET_SHIFT(hwdata->conf); ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 off = GET_REG_OFFSET(clk_hw_data->conf); ++ u32 shift = GET_SHIFT(clk_hw_data->conf); + const u32 clk_src_266 = 2; + u32 msk, val, bitmask; + unsigned long flags; +@@ -203,7 +219,7 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and + * the index to value mapping is done by adding 1 to the index. + */ +- bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; ++ bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16; + msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; + spin_lock_irqsave(&priv->rmw_lock, flags); + if (index != clk_src_266) { +@@ -232,12 +248,12 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + + static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) + { +- struct sd_hw_data *hwdata = to_sd_hw_data(hw); +- struct rzg2l_cpg_priv *priv = hwdata->priv; +- u32 val = readl(priv->base + GET_REG_OFFSET(hwdata->conf)); ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); + +- val >>= GET_SHIFT(hwdata->conf); +- val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0); ++ val >>= GET_SHIFT(clk_hw_data->conf); ++ val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); + + return val ? val - 1 : 0; + } +@@ -253,17 +269,17 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, + void __iomem *base, + struct rzg2l_cpg_priv *priv) + { +- struct sd_hw_data *clk_hw_data; ++ struct sd_hw_data *sd_hw_data; + struct clk_init_data init; + struct clk_hw *clk_hw; + int ret; + +- clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); +- if (!clk_hw_data) ++ sd_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_hw_data), GFP_KERNEL); ++ if (!sd_hw_data) + return ERR_PTR(-ENOMEM); + +- clk_hw_data->priv = priv; +- clk_hw_data->conf = core->conf; ++ sd_hw_data->hw_data.priv = priv; ++ sd_hw_data->hw_data.conf = core->conf; + + init.name = GET_SHIFT(core->conf) ? "sd1" : "sd0"; + init.ops = &rzg2l_cpg_sd_clk_mux_ops; +@@ -271,7 +287,7 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, + init.num_parents = core->num_parents; + init.parent_names = core->parent_names; + +- clk_hw = &clk_hw_data->hw; ++ clk_hw = &sd_hw_data->hw_data.hw; + clk_hw->init = &init; + + ret = devm_clk_hw_register(priv->dev, clk_hw); +-- +2.39.5 + diff --git a/queue-6.6/clk-renesas-rzg2l-refactor-sd-mux-driver.patch b/queue-6.6/clk-renesas-rzg2l-refactor-sd-mux-driver.patch new file mode 100644 index 0000000000..c5d7af30a1 --- /dev/null +++ b/queue-6.6/clk-renesas-rzg2l-refactor-sd-mux-driver.patch @@ -0,0 +1,423 @@ +From 5d8c3205387fa88daad4d14dd108caaa828a094e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Oct 2023 13:39:57 +0300 +Subject: clk: renesas: rzg2l: Refactor SD mux driver + +From: Claudiu Beznea + +[ Upstream commit 16b86e5c03c5b3ef35bf5126b35384faa97428f0 ] + +Refactor SD MUX driver to be able to reuse the same code on RZ/G3S. +RZ/G2{L,UL} has a limitation with regards to switching the clock source +for SD MUX (MUX clock source has to be switched to 266MHz before +switching b/w 533MHz and 400MHz). Rework the handling of this limitation +to use a clock notifier that is registered according to platform based +initialization data, so the SD MUX code can be reused on RZ/G3S. + +As RZ/G2{L,UL} and RZ/G3S use different bits in different registers to +check if the clock switching has been done, this configuration (register +offset, register bits and bitfield width) is now passed through struct +cpg_core_clk::sconf (status configuration) from platform specific +initialization code. + +Along with struct cpg_core_clk::sconf the mux table indices are also +passed from platform specific initialization code. + +Also, mux flags are now passed to DEF_SD_MUX() as they will be used +later by RZ/G3S. + +CPG_WEN_BIT macro has been introduced to select properly the WEN bit +of various registers. + +Signed-off-by: Claudiu Beznea +Reviewed-by: Geert Uytterhoeven +Link: https://lore.kernel.org/r/20231006103959.197485-3-claudiu.beznea.uj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 7f22a298d926 ("clk: renesas: r9a07g043: Fix HP clock source for RZ/Five") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a07g043-cpg.c | 12 ++- + drivers/clk/renesas/r9a07g044-cpg.c | 12 ++- + drivers/clk/renesas/rzg2l-cpg.c | 150 ++++++++++++++++++++-------- + drivers/clk/renesas/rzg2l-cpg.h | 16 ++- + 4 files changed, 139 insertions(+), 51 deletions(-) + +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 8181ddf652fdc..55c58b9a9b804 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -21,6 +21,10 @@ + #define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) + #define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) + ++/* Clock status configuration. */ ++#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) ++#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G043_CLK_P0_DIV2, +@@ -85,6 +89,8 @@ static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; + static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; + static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; + ++static const u32 mtable_sdhi[] = { 1, 2, 3 }; ++ + static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), +@@ -130,8 +136,10 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + DEF_MUX("HP", R9A07G043_CLK_HP, SEL_PLL6_2, sel_pll6_2), + DEF_FIXED("SPI0", R9A07G043_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, sel_shdi), +- DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, sel_shdi), ++ DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), ++ DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), + }; +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index d4dcf5d896d40..1047278c9079a 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -22,6 +22,10 @@ + #define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) + #define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) + ++/* Clock status configuration. */ ++#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) ++#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A, +@@ -105,6 +109,8 @@ static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; + static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; + static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" }; + ++static const u32 mtable_sdhi[] = { 1, 2, 3 }; ++ + static const struct { + struct cpg_core_clk common[56]; + #ifdef CONFIG_CLK_R9A07G054 +@@ -170,8 +176,10 @@ static const struct { + DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, sel_pll6_2), + DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), +- DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, sel_shdi), +- DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, sel_shdi), ++ DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), ++ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, ++ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), + DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8), +diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c +index 280d61f1e174c..77eefb6ee4538 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.c ++++ b/drivers/clk/renesas/rzg2l-cpg.c +@@ -56,31 +56,37 @@ + #define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff) + #define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff) + ++#define CPG_WEN_BIT BIT(16) ++ + #define MAX_VCLK_FREQ (148500000) + + /** + * struct clk_hw_data - clock hardware data + * @hw: clock hw + * @conf: clock configuration (register offset, shift, width) ++ * @sconf: clock status configuration (register offset, shift, width) + * @priv: CPG private data structure + */ + struct clk_hw_data { + struct clk_hw hw; + u32 conf; ++ u32 sconf; + struct rzg2l_cpg_priv *priv; + }; + + #define to_clk_hw_data(_hw) container_of(_hw, struct clk_hw_data, hw) + + /** +- * struct sd_hw_data - SD clock hardware data ++ * struct sd_mux_hw_data - SD MUX clock hardware data + * @hw_data: clock hw data ++ * @mtable: clock mux table + */ +-struct sd_hw_data { ++struct sd_mux_hw_data { + struct clk_hw_data hw_data; ++ const u32 *mtable; + }; + +-#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw_data) ++#define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data) + + struct rzg2l_pll5_param { + u32 pl5_fracin; +@@ -137,6 +143,76 @@ static void rzg2l_cpg_del_clk_provider(void *data) + of_clk_del_provider(data); + } + ++/* Must be called in atomic context. */ ++static int rzg2l_cpg_wait_clk_update_done(void __iomem *base, u32 conf) ++{ ++ u32 bitmask = GENMASK(GET_WIDTH(conf) - 1, 0) << GET_SHIFT(conf); ++ u32 off = GET_REG_OFFSET(conf); ++ u32 val; ++ ++ return readl_poll_timeout_atomic(base + off, val, !(val & bitmask), 10, 200); ++} ++ ++int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, ++ void *data) ++{ ++ struct clk_notifier_data *cnd = data; ++ struct clk_hw *hw = __clk_get_hw(cnd->clk); ++ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct rzg2l_cpg_priv *priv = clk_hw_data->priv; ++ u32 off = GET_REG_OFFSET(clk_hw_data->conf); ++ u32 shift = GET_SHIFT(clk_hw_data->conf); ++ const u32 clk_src_266 = 3; ++ unsigned long flags; ++ int ret; ++ ++ if (event != PRE_RATE_CHANGE || (cnd->new_rate / MEGA == 266)) ++ return NOTIFY_DONE; ++ ++ spin_lock_irqsave(&priv->rmw_lock, flags); ++ ++ /* ++ * As per the HW manual, we should not directly switch from 533 MHz to ++ * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) ++ * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, ++ * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 ++ * (400 MHz)). ++ * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock ++ * switching register is prohibited. ++ * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and ++ * the index to value mapping is done by adding 1 to the index. ++ */ ++ ++ writel((CPG_WEN_BIT | clk_src_266) << shift, priv->base + off); ++ ++ /* Wait for the update done. */ ++ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); ++ ++ spin_unlock_irqrestore(&priv->rmw_lock, flags); ++ ++ if (ret) ++ dev_err(priv->dev, "failed to switch to safe clk source\n"); ++ ++ return notifier_from_errno(ret); ++} ++ ++static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core, ++ struct rzg2l_cpg_priv *priv) ++{ ++ struct notifier_block *nb; ++ ++ if (!core->notifier) ++ return 0; ++ ++ nb = devm_kzalloc(priv->dev, sizeof(*nb), GFP_KERNEL); ++ if (!nb) ++ return -ENOMEM; ++ ++ nb->notifier_call = core->notifier; ++ ++ return clk_notifier_register(hw->clk, nb); ++} ++ + static struct clk * __init + rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, + struct clk **clks, +@@ -200,48 +276,27 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, + static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + { + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; + u32 off = GET_REG_OFFSET(clk_hw_data->conf); + u32 shift = GET_SHIFT(clk_hw_data->conf); +- const u32 clk_src_266 = 2; +- u32 msk, val, bitmask; + unsigned long flags; ++ u32 val; + int ret; + +- /* +- * As per the HW manual, we should not directly switch from 533 MHz to +- * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) +- * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, +- * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 +- * (400 MHz)). +- * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock +- * switching register is prohibited. +- * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and +- * the index to value mapping is done by adding 1 to the index. +- */ +- bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16; +- msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; ++ val = clk_mux_index_to_val(sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, index); ++ + spin_lock_irqsave(&priv->rmw_lock, flags); +- if (index != clk_src_266) { +- writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); +- +- ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, +- !(val & msk), 10, +- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +- if (ret) +- goto unlock; +- } + +- writel(bitmask | ((index + 1) << shift), priv->base + off); ++ writel((CPG_WEN_BIT | val) << shift, priv->base + off); ++ ++ /* Wait for the update done. */ ++ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); + +- ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, +- !(val & msk), 10, +- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +-unlock: + spin_unlock_irqrestore(&priv->rmw_lock, flags); + + if (ret) +- dev_err(priv->dev, "failed to switch clk source\n"); ++ dev_err(priv->dev, "Failed to switch parent\n"); + + return ret; + } +@@ -249,13 +304,15 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) + { + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); ++ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; +- u32 val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); ++ u32 val; + ++ val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); + val >>= GET_SHIFT(clk_hw_data->conf); + val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); + +- return val ? val - 1 : 0; ++ return clk_mux_val_to_index(hw, sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, val); + } + + static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { +@@ -269,31 +326,40 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, + void __iomem *base, + struct rzg2l_cpg_priv *priv) + { +- struct sd_hw_data *sd_hw_data; ++ struct sd_mux_hw_data *sd_mux_hw_data; + struct clk_init_data init; + struct clk_hw *clk_hw; + int ret; + +- sd_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_hw_data), GFP_KERNEL); +- if (!sd_hw_data) ++ sd_mux_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_mux_hw_data), GFP_KERNEL); ++ if (!sd_mux_hw_data) + return ERR_PTR(-ENOMEM); + +- sd_hw_data->hw_data.priv = priv; +- sd_hw_data->hw_data.conf = core->conf; ++ sd_mux_hw_data->hw_data.priv = priv; ++ sd_mux_hw_data->hw_data.conf = core->conf; ++ sd_mux_hw_data->hw_data.sconf = core->sconf; ++ sd_mux_hw_data->mtable = core->mtable; + + init.name = GET_SHIFT(core->conf) ? "sd1" : "sd0"; + init.ops = &rzg2l_cpg_sd_clk_mux_ops; +- init.flags = 0; ++ init.flags = core->flag; + init.num_parents = core->num_parents; + init.parent_names = core->parent_names; + +- clk_hw = &sd_hw_data->hw_data.hw; ++ clk_hw = &sd_mux_hw_data->hw_data.hw; + clk_hw->init = &init; + + ret = devm_clk_hw_register(priv->dev, clk_hw); + if (ret) + return ERR_PTR(ret); + ++ ret = rzg2l_register_notifier(clk_hw, core, priv); ++ if (ret) { ++ dev_err(priv->dev, "Failed to register notifier for %s\n", ++ core->name); ++ return ERR_PTR(ret); ++ } ++ + return clk_hw->clk; + } + +diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h +index 705898bef438c..e662459cc6d96 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.h ++++ b/drivers/clk/renesas/rzg2l-cpg.h +@@ -9,6 +9,8 @@ + #ifndef __RENESAS_RZG2L_CPG_H__ + #define __RENESAS_RZG2L_CPG_H__ + ++#include ++ + #define CPG_SIPLL5_STBY (0x140) + #define CPG_SIPLL5_CLK1 (0x144) + #define CPG_SIPLL5_CLK3 (0x14C) +@@ -42,8 +44,6 @@ + #define CPG_CLKSTATUS_SELSDHI0_STS BIT(28) + #define CPG_CLKSTATUS_SELSDHI1_STS BIT(29) + +-#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 200 +- + /* n = 0/1/2 for PLL1/4/6 */ + #define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n)) + #define CPG_SAMPLL_CLK2(n) (0x08 + (16 * n)) +@@ -86,8 +86,11 @@ struct cpg_core_clk { + unsigned int mult; + unsigned int type; + unsigned int conf; ++ unsigned int sconf; + const struct clk_div_table *dtable; ++ const u32 *mtable; + const char * const *parent_names; ++ notifier_fn_t notifier; + u32 flag; + u32 mux_flags; + int num_parents; +@@ -147,10 +150,11 @@ enum clk_types { + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .mux_flags = CLK_MUX_READ_ONLY) +-#define DEF_SD_MUX(_name, _id, _conf, _parent_names) \ +- DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, \ ++#define DEF_SD_MUX(_name, _id, _conf, _sconf, _parent_names, _mtable, _clk_flags, _notifier) \ ++ DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \ + .parent_names = _parent_names, \ +- .num_parents = ARRAY_SIZE(_parent_names)) ++ .num_parents = ARRAY_SIZE(_parent_names), \ ++ .mtable = _mtable, .flag = _clk_flags, .notifier = _notifier) + #define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \ + DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent) + #define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names) \ +@@ -269,4 +273,6 @@ extern const struct rzg2l_cpg_info r9a07g044_cpg_info; + extern const struct rzg2l_cpg_info r9a07g054_cpg_info; + extern const struct rzg2l_cpg_info r9a09g011_cpg_info; + ++int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, void *data); ++ + #endif +-- +2.39.5 + diff --git a/queue-6.6/clk-renesas-rzg2l-remove-cpg_sdhi_dsel-from-generic-.patch b/queue-6.6/clk-renesas-rzg2l-remove-cpg_sdhi_dsel-from-generic-.patch new file mode 100644 index 0000000000..fa6d891e5b --- /dev/null +++ b/queue-6.6/clk-renesas-rzg2l-remove-cpg_sdhi_dsel-from-generic-.patch @@ -0,0 +1,85 @@ +From 284cf9002b5ba9ae790bcce856d597906dfc1211 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Sep 2023 08:38:56 +0300 +Subject: clk: renesas: rzg2l: Remove CPG_SDHI_DSEL from generic header + +From: Claudiu Beznea + +[ Upstream commit 3e8008fcf6b7f7c65ad2718c18fb79f37007f1a5 ] + +Remove CPG_SDHI_DSEL and its bits from the generic header as RZ/G3S has +different offset registers and bits for this, thus avoid mixing them. + +Signed-off-by: Claudiu Beznea +Reviewed-by: Geert Uytterhoeven +Link: https://lore.kernel.org/r/20230929053915.1530607-10-claudiu.beznea@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 7f22a298d926 ("clk: renesas: r9a07g043: Fix HP clock source for RZ/Five") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a07g043-cpg.c | 7 +++++++ + drivers/clk/renesas/r9a07g044-cpg.c | 7 +++++++ + drivers/clk/renesas/rzg2l-cpg.h | 4 ---- + 3 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 6c6bc79b2e9ce..8181ddf652fdc 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -14,6 +14,13 @@ + + #include "rzg2l-cpg.h" + ++/* Specific registers. */ ++#define CPG_PL2SDHI_DSEL (0x218) ++ ++/* Clock select configuration. */ ++#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) ++#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G043_CLK_P0_DIV2, +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index c597414a94d8a..d4dcf5d896d40 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -15,6 +15,13 @@ + + #include "rzg2l-cpg.h" + ++/* Specific registers. */ ++#define CPG_PL2SDHI_DSEL (0x218) ++ ++/* Clock select configuration. */ ++#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) ++#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) ++ + enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A, +diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h +index 097fd8f616806..705898bef438c 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.h ++++ b/drivers/clk/renesas/rzg2l-cpg.h +@@ -19,7 +19,6 @@ + #define CPG_PL2_DDIV (0x204) + #define CPG_PL3A_DDIV (0x208) + #define CPG_PL6_DDIV (0x210) +-#define CPG_PL2SDHI_DSEL (0x218) + #define CPG_CLKSTATUS (0x280) + #define CPG_PL3_SSEL (0x408) + #define CPG_PL6_SSEL (0x414) +@@ -69,9 +68,6 @@ + #define SEL_PLL6_2 SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1) + #define SEL_GPU2 SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1) + +-#define SEL_SDHI0 DDIV_PACK(CPG_PL2SDHI_DSEL, 0, 2) +-#define SEL_SDHI1 DDIV_PACK(CPG_PL2SDHI_DSEL, 4, 2) +- + #define EXTAL_FREQ_IN_MEGA_HZ (24) + + /** +-- +2.39.5 + diff --git a/queue-6.6/clk-renesas-rzg2l-use-u32-for-flag-and-mux_flags.patch b/queue-6.6/clk-renesas-rzg2l-use-u32-for-flag-and-mux_flags.patch new file mode 100644 index 0000000000..68c62fd961 --- /dev/null +++ b/queue-6.6/clk-renesas-rzg2l-use-u32-for-flag-and-mux_flags.patch @@ -0,0 +1,39 @@ +From 0983110b896d891c66360dedb6730af4ac7bae61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Sep 2023 07:51:34 +0300 +Subject: clk: renesas: rzg2l: Use u32 for flag and mux_flags + +From: Claudiu Beznea + +[ Upstream commit 897a3e34d6e73d2386715d5c44c57992f2c0eada ] + +flag and mux_flags are intended to keep bit masks. Use u32 type for it. + +Signed-off-by: Claudiu Beznea +Reviewed-by: Geert Uytterhoeven +Link: https://lore.kernel.org/r/20230912045157.177966-15-claudiu.beznea.uj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 7f22a298d926 ("clk: renesas: r9a07g043: Fix HP clock source for RZ/Five") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/rzg2l-cpg.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h +index 91e9c2569f801..097fd8f616806 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.h ++++ b/drivers/clk/renesas/rzg2l-cpg.h +@@ -92,8 +92,8 @@ struct cpg_core_clk { + unsigned int conf; + const struct clk_div_table *dtable; + const char * const *parent_names; +- int flag; +- int mux_flags; ++ u32 flag; ++ u32 mux_flags; + int num_parents; + }; + +-- +2.39.5 + diff --git a/queue-6.6/cpufreq-sched-explicitly-synchronize-limits_changed-.patch b/queue-6.6/cpufreq-sched-explicitly-synchronize-limits_changed-.patch new file mode 100644 index 0000000000..a915236ded --- /dev/null +++ b/queue-6.6/cpufreq-sched-explicitly-synchronize-limits_changed-.patch @@ -0,0 +1,98 @@ +From 729d8d5b761338514acf024014418fbfc19fca5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Apr 2025 11:59:15 +0200 +Subject: cpufreq/sched: Explicitly synchronize limits_changed flag handling + +From: Rafael J. Wysocki + +[ Upstream commit 79443a7e9da3c9f68290a8653837e23aba0fa89f ] + +The handling of the limits_changed flag in struct sugov_policy needs to +be explicitly synchronized to ensure that cpufreq policy limits updates +will not be missed in some cases. + +Without that synchronization it is theoretically possible that +the limits_changed update in sugov_should_update_freq() will be +reordered with respect to the reads of the policy limits in +cpufreq_driver_resolve_freq() and in that case, if the limits_changed +update in sugov_limits() clobbers the one in sugov_should_update_freq(), +the new policy limits may not take effect for a long time. + +Likewise, the limits_changed update in sugov_limits() may theoretically +get reordered with respect to the updates of the policy limits in +cpufreq_set_policy() and if sugov_should_update_freq() runs between +them, the policy limits change may be missed. + +To ensure that the above situations will not take place, add memory +barriers preventing the reordering in question from taking place and +add READ_ONCE() and WRITE_ONCE() annotations around all of the +limits_changed flag updates to prevent the compiler from messing up +with that code. + +Fixes: 600f5badb78c ("cpufreq: schedutil: Don't skip freq update when limits change") +Cc: 5.3+ # 5.3+ +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Christian Loehle +Link: https://patch.msgid.link/3376719.44csPzL39Z@rjwysocki.net +Signed-off-by: Sasha Levin +--- + kernel/sched/cpufreq_schedutil.c | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index f84473f73ed00..776be0549162c 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -81,9 +81,20 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) + if (!cpufreq_this_cpu_can_update(sg_policy->policy)) + return false; + +- if (unlikely(sg_policy->limits_changed)) { +- sg_policy->limits_changed = false; ++ if (unlikely(READ_ONCE(sg_policy->limits_changed))) { ++ WRITE_ONCE(sg_policy->limits_changed, false); + sg_policy->need_freq_update = true; ++ ++ /* ++ * The above limits_changed update must occur before the reads ++ * of policy limits in cpufreq_driver_resolve_freq() or a policy ++ * limits update might be missed, so use a memory barrier to ++ * ensure it. ++ * ++ * This pairs with the write memory barrier in sugov_limits(). ++ */ ++ smp_mb(); ++ + return true; + } + +@@ -334,7 +345,7 @@ static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; } + static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu) + { + if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_min) +- sg_cpu->sg_policy->limits_changed = true; ++ WRITE_ONCE(sg_cpu->sg_policy->limits_changed, true); + } + + static inline bool sugov_update_single_common(struct sugov_cpu *sg_cpu, +@@ -844,7 +855,16 @@ static void sugov_limits(struct cpufreq_policy *policy) + mutex_unlock(&sg_policy->work_lock); + } + +- sg_policy->limits_changed = true; ++ /* ++ * The limits_changed update below must take place before the updates ++ * of policy limits in cpufreq_set_policy() or a policy limits update ++ * might be missed, so use a memory barrier to ensure it. ++ * ++ * This pairs with the memory barrier in sugov_should_update_freq(). ++ */ ++ smp_wmb(); ++ ++ WRITE_ONCE(sg_policy->limits_changed, true); + } + + struct cpufreq_governor schedutil_gov = { +-- +2.39.5 + diff --git a/queue-6.6/iio-adc-ad7768-1-fix-conversion-result-sign.patch b/queue-6.6/iio-adc-ad7768-1-fix-conversion-result-sign.patch new file mode 100644 index 0000000000..0cccfeb051 --- /dev/null +++ b/queue-6.6/iio-adc-ad7768-1-fix-conversion-result-sign.patch @@ -0,0 +1,55 @@ +From e89390d52a59a6ac1ad6595a78fca9808a72fcdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 18:00:29 -0300 +Subject: iio: adc: ad7768-1: Fix conversion result sign + +From: Sergiu Cuciurean + +[ Upstream commit 8236644f5ecb180e80ad92d691c22bc509b747bb ] + +The ad7768-1 ADC output code is two's complement, meaning that the voltage +conversion result is a signed value.. Since the value is a 24 bit one, +stored in a 32 bit variable, the sign should be extended in order to get +the correct representation. + +Also the channel description has been updated to signed representation, +to match the ADC specifications. + +Fixes: a5f8c7da3dbe ("iio: adc: Add AD7768-1 ADC basic support") +Reviewed-by: David Lechner +Reviewed-by: Marcelo Schmitt +Signed-off-by: Sergiu Cuciurean +Signed-off-by: Jonathan Santos +Cc: +Link: https://patch.msgid.link/505994d3b71c2aa38ba714d909a68e021f12124c.1741268122.git.Jonathan.Santos@analog.com +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/adc/ad7768-1.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c +index 19d604f5701d6..74b0c85944bd6 100644 +--- a/drivers/iio/adc/ad7768-1.c ++++ b/drivers/iio/adc/ad7768-1.c +@@ -142,7 +142,7 @@ static const struct iio_chan_spec ad7768_channels[] = { + .channel = 0, + .scan_index = 0, + .scan_type = { +- .sign = 'u', ++ .sign = 's', + .realbits = 24, + .storagebits = 32, + .shift = 8, +@@ -374,7 +374,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, + iio_device_release_direct_mode(indio_dev); + if (ret < 0) + return ret; +- *val = ret; ++ *val = sign_extend32(ret, chan->scan_type.realbits - 1); + + return IIO_VAL_INT; + +-- +2.39.5 + diff --git a/queue-6.6/iio-adc-ad7768-1-move-setting-of-val-a-bit-later-to-.patch b/queue-6.6/iio-adc-ad7768-1-move-setting-of-val-a-bit-later-to-.patch new file mode 100644 index 0000000000..eaf12cc1e1 --- /dev/null +++ b/queue-6.6/iio-adc-ad7768-1-move-setting-of-val-a-bit-later-to-.patch @@ -0,0 +1,47 @@ +From 026a1b9371f61a8942da5bb65d48f02d1e899ccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Feb 2025 14:16:12 +0000 +Subject: iio: adc: ad7768-1: Move setting of val a bit later to avoid + unnecessary return value check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jonathan Cameron + +[ Upstream commit 0af1c801a15225304a6328258efbf2bee245c654 ] + +The data used is all in local variables so there is no advantage +in setting *val = ret with the direct mode claim held. +Move it later to after error check. + +Reviewed-by: Nuno Sá +Link: https://patch.msgid.link/20250217141630.897334-13-jic23@kernel.org +Signed-off-by: Jonathan Cameron +Stable-dep-of: 8236644f5ecb ("iio: adc: ad7768-1: Fix conversion result sign") +Signed-off-by: Sasha Levin +--- + drivers/iio/adc/ad7768-1.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c +index 70a25949142c0..19d604f5701d6 100644 +--- a/drivers/iio/adc/ad7768-1.c ++++ b/drivers/iio/adc/ad7768-1.c +@@ -370,12 +370,11 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, + return ret; + + ret = ad7768_scan_direct(indio_dev); +- if (ret >= 0) +- *val = ret; + + iio_device_release_direct_mode(indio_dev); + if (ret < 0) + return ret; ++ *val = ret; + + return IIO_VAL_INT; + +-- +2.39.5 + diff --git a/queue-6.6/media-subdev-add-v4l2_subdev_is_streaming.patch b/queue-6.6/media-subdev-add-v4l2_subdev_is_streaming.patch new file mode 100644 index 0000000000..056a4d1c8f --- /dev/null +++ b/queue-6.6/media-subdev-add-v4l2_subdev_is_streaming.patch @@ -0,0 +1,86 @@ +From c934048cb837aedc4a57e951e0a3708d8e5de14e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Apr 2024 18:39:09 +0300 +Subject: media: subdev: Add v4l2_subdev_is_streaming() + +From: Tomi Valkeinen + +[ Upstream commit 5f3ce14fae742d1d23061c3122d93edb879ebf53 ] + +Add a helper function which returns whether the subdevice is streaming, +i.e. if .s_stream or .enable_streams has been called successfully. + +Reviewed-by: Umang Jain +Reviewed-by: Laurent Pinchart +Tested-by: Umang Jain +Signed-off-by: Tomi Valkeinen +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Stable-dep-of: 36cef585e2a3 ("media: vimc: skip .s_stream() for stopped entities") +Signed-off-by: Sasha Levin +--- + drivers/media/v4l2-core/v4l2-subdev.c | 25 +++++++++++++++++++++++++ + include/media/v4l2-subdev.h | 13 +++++++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index f555fd3c4b76d..5f115438d0722 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -2240,6 +2240,31 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + } + EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event); + ++bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd) ++{ ++ struct v4l2_subdev_state *state; ++ ++ if (!v4l2_subdev_has_op(sd, pad, enable_streams)) ++ return sd->s_stream_enabled; ++ ++ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) ++ return !!sd->enabled_pads; ++ ++ state = v4l2_subdev_get_locked_active_state(sd); ++ ++ for (unsigned int i = 0; i < state->stream_configs.num_configs; ++i) { ++ const struct v4l2_subdev_stream_config *cfg; ++ ++ cfg = &state->stream_configs.configs[i]; ++ ++ if (cfg->enabled) ++ return true; ++ } ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(v4l2_subdev_is_streaming); ++ + int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd) + { + #if IS_REACHABLE(CONFIG_LEDS_CLASS) +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index 0a8d75b009ea2..b4fcd0164048e 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -1918,4 +1918,17 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers; + void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + const struct v4l2_event *ev); + ++/** ++ * v4l2_subdev_is_streaming() - Returns if the subdevice is streaming ++ * @sd: The subdevice ++ * ++ * v4l2_subdev_is_streaming() tells if the subdevice is currently streaming. ++ * "Streaming" here means whether .s_stream() or .enable_streams() has been ++ * successfully called, and the streaming has not yet been disabled. ++ * ++ * If the subdevice implements .enable_streams() this function must be called ++ * while holding the active state lock. ++ */ ++bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd); ++ + #endif /* _V4L2_SUBDEV_H */ +-- +2.39.5 + diff --git a/queue-6.6/media-subdev-fix-use-of-sd-enabled_streams-in-call_s.patch b/queue-6.6/media-subdev-fix-use-of-sd-enabled_streams-in-call_s.patch new file mode 100644 index 0000000000..7414cb8d00 --- /dev/null +++ b/queue-6.6/media-subdev-fix-use-of-sd-enabled_streams-in-call_s.patch @@ -0,0 +1,88 @@ +From dd7c987d06ba1d289b5b2df295bd1220dcb453ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Apr 2024 18:39:07 +0300 +Subject: media: subdev: Fix use of sd->enabled_streams in call_s_stream() + +From: Tomi Valkeinen + +[ Upstream commit 1d7804281df3f09f0a109d00406e859a00bae7ae ] + +call_s_stream() uses sd->enabled_streams to track whether streaming has +already been enabled. However, +v4l2_subdev_enable/disable_streams_fallback(), which was the original +user of this field, already uses it, and +v4l2_subdev_enable/disable_streams_fallback() will call call_s_stream(). + +This leads to a conflict as both functions set the field. Afaics, both +functions set the field to the same value, so it won't cause a runtime +bug, but it's still wrong and if we, e.g., change how +v4l2_subdev_enable/disable_streams_fallback() operates we might easily +cause bugs. + +Fix this by adding a new field, 's_stream_enabled', for +call_s_stream(). + +Reviewed-by: Umang Jain +Reviewed-by: Laurent Pinchart +Tested-by: Umang Jain +Signed-off-by: Tomi Valkeinen +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Stable-dep-of: 36cef585e2a3 ("media: vimc: skip .s_stream() for stopped entities") +Signed-off-by: Sasha Levin +--- + drivers/media/v4l2-core/v4l2-subdev.c | 8 ++------ + include/media/v4l2-subdev.h | 3 +++ + 2 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index a32ef739eb449..8bfbe9d5fe3c4 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -363,12 +363,8 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) + * The .s_stream() operation must never be called to start or stop an + * already started or stopped subdev. Catch offenders but don't return + * an error yet to avoid regressions. +- * +- * As .s_stream() is mutually exclusive with the .enable_streams() and +- * .disable_streams() operation, we can use the enabled_streams field +- * to store the subdev streaming state. + */ +- if (WARN_ON(!!sd->enabled_streams == !!enable)) ++ if (WARN_ON(sd->s_stream_enabled == !!enable)) + return 0; + + ret = sd->ops->video->s_stream(sd, enable); +@@ -379,7 +375,7 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) + } + + if (!ret) { +- sd->enabled_streams = enable ? BIT(0) : 0; ++ sd->s_stream_enabled = enable; + + #if IS_REACHABLE(CONFIG_LEDS_CLASS) + if (!IS_ERR_OR_NULL(sd->privacy_led)) { +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index ab2a7ef61d420..ee570dfbd791d 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -1042,6 +1042,8 @@ struct v4l2_subdev_platform_data { + * v4l2_subdev_enable_streams() and + * v4l2_subdev_disable_streams() helper functions for fallback + * cases. ++ * @s_stream_enabled: Tracks whether streaming has been enabled with s_stream. ++ * This is only for call_s_stream() internal use. + * + * Each instance of a subdev driver should create this struct, either + * stand-alone or embedded in a larger struct. +@@ -1090,6 +1092,7 @@ struct v4l2_subdev { + */ + struct v4l2_subdev_state *active_state; + u64 enabled_streams; ++ bool s_stream_enabled; + }; + + +-- +2.39.5 + diff --git a/queue-6.6/media-subdev-improve-v4l2_subdev_enable-disable_stre.patch b/queue-6.6/media-subdev-improve-v4l2_subdev_enable-disable_stre.patch new file mode 100644 index 0000000000..d2778f6944 --- /dev/null +++ b/queue-6.6/media-subdev-improve-v4l2_subdev_enable-disable_stre.patch @@ -0,0 +1,192 @@ +From e11aaf8a58515fd209523fa67b68c01ba00ea543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Apr 2024 18:39:08 +0300 +Subject: media: subdev: Improve v4l2_subdev_enable/disable_streams_fallback + +From: Tomi Valkeinen + +[ Upstream commit 61d6c8c896c1ccde350c281817847a32b0c6b83b ] + +v4l2_subdev_enable/disable_streams_fallback() supports falling back to +.s_stream() for subdevs with a single source pad. It also tracks the +enabled streams for that one pad in the sd->enabled_streams field. + +Tracking the enabled streams with sd->enabled_streams does not make +sense, as with .s_stream() there can only be a single stream per pad. +Thus, as the v4l2_subdev_enable/disable_streams_fallback() only supports +a single source pad, all we really need is a boolean which tells whether +streaming has been enabled on this pad or not. + +However, as we only need a true/false state for a pad (instead of +tracking which streams have been enabled for a pad), we can easily +extend the fallback mechanism to support multiple source pads as we only +need to keep track of which pads have been enabled. + +Change the sd->enabled_streams field to sd->enabled_pads, which is a +64-bit bitmask tracking the enabled source pads. With this change we can +remove the restriction that +v4l2_subdev_enable/disable_streams_fallback() only supports a single +source pad. + +Reviewed-by: Laurent Pinchart +Tested-by: Umang Jain +Signed-off-by: Tomi Valkeinen +Signed-off-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Stable-dep-of: 36cef585e2a3 ("media: vimc: skip .s_stream() for stopped entities") +Signed-off-by: Sasha Levin +--- + drivers/media/v4l2-core/v4l2-subdev.c | 68 ++++++++++++++++----------- + include/media/v4l2-subdev.h | 9 ++-- + 2 files changed, 44 insertions(+), 33 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index 8bfbe9d5fe3c4..f555fd3c4b76d 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -1925,37 +1925,43 @@ static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) + { + struct device *dev = sd->entity.graph_obj.mdev->dev; +- unsigned int i; + int ret; + + /* + * The subdev doesn't implement pad-based stream enable, fall back +- * on the .s_stream() operation. This can only be done for subdevs that +- * have a single source pad, as sd->enabled_streams is global to the +- * subdev. ++ * to the .s_stream() operation. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + +- for (i = 0; i < sd->entity.num_pads; ++i) { +- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) +- return -EOPNOTSUPP; +- } ++ /* ++ * .s_stream() means there is no streams support, so the only allowed ++ * stream is the implicit stream 0. ++ */ ++ if (streams_mask != BIT_ULL(0)) ++ return -EOPNOTSUPP; ++ ++ /* ++ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices ++ * with 64 pads or less can be supported. ++ */ ++ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE) ++ return -EOPNOTSUPP; + +- if (sd->enabled_streams & streams_mask) { +- dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n", +- streams_mask, sd->entity.name, pad); ++ if (sd->enabled_pads & BIT_ULL(pad)) { ++ dev_dbg(dev, "pad %u already enabled on %s\n", ++ pad, sd->entity.name); + return -EALREADY; + } + +- /* Start streaming when the first streams are enabled. */ +- if (!sd->enabled_streams) { ++ /* Start streaming when the first pad is enabled. */ ++ if (!sd->enabled_pads) { + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret) + return ret; + } + +- sd->enabled_streams |= streams_mask; ++ sd->enabled_pads |= BIT_ULL(pad); + + return 0; + } +@@ -2042,37 +2048,43 @@ static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) + { + struct device *dev = sd->entity.graph_obj.mdev->dev; +- unsigned int i; + int ret; + + /* +- * If the subdev doesn't implement pad-based stream enable, fall back +- * on the .s_stream() operation. This can only be done for subdevs that +- * have a single source pad, as sd->enabled_streams is global to the +- * subdev. ++ * If the subdev doesn't implement pad-based stream enable, fall back ++ * to the .s_stream() operation. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + +- for (i = 0; i < sd->entity.num_pads; ++i) { +- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) +- return -EOPNOTSUPP; +- } ++ /* ++ * .s_stream() means there is no streams support, so the only allowed ++ * stream is the implicit stream 0. ++ */ ++ if (streams_mask != BIT_ULL(0)) ++ return -EOPNOTSUPP; ++ ++ /* ++ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices ++ * with 64 pads or less can be supported. ++ */ ++ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE) ++ return -EOPNOTSUPP; + +- if ((sd->enabled_streams & streams_mask) != streams_mask) { +- dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n", +- streams_mask, sd->entity.name, pad); ++ if (!(sd->enabled_pads & BIT_ULL(pad))) { ++ dev_dbg(dev, "pad %u already disabled on %s\n", ++ pad, sd->entity.name); + return -EALREADY; + } + + /* Stop streaming when the last streams are disabled. */ +- if (!(sd->enabled_streams & ~streams_mask)) { ++ if (!(sd->enabled_pads & ~BIT_ULL(pad))) { + ret = v4l2_subdev_call(sd, video, s_stream, 0); + if (ret) + return ret; + } + +- sd->enabled_streams &= ~streams_mask; ++ sd->enabled_pads &= ~BIT_ULL(pad); + + return 0; + } +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index ee570dfbd791d..0a8d75b009ea2 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -1038,10 +1038,9 @@ struct v4l2_subdev_platform_data { + * @active_state: Active state for the subdev (NULL for subdevs tracking the + * state internally). Initialized by calling + * v4l2_subdev_init_finalize(). +- * @enabled_streams: Bitmask of enabled streams used by +- * v4l2_subdev_enable_streams() and +- * v4l2_subdev_disable_streams() helper functions for fallback +- * cases. ++ * @enabled_pads: Bitmask of enabled pads used by v4l2_subdev_enable_streams() ++ * and v4l2_subdev_disable_streams() helper functions for ++ * fallback cases. + * @s_stream_enabled: Tracks whether streaming has been enabled with s_stream. + * This is only for call_s_stream() internal use. + * +@@ -1091,7 +1090,7 @@ struct v4l2_subdev { + * doesn't support it. + */ + struct v4l2_subdev_state *active_state; +- u64 enabled_streams; ++ u64 enabled_pads; + bool s_stream_enabled; + }; + +-- +2.39.5 + diff --git a/queue-6.6/media-vimc-skip-.s_stream-for-stopped-entities.patch b/queue-6.6/media-vimc-skip-.s_stream-for-stopped-entities.patch new file mode 100644 index 0000000000..1b1b3f5f4f --- /dev/null +++ b/queue-6.6/media-vimc-skip-.s_stream-for-stopped-entities.patch @@ -0,0 +1,77 @@ +From 5174a714d9c786e83d548edae7added9c030eb13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 2 Mar 2025 17:58:25 +0300 +Subject: media: vimc: skip .s_stream() for stopped entities + +From: Nikita Zhandarovich + +[ Upstream commit 36cef585e2a31e4ddf33a004b0584a7a572246de ] + +Syzbot reported [1] a warning prompted by a check in call_s_stream() +that checks whether .s_stream() operation is warranted for unstarted +or stopped subdevs. + +Add a simple fix in vimc_streamer_pipeline_terminate() ensuring that +entities skip a call to .s_stream() unless they have been previously +properly started. + +[1] Syzbot report: +------------[ cut here ]------------ +WARNING: CPU: 0 PID: 5933 at drivers/media/v4l2-core/v4l2-subdev.c:460 call_s_stream+0x2df/0x350 drivers/media/v4l2-core/v4l2-subdev.c:460 +Modules linked in: +CPU: 0 UID: 0 PID: 5933 Comm: syz-executor330 Not tainted 6.13.0-rc2-syzkaller-00362-g2d8308bf5b67 #0 +... +Call Trace: + + vimc_streamer_pipeline_terminate+0x218/0x320 drivers/media/test-drivers/vimc/vimc-streamer.c:62 + vimc_streamer_pipeline_init drivers/media/test-drivers/vimc/vimc-streamer.c:101 [inline] + vimc_streamer_s_stream+0x650/0x9a0 drivers/media/test-drivers/vimc/vimc-streamer.c:203 + vimc_capture_start_streaming+0xa1/0x130 drivers/media/test-drivers/vimc/vimc-capture.c:256 + vb2_start_streaming+0x15f/0x5a0 drivers/media/common/videobuf2/videobuf2-core.c:1789 + vb2_core_streamon+0x2a7/0x450 drivers/media/common/videobuf2/videobuf2-core.c:2348 + vb2_streamon drivers/media/common/videobuf2/videobuf2-v4l2.c:875 [inline] + vb2_ioctl_streamon+0xf4/0x170 drivers/media/common/videobuf2/videobuf2-v4l2.c:1118 + __video_do_ioctl+0xaf0/0xf00 drivers/media/v4l2-core/v4l2-ioctl.c:3122 + video_usercopy+0x4d2/0x1620 drivers/media/v4l2-core/v4l2-ioctl.c:3463 + v4l2_ioctl+0x1ba/0x250 drivers/media/v4l2-core/v4l2-dev.c:366 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:906 [inline] + __se_sys_ioctl fs/ioctl.c:892 [inline] + __x64_sys_ioctl+0x190/0x200 fs/ioctl.c:892 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0xcd/0x250 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f2b85c01b19 +... + +Reported-by: syzbot+5bcd7c809d365e14c4df@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=5bcd7c809d365e14c4df +Fixes: adc589d2a208 ("media: vimc: Add vimc-streamer for stream control") +Cc: stable@vger.kernel.org +Signed-off-by: Nikita Zhandarovich +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/test-drivers/vimc/vimc-streamer.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c +index 807551a5143b7..15d863f97cbf9 100644 +--- a/drivers/media/test-drivers/vimc/vimc-streamer.c ++++ b/drivers/media/test-drivers/vimc/vimc-streamer.c +@@ -59,6 +59,12 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) + continue; + + sd = media_entity_to_v4l2_subdev(ved->ent); ++ /* ++ * Do not call .s_stream() to stop an already ++ * stopped/unstarted subdev. ++ */ ++ if (!v4l2_subdev_is_streaming(sd)) ++ continue; + v4l2_subdev_call(sd, video, s_stream, 0); + } + } +-- +2.39.5 + diff --git a/queue-6.6/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch b/queue-6.6/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch new file mode 100644 index 0000000000..632540026a --- /dev/null +++ b/queue-6.6/memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch @@ -0,0 +1,55 @@ +From 39e286a6981e02a7d95283925a8da6b714a2e347 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Mar 2025 16:09:34 -0700 +Subject: memcg: drain obj stock on cpu hotplug teardown + +From: Shakeel Butt + +[ Upstream commit 9f01b4954490d4ccdbcc2b9be34a9921ceee9cbb ] + +Currently on cpu hotplug teardown, only memcg stock is drained but we +need to drain the obj stock as well otherwise we will miss the stats +accumulated on the target cpu as well as the nr_bytes cached. The stats +include MEMCG_KMEM, NR_SLAB_RECLAIMABLE_B & NR_SLAB_UNRECLAIMABLE_B. In +addition we are leaking reference to struct obj_cgroup object. + +Link: https://lkml.kernel.org/r/20250310230934.2913113-1-shakeel.butt@linux.dev +Fixes: bf4f059954dc ("mm: memcg/slab: obj_cgroup API") +Signed-off-by: Shakeel Butt +Reviewed-by: Roman Gushchin +Acked-by: Johannes Weiner +Cc: Michal Hocko +Cc: Muchun Song +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + mm/memcontrol.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index 9bf5a69e20d87..ab9afcd372a93 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -2378,9 +2378,18 @@ static void drain_all_stock(struct mem_cgroup *root_memcg) + static int memcg_hotplug_cpu_dead(unsigned int cpu) + { + struct memcg_stock_pcp *stock; ++ struct obj_cgroup *old; ++ unsigned long flags; + + stock = &per_cpu(memcg_stock, cpu); ++ ++ /* drain_obj_stock requires stock_lock */ ++ local_lock_irqsave(&memcg_stock.stock_lock, flags); ++ old = drain_obj_stock(stock); ++ local_unlock_irqrestore(&memcg_stock.stock_lock, flags); ++ + drain_stock(stock); ++ obj_cgroup_put(old); + + return 0; + } +-- +2.39.5 + diff --git a/queue-6.6/mmc-sdhci-msm-fix-dev-reference-leaked-through-of_qc.patch b/queue-6.6/mmc-sdhci-msm-fix-dev-reference-leaked-through-of_qc.patch new file mode 100644 index 0000000000..059518467f --- /dev/null +++ b/queue-6.6/mmc-sdhci-msm-fix-dev-reference-leaked-through-of_qc.patch @@ -0,0 +1,42 @@ +From b8c670593fd24deaae7765b8c422d2a89e1a9559 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jan 2025 14:18:51 +0000 +Subject: mmc: sdhci-msm: fix dev reference leaked through of_qcom_ice_get + +From: Tudor Ambarus + +[ Upstream commit cbef7442fba510b7eb229dcc9f39d3dde4a159a4 ] + +The driver leaks the device reference taken with +of_find_device_by_node(). Fix the leak by using devm_of_qcom_ice_get(). + +Fixes: c7eed31e235c ("mmc: sdhci-msm: Switch to the new ICE API") +Cc: stable@vger.kernel.org +Signed-off-by: Tudor Ambarus +Reviewed-by: Krzysztof Kozlowski +Acked-by: Ulf Hansson +Reviewed-by: Abel Vesa +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20250117-qcom-ice-fix-dev-leak-v2-2-1ffa5b6884cb@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/sdhci-msm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c +index 945d08531de37..82808cc373f68 100644 +--- a/drivers/mmc/host/sdhci-msm.c ++++ b/drivers/mmc/host/sdhci-msm.c +@@ -1866,7 +1866,7 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, + if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS)) + return 0; + +- ice = of_qcom_ice_get(dev); ++ ice = devm_of_qcom_ice_get(dev); + if (ice == ERR_PTR(-EOPNOTSUPP)) { + dev_warn(dev, "Disabling inline encryption support\n"); + ice = NULL; +-- +2.39.5 + diff --git a/queue-6.6/net-dsa-mv88e6xxx-fix-internal-phys-for-6320-family.patch b/queue-6.6/net-dsa-mv88e6xxx-fix-internal-phys-for-6320-family.patch new file mode 100644 index 0000000000..4a2de90c99 --- /dev/null +++ b/queue-6.6/net-dsa-mv88e6xxx-fix-internal-phys-for-6320-family.patch @@ -0,0 +1,53 @@ +From fd9dff4ec1261b7ea9ac8f5cd89dc77757bec832 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Mar 2025 18:32:49 +0100 +Subject: net: dsa: mv88e6xxx: fix internal PHYs for 6320 family +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +[ Upstream commit 52fdc41c3278c981066a461d03d5477ebfcf270c ] + +Fix internal PHYs definition for the 6320 family, which has only 2 +internal PHYs (on ports 3 and 4). + +Fixes: bc3931557d1d ("net: dsa: mv88e6xxx: Add number of internal PHYs") +Signed-off-by: Marek Behún +Cc: # 6.6.x +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250317173250.28780-7-kabel@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/mv88e6xxx/chip.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index da7260e505a2e..d66448f0833cc 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -6114,7 +6114,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .num_databases = 4096, + .num_macs = 8192, + .num_ports = 7, +- .num_internal_phys = 5, ++ .num_internal_phys = 2, ++ .internal_phys_offset = 3, + .num_gpio = 15, + .max_vid = 4095, + .port_base_addr = 0x10, +@@ -6139,7 +6140,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { + .num_databases = 4096, + .num_macs = 8192, + .num_ports = 7, +- .num_internal_phys = 5, ++ .num_internal_phys = 2, ++ .internal_phys_offset = 3, + .num_gpio = 15, + .max_vid = 4095, + .port_base_addr = 0x10, +-- +2.39.5 + diff --git a/queue-6.6/net-dsa-mv88e6xxx-fix-vtu-methods-for-6320-family.patch b/queue-6.6/net-dsa-mv88e6xxx-fix-vtu-methods-for-6320-family.patch new file mode 100644 index 0000000000..146db19517 --- /dev/null +++ b/queue-6.6/net-dsa-mv88e6xxx-fix-vtu-methods-for-6320-family.patch @@ -0,0 +1,55 @@ +From a2b3dae082dfc1c3e9ef5bf75656a748a81a7b64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Mar 2025 18:32:44 +0100 +Subject: net: dsa: mv88e6xxx: fix VTU methods for 6320 family +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +[ Upstream commit f9a457722cf5e3534be5ffab549d6b49737fca72 ] + +The VTU registers of the 6320 family use the 6352 semantics, not 6185. +Fix it. + +Fixes: b8fee9571063 ("net: dsa: mv88e6xxx: add VLAN Get Next support") +Signed-off-by: Marek Behún +Cc: # 5.15.x +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20250317173250.28780-2-kabel@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/mv88e6xxx/chip.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index d66448f0833cc..bf93d700802be 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -5071,8 +5071,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, +- .vtu_getnext = mv88e6185_g1_vtu_getnext, +- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, ++ .vtu_getnext = mv88e6352_g1_vtu_getnext, ++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, +@@ -5120,8 +5120,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .reset = mv88e6352_g1_reset, +- .vtu_getnext = mv88e6185_g1_vtu_getnext, +- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, ++ .vtu_getnext = mv88e6352_g1_vtu_getnext, ++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, +-- +2.39.5 + diff --git a/queue-6.6/of-resolver-fix-device-node-refcount-leakage-in-of_r.patch b/queue-6.6/of-resolver-fix-device-node-refcount-leakage-in-of_r.patch new file mode 100644 index 0000000000..b00b6d3c46 --- /dev/null +++ b/queue-6.6/of-resolver-fix-device-node-refcount-leakage-in-of_r.patch @@ -0,0 +1,45 @@ +From 84e7dd59cb3f1158a50edf794334fbe7de749cfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Feb 2025 17:01:55 -0600 +Subject: of: resolver: Fix device node refcount leakage in + of_resolve_phandles() + +From: Zijun Hu + +[ Upstream commit a46a0805635d07de50c2ac71588345323c13b2f9 ] + +In of_resolve_phandles(), refcount of device node @local_fixups will be +increased if the for_each_child_of_node() exits early, but nowhere to +decrease the refcount, so cause refcount leakage for the node. + +Fix by using __free() on @local_fixups. + +Fixes: da56d04c806a ("of/resolver: Switch to new local fixups format.") +Cc: stable@vger.kernel.org +Signed-off-by: Zijun Hu +Link: https://lore.kernel.org/r/20250209-of_irq_fix-v2-9-93e3a2659aa7@quicinc.com +[robh: Use __free() instead] +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + drivers/of/resolver.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c +index 2dd19dc6987c7..d5c1b2a126a56 100644 +--- a/drivers/of/resolver.c ++++ b/drivers/of/resolver.c +@@ -262,8 +262,9 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, + */ + int of_resolve_phandles(struct device_node *overlay) + { +- struct device_node *child, *local_fixups, *refnode; ++ struct device_node *child, *refnode; + struct device_node *overlay_fixups; ++ struct device_node __free(device_node) *local_fixups = NULL; + struct property *prop; + const char *refpath; + phandle phandle, phandle_delta; +-- +2.39.5 + diff --git a/queue-6.6/of-resolver-simplify-of_resolve_phandles-using-__fre.patch b/queue-6.6/of-resolver-simplify-of_resolve_phandles-using-__fre.patch new file mode 100644 index 0000000000..f12a102f06 --- /dev/null +++ b/queue-6.6/of-resolver-simplify-of_resolve_phandles-using-__fre.patch @@ -0,0 +1,114 @@ +From a4016669fb34722fcdd808db8371ef8146c36c82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Feb 2025 20:59:02 +0800 +Subject: of: resolver: Simplify of_resolve_phandles() using __free() + +From: Rob Herring (Arm) + +[ Upstream commit 5275e8b5293f65cc82a5ee5eab02dd573b911d6e ] + +Use the __free() cleanup to simplify of_resolve_phandles() and remove +all the goto's. + +Signed-off-by: Rob Herring (Arm) +Stable-dep-of: a46a0805635d ("of: resolver: Fix device node refcount leakage in of_resolve_phandles()") +Signed-off-by: Sasha Levin +--- + drivers/of/resolver.c | 34 +++++++++++----------------------- + 1 file changed, 11 insertions(+), 23 deletions(-) + +diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c +index b278ab4338ceb..2dd19dc6987c7 100644 +--- a/drivers/of/resolver.c ++++ b/drivers/of/resolver.c +@@ -263,24 +263,20 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, + int of_resolve_phandles(struct device_node *overlay) + { + struct device_node *child, *local_fixups, *refnode; +- struct device_node *tree_symbols, *overlay_fixups; ++ struct device_node *overlay_fixups; + struct property *prop; + const char *refpath; + phandle phandle, phandle_delta; + int err; + +- tree_symbols = NULL; +- + if (!overlay) { + pr_err("null overlay\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + if (!of_node_check_flag(overlay, OF_DETACHED)) { + pr_err("overlay not detached\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + phandle_delta = live_tree_max_phandle() + 1; +@@ -292,7 +288,7 @@ int of_resolve_phandles(struct device_node *overlay) + + err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); + if (err) +- goto out; ++ return err; + + overlay_fixups = NULL; + +@@ -301,16 +297,13 @@ int of_resolve_phandles(struct device_node *overlay) + overlay_fixups = child; + } + +- if (!overlay_fixups) { +- err = 0; +- goto out; +- } ++ if (!overlay_fixups) ++ return 0; + +- tree_symbols = of_find_node_by_path("/__symbols__"); ++ struct device_node __free(device_node) *tree_symbols = of_find_node_by_path("/__symbols__"); + if (!tree_symbols) { + pr_err("no symbols in root of device tree.\n"); +- err = -EINVAL; +- goto out; ++ return -EINVAL; + } + + for_each_property_of_node(overlay_fixups, prop) { +@@ -324,14 +317,12 @@ int of_resolve_phandles(struct device_node *overlay) + if (err) { + pr_err("node label '%s' not found in live devicetree symbols table\n", + prop->name); +- goto out; ++ return err; + } + + refnode = of_find_node_by_path(refpath); +- if (!refnode) { +- err = -ENOENT; +- goto out; +- } ++ if (!refnode) ++ return -ENOENT; + + phandle = refnode->phandle; + of_node_put(refnode); +@@ -341,11 +332,8 @@ int of_resolve_phandles(struct device_node *overlay) + break; + } + +-out: + if (err) + pr_err("overlay phandle fixup failed: %d\n", err); +- of_node_put(tree_symbols); +- + return err; + } + EXPORT_SYMBOL_GPL(of_resolve_phandles); +-- +2.39.5 + diff --git a/queue-6.6/pci-fix-reference-leak-in-pci_register_host_bridge.patch b/queue-6.6/pci-fix-reference-leak-in-pci_register_host_bridge.patch new file mode 100644 index 0000000000..1e66120453 --- /dev/null +++ b/queue-6.6/pci-fix-reference-leak-in-pci_register_host_bridge.patch @@ -0,0 +1,67 @@ +From 2509e58b469d642891e8e7e00597e39b82a9258c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 10:14:40 +0800 +Subject: PCI: Fix reference leak in pci_register_host_bridge() + +From: Ma Ke + +[ Upstream commit 804443c1f27883926de94c849d91f5b7d7d696e9 ] + +If device_register() fails, call put_device() to give up the reference to +avoid a memory leak, per the comment at device_register(). + +Found by code review. + +Link: https://lore.kernel.org/r/20250225021440.3130264-1-make24@iscas.ac.cn +Fixes: 37d6a0a6f470 ("PCI: Add pci_register_host_bridge() interface") +Signed-off-by: Ma Ke +[bhelgaas: squash Dan Carpenter's double free fix from +https://lore.kernel.org/r/db806a6c-a91b-4e5a-a84b-6b7e01bdac85@stanley.mountain] +Signed-off-by: Bjorn Helgaas +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 8e5d818c29a98..b7cec139d816b 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -885,6 +885,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + resource_size_t offset, next_offset; + LIST_HEAD(resources); + struct resource *res, *next_res; ++ bool bus_registered = false; + char addr[64], *fmt; + const char *name; + int err; +@@ -948,6 +949,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + name = dev_name(&bus->dev); + + err = device_register(&bus->dev); ++ bus_registered = true; + if (err) + goto unregister; + +@@ -1031,12 +1033,15 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) + unregister: + put_device(&bridge->dev); + device_del(&bridge->dev); +- + free: + #ifdef CONFIG_PCI_DOMAINS_GENERIC + pci_bus_release_domain_nr(bus, parent); + #endif +- kfree(bus); ++ if (bus_registered) ++ put_device(&bus->dev); ++ else ++ kfree(bus); ++ + return err; + } + +-- +2.39.5 + diff --git a/queue-6.6/s390-pci-report-pci-error-recovery-results-via-sclp.patch b/queue-6.6/s390-pci-report-pci-error-recovery-results-via-sclp.patch new file mode 100644 index 0000000000..495ca186c5 --- /dev/null +++ b/queue-6.6/s390-pci-report-pci-error-recovery-results-via-sclp.patch @@ -0,0 +1,380 @@ +From bc44df3dd096499912449d45aadf335fcb507754 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Dec 2024 14:47:28 +0100 +Subject: s390/pci: Report PCI error recovery results via SCLP + +From: Niklas Schnelle + +[ Upstream commit 4ec6054e7321dc24ebccaa08b3af0d590f5666e6 ] + +Add a mechanism with which the status of PCI error recovery runs +is reported to the platform. Together with the status supply additional +information that may aid in problem determination. + +Reviewed-by: Halil Pasic +Signed-off-by: Niklas Schnelle +Signed-off-by: Alexander Gordeev +Stable-dep-of: aa9f168d55dc ("s390/pci: Support mmap() of PCI resources except for ISM devices") +Signed-off-by: Sasha Levin +--- + arch/s390/include/asm/sclp.h | 33 +++++++++++ + arch/s390/pci/Makefile | 2 +- + arch/s390/pci/pci_event.c | 21 +++++-- + arch/s390/pci/pci_report.c | 111 +++++++++++++++++++++++++++++++++++ + arch/s390/pci/pci_report.h | 16 +++++ + drivers/s390/char/sclp.h | 14 ----- + drivers/s390/char/sclp_pci.c | 19 ------ + 7 files changed, 178 insertions(+), 38 deletions(-) + create mode 100644 arch/s390/pci/pci_report.c + create mode 100644 arch/s390/pci/pci_report.h + +diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h +index 5742d23bba137..d4a7a178e3584 100644 +--- a/arch/s390/include/asm/sclp.h ++++ b/arch/s390/include/asm/sclp.h +@@ -16,6 +16,11 @@ + /* 24 + 16 * SCLP_MAX_CORES */ + #define EXT_SCCB_READ_CPU (3 * PAGE_SIZE) + ++#define SCLP_ERRNOTIFY_AQ_RESET 0 ++#define SCLP_ERRNOTIFY_AQ_REPAIR 1 ++#define SCLP_ERRNOTIFY_AQ_INFO_LOG 2 ++#define SCLP_ERRNOTIFY_AQ_OPTICS_DATA 3 ++ + #ifndef __ASSEMBLY__ + #include + #include +@@ -109,6 +114,34 @@ struct sclp_info { + }; + extern struct sclp_info sclp; + ++struct sccb_header { ++ u16 length; ++ u8 function_code; ++ u8 control_mask[3]; ++ u16 response_code; ++} __packed; ++ ++struct evbuf_header { ++ u16 length; ++ u8 type; ++ u8 flags; ++ u16 _reserved; ++} __packed; ++ ++struct err_notify_evbuf { ++ struct evbuf_header header; ++ u8 action; ++ u8 atype; ++ u32 fh; ++ u32 fid; ++ u8 data[]; ++} __packed; ++ ++struct err_notify_sccb { ++ struct sccb_header header; ++ struct err_notify_evbuf evbuf; ++} __packed; ++ + struct zpci_report_error_header { + u8 version; /* Interface version byte */ + u8 action; /* Action qualifier byte +diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile +index 5ae31ca9dd441..eeef68901a15c 100644 +--- a/arch/s390/pci/Makefile ++++ b/arch/s390/pci/Makefile +@@ -5,5 +5,5 @@ + + obj-$(CONFIG_PCI) += pci.o pci_irq.o pci_dma.o pci_clp.o pci_sysfs.o \ + pci_event.o pci_debug.o pci_insn.o pci_mmio.o \ +- pci_bus.o pci_kvm_hook.o ++ pci_bus.o pci_kvm_hook.o pci_report.o + obj-$(CONFIG_PCI_IOV) += pci_iov.o +diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c +index b3961f1016ea0..ed8c7f61e642b 100644 +--- a/arch/s390/pci/pci_event.c ++++ b/arch/s390/pci/pci_event.c +@@ -16,6 +16,7 @@ + #include + + #include "pci_bus.h" ++#include "pci_report.h" + + /* Content Code Description for PCI Function Error */ + struct zpci_ccdf_err { +@@ -162,6 +163,8 @@ static pci_ers_result_t zpci_event_do_reset(struct pci_dev *pdev, + static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) + { + pci_ers_result_t ers_res = PCI_ERS_RESULT_DISCONNECT; ++ struct zpci_dev *zdev = to_zpci(pdev); ++ char *status_str = "success"; + struct pci_driver *driver; + + /* +@@ -179,29 +182,37 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) + if (is_passed_through(to_zpci(pdev))) { + pr_info("%s: Cannot be recovered in the host because it is a pass-through device\n", + pci_name(pdev)); ++ status_str = "failed (pass-through)"; + goto out_unlock; + } + + driver = to_pci_driver(pdev->dev.driver); + if (!is_driver_supported(driver)) { +- if (!driver) ++ if (!driver) { + pr_info("%s: Cannot be recovered because no driver is bound to the device\n", + pci_name(pdev)); +- else ++ status_str = "failed (no driver)"; ++ } else { + pr_info("%s: The %s driver bound to the device does not support error recovery\n", + pci_name(pdev), + driver->name); ++ status_str = "failed (no driver support)"; ++ } + goto out_unlock; + } + + ers_res = zpci_event_notify_error_detected(pdev, driver); +- if (ers_result_indicates_abort(ers_res)) ++ if (ers_result_indicates_abort(ers_res)) { ++ status_str = "failed (abort on detection)"; + goto out_unlock; ++ } + + if (ers_res == PCI_ERS_RESULT_CAN_RECOVER) { + ers_res = zpci_event_do_error_state_clear(pdev, driver); +- if (ers_result_indicates_abort(ers_res)) ++ if (ers_result_indicates_abort(ers_res)) { ++ status_str = "failed (abort on MMIO enable)"; + goto out_unlock; ++ } + } + + if (ers_res == PCI_ERS_RESULT_NEED_RESET) +@@ -210,6 +221,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) + if (ers_res != PCI_ERS_RESULT_RECOVERED) { + pr_err("%s: Automatic recovery failed; operator intervention is required\n", + pci_name(pdev)); ++ status_str = "failed (driver can't recover)"; + goto out_unlock; + } + +@@ -218,6 +230,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) + driver->err_handler->resume(pdev); + out_unlock: + pci_dev_unlock(pdev); ++ zpci_report_status(zdev, "recovery", status_str); + + return ers_res; + } +diff --git a/arch/s390/pci/pci_report.c b/arch/s390/pci/pci_report.c +new file mode 100644 +index 0000000000000..2754c9c161f5b +--- /dev/null ++++ b/arch/s390/pci/pci_report.c +@@ -0,0 +1,111 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright IBM Corp. 2024 ++ * ++ * Author(s): ++ * Niklas Schnelle ++ * ++ */ ++ ++#define KMSG_COMPONENT "zpci" ++#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "pci_report.h" ++ ++#define ZPCI_ERR_LOG_ID_KERNEL_REPORT 0x4714 ++ ++struct zpci_report_error_data { ++ u64 timestamp; ++ u64 err_log_id; ++ char log_data[]; ++} __packed; ++ ++#define ZPCI_REPORT_SIZE (PAGE_SIZE - sizeof(struct err_notify_sccb)) ++#define ZPCI_REPORT_DATA_SIZE (ZPCI_REPORT_SIZE - sizeof(struct zpci_report_error_data)) ++ ++struct zpci_report_error { ++ struct zpci_report_error_header header; ++ struct zpci_report_error_data data; ++} __packed; ++ ++static const char *zpci_state_str(pci_channel_state_t state) ++{ ++ switch (state) { ++ case pci_channel_io_normal: ++ return "normal"; ++ case pci_channel_io_frozen: ++ return "frozen"; ++ case pci_channel_io_perm_failure: ++ return "permanent-failure"; ++ default: ++ return "invalid"; ++ }; ++} ++ ++/** ++ * zpci_report_status - Report the status of operations on a PCI device ++ * @zdev: The PCI device for which to report status ++ * @operation: A string representing the operation reported ++ * @status: A string representing the status of the operation ++ * ++ * This function creates a human readable report about an operation such as ++ * PCI device recovery and forwards this to the platform using the SCLP Write ++ * Event Data mechanism. Besides the operation and status strings the report ++ * also contains additional information about the device deemed useful for ++ * debug such as the currently bound device driver, if any, and error state. ++ * ++ * Return: 0 on success an error code < 0 otherwise. ++ */ ++int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status) ++{ ++ struct zpci_report_error *report; ++ struct pci_driver *driver = NULL; ++ struct pci_dev *pdev = NULL; ++ char *buf, *end; ++ int ret; ++ ++ if (!zdev || !zdev->zbus) ++ return -ENODEV; ++ ++ /* Protected virtualization hosts get nothing from us */ ++ if (prot_virt_guest) ++ return -ENODATA; ++ ++ report = (void *)get_zeroed_page(GFP_KERNEL); ++ if (!report) ++ return -ENOMEM; ++ if (zdev->zbus->bus) ++ pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn); ++ if (pdev) ++ driver = to_pci_driver(pdev->dev.driver); ++ ++ buf = report->data.log_data; ++ end = report->data.log_data + ZPCI_REPORT_DATA_SIZE; ++ buf += scnprintf(buf, end - buf, "report: %s\n", operation); ++ buf += scnprintf(buf, end - buf, "status: %s\n", status); ++ buf += scnprintf(buf, end - buf, "state: %s\n", ++ (pdev) ? zpci_state_str(pdev->error_state) : "n/a"); ++ buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a"); ++ ++ report->header.version = 1; ++ report->header.action = SCLP_ERRNOTIFY_AQ_INFO_LOG; ++ report->header.length = buf - (char *)&report->data; ++ report->data.timestamp = ktime_get_clocktai_seconds(); ++ report->data.err_log_id = ZPCI_ERR_LOG_ID_KERNEL_REPORT; ++ ++ ret = sclp_pci_report(&report->header, zdev->fh, zdev->fid); ++ if (ret) ++ pr_err("Reporting PCI status failed with code %d\n", ret); ++ else ++ pr_info("Reported PCI device status\n"); ++ ++ free_page((unsigned long)report); ++ ++ return ret; ++} +diff --git a/arch/s390/pci/pci_report.h b/arch/s390/pci/pci_report.h +new file mode 100644 +index 0000000000000..e08003d51a972 +--- /dev/null ++++ b/arch/s390/pci/pci_report.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright IBM Corp. 2024 ++ * ++ * Author(s): ++ * Niklas Schnelle ++ * ++ */ ++#ifndef __S390_PCI_REPORT_H ++#define __S390_PCI_REPORT_H ++ ++struct zpci_dev; ++ ++int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status); ++ ++#endif /* __S390_PCI_REPORT_H */ +diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h +index 6a23ec286c702..25fd4d8547483 100644 +--- a/drivers/s390/char/sclp.h ++++ b/drivers/s390/char/sclp.h +@@ -84,13 +84,6 @@ typedef unsigned int sclp_cmdw_t; + + typedef u64 sccb_mask_t; + +-struct sccb_header { +- u16 length; +- u8 function_code; +- u8 control_mask[3]; +- u16 response_code; +-} __attribute__((packed)); +- + struct init_sccb { + struct sccb_header header; + u16 _reserved; +@@ -237,13 +230,6 @@ struct gds_vector { + u16 gds_id; + } __attribute__((packed)); + +-struct evbuf_header { +- u16 length; +- u8 type; +- u8 flags; +- u16 _reserved; +-} __attribute__((packed)); +- + struct sclp_req { + struct list_head list; /* list_head for request queueing. */ + sclp_cmdw_t command; /* sclp command to execute */ +diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c +index c3466a8c56bb5..56400886f7fca 100644 +--- a/drivers/s390/char/sclp_pci.c ++++ b/drivers/s390/char/sclp_pci.c +@@ -24,30 +24,11 @@ + + #define SCLP_ATYPE_PCI 2 + +-#define SCLP_ERRNOTIFY_AQ_RESET 0 +-#define SCLP_ERRNOTIFY_AQ_REPAIR 1 +-#define SCLP_ERRNOTIFY_AQ_INFO_LOG 2 +-#define SCLP_ERRNOTIFY_AQ_OPTICS_DATA 3 +- + static DEFINE_MUTEX(sclp_pci_mutex); + static struct sclp_register sclp_pci_event = { + .send_mask = EVTYP_ERRNOTIFY_MASK, + }; + +-struct err_notify_evbuf { +- struct evbuf_header header; +- u8 action; +- u8 atype; +- u32 fh; +- u32 fid; +- u8 data[]; +-} __packed; +- +-struct err_notify_sccb { +- struct sccb_header header; +- struct err_notify_evbuf evbuf; +-} __packed; +- + struct pci_cfg_sccb { + struct sccb_header header; + u8 atype; /* adapter type */ +-- +2.39.5 + diff --git a/queue-6.6/s390-pci-support-mmap-of-pci-resources-except-for-is.patch b/queue-6.6/s390-pci-support-mmap-of-pci-resources-except-for-is.patch new file mode 100644 index 0000000000..be707dd115 --- /dev/null +++ b/queue-6.6/s390-pci-support-mmap-of-pci-resources-except-for-is.patch @@ -0,0 +1,154 @@ +From bb8589b36d58725be67b9d983251d9a9b1437f2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Feb 2025 13:07:47 +0100 +Subject: s390/pci: Support mmap() of PCI resources except for ISM devices + +From: Niklas Schnelle + +[ Upstream commit aa9f168d55dc47c0de564f7dfe0e90467c9fee71 ] + +So far s390 does not allow mmap() of PCI resources to user-space via the +usual mechanisms, though it does use it for RDMA. For the PCI sysfs +resource files and /proc/bus/pci it defines neither HAVE_PCI_MMAP nor +ARCH_GENERIC_PCI_MMAP_RESOURCE. For vfio-pci s390 previously relied on +disabled VFIO_PCI_MMAP and now relies on setting pdev->non_mappable_bars +for all devices. + +This is partly because access to mapped PCI resources from user-space +requires special PCI load/store memory-I/O (MIO) instructions, or the +special MMIO syscalls when these are not available. Still, such access is +possible and useful not just for RDMA, in fact not being able to mmap() PCI +resources has previously caused extra work when testing devices. + +One thing that doesn't work with PCI resources mapped to user-space though +is the s390 specific virtual ISM device. Not only because the BAR size of +256 TiB prevents mapping the whole BAR but also because access requires use +of the legacy PCI instructions which are not accessible to user-space on +systems with the newer MIO PCI instructions. + +Now with the pdev->non_mappable_bars flag ISM can be excluded from mapping +its resources while making this functionality available for all other PCI +devices. To this end introduce a minimal implementation of PCI_QUIRKS and +use that to set pdev->non_mappable_bars for ISM devices only. Then also set +ARCH_GENERIC_PCI_MMAP_RESOURCE to take advantage of the generic +implementation of pci_mmap_resource_range() enabling only the newer sysfs +mmap() interface. This follows the recommendation in +Documentation/PCI/sysfs-pci.rst. + +Link: https://lore.kernel.org/r/20250226-vfio_pci_mmap-v7-3-c5c0f1d26efd@linux.ibm.com +Signed-off-by: Niklas Schnelle +Signed-off-by: Bjorn Helgaas +Signed-off-by: Sasha Levin +--- + arch/s390/Kconfig | 4 +--- + arch/s390/include/asm/pci.h | 3 +++ + arch/s390/pci/Makefile | 2 +- + arch/s390/pci/pci_fixup.c | 23 +++++++++++++++++++++++ + drivers/s390/net/ism_drv.c | 1 - + include/linux/pci_ids.h | 1 + + 6 files changed, 29 insertions(+), 5 deletions(-) + create mode 100644 arch/s390/pci/pci_fixup.c + +diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig +index bd4782f23f66d..0882016af57c0 100644 +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -38,9 +38,6 @@ config AUDIT_ARCH + config NO_IOPORT_MAP + def_bool y + +-config PCI_QUIRKS +- def_bool n +- + config ARCH_SUPPORTS_UPROBES + def_bool y + +@@ -229,6 +226,7 @@ config S390 + select PCI_DOMAINS if PCI + select PCI_MSI if PCI + select PCI_MSI_ARCH_FALLBACKS if PCI_MSI ++ select PCI_QUIRKS if PCI + select SPARSE_IRQ + select SWIOTLB + select SYSCTL_EXCEPTION_TRACE +diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h +index b248694e00247..211c69cd1f9c9 100644 +--- a/arch/s390/include/asm/pci.h ++++ b/arch/s390/include/asm/pci.h +@@ -11,6 +11,9 @@ + #include + #include + ++#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1 ++#define arch_can_pci_mmap_wc() 1 ++ + #define PCIBIOS_MIN_IO 0x1000 + #define PCIBIOS_MIN_MEM 0x10000000 + +diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile +index eeef68901a15c..2f8dd3f688391 100644 +--- a/arch/s390/pci/Makefile ++++ b/arch/s390/pci/Makefile +@@ -5,5 +5,5 @@ + + obj-$(CONFIG_PCI) += pci.o pci_irq.o pci_dma.o pci_clp.o pci_sysfs.o \ + pci_event.o pci_debug.o pci_insn.o pci_mmio.o \ +- pci_bus.o pci_kvm_hook.o pci_report.o ++ pci_bus.o pci_kvm_hook.o pci_report.o pci_fixup.o + obj-$(CONFIG_PCI_IOV) += pci_iov.o +diff --git a/arch/s390/pci/pci_fixup.c b/arch/s390/pci/pci_fixup.c +new file mode 100644 +index 0000000000000..35688b6450983 +--- /dev/null ++++ b/arch/s390/pci/pci_fixup.c +@@ -0,0 +1,23 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Exceptions for specific devices, ++ * ++ * Copyright IBM Corp. 2025 ++ * ++ * Author(s): ++ * Niklas Schnelle ++ */ ++#include ++ ++static void zpci_ism_bar_no_mmap(struct pci_dev *pdev) ++{ ++ /* ++ * ISM's BAR is special. Drivers written for ISM know ++ * how to handle this but others need to be aware of their ++ * special nature e.g. to prevent attempts to mmap() it. ++ */ ++ pdev->non_mappable_bars = 1; ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IBM, ++ PCI_DEVICE_ID_IBM_ISM, ++ zpci_ism_bar_no_mmap); +diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c +index af0d90beba638..390ebd4d7f3bc 100644 +--- a/drivers/s390/net/ism_drv.c ++++ b/drivers/s390/net/ism_drv.c +@@ -20,7 +20,6 @@ + MODULE_DESCRIPTION("ISM driver for s390"); + MODULE_LICENSE("GPL"); + +-#define PCI_DEVICE_ID_IBM_ISM 0x04ED + #define DRV_NAME "ism" + + static const struct pci_device_id ism_device_table[] = { +diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h +index 3dce2be622e74..dcb9d5ac06937 100644 +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -517,6 +517,7 @@ + #define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM 0x0251 + #define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361 + #define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252 ++#define PCI_DEVICE_ID_IBM_ISM 0x04ed + + #define PCI_SUBVENDOR_ID_IBM 0x1014 + #define PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT 0x03d4 +-- +2.39.5 + diff --git a/queue-6.6/s390-sclp-allow-user-space-to-provide-pci-reports-fo.patch b/queue-6.6/s390-sclp-allow-user-space-to-provide-pci-reports-fo.patch new file mode 100644 index 0000000000..2028f427c4 --- /dev/null +++ b/queue-6.6/s390-sclp-allow-user-space-to-provide-pci-reports-fo.patch @@ -0,0 +1,44 @@ +From 3975b23c37050e63853cd7e5082ceda8ea50d152 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Oct 2024 15:07:27 +0200 +Subject: s390/sclp: Allow user-space to provide PCI reports for optical + modules + +From: Niklas Schnelle + +[ Upstream commit e9ab04490667249633fb397be17db46a8fa6d130 ] + +The new SCLP action qualifier 3 is used by user-space code to provide +optical module monitoring data to the platform. + +Signed-off-by: Niklas Schnelle +Signed-off-by: Heiko Carstens +Stable-dep-of: aa9f168d55dc ("s390/pci: Support mmap() of PCI resources except for ISM devices") +Signed-off-by: Sasha Levin +--- + drivers/s390/char/sclp_pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c +index a3e5a5fb0c1e7..c3466a8c56bb5 100644 +--- a/drivers/s390/char/sclp_pci.c ++++ b/drivers/s390/char/sclp_pci.c +@@ -27,6 +27,7 @@ + #define SCLP_ERRNOTIFY_AQ_RESET 0 + #define SCLP_ERRNOTIFY_AQ_REPAIR 1 + #define SCLP_ERRNOTIFY_AQ_INFO_LOG 2 ++#define SCLP_ERRNOTIFY_AQ_OPTICS_DATA 3 + + static DEFINE_MUTEX(sclp_pci_mutex); + static struct sclp_register sclp_pci_event = { +@@ -116,6 +117,7 @@ static int sclp_pci_check_report(struct zpci_report_error_header *report) + case SCLP_ERRNOTIFY_AQ_RESET: + case SCLP_ERRNOTIFY_AQ_REPAIR: + case SCLP_ERRNOTIFY_AQ_INFO_LOG: ++ case SCLP_ERRNOTIFY_AQ_OPTICS_DATA: + break; + default: + return -EINVAL; +-- +2.39.5 + diff --git a/queue-6.6/s390-virtio_ccw-don-t-allocate-assign-airqs-for-non-.patch b/queue-6.6/s390-virtio_ccw-don-t-allocate-assign-airqs-for-non-.patch new file mode 100644 index 0000000000..76902afbf7 --- /dev/null +++ b/queue-6.6/s390-virtio_ccw-don-t-allocate-assign-airqs-for-non-.patch @@ -0,0 +1,145 @@ +From 3867566eb8a43354f101dbb141dc38e7f9f8395f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Apr 2025 22:36:21 +0200 +Subject: s390/virtio_ccw: Don't allocate/assign airqs for non-existing queues + +From: David Hildenbrand + +[ Upstream commit 2ccd42b959aaf490333dbd3b9b102eaf295c036a ] + +If we finds a vq without a name in our input array in +virtio_ccw_find_vqs(), we treat it as "non-existing" and set the vq pointer +to NULL; we will not call virtio_ccw_setup_vq() to allocate/setup a vq. + +Consequently, we create only a queue if it actually exists (name != NULL) +and assign an incremental queue index to each such existing queue. + +However, in virtio_ccw_register_adapter_ind()->get_airq_indicator() we +will not ignore these "non-existing queues", but instead assign an airq +indicator to them. + +Besides never releasing them in virtio_ccw_drop_indicators() (because +there is no virtqueue), the bigger issue seems to be that there will be a +disagreement between the device and the Linux guest about the airq +indicator to be used for notifying a queue, because the indicator bit +for adapter I/O interrupt is derived from the queue index. + +The virtio spec states under "Setting Up Two-Stage Queue Indicators": + + ... indicator contains the guest address of an area wherein the + indicators for the devices are contained, starting at bit_nr, one + bit per virtqueue of the device. + +And further in "Notification via Adapter I/O Interrupts": + + For notifying the driver of virtqueue buffers, the device sets the + bit in the guest-provided indicator area at the corresponding + offset. + +For example, QEMU uses in virtio_ccw_notify() the queue index (passed as +"vector") to select the relevant indicator bit. If a queue does not exist, +it does not have a corresponding indicator bit assigned, because it +effectively doesn't have a queue index. + +Using a virtio-balloon-ccw device under QEMU with free-page-hinting +disabled ("free-page-hint=off") but free-page-reporting enabled +("free-page-reporting=on") will result in free page reporting +not working as expected: in the virtio_balloon driver, we'll be stuck +forever in virtballoon_free_page_report()->wait_event(), because the +waitqueue will not be woken up as the notification from the device is +lost: it would use the wrong indicator bit. + +Free page reporting stops working and we get splats (when configured to +detect hung wqs) like: + + INFO: task kworker/1:3:463 blocked for more than 61 seconds. + Not tainted 6.14.0 #4 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:kworker/1:3 [...] + Workqueue: events page_reporting_process + Call Trace: + [<000002f404e6dfb2>] __schedule+0x402/0x1640 + [<000002f404e6f22e>] schedule+0x3e/0xe0 + [<000002f3846a88fa>] virtballoon_free_page_report+0xaa/0x110 [virtio_balloon] + [<000002f40435c8a4>] page_reporting_process+0x2e4/0x740 + [<000002f403fd3ee2>] process_one_work+0x1c2/0x400 + [<000002f403fd4b96>] worker_thread+0x296/0x420 + [<000002f403fe10b4>] kthread+0x124/0x290 + [<000002f403f4e0dc>] __ret_from_fork+0x3c/0x60 + [<000002f404e77272>] ret_from_fork+0xa/0x38 + +There was recently a discussion [1] whether the "holes" should be +treated differently again, effectively assigning also non-existing +queues a queue index: that should also fix the issue, but requires other +workarounds to not break existing setups. + +Let's fix it without affecting existing setups for now by properly ignoring +the non-existing queues, so the indicator bits will match the queue +indexes. + +[1] https://lore.kernel.org/all/cover.1720611677.git.mst@redhat.com/ + +Fixes: a229989d975e ("virtio: don't allocate vqs when names[i] = NULL") +Reported-by: Chandra Merla +Cc: stable@vger.kernel.org +Signed-off-by: David Hildenbrand +Tested-by: Thomas Huth +Reviewed-by: Thomas Huth +Reviewed-by: Cornelia Huck +Acked-by: Michael S. Tsirkin +Acked-by: Christian Borntraeger +Link: https://lore.kernel.org/r/20250402203621.940090-1-david@redhat.com +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + drivers/s390/virtio/virtio_ccw.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c +index ac77951c30c46..75aeb7f8ed099 100644 +--- a/drivers/s390/virtio/virtio_ccw.c ++++ b/drivers/s390/virtio/virtio_ccw.c +@@ -263,11 +263,17 @@ static struct airq_info *new_airq_info(int index) + static unsigned long *get_airq_indicator(struct virtqueue *vqs[], int nvqs, + u64 *first, void **airq_info) + { +- int i, j; ++ int i, j, queue_idx, highest_queue_idx = -1; + struct airq_info *info; + unsigned long *indicator_addr = NULL; + unsigned long bit, flags; + ++ /* Array entries without an actual queue pointer must be ignored. */ ++ for (i = 0; i < nvqs; i++) { ++ if (vqs[i]) ++ highest_queue_idx++; ++ } ++ + for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) { + mutex_lock(&airq_areas_lock); + if (!airq_areas[i]) +@@ -277,7 +283,7 @@ static unsigned long *get_airq_indicator(struct virtqueue *vqs[], int nvqs, + if (!info) + return NULL; + write_lock_irqsave(&info->lock, flags); +- bit = airq_iv_alloc(info->aiv, nvqs); ++ bit = airq_iv_alloc(info->aiv, highest_queue_idx + 1); + if (bit == -1UL) { + /* Not enough vacancies. */ + write_unlock_irqrestore(&info->lock, flags); +@@ -286,8 +292,10 @@ static unsigned long *get_airq_indicator(struct virtqueue *vqs[], int nvqs, + *first = bit; + *airq_info = info; + indicator_addr = info->aiv->vector; +- for (j = 0; j < nvqs; j++) { +- airq_iv_set_ptr(info->aiv, bit + j, ++ for (j = 0, queue_idx = 0; j < nvqs; j++) { ++ if (!vqs[j]) ++ continue; ++ airq_iv_set_ptr(info->aiv, bit + queue_idx++, + (unsigned long)vqs[j]); + } + write_unlock_irqrestore(&info->lock, flags); +-- +2.39.5 + diff --git a/queue-6.6/s390-virtio_ccw-fix-virtual-vs-physical-address-conf.patch b/queue-6.6/s390-virtio_ccw-fix-virtual-vs-physical-address-conf.patch new file mode 100644 index 0000000000..eadef7bddd --- /dev/null +++ b/queue-6.6/s390-virtio_ccw-fix-virtual-vs-physical-address-conf.patch @@ -0,0 +1,320 @@ +From 060468bc4467e6f881fe984e6dc8054999ede5d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Mar 2024 13:28:07 +0100 +Subject: s390/virtio_ccw: fix virtual vs physical address confusion + +From: Halil Pasic + +[ Upstream commit d5cc41686990fa522ce573e5c6c7a619f10c3fd1 ] + +Fix virtual vs physical address confusion and use new dma types and helper +functions to allow for type checking. This does not fix a bug since virtual +and physical address spaces are currently the same. + +Signed-off-by: Halil Pasic +Reviewed-by: Eric Farman +Signed-off-by: Heiko Carstens +Stable-dep-of: 2ccd42b959aa ("s390/virtio_ccw: Don't allocate/assign airqs for non-existing queues") +Signed-off-by: Sasha Levin +--- + drivers/s390/virtio/virtio_ccw.c | 78 ++++++++++++++++---------------- + 1 file changed, 39 insertions(+), 39 deletions(-) + +diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c +index ac67576301bf5..ac77951c30c46 100644 +--- a/drivers/s390/virtio/virtio_ccw.c ++++ b/drivers/s390/virtio/virtio_ccw.c +@@ -85,19 +85,19 @@ static inline unsigned long *indicators2(struct virtio_ccw_device *vcdev) + } + + struct vq_info_block_legacy { +- __u64 queue; ++ dma64_t queue; + __u32 align; + __u16 index; + __u16 num; + } __packed; + + struct vq_info_block { +- __u64 desc; ++ dma64_t desc; + __u32 res0; + __u16 index; + __u16 num; +- __u64 avail; +- __u64 used; ++ dma64_t avail; ++ dma64_t used; + } __packed; + + struct virtio_feature_desc { +@@ -106,8 +106,8 @@ struct virtio_feature_desc { + } __packed; + + struct virtio_thinint_area { +- unsigned long summary_indicator; +- unsigned long indicator; ++ dma64_t summary_indicator; ++ dma64_t indicator; + u64 bit_nr; + u8 isc; + } __packed; +@@ -260,12 +260,12 @@ static struct airq_info *new_airq_info(int index) + return info; + } + +-static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs, +- u64 *first, void **airq_info) ++static unsigned long *get_airq_indicator(struct virtqueue *vqs[], int nvqs, ++ u64 *first, void **airq_info) + { + int i, j; + struct airq_info *info; +- unsigned long indicator_addr = 0; ++ unsigned long *indicator_addr = NULL; + unsigned long bit, flags; + + for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) { +@@ -275,7 +275,7 @@ static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs, + info = airq_areas[i]; + mutex_unlock(&airq_areas_lock); + if (!info) +- return 0; ++ return NULL; + write_lock_irqsave(&info->lock, flags); + bit = airq_iv_alloc(info->aiv, nvqs); + if (bit == -1UL) { +@@ -285,7 +285,7 @@ static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs, + } + *first = bit; + *airq_info = info; +- indicator_addr = (unsigned long)info->aiv->vector; ++ indicator_addr = info->aiv->vector; + for (j = 0; j < nvqs; j++) { + airq_iv_set_ptr(info->aiv, bit + j, + (unsigned long)vqs[j]); +@@ -358,11 +358,11 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, + if (!thinint_area) + return; + thinint_area->summary_indicator = +- (unsigned long) get_summary_indicator(airq_info); ++ virt_to_dma64(get_summary_indicator(airq_info)); + thinint_area->isc = VIRTIO_AIRQ_ISC; + ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER; + ccw->count = sizeof(*thinint_area); +- ccw->cda = (__u32)virt_to_phys(thinint_area); ++ ccw->cda = virt_to_dma32(thinint_area); + } else { + /* payload is the address of the indicators */ + indicatorp = ccw_device_dma_zalloc(vcdev->cdev, +@@ -372,7 +372,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, + *indicatorp = 0; + ccw->cmd_code = CCW_CMD_SET_IND; + ccw->count = sizeof(indicators(vcdev)); +- ccw->cda = (__u32)virt_to_phys(indicatorp); ++ ccw->cda = virt_to_dma32(indicatorp); + } + /* Deregister indicators from host. */ + *indicators(vcdev) = 0; +@@ -426,7 +426,7 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, + ccw->cmd_code = CCW_CMD_READ_VQ_CONF; + ccw->flags = 0; + ccw->count = sizeof(struct vq_config_block); +- ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->config_block); ++ ccw->cda = virt_to_dma32(&vcdev->dma_area->config_block); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF); + if (ret) + return ret; +@@ -463,7 +463,7 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw) + } + ccw->cmd_code = CCW_CMD_SET_VQ; + ccw->flags = 0; +- ccw->cda = (__u32)virt_to_phys(info->info_block); ++ ccw->cda = virt_to_dma32(info->info_block); + ret = ccw_io_helper(vcdev, ccw, + VIRTIO_CCW_DOING_SET_VQ | index); + /* +@@ -556,22 +556,22 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, + /* Register it with the host. */ + queue = virtqueue_get_desc_addr(vq); + if (vcdev->revision == 0) { +- info->info_block->l.queue = queue; ++ info->info_block->l.queue = u64_to_dma64(queue); + info->info_block->l.align = KVM_VIRTIO_CCW_RING_ALIGN; + info->info_block->l.index = i; + info->info_block->l.num = info->num; + ccw->count = sizeof(info->info_block->l); + } else { +- info->info_block->s.desc = queue; ++ info->info_block->s.desc = u64_to_dma64(queue); + info->info_block->s.index = i; + info->info_block->s.num = info->num; +- info->info_block->s.avail = (__u64)virtqueue_get_avail_addr(vq); +- info->info_block->s.used = (__u64)virtqueue_get_used_addr(vq); ++ info->info_block->s.avail = u64_to_dma64(virtqueue_get_avail_addr(vq)); ++ info->info_block->s.used = u64_to_dma64(virtqueue_get_used_addr(vq)); + ccw->count = sizeof(info->info_block->s); + } + ccw->cmd_code = CCW_CMD_SET_VQ; + ccw->flags = 0; +- ccw->cda = (__u32)virt_to_phys(info->info_block); ++ ccw->cda = virt_to_dma32(info->info_block); + err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i); + if (err) { + dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n"); +@@ -605,7 +605,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev, + { + int ret; + struct virtio_thinint_area *thinint_area = NULL; +- unsigned long indicator_addr; ++ unsigned long *indicator_addr; + struct airq_info *info; + + thinint_area = ccw_device_dma_zalloc(vcdev->cdev, +@@ -622,15 +622,15 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev, + ret = -ENOSPC; + goto out; + } +- thinint_area->indicator = virt_to_phys((void *)indicator_addr); ++ thinint_area->indicator = virt_to_dma64(indicator_addr); + info = vcdev->airq_info; + thinint_area->summary_indicator = +- virt_to_phys(get_summary_indicator(info)); ++ virt_to_dma64(get_summary_indicator(info)); + thinint_area->isc = VIRTIO_AIRQ_ISC; + ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER; + ccw->flags = CCW_FLAG_SLI; + ccw->count = sizeof(*thinint_area); +- ccw->cda = (__u32)virt_to_phys(thinint_area); ++ ccw->cda = virt_to_dma32(thinint_area); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER); + if (ret) { + if (ret == -EOPNOTSUPP) { +@@ -658,7 +658,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, + struct irq_affinity *desc) + { + struct virtio_ccw_device *vcdev = to_vc_device(vdev); +- unsigned long *indicatorp = NULL; ++ dma64_t *indicatorp = NULL; + int ret, i, queue_idx = 0; + struct ccw1 *ccw; + +@@ -690,7 +690,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, + sizeof(indicators(vcdev))); + if (!indicatorp) + goto out; +- *indicatorp = (unsigned long) indicators(vcdev); ++ *indicatorp = virt_to_dma64(indicators(vcdev)); + if (vcdev->is_thinint) { + ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw); + if (ret) +@@ -703,18 +703,18 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, + ccw->cmd_code = CCW_CMD_SET_IND; + ccw->flags = 0; + ccw->count = sizeof(indicators(vcdev)); +- ccw->cda = (__u32)virt_to_phys(indicatorp); ++ ccw->cda = virt_to_dma32(indicatorp); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND); + if (ret) + goto out; + } + /* Register indicators2 with host for config changes */ +- *indicatorp = (unsigned long) indicators2(vcdev); ++ *indicatorp = virt_to_dma64(indicators2(vcdev)); + *indicators2(vcdev) = 0; + ccw->cmd_code = CCW_CMD_SET_CONF_IND; + ccw->flags = 0; + ccw->count = sizeof(indicators2(vcdev)); +- ccw->cda = (__u32)virt_to_phys(indicatorp); ++ ccw->cda = virt_to_dma32(indicatorp); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND); + if (ret) + goto out; +@@ -776,7 +776,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev) + ccw->cmd_code = CCW_CMD_READ_FEAT; + ccw->flags = 0; + ccw->count = sizeof(*features); +- ccw->cda = (__u32)virt_to_phys(features); ++ ccw->cda = virt_to_dma32(features); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT); + if (ret) { + rc = 0; +@@ -793,7 +793,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev) + ccw->cmd_code = CCW_CMD_READ_FEAT; + ccw->flags = 0; + ccw->count = sizeof(*features); +- ccw->cda = (__u32)virt_to_phys(features); ++ ccw->cda = virt_to_dma32(features); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT); + if (ret == 0) + rc |= (u64)le32_to_cpu(features->features) << 32; +@@ -846,7 +846,7 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev) + ccw->cmd_code = CCW_CMD_WRITE_FEAT; + ccw->flags = 0; + ccw->count = sizeof(*features); +- ccw->cda = (__u32)virt_to_phys(features); ++ ccw->cda = virt_to_dma32(features); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT); + if (ret) + goto out_free; +@@ -860,7 +860,7 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev) + ccw->cmd_code = CCW_CMD_WRITE_FEAT; + ccw->flags = 0; + ccw->count = sizeof(*features); +- ccw->cda = (__u32)virt_to_phys(features); ++ ccw->cda = virt_to_dma32(features); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT); + + out_free: +@@ -892,7 +892,7 @@ static void virtio_ccw_get_config(struct virtio_device *vdev, + ccw->cmd_code = CCW_CMD_READ_CONF; + ccw->flags = 0; + ccw->count = offset + len; +- ccw->cda = (__u32)virt_to_phys(config_area); ++ ccw->cda = virt_to_dma32(config_area); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG); + if (ret) + goto out_free; +@@ -939,7 +939,7 @@ static void virtio_ccw_set_config(struct virtio_device *vdev, + ccw->cmd_code = CCW_CMD_WRITE_CONF; + ccw->flags = 0; + ccw->count = offset + len; +- ccw->cda = (__u32)virt_to_phys(config_area); ++ ccw->cda = virt_to_dma32(config_area); + ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG); + + out_free: +@@ -963,7 +963,7 @@ static u8 virtio_ccw_get_status(struct virtio_device *vdev) + ccw->cmd_code = CCW_CMD_READ_STATUS; + ccw->flags = 0; + ccw->count = sizeof(vcdev->dma_area->status); +- ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status); ++ ccw->cda = virt_to_dma32(&vcdev->dma_area->status); + ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS); + /* + * If the channel program failed (should only happen if the device +@@ -992,11 +992,11 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status) + ccw->cmd_code = CCW_CMD_WRITE_STATUS; + ccw->flags = 0; + ccw->count = sizeof(status); +- ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status); + /* We use ssch for setting the status which is a serializing + * instruction that guarantees the memory writes have + * completed before ssch. + */ ++ ccw->cda = virt_to_dma32(&vcdev->dma_area->status); + ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS); + /* Write failed? We assume status is unchanged. */ + if (ret) +@@ -1291,7 +1291,7 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev) + ccw->cmd_code = CCW_CMD_SET_VIRTIO_REV; + ccw->flags = 0; + ccw->count = sizeof(*rev); +- ccw->cda = (__u32)virt_to_phys(rev); ++ ccw->cda = virt_to_dma32(rev); + + vcdev->revision = VIRTIO_CCW_REV_MAX; + do { +-- +2.39.5 + diff --git a/queue-6.6/sched-cpufreq-rework-schedutil-governor-performance-.patch b/queue-6.6/sched-cpufreq-rework-schedutil-governor-performance-.patch new file mode 100644 index 0000000000..1f3c286394 --- /dev/null +++ b/queue-6.6/sched-cpufreq-rework-schedutil-governor-performance-.patch @@ -0,0 +1,375 @@ +From c0590d9e18fc2cdf8387e49c05e551d43ba56f59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Nov 2023 14:39:03 +0100 +Subject: sched/cpufreq: Rework schedutil governor performance estimation + +From: Vincent Guittot + +[ Upstream commit 9c0b4bb7f6303c9c4e2e34984c46f5a86478f84d ] + +The current method to take into account uclamp hints when estimating the +target frequency can end in a situation where the selected target +frequency is finally higher than uclamp hints, whereas there are no real +needs. Such cases mainly happen because we are currently mixing the +traditional scheduler utilization signal with the uclamp performance +hints. By adding these 2 metrics, we loose an important information when +it comes to select the target frequency, and we have to make some +assumptions which can't fit all cases. + +Rework the interface between the scheduler and schedutil governor in order +to propagate all information down to the cpufreq governor. + +effective_cpu_util() interface changes and now returns the actual +utilization of the CPU with 2 optional inputs: + +- The minimum performance for this CPU; typically the capacity to handle + the deadline task and the interrupt pressure. But also uclamp_min + request when available. + +- The maximum targeting performance for this CPU which reflects the + maximum level that we would like to not exceed. By default it will be + the CPU capacity but can be reduced because of some performance hints + set with uclamp. The value can be lower than actual utilization and/or + min performance level. + +A new sugov_effective_cpu_perf() interface is also available to compute +the final performance level that is targeted for the CPU, after applying +some cpufreq headroom and taking into account all inputs. + +With these 2 functions, schedutil is now able to decide when it must go +above uclamp hints. It now also has a generic way to get the min +performance level. + +The dependency between energy model and cpufreq governor and its headroom +policy doesn't exist anymore. + +eenv_pd_max_util() asks schedutil for the targeted performance after +applying the impact of the waking task. + +[ mingo: Refined the changelog & C comments. ] + +Signed-off-by: Vincent Guittot +Signed-off-by: Ingo Molnar +Acked-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/20231122133904.446032-2-vincent.guittot@linaro.org +Stable-dep-of: 79443a7e9da3 ("cpufreq/sched: Explicitly synchronize limits_changed flag handling") +Signed-off-by: Sasha Levin +--- + include/linux/energy_model.h | 1 - + kernel/sched/core.c | 90 ++++++++++++++------------------ + kernel/sched/cpufreq_schedutil.c | 35 +++++++++---- + kernel/sched/fair.c | 22 ++++++-- + kernel/sched/sched.h | 24 +++------ + 5 files changed, 89 insertions(+), 83 deletions(-) + +diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h +index b9caa01dfac48..adec808b371a1 100644 +--- a/include/linux/energy_model.h ++++ b/include/linux/energy_model.h +@@ -243,7 +243,6 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd, + scale_cpu = arch_scale_cpu_capacity(cpu); + ps = &pd->table[pd->nr_perf_states - 1]; + +- max_util = map_util_perf(max_util); + max_util = min(max_util, allowed_cpu_cap); + freq = map_util_freq(max_util, ps->frequency, scale_cpu); + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 41f035744683b..760a6c3781cbf 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -7406,18 +7406,13 @@ int sched_core_idle_cpu(int cpu) + * required to meet deadlines. + */ + unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, +- enum cpu_util_type type, +- struct task_struct *p) ++ unsigned long *min, ++ unsigned long *max) + { +- unsigned long dl_util, util, irq, max; ++ unsigned long util, irq, scale; + struct rq *rq = cpu_rq(cpu); + +- max = arch_scale_cpu_capacity(cpu); +- +- if (!uclamp_is_used() && +- type == FREQUENCY_UTIL && rt_rq_is_runnable(&rq->rt)) { +- return max; +- } ++ scale = arch_scale_cpu_capacity(cpu); + + /* + * Early check to see if IRQ/steal time saturates the CPU, can be +@@ -7425,45 +7420,49 @@ unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, + * update_irq_load_avg(). + */ + irq = cpu_util_irq(rq); +- if (unlikely(irq >= max)) +- return max; ++ if (unlikely(irq >= scale)) { ++ if (min) ++ *min = scale; ++ if (max) ++ *max = scale; ++ return scale; ++ } ++ ++ if (min) { ++ /* ++ * The minimum utilization returns the highest level between: ++ * - the computed DL bandwidth needed with the IRQ pressure which ++ * steals time to the deadline task. ++ * - The minimum performance requirement for CFS and/or RT. ++ */ ++ *min = max(irq + cpu_bw_dl(rq), uclamp_rq_get(rq, UCLAMP_MIN)); ++ ++ /* ++ * When an RT task is runnable and uclamp is not used, we must ++ * ensure that the task will run at maximum compute capacity. ++ */ ++ if (!uclamp_is_used() && rt_rq_is_runnable(&rq->rt)) ++ *min = max(*min, scale); ++ } + + /* + * Because the time spend on RT/DL tasks is visible as 'lost' time to + * CFS tasks and we use the same metric to track the effective + * utilization (PELT windows are synchronized) we can directly add them + * to obtain the CPU's actual utilization. +- * +- * CFS and RT utilization can be boosted or capped, depending on +- * utilization clamp constraints requested by currently RUNNABLE +- * tasks. +- * When there are no CFS RUNNABLE tasks, clamps are released and +- * frequency will be gracefully reduced with the utilization decay. + */ + util = util_cfs + cpu_util_rt(rq); +- if (type == FREQUENCY_UTIL) +- util = uclamp_rq_util_with(rq, util, p); +- +- dl_util = cpu_util_dl(rq); ++ util += cpu_util_dl(rq); + + /* +- * For frequency selection we do not make cpu_util_dl() a permanent part +- * of this sum because we want to use cpu_bw_dl() later on, but we need +- * to check if the CFS+RT+DL sum is saturated (ie. no idle time) such +- * that we select f_max when there is no idle time. +- * +- * NOTE: numerical errors or stop class might cause us to not quite hit +- * saturation when we should -- something for later. ++ * The maximum hint is a soft bandwidth requirement, which can be lower ++ * than the actual utilization because of uclamp_max requirements. + */ +- if (util + dl_util >= max) +- return max; ++ if (max) ++ *max = min(scale, uclamp_rq_get(rq, UCLAMP_MAX)); + +- /* +- * OTOH, for energy computation we need the estimated running time, so +- * include util_dl and ignore dl_bw. +- */ +- if (type == ENERGY_UTIL) +- util += dl_util; ++ if (util >= scale) ++ return scale; + + /* + * There is still idle time; further improve the number by using the +@@ -7474,28 +7473,15 @@ unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, + * U' = irq + --------- * U + * max + */ +- util = scale_irq_capacity(util, irq, max); ++ util = scale_irq_capacity(util, irq, scale); + util += irq; + +- /* +- * Bandwidth required by DEADLINE must always be granted while, for +- * FAIR and RT, we use blocked utilization of IDLE CPUs as a mechanism +- * to gracefully reduce the frequency when no tasks show up for longer +- * periods of time. +- * +- * Ideally we would like to set bw_dl as min/guaranteed freq and util + +- * bw_dl as requested freq. However, cpufreq is not yet ready for such +- * an interface. So, we only do the latter for now. +- */ +- if (type == FREQUENCY_UTIL) +- util += cpu_bw_dl(rq); +- +- return min(max, util); ++ return min(scale, util); + } + + unsigned long sched_cpu_util(int cpu) + { +- return effective_cpu_util(cpu, cpu_util_cfs(cpu), ENERGY_UTIL, NULL); ++ return effective_cpu_util(cpu, cpu_util_cfs(cpu), NULL, NULL); + } + #endif /* CONFIG_SMP */ + +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index 259521b179aa1..f84473f73ed00 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -47,7 +47,7 @@ struct sugov_cpu { + u64 last_update; + + unsigned long util; +- unsigned long bw_dl; ++ unsigned long bw_min; + + /* The field below is for single-CPU policies only: */ + #ifdef CONFIG_NO_HZ_COMMON +@@ -155,7 +155,6 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, + unsigned int freq = arch_scale_freq_invariant() ? + policy->cpuinfo.max_freq : policy->cur; + +- util = map_util_perf(util); + freq = map_util_freq(util, freq, max); + + if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update) +@@ -165,14 +164,30 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, + return cpufreq_driver_resolve_freq(policy, freq); + } + ++unsigned long sugov_effective_cpu_perf(int cpu, unsigned long actual, ++ unsigned long min, ++ unsigned long max) ++{ ++ /* Add dvfs headroom to actual utilization */ ++ actual = map_util_perf(actual); ++ /* Actually we don't need to target the max performance */ ++ if (actual < max) ++ max = actual; ++ ++ /* ++ * Ensure at least minimum performance while providing more compute ++ * capacity when possible. ++ */ ++ return max(min, max); ++} ++ + static void sugov_get_util(struct sugov_cpu *sg_cpu) + { +- unsigned long util = cpu_util_cfs_boost(sg_cpu->cpu); +- struct rq *rq = cpu_rq(sg_cpu->cpu); ++ unsigned long min, max, util = cpu_util_cfs_boost(sg_cpu->cpu); + +- sg_cpu->bw_dl = cpu_bw_dl(rq); +- sg_cpu->util = effective_cpu_util(sg_cpu->cpu, util, +- FREQUENCY_UTIL, NULL); ++ util = effective_cpu_util(sg_cpu->cpu, util, &min, &max); ++ sg_cpu->bw_min = min; ++ sg_cpu->util = sugov_effective_cpu_perf(sg_cpu->cpu, util, min, max); + } + + /** +@@ -318,7 +333,7 @@ static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; } + */ + static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu) + { +- if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl) ++ if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_min) + sg_cpu->sg_policy->limits_changed = true; + } + +@@ -419,8 +434,8 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, + sugov_cpu_is_busy(sg_cpu) && sg_cpu->util < prev_util) + sg_cpu->util = prev_util; + +- cpufreq_driver_adjust_perf(sg_cpu->cpu, map_util_perf(sg_cpu->bw_dl), +- map_util_perf(sg_cpu->util), max_cap); ++ cpufreq_driver_adjust_perf(sg_cpu->cpu, sg_cpu->bw_min, ++ sg_cpu->util, max_cap); + + sg_cpu->sg_policy->last_freq_update_time = time; + } +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 050cc41585f8b..268e2a49b964e 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -7859,7 +7859,7 @@ static inline void eenv_pd_busy_time(struct energy_env *eenv, + for_each_cpu(cpu, pd_cpus) { + unsigned long util = cpu_util(cpu, p, -1, 0); + +- busy_time += effective_cpu_util(cpu, util, ENERGY_UTIL, NULL); ++ busy_time += effective_cpu_util(cpu, util, NULL, NULL); + } + + eenv->pd_busy_time = min(eenv->pd_cap, busy_time); +@@ -7882,7 +7882,7 @@ eenv_pd_max_util(struct energy_env *eenv, struct cpumask *pd_cpus, + for_each_cpu(cpu, pd_cpus) { + struct task_struct *tsk = (cpu == dst_cpu) ? p : NULL; + unsigned long util = cpu_util(cpu, p, dst_cpu, 1); +- unsigned long eff_util; ++ unsigned long eff_util, min, max; + + /* + * Performance domain frequency: utilization clamping +@@ -7891,7 +7891,23 @@ eenv_pd_max_util(struct energy_env *eenv, struct cpumask *pd_cpus, + * NOTE: in case RT tasks are running, by default the + * FREQUENCY_UTIL's utilization can be max OPP. + */ +- eff_util = effective_cpu_util(cpu, util, FREQUENCY_UTIL, tsk); ++ eff_util = effective_cpu_util(cpu, util, &min, &max); ++ ++ /* Task's uclamp can modify min and max value */ ++ if (tsk && uclamp_is_used()) { ++ min = max(min, uclamp_eff_value(p, UCLAMP_MIN)); ++ ++ /* ++ * If there is no active max uclamp constraint, ++ * directly use task's one, otherwise keep max. ++ */ ++ if (uclamp_rq_is_idle(cpu_rq(cpu))) ++ max = uclamp_eff_value(p, UCLAMP_MAX); ++ else ++ max = max(max, uclamp_eff_value(p, UCLAMP_MAX)); ++ } ++ ++ eff_util = sugov_effective_cpu_perf(cpu, eff_util, min, max); + max_util = max(max_util, eff_util); + } + +diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h +index f84b2e9feeb6d..60dc51f43dd91 100644 +--- a/kernel/sched/sched.h ++++ b/kernel/sched/sched.h +@@ -2984,24 +2984,14 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} + #endif + + #ifdef CONFIG_SMP +-/** +- * enum cpu_util_type - CPU utilization type +- * @FREQUENCY_UTIL: Utilization used to select frequency +- * @ENERGY_UTIL: Utilization used during energy calculation +- * +- * The utilization signals of all scheduling classes (CFS/RT/DL) and IRQ time +- * need to be aggregated differently depending on the usage made of them. This +- * enum is used within effective_cpu_util() to differentiate the types of +- * utilization expected by the callers, and adjust the aggregation accordingly. +- */ +-enum cpu_util_type { +- FREQUENCY_UTIL, +- ENERGY_UTIL, +-}; +- + unsigned long effective_cpu_util(int cpu, unsigned long util_cfs, +- enum cpu_util_type type, +- struct task_struct *p); ++ unsigned long *min, ++ unsigned long *max); ++ ++unsigned long sugov_effective_cpu_perf(int cpu, unsigned long actual, ++ unsigned long min, ++ unsigned long max); ++ + + /* + * Verify the fitness of task @p to run on @cpu taking into account the +-- +2.39.5 + diff --git a/queue-6.6/sched-topology-consolidate-and-clean-up-access-to-a-.patch b/queue-6.6/sched-topology-consolidate-and-clean-up-access-to-a-.patch new file mode 100644 index 0000000000..293b4ff10c --- /dev/null +++ b/queue-6.6/sched-topology-consolidate-and-clean-up-access-to-a-.patch @@ -0,0 +1,276 @@ +From 353421b4bbdde7120bb1d8acbdc64bccd67e5fd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Oct 2023 12:36:16 +0200 +Subject: sched/topology: Consolidate and clean up access to a CPU's max + compute capacity + +From: Vincent Guittot + +[ Upstream commit 7bc263840bc3377186cb06b003ac287bb2f18ce2 ] + +Remove the rq::cpu_capacity_orig field and use arch_scale_cpu_capacity() +instead. + +The scheduler uses 3 methods to get access to a CPU's max compute capacity: + + - arch_scale_cpu_capacity(cpu) which is the default way to get a CPU's capacity. + + - cpu_capacity_orig field which is periodically updated with + arch_scale_cpu_capacity(). + + - capacity_orig_of(cpu) which encapsulates rq->cpu_capacity_orig. + +There is no real need to save the value returned by arch_scale_cpu_capacity() +in struct rq. arch_scale_cpu_capacity() returns: + + - either a per_cpu variable. + + - or a const value for systems which have only one capacity. + +Remove rq::cpu_capacity_orig and use arch_scale_cpu_capacity() everywhere. + +No functional changes. + +Some performance tests on Arm64: + + - small SMP device (hikey): no noticeable changes + - HMP device (RB5): hackbench shows minor improvement (1-2%) + - large smp (thx2): hackbench and tbench shows minor improvement (1%) + +Signed-off-by: Vincent Guittot +Signed-off-by: Ingo Molnar +Reviewed-by: Dietmar Eggemann +Link: https://lore.kernel.org/r/20231009103621.374412-2-vincent.guittot@linaro.org +Stable-dep-of: 79443a7e9da3 ("cpufreq/sched: Explicitly synchronize limits_changed flag handling") +Signed-off-by: Sasha Levin +--- + Documentation/scheduler/sched-capacity.rst | 13 +++++++------ + kernel/sched/core.c | 2 +- + kernel/sched/cpudeadline.c | 2 +- + kernel/sched/deadline.c | 4 ++-- + kernel/sched/fair.c | 18 ++++++++---------- + kernel/sched/rt.c | 2 +- + kernel/sched/sched.h | 6 ------ + kernel/sched/topology.c | 7 +++++-- + 8 files changed, 25 insertions(+), 29 deletions(-) + +diff --git a/Documentation/scheduler/sched-capacity.rst b/Documentation/scheduler/sched-capacity.rst +index e2c1cf7431588..de414b33dd2ab 100644 +--- a/Documentation/scheduler/sched-capacity.rst ++++ b/Documentation/scheduler/sched-capacity.rst +@@ -39,14 +39,15 @@ per Hz, leading to:: + ------------------- + + Two different capacity values are used within the scheduler. A CPU's +-``capacity_orig`` is its maximum attainable capacity, i.e. its maximum +-attainable performance level. A CPU's ``capacity`` is its ``capacity_orig`` to +-which some loss of available performance (e.g. time spent handling IRQs) is +-subtracted. ++``original capacity`` is its maximum attainable capacity, i.e. its maximum ++attainable performance level. This original capacity is returned by ++the function arch_scale_cpu_capacity(). A CPU's ``capacity`` is its ``original ++capacity`` to which some loss of available performance (e.g. time spent ++handling IRQs) is subtracted. + + Note that a CPU's ``capacity`` is solely intended to be used by the CFS class, +-while ``capacity_orig`` is class-agnostic. The rest of this document will use +-the term ``capacity`` interchangeably with ``capacity_orig`` for the sake of ++while ``original capacity`` is class-agnostic. The rest of this document will use ++the term ``capacity`` interchangeably with ``original capacity`` for the sake of + brevity. + + 1.3 Platform examples +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 8c5f75af07db0..41f035744683b 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -10048,7 +10048,7 @@ void __init sched_init(void) + #ifdef CONFIG_SMP + rq->sd = NULL; + rq->rd = NULL; +- rq->cpu_capacity = rq->cpu_capacity_orig = SCHED_CAPACITY_SCALE; ++ rq->cpu_capacity = SCHED_CAPACITY_SCALE; + rq->balance_callback = &balance_push_callback; + rq->active_balance = 0; + rq->next_balance = jiffies; +diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c +index 57c92d751bcd7..95baa12a10293 100644 +--- a/kernel/sched/cpudeadline.c ++++ b/kernel/sched/cpudeadline.c +@@ -131,7 +131,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p, + if (!dl_task_fits_capacity(p, cpu)) { + cpumask_clear_cpu(cpu, later_mask); + +- cap = capacity_orig_of(cpu); ++ cap = arch_scale_cpu_capacity(cpu); + + if (cap > max_cap || + (cpu == task_cpu(p) && cap == max_cap)) { +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 6c639e48e49a9..a15cf7969953a 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -132,7 +132,7 @@ static inline unsigned long __dl_bw_capacity(const struct cpumask *mask) + int i; + + for_each_cpu_and(i, mask, cpu_active_mask) +- cap += capacity_orig_of(i); ++ cap += arch_scale_cpu_capacity(i); + + return cap; + } +@@ -144,7 +144,7 @@ static inline unsigned long __dl_bw_capacity(const struct cpumask *mask) + static inline unsigned long dl_bw_capacity(int i) + { + if (!sched_asym_cpucap_active() && +- capacity_orig_of(i) == SCHED_CAPACITY_SCALE) { ++ arch_scale_cpu_capacity(i) == SCHED_CAPACITY_SCALE) { + return dl_bw_cpus(i) << SCHED_CAPACITY_SHIFT; + } else { + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 2808dbdd03847..050cc41585f8b 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -4951,7 +4951,7 @@ static inline void util_est_update(struct cfs_rq *cfs_rq, + * To avoid overestimation of actual task utilization, skip updates if + * we cannot grant there is idle time in this CPU. + */ +- if (task_util(p) > capacity_orig_of(cpu_of(rq_of(cfs_rq)))) ++ if (task_util(p) > arch_scale_cpu_capacity(cpu_of(rq_of(cfs_rq)))) + return; + + /* +@@ -4999,14 +4999,14 @@ static inline int util_fits_cpu(unsigned long util, + return fits; + + /* +- * We must use capacity_orig_of() for comparing against uclamp_min and ++ * We must use arch_scale_cpu_capacity() for comparing against uclamp_min and + * uclamp_max. We only care about capacity pressure (by using + * capacity_of()) for comparing against the real util. + * + * If a task is boosted to 1024 for example, we don't want a tiny + * pressure to skew the check whether it fits a CPU or not. + * +- * Similarly if a task is capped to capacity_orig_of(little_cpu), it ++ * Similarly if a task is capped to arch_scale_cpu_capacity(little_cpu), it + * should fit a little cpu even if there's some pressure. + * + * Only exception is for thermal pressure since it has a direct impact +@@ -5018,7 +5018,7 @@ static inline int util_fits_cpu(unsigned long util, + * For uclamp_max, we can tolerate a drop in performance level as the + * goal is to cap the task. So it's okay if it's getting less. + */ +- capacity_orig = capacity_orig_of(cpu); ++ capacity_orig = arch_scale_cpu_capacity(cpu); + capacity_orig_thermal = capacity_orig - arch_scale_thermal_pressure(cpu); + + /* +@@ -7515,7 +7515,7 @@ select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target) + * Look for the CPU with best capacity. + */ + else if (fits < 0) +- cpu_cap = capacity_orig_of(cpu) - thermal_load_avg(cpu_rq(cpu)); ++ cpu_cap = arch_scale_cpu_capacity(cpu) - thermal_load_avg(cpu_rq(cpu)); + + /* + * First, select CPU which fits better (-1 being better than 0). +@@ -7757,7 +7757,7 @@ cpu_util(int cpu, struct task_struct *p, int dst_cpu, int boost) + util = max(util, util_est); + } + +- return min(util, capacity_orig_of(cpu)); ++ return min(util, arch_scale_cpu_capacity(cpu)); + } + + unsigned long cpu_util_cfs(int cpu) +@@ -9544,8 +9544,6 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) + unsigned long capacity = scale_rt_capacity(cpu); + struct sched_group *sdg = sd->groups; + +- cpu_rq(cpu)->cpu_capacity_orig = arch_scale_cpu_capacity(cpu); +- + if (!capacity) + capacity = 1; + +@@ -9621,7 +9619,7 @@ static inline int + check_cpu_capacity(struct rq *rq, struct sched_domain *sd) + { + return ((rq->cpu_capacity * sd->imbalance_pct) < +- (rq->cpu_capacity_orig * 100)); ++ (arch_scale_cpu_capacity(cpu_of(rq)) * 100)); + } + + /* +@@ -9632,7 +9630,7 @@ check_cpu_capacity(struct rq *rq, struct sched_domain *sd) + static inline int check_misfit_status(struct rq *rq, struct sched_domain *sd) + { + return rq->misfit_task_load && +- (rq->cpu_capacity_orig < rq->rd->max_cpu_capacity || ++ (arch_scale_cpu_capacity(rq->cpu) < rq->rd->max_cpu_capacity || + check_cpu_capacity(rq, sd)); + } + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index b89223a973168..91b1ee0d81fce 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -519,7 +519,7 @@ static inline bool rt_task_fits_capacity(struct task_struct *p, int cpu) + min_cap = uclamp_eff_value(p, UCLAMP_MIN); + max_cap = uclamp_eff_value(p, UCLAMP_MAX); + +- cpu_cap = capacity_orig_of(cpu); ++ cpu_cap = arch_scale_cpu_capacity(cpu); + + return cpu_cap >= min(min_cap, max_cap); + } +diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h +index d48c6a292a83d..f84b2e9feeb6d 100644 +--- a/kernel/sched/sched.h ++++ b/kernel/sched/sched.h +@@ -1048,7 +1048,6 @@ struct rq { + struct sched_domain __rcu *sd; + + unsigned long cpu_capacity; +- unsigned long cpu_capacity_orig; + + struct balance_callback *balance_callback; + +@@ -2985,11 +2984,6 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} + #endif + + #ifdef CONFIG_SMP +-static inline unsigned long capacity_orig_of(int cpu) +-{ +- return cpu_rq(cpu)->cpu_capacity_orig; +-} +- + /** + * enum cpu_util_type - CPU utilization type + * @FREQUENCY_UTIL: Utilization used to select frequency +diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c +index 2ed884bb36213..c61698cff0f3a 100644 +--- a/kernel/sched/topology.c ++++ b/kernel/sched/topology.c +@@ -2486,12 +2486,15 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att + /* Attach the domains */ + rcu_read_lock(); + for_each_cpu(i, cpu_map) { ++ unsigned long capacity; ++ + rq = cpu_rq(i); + sd = *per_cpu_ptr(d.sd, i); + ++ capacity = arch_scale_cpu_capacity(i); + /* Use READ_ONCE()/WRITE_ONCE() to avoid load/store tearing: */ +- if (rq->cpu_capacity_orig > READ_ONCE(d.rd->max_cpu_capacity)) +- WRITE_ONCE(d.rd->max_cpu_capacity, rq->cpu_capacity_orig); ++ if (capacity > READ_ONCE(d.rd->max_cpu_capacity)) ++ WRITE_ONCE(d.rd->max_cpu_capacity, capacity); + + cpu_attach_domain(sd, d.rd, i); + } +-- +2.39.5 + diff --git a/queue-6.6/scsi-ufs-qcom-fix-dev-reference-leaked-through-of_qc.patch b/queue-6.6/scsi-ufs-qcom-fix-dev-reference-leaked-through-of_qc.patch new file mode 100644 index 0000000000..50e185a60d --- /dev/null +++ b/queue-6.6/scsi-ufs-qcom-fix-dev-reference-leaked-through-of_qc.patch @@ -0,0 +1,42 @@ +From caf79cff3aded95c4b9003cddc1d8117adcc74a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jan 2025 14:18:52 +0000 +Subject: scsi: ufs: qcom: fix dev reference leaked through of_qcom_ice_get + +From: Tudor Ambarus + +[ Upstream commit ded40f32b55f7f2f4ed9627dd3c37a1fe89ed8c6 ] + +The driver leaks the device reference taken with +of_find_device_by_node(). Fix the leak by using devm_of_qcom_ice_get(). + +Fixes: 56541c7c4468 ("scsi: ufs: ufs-qcom: Switch to the new ICE API") +Cc: stable@vger.kernel.org +Signed-off-by: Tudor Ambarus +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Abel Vesa +Acked-by: Martin K. Petersen # SCSI +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20250117-qcom-ice-fix-dev-leak-v2-3-1ffa5b6884cb@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/ufs/host/ufs-qcom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c +index 51ed40529f9a7..c6417ef074a47 100644 +--- a/drivers/ufs/host/ufs-qcom.c ++++ b/drivers/ufs/host/ufs-qcom.c +@@ -121,7 +121,7 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) + struct device *dev = hba->dev; + struct qcom_ice *ice; + +- ice = of_qcom_ice_get(dev); ++ ice = devm_of_qcom_ice_get(dev); + if (ice == ERR_PTR(-EOPNOTSUPP)) { + dev_warn(dev, "Disabling inline encryption support\n"); + ice = NULL; +-- +2.39.5 + diff --git a/queue-6.6/series b/queue-6.6/series index 673df00e1a..fc293d40dd 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -1 +1,44 @@ module-sign-with-sha512-instead-of-sha1-by-default.patch +memcg-drain-obj-stock-on-cpu-hotplug-teardown.patch +x86-extable-remove-unused-fixup-type-ex_type_copy.patch +x86-mce-use-is_copy_from_user-to-determine-copy-from.patch +tracing-add-__string_len-example.patch +tracing-add-__print_dynamic_array-helper.patch +tracing-verify-event-formats-that-have-p.patch +media-subdev-fix-use-of-sd-enabled_streams-in-call_s.patch +media-subdev-improve-v4l2_subdev_enable-disable_stre.patch +media-subdev-add-v4l2_subdev_is_streaming.patch +media-vimc-skip-.s_stream-for-stopped-entities.patch +soc-qcom-ice-introduce-devm_of_qcom_ice_get.patch +mmc-sdhci-msm-fix-dev-reference-leaked-through-of_qc.patch +auxdisplay-hd44780-convert-to-platform-remove-callba.patch +auxdisplay-hd44780-fix-an-api-misuse-in-hd44780.c.patch +net-dsa-mv88e6xxx-fix-internal-phys-for-6320-family.patch +net-dsa-mv88e6xxx-fix-vtu-methods-for-6320-family.patch +asoc-qcom-q6apm-dai-drop-unused-q6apm_dai_rtd-fields.patch +asoc-q6apm-dai-schedule-all-available-frames-to-avoi.patch +asoc-qcom-lpass-make-asoc_qcom_lpass_cpu_platform_re.patch +asoc-qcom-fix-trivial-code-style-issues.patch +asoc-q6apm-dai-make-use-of-q6apm_get_hw_pointer.patch +iio-adc-ad7768-1-move-setting-of-val-a-bit-later-to-.patch +iio-adc-ad7768-1-fix-conversion-result-sign.patch +arm64-tegra-remove-the-orin-nx-nano-suspend-key.patch +clk-renesas-rzg2l-use-u32-for-flag-and-mux_flags.patch +clk-renesas-rzg2l-add-struct-clk_hw_data.patch +clk-renesas-rzg2l-remove-cpg_sdhi_dsel-from-generic-.patch +clk-renesas-rzg2l-refactor-sd-mux-driver.patch +clk-renesas-r9a07g04-34-use-sel_sdhi1_sts-status-con.patch +clk-renesas-r9a07g04-34-fix-typo-for-sel_shdi-variab.patch +clk-renesas-r9a07g043-fix-hp-clock-source-for-rz-fiv.patch +of-resolver-simplify-of_resolve_phandles-using-__fre.patch +of-resolver-fix-device-node-refcount-leakage-in-of_r.patch +pci-fix-reference-leak-in-pci_register_host_bridge.patch +s390-virtio_ccw-fix-virtual-vs-physical-address-conf.patch +s390-virtio_ccw-don-t-allocate-assign-airqs-for-non-.patch +scsi-ufs-qcom-fix-dev-reference-leaked-through-of_qc.patch +s390-sclp-allow-user-space-to-provide-pci-reports-fo.patch +s390-pci-report-pci-error-recovery-results-via-sclp.patch +s390-pci-support-mmap-of-pci-resources-except-for-is.patch +sched-topology-consolidate-and-clean-up-access-to-a-.patch +sched-cpufreq-rework-schedutil-governor-performance-.patch +cpufreq-sched-explicitly-synchronize-limits_changed-.patch diff --git a/queue-6.6/soc-qcom-ice-introduce-devm_of_qcom_ice_get.patch b/queue-6.6/soc-qcom-ice-introduce-devm_of_qcom_ice_get.patch new file mode 100644 index 0000000000..acd5a767fe --- /dev/null +++ b/queue-6.6/soc-qcom-ice-introduce-devm_of_qcom_ice_get.patch @@ -0,0 +1,107 @@ +From 40b27638f9cbdfc2f28f6e2019f479968a200d8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jan 2025 14:18:50 +0000 +Subject: soc: qcom: ice: introduce devm_of_qcom_ice_get + +From: Tudor Ambarus + +[ Upstream commit 1c13d6060d612601a61423f2e8fbf9e48126acca ] + +Callers of of_qcom_ice_get() leak the device reference taken by +of_find_device_by_node(). Introduce devm variant for of_qcom_ice_get(). +Existing consumers need the ICE instance for the entire life of their +device, thus exporting qcom_ice_put() is not required. + +Signed-off-by: Tudor Ambarus +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Abel Vesa +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20250117-qcom-ice-fix-dev-leak-v2-1-1ffa5b6884cb@linaro.org +Signed-off-by: Bjorn Andersson +Stable-dep-of: cbef7442fba5 ("mmc: sdhci-msm: fix dev reference leaked through of_qcom_ice_get") +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ice.c | 48 ++++++++++++++++++++++++++++++++++++++++++ + include/soc/qcom/ice.h | 2 ++ + 2 files changed, 50 insertions(+) + +diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c +index fbab7fe5c652b..d6e205e3812a9 100644 +--- a/drivers/soc/qcom/ice.c ++++ b/drivers/soc/qcom/ice.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -328,6 +329,53 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) + } + EXPORT_SYMBOL_GPL(of_qcom_ice_get); + ++static void qcom_ice_put(const struct qcom_ice *ice) ++{ ++ struct platform_device *pdev = to_platform_device(ice->dev); ++ ++ if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice")) ++ platform_device_put(pdev); ++} ++ ++static void devm_of_qcom_ice_put(struct device *dev, void *res) ++{ ++ qcom_ice_put(*(struct qcom_ice **)res); ++} ++ ++/** ++ * devm_of_qcom_ice_get() - Devres managed helper to get an ICE instance from ++ * a DT node. ++ * @dev: device pointer for the consumer device. ++ * ++ * This function will provide an ICE instance either by creating one for the ++ * consumer device if its DT node provides the 'ice' reg range and the 'ice' ++ * clock (for legacy DT style). On the other hand, if consumer provides a ++ * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already ++ * be created and so this function will return that instead. ++ * ++ * Return: ICE pointer on success, NULL if there is no ICE data provided by the ++ * consumer or ERR_PTR() on error. ++ */ ++struct qcom_ice *devm_of_qcom_ice_get(struct device *dev) ++{ ++ struct qcom_ice *ice, **dr; ++ ++ dr = devres_alloc(devm_of_qcom_ice_put, sizeof(*dr), GFP_KERNEL); ++ if (!dr) ++ return ERR_PTR(-ENOMEM); ++ ++ ice = of_qcom_ice_get(dev); ++ if (!IS_ERR_OR_NULL(ice)) { ++ *dr = ice; ++ devres_add(dev, dr); ++ } else { ++ devres_free(dr); ++ } ++ ++ return ice; ++} ++EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get); ++ + static int qcom_ice_probe(struct platform_device *pdev) + { + struct qcom_ice *engine; +diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h +index 5870a94599a25..d5f6a228df659 100644 +--- a/include/soc/qcom/ice.h ++++ b/include/soc/qcom/ice.h +@@ -34,4 +34,6 @@ int qcom_ice_program_key(struct qcom_ice *ice, + int slot); + int qcom_ice_evict_key(struct qcom_ice *ice, int slot); + struct qcom_ice *of_qcom_ice_get(struct device *dev); ++struct qcom_ice *devm_of_qcom_ice_get(struct device *dev); ++ + #endif /* __QCOM_ICE_H__ */ +-- +2.39.5 + diff --git a/queue-6.6/tracing-add-__print_dynamic_array-helper.patch b/queue-6.6/tracing-add-__print_dynamic_array-helper.patch new file mode 100644 index 0000000000..1e145b86c3 --- /dev/null +++ b/queue-6.6/tracing-add-__print_dynamic_array-helper.patch @@ -0,0 +1,94 @@ +From 6df2d8dfa5e9dfaac719bc16a39fc3bdb0e18a3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Oct 2024 19:36:28 +0000 +Subject: tracing: Add __print_dynamic_array() helper + +From: Steven Rostedt + +[ Upstream commit e52750fb1458ae9ea5860a08ed7a149185bc5b97 ] + +When printing a dynamic array in a trace event, the method is rather ugly. +It has the format of: + + __print_array(__get_dynamic_array(array), + __get_dynmaic_array_len(array) / el_size, el_size) + +Since dynamic arrays are known to the tracing infrastructure, create a +helper macro that does the above for you. + + __print_dynamic_array(array, el_size) + +Which would expand to the same output. + +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Avadhut Naik +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Qiuxu Zhuo +Link: https://lore.kernel.org/r/20241022194158.110073-3-avadhut.naik@amd.com +Stable-dep-of: ea8d7647f9dd ("tracing: Verify event formats that have "%*p.."") +Signed-off-by: Sasha Levin +--- + include/trace/stages/stage3_trace_output.h | 8 ++++++++ + include/trace/stages/stage7_class_define.h | 1 + + samples/trace_events/trace-events-sample.h | 7 ++++++- + 3 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/include/trace/stages/stage3_trace_output.h b/include/trace/stages/stage3_trace_output.h +index c1fb1355d3094..1e7b0bef95f52 100644 +--- a/include/trace/stages/stage3_trace_output.h ++++ b/include/trace/stages/stage3_trace_output.h +@@ -119,6 +119,14 @@ + trace_print_array_seq(p, array, count, el_size); \ + }) + ++#undef __print_dynamic_array ++#define __print_dynamic_array(array, el_size) \ ++ ({ \ ++ __print_array(__get_dynamic_array(array), \ ++ __get_dynamic_array_len(array) / (el_size), \ ++ (el_size)); \ ++ }) ++ + #undef __print_hex_dump + #define __print_hex_dump(prefix_str, prefix_type, \ + rowsize, groupsize, buf, len, ascii) \ +diff --git a/include/trace/stages/stage7_class_define.h b/include/trace/stages/stage7_class_define.h +index bcb960d16fc0e..fcd564a590f43 100644 +--- a/include/trace/stages/stage7_class_define.h ++++ b/include/trace/stages/stage7_class_define.h +@@ -22,6 +22,7 @@ + #undef __get_rel_cpumask + #undef __get_rel_sockaddr + #undef __print_array ++#undef __print_dynamic_array + #undef __print_hex_dump + #undef __get_buf + +diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h +index 04541dfbd44cc..24ec968d481fb 100644 +--- a/samples/trace_events/trace-events-sample.h ++++ b/samples/trace_events/trace-events-sample.h +@@ -317,7 +317,7 @@ TRACE_EVENT(foo_bar, + __assign_cpumask(cpum, cpumask_bits(mask)); + ), + +- TP_printk("foo %s %d %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, ++ TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, + + /* + * Notice here the use of some helper functions. This includes: +@@ -361,6 +361,11 @@ TRACE_EVENT(foo_bar, + __print_array(__get_dynamic_array(list), + __get_dynamic_array_len(list) / sizeof(int), + sizeof(int)), ++ ++/* A shortcut is to use __print_dynamic_array for dynamic arrays */ ++ ++ __print_dynamic_array(list, sizeof(int)), ++ + __get_str(str), __get_str(lstr), + __get_bitmask(cpus), __get_cpumask(cpum), + __get_str(vstr)) +-- +2.39.5 + diff --git a/queue-6.6/tracing-add-__string_len-example.patch b/queue-6.6/tracing-add-__string_len-example.patch new file mode 100644 index 0000000000..f496abe19c --- /dev/null +++ b/queue-6.6/tracing-add-__string_len-example.patch @@ -0,0 +1,63 @@ +From 2434468173bcf0cd40b4214e532ae96afe32f738 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Feb 2024 15:28:27 -0500 +Subject: tracing: Add __string_len() example + +From: Steven Rostedt (Google) + +[ Upstream commit dd6ae6d90a84d4bec49887c7aa2b22aa1c8b2897 ] + +There's no example code that uses __string_len(), and since the sample +code is used for testing the event logic, add a use case. + +Link: https://lore.kernel.org/linux-trace-kernel/20240223152827.5f9f78e2@gandalf.local.home + +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: ea8d7647f9dd ("tracing: Verify event formats that have "%*p.."") +Signed-off-by: Sasha Levin +--- + samples/trace_events/trace-events-sample.h | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h +index 1c6b843b8c4ee..04541dfbd44cc 100644 +--- a/samples/trace_events/trace-events-sample.h ++++ b/samples/trace_events/trace-events-sample.h +@@ -302,6 +302,7 @@ TRACE_EVENT(foo_bar, + __bitmask( cpus, num_possible_cpus() ) + __cpumask( cpum ) + __vstring( vstr, fmt, va ) ++ __string_len( lstr, foo, bar / 2 < strlen(foo) ? bar / 2 : strlen(foo) ) + ), + + TP_fast_assign( +@@ -310,12 +311,13 @@ TRACE_EVENT(foo_bar, + memcpy(__get_dynamic_array(list), lst, + __length_of(lst) * sizeof(int)); + __assign_str(str, string); ++ __assign_str(lstr, foo); + __assign_vstr(vstr, fmt, va); + __assign_bitmask(cpus, cpumask_bits(mask), num_possible_cpus()); + __assign_cpumask(cpum, cpumask_bits(mask)); + ), + +- TP_printk("foo %s %d %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, ++ TP_printk("foo %s %d %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, + + /* + * Notice here the use of some helper functions. This includes: +@@ -359,7 +361,8 @@ TRACE_EVENT(foo_bar, + __print_array(__get_dynamic_array(list), + __get_dynamic_array_len(list) / sizeof(int), + sizeof(int)), +- __get_str(str), __get_bitmask(cpus), __get_cpumask(cpum), ++ __get_str(str), __get_str(lstr), ++ __get_bitmask(cpus), __get_cpumask(cpum), + __get_str(vstr)) + ); + +-- +2.39.5 + diff --git a/queue-6.6/tracing-verify-event-formats-that-have-p.patch b/queue-6.6/tracing-verify-event-formats-that-have-p.patch new file mode 100644 index 0000000000..2b9096898c --- /dev/null +++ b/queue-6.6/tracing-verify-event-formats-that-have-p.patch @@ -0,0 +1,93 @@ +From 38da287b837b0b7d2fffa21e297ee7abdf7eff5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Mar 2025 19:53:11 -0400 +Subject: tracing: Verify event formats that have "%*p.." + +From: Steven Rostedt + +[ Upstream commit ea8d7647f9ddf1f81e2027ed305299797299aa03 ] + +The trace event verifier checks the formats of trace events to make sure +that they do not point at memory that is not in the trace event itself or +in data that will never be freed. If an event references data that was +allocated when the event triggered and that same data is freed before the +event is read, then the kernel can crash by reading freed memory. + +The verifier runs at boot up (or module load) and scans the print formats +of the events and checks their arguments to make sure that dereferenced +pointers are safe. If the format uses "%*p.." the verifier will ignore it, +and that could be dangerous. Cover this case as well. + +Also add to the sample code a use case of "%*pbl". + +Link: https://lore.kernel.org/all/bcba4d76-2c3f-4d11-baf0-02905db953dd@oracle.com/ + +Cc: stable@vger.kernel.org +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Fixes: 5013f454a352c ("tracing: Add check of trace event print fmts for dereferencing pointers") +Link: https://lore.kernel.org/20250327195311.2d89ec66@gandalf.local.home +Reported-by: Libo Chen +Reviewed-by: Libo Chen +Tested-by: Libo Chen +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events.c | 7 +++++++ + samples/trace_events/trace-events-sample.h | 8 ++++++-- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 1a936978c2b1a..5f74e9f9c8a73 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -470,6 +470,7 @@ static void test_event_printk(struct trace_event_call *call) + case '%': + continue; + case 'p': ++ do_pointer: + /* Find dereferencing fields */ + switch (fmt[i + 1]) { + case 'B': case 'R': case 'r': +@@ -498,6 +499,12 @@ static void test_event_printk(struct trace_event_call *call) + continue; + if (fmt[i + j] == '*') { + star = true; ++ /* Handle %*pbl case */ ++ if (!j && fmt[i + 1] == 'p') { ++ arg++; ++ i++; ++ goto do_pointer; ++ } + continue; + } + if ((fmt[i + j] == 's')) { +diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h +index 24ec968d481fb..06be777b3b14b 100644 +--- a/samples/trace_events/trace-events-sample.h ++++ b/samples/trace_events/trace-events-sample.h +@@ -317,7 +317,8 @@ TRACE_EVENT(foo_bar, + __assign_cpumask(cpum, cpumask_bits(mask)); + ), + +- TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, ++ TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s [%d] %*pbl", ++ __entry->foo, __entry->bar, + + /* + * Notice here the use of some helper functions. This includes: +@@ -368,7 +369,10 @@ TRACE_EVENT(foo_bar, + + __get_str(str), __get_str(lstr), + __get_bitmask(cpus), __get_cpumask(cpum), +- __get_str(vstr)) ++ __get_str(vstr), ++ __get_dynamic_array_len(cpus), ++ __get_dynamic_array_len(cpus), ++ __get_dynamic_array(cpus)) + ); + + /* +-- +2.39.5 + diff --git a/queue-6.6/x86-extable-remove-unused-fixup-type-ex_type_copy.patch b/queue-6.6/x86-extable-remove-unused-fixup-type-ex_type_copy.patch new file mode 100644 index 0000000000..6d096e5a13 --- /dev/null +++ b/queue-6.6/x86-extable-remove-unused-fixup-type-ex_type_copy.patch @@ -0,0 +1,100 @@ +From 70730dbdbf50453acfc8f859de449e0b91d8ac9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Feb 2024 16:26:25 +0800 +Subject: x86/extable: Remove unused fixup type EX_TYPE_COPY + +From: Tong Tiangen + +[ Upstream commit cb517619f96718a4c3c2534a3124177633f8998d ] + +After + + 034ff37d3407 ("x86: rewrite '__copy_user_nocache' function") + +rewrote __copy_user_nocache() to use EX_TYPE_UACCESS instead of the +EX_TYPE_COPY exception type, there are no more EX_TYPE_COPY users, so +remove it. + + [ bp: Massage commit message. ] + +Signed-off-by: Tong Tiangen +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20240204082627.3892816-2-tongtiangen@huawei.com +Stable-dep-of: 1a15bb8303b6 ("x86/mce: use is_copy_from_user() to determine copy-from-user context") +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/asm.h | 3 --- + arch/x86/include/asm/extable_fixup_types.h | 2 +- + arch/x86/kernel/cpu/mce/severity.c | 1 - + arch/x86/mm/extable.c | 9 --------- + 4 files changed, 1 insertion(+), 14 deletions(-) + +diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h +index ca8eed1d496ab..2bec0c89a95c2 100644 +--- a/arch/x86/include/asm/asm.h ++++ b/arch/x86/include/asm/asm.h +@@ -229,9 +229,6 @@ register unsigned long current_stack_pointer asm(_ASM_SP); + #define _ASM_EXTABLE_UA(from, to) \ + _ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS) + +-#define _ASM_EXTABLE_CPY(from, to) \ +- _ASM_EXTABLE_TYPE(from, to, EX_TYPE_COPY) +- + #define _ASM_EXTABLE_FAULT(from, to) \ + _ASM_EXTABLE_TYPE(from, to, EX_TYPE_FAULT) + +diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h +index 991e31cfde94c..afad9c0b07e0c 100644 +--- a/arch/x86/include/asm/extable_fixup_types.h ++++ b/arch/x86/include/asm/extable_fixup_types.h +@@ -36,7 +36,7 @@ + #define EX_TYPE_DEFAULT 1 + #define EX_TYPE_FAULT 2 + #define EX_TYPE_UACCESS 3 +-#define EX_TYPE_COPY 4 ++/* unused, was: #define EX_TYPE_COPY 4 */ + #define EX_TYPE_CLEAR_FS 5 + #define EX_TYPE_FPU_RESTORE 6 + #define EX_TYPE_BPF 7 +diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c +index c4477162c07d1..bca780fa5e577 100644 +--- a/arch/x86/kernel/cpu/mce/severity.c ++++ b/arch/x86/kernel/cpu/mce/severity.c +@@ -290,7 +290,6 @@ static noinstr int error_context(struct mce *m, struct pt_regs *regs) + + switch (fixup_type) { + case EX_TYPE_UACCESS: +- case EX_TYPE_COPY: + if (!copy_user) + return IN_KERNEL; + m->kflags |= MCE_IN_KERNEL_COPYIN; +diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c +index 271dcb2deabc3..2354c0156e51c 100644 +--- a/arch/x86/mm/extable.c ++++ b/arch/x86/mm/extable.c +@@ -163,13 +163,6 @@ static bool ex_handler_uaccess(const struct exception_table_entry *fixup, + return ex_handler_default(fixup, regs); + } + +-static bool ex_handler_copy(const struct exception_table_entry *fixup, +- struct pt_regs *regs, int trapnr) +-{ +- WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?"); +- return ex_handler_fault(fixup, regs, trapnr); +-} +- + static bool ex_handler_msr(const struct exception_table_entry *fixup, + struct pt_regs *regs, bool wrmsr, bool safe, int reg) + { +@@ -267,8 +260,6 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, + return ex_handler_fault(e, regs, trapnr); + case EX_TYPE_UACCESS: + return ex_handler_uaccess(e, regs, trapnr, fault_addr); +- case EX_TYPE_COPY: +- return ex_handler_copy(e, regs, trapnr); + case EX_TYPE_CLEAR_FS: + return ex_handler_clear_fs(e, regs); + case EX_TYPE_FPU_RESTORE: +-- +2.39.5 + diff --git a/queue-6.6/x86-mce-use-is_copy_from_user-to-determine-copy-from.patch b/queue-6.6/x86-mce-use-is_copy_from_user-to-determine-copy-from.patch new file mode 100644 index 0000000000..666eb09868 --- /dev/null +++ b/queue-6.6/x86-mce-use-is_copy_from_user-to-determine-copy-from.patch @@ -0,0 +1,215 @@ +From 5cf79acb14c12a4486de5c5281419719a2098849 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Mar 2025 19:28:50 +0800 +Subject: x86/mce: use is_copy_from_user() to determine copy-from-user context + +From: Shuai Xue + +[ Upstream commit 1a15bb8303b6b104e78028b6c68f76a0d4562134 ] + +Patch series "mm/hwpoison: Fix regressions in memory failure handling", +v4. + +## 1. What am I trying to do: + +This patchset resolves two critical regressions related to memory failure +handling that have appeared in the upstream kernel since version 5.17, as +compared to 5.10 LTS. + + - copyin case: poison found in user page while kernel copying from user space + - instr case: poison found while instruction fetching in user space + +## 2. What is the expected outcome and why + +- For copyin case: + +Kernel can recover from poison found where kernel is doing get_user() or +copy_from_user() if those places get an error return and the kernel return +-EFAULT to the process instead of crashing. More specifily, MCE handler +checks the fixup handler type to decide whether an in kernel #MC can be +recovered. When EX_TYPE_UACCESS is found, the PC jumps to recovery code +specified in _ASM_EXTABLE_FAULT() and return a -EFAULT to user space. + +- For instr case: + +If a poison found while instruction fetching in user space, full recovery +is possible. User process takes #PF, Linux allocates a new page and fills +by reading from storage. + +## 3. What actually happens and why + +- For copyin case: kernel panic since v5.17 + +Commit 4c132d1d844a ("x86/futex: Remove .fixup usage") introduced a new +extable fixup type, EX_TYPE_EFAULT_REG, and later patches updated the +extable fixup type for copy-from-user operations, changing it from +EX_TYPE_UACCESS to EX_TYPE_EFAULT_REG. It breaks previous EX_TYPE_UACCESS +handling when posion found in get_user() or copy_from_user(). + +- For instr case: user process is killed by a SIGBUS signal due to #CMCI + and #MCE race + +When an uncorrected memory error is consumed there is a race between the +CMCI from the memory controller reporting an uncorrected error with a UCNA +signature, and the core reporting and SRAR signature machine check when +the data is about to be consumed. + +### Background: why *UN*corrected errors tied to *C*MCI in Intel platform [1] + +Prior to Icelake memory controllers reported patrol scrub events that +detected a previously unseen uncorrected error in memory by signaling a +broadcast machine check with an SRAO (Software Recoverable Action +Optional) signature in the machine check bank. This was overkill because +it's not an urgent problem that no core is on the verge of consuming that +bad data. It's also found that multi SRAO UCE may cause nested MCE +interrupts and finally become an IERR. + +Hence, Intel downgrades the machine check bank signature of patrol scrub +from SRAO to UCNA (Uncorrected, No Action required), and signal changed to +#CMCI. Just to add to the confusion, Linux does take an action (in +uc_decode_notifier()) to try to offline the page despite the UC*NA* +signature name. + +### Background: why #CMCI and #MCE race when poison is consuming in + Intel platform [1] + +Having decided that CMCI/UCNA is the best action for patrol scrub errors, +the memory controller uses it for reads too. But the memory controller is +executing asynchronously from the core, and can't tell the difference +between a "real" read and a speculative read. So it will do CMCI/UCNA if +an error is found in any read. + +Thus: + +1) Core is clever and thinks address A is needed soon, issues a + speculative read. + +2) Core finds it is going to use address A soon after sending the read + request + +3) The CMCI from the memory controller is in a race with MCE from the + core that will soon try to retire the load from address A. + +Quite often (because speculation has got better) the CMCI from the memory +controller is delivered before the core is committed to the instruction +reading address A, so the interrupt is taken, and Linux offlines the page +(marking it as poison). + +## Why user process is killed for instr case + +Commit 046545a661af ("mm/hwpoison: fix error page recovered but reported +"not recovered"") tries to fix noise message "Memory error not recovered" +and skips duplicate SIGBUSs due to the race. But it also introduced a bug +that kill_accessing_process() return -EHWPOISON for instr case, as result, +kill_me_maybe() send a SIGBUS to user process. + +# 4. The fix, in my opinion, should be: + +- For copyin case: + +The key point is whether the error context is in a read from user memory. +We do not care about the ex-type if we know its a MOV reading from +userspace. + +is_copy_from_user() return true when both of the following two checks are +true: + + - the current instruction is copy + - source address is user memory + +If copy_user is true, we set + +m->kflags |= MCE_IN_KERNEL_COPYIN | MCE_IN_KERNEL_RECOV; + +Then do_machine_check() will try fixup_exception() first. + +- For instr case: let kill_accessing_process() return 0 to prevent a SIGBUS. + +- For patch 3: + +The return value of memory_failure() is quite important while discussed +instr case regression with Tony and Miaohe for patch 2, so add comment +about the return value. + +This patch (of 3): + +Commit 4c132d1d844a ("x86/futex: Remove .fixup usage") introduced a new +extable fixup type, EX_TYPE_EFAULT_REG, and commit 4c132d1d844a +("x86/futex: Remove .fixup usage") updated the extable fixup type for +copy-from-user operations, changing it from EX_TYPE_UACCESS to +EX_TYPE_EFAULT_REG. The error context for copy-from-user operations no +longer functions as an in-kernel recovery context. Consequently, the +error context for copy-from-user operations no longer functions as an +in-kernel recovery context, resulting in kernel panics with the message: +"Machine check: Data load in unrecoverable area of kernel." + +To address this, it is crucial to identify if an error context involves a +read operation from user memory. The function is_copy_from_user() can be +utilized to determine: + + - the current operation is copy + - when reading user memory + +When these conditions are met, is_copy_from_user() will return true, +confirming that it is indeed a direct copy from user memory. This check +is essential for correctly handling the context of errors in these +operations without relying on the extable fixup types that previously +allowed for in-kernel recovery. + +So, use is_copy_from_user() to determine if a context is copy user directly. + +Link: https://lkml.kernel.org/r/20250312112852.82415-1-xueshuai@linux.alibaba.com +Link: https://lkml.kernel.org/r/20250312112852.82415-2-xueshuai@linux.alibaba.com +Fixes: 4c132d1d844a ("x86/futex: Remove .fixup usage") +Signed-off-by: Shuai Xue +Suggested-by: Peter Zijlstra +Acked-by: Borislav Petkov (AMD) +Tested-by: Tony Luck +Cc: Baolin Wang +Cc: Borislav Betkov +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: "H. Peter Anvin" +Cc: Ingo Molnar +Cc: Josh Poimboeuf +Cc: Miaohe Lin +Cc: Naoya Horiguchi +Cc: Ruidong Tian +Cc: Thomas Gleinxer +Cc: Yazen Ghannam +Cc: Jane Chu +Cc: Jarkko Sakkinen +Cc: Jonathan Cameron +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/mce/severity.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c +index bca780fa5e577..9c5754229d6ed 100644 +--- a/arch/x86/kernel/cpu/mce/severity.c ++++ b/arch/x86/kernel/cpu/mce/severity.c +@@ -288,13 +288,12 @@ static noinstr int error_context(struct mce *m, struct pt_regs *regs) + copy_user = is_copy_from_user(regs); + instrumentation_end(); + +- switch (fixup_type) { +- case EX_TYPE_UACCESS: +- if (!copy_user) +- return IN_KERNEL; +- m->kflags |= MCE_IN_KERNEL_COPYIN; +- fallthrough; ++ if (copy_user) { ++ m->kflags |= MCE_IN_KERNEL_COPYIN | MCE_IN_KERNEL_RECOV; ++ return IN_KERNEL_RECOV; ++ } + ++ switch (fixup_type) { + case EX_TYPE_FAULT_MCE_SAFE: + case EX_TYPE_DEFAULT_MCE_SAFE: + m->kflags |= MCE_IN_KERNEL_RECOV; +-- +2.39.5 +