From 76645c1fd682c9df746c3f7c149b868ceff914fb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 23 Apr 2026 09:58:01 +0200 Subject: [PATCH 001/655] spi: mpc52xx: clean up interrupt handling The driver is relying on the assumption that the invalid interrupt 0 can be freed without any side effects, but that is not the case on architectures like x86 where it would trigger a warning about freeing an already free interrupt. This should not cause any trouble on powerpc where this driver is used, but make the code more portable (and obviously correct) by making sure that the interrupts have been requested before freeing them. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260423075801.2252318-1-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-mpc52xx.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 924d820448fb..04c2270cd2cf 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -472,13 +472,15 @@ static int mpc52xx_spi_probe(struct platform_device *op) if (ms->irq0 && ms->irq1) { rc = request_irq(ms->irq0, mpc52xx_spi_irq, 0, "mpc5200-spi-modf", ms); - rc |= request_irq(ms->irq1, mpc52xx_spi_irq, 0, - "mpc5200-spi-spif", ms); - if (rc) { - free_irq(ms->irq0, ms); - free_irq(ms->irq1, ms); - ms->irq0 = ms->irq1 = 0; + if (rc == 0) { + rc = request_irq(ms->irq1, mpc52xx_spi_irq, 0, + "mpc5200-spi-spif", ms); + if (rc) + free_irq(ms->irq0, ms); } + + if (rc) + ms->irq0 = ms->irq1 = 0; } else { /* operate in polled mode */ ms->irq0 = ms->irq1 = 0; @@ -498,8 +500,10 @@ static int mpc52xx_spi_probe(struct platform_device *op) err_register: dev_err(&ms->host->dev, "initialization failed\n"); - free_irq(ms->irq0, ms); - free_irq(ms->irq1, ms); + if (ms->irq0) { + free_irq(ms->irq0, ms); + free_irq(ms->irq1, ms); + } cancel_work_sync(&ms->work); err_gpio: while (i-- > 0) @@ -522,8 +526,10 @@ static void mpc52xx_spi_remove(struct platform_device *op) spi_unregister_controller(host); - free_irq(ms->irq0, ms); - free_irq(ms->irq1, ms); + if (ms->irq0) { + free_irq(ms->irq0, ms); + free_irq(ms->irq1, ms); + } cancel_work_sync(&ms->work); From a8fccc792f42bbaa1bec5d9e1e0a30ffa9654e2f Mon Sep 17 00:00:00 2001 From: Louis-Alexis Eyraud Date: Tue, 14 Apr 2026 13:44:10 +0200 Subject: [PATCH 002/655] regulator: dt-bindings: mt6360: add buck regulator supplies MT6360 PMIC provides 2 buck and 6 ldo regulators, that have each one a separate supply. Currently, the supplies for the ldo regulators are described in the dt-bindings but the ones for the buck regulators are not. Add the descriptions for these missing supplies. Signed-off-by: Louis-Alexis Eyraud Link: https://patch.msgid.link/20260414-mtk-g1200-pmic-cleanup-v1-1-2a7193ed4e93@collabora.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/mt6360-regulator.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/mt6360-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6360-regulator.yaml index 9c879bc3c360..cbb74e8e875d 100644 --- a/Documentation/devicetree/bindings/regulator/mt6360-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/mt6360-regulator.yaml @@ -17,6 +17,10 @@ properties: compatible: const: mediatek,mt6360-regulator + BUCK1_VIN-supply: + description: Input supply phandle(s) for BUCK1 + BUCK2_VIN-supply: + description: Input supply phandle(s) for BUCK2 LDO_VIN1-supply: description: Input supply phandle(s) for LDO1/2/3 LDO_VIN2-supply: From 63f34e35f87f32fb8e92525516e5eaf30cbf0973 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 21 Apr 2026 14:36:14 +0200 Subject: [PATCH 003/655] spi: cadence: rename probe error labels The "clk_dis_all" error label is not used to disable clocks since commit f64b1600f92e ("spi: spi-cadence: Use helper function devm_clk_get_enabled()"). Similarly, "remove_ctlr" drops a reference rather than deregisters the controller. Rename the labels after what they do. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260421123615.1533617-4-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 891e2ba36958..f27586151ca9 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -656,21 +656,21 @@ static int cdns_spi_probe(struct platform_device *pdev) xspi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(xspi->regs)) { ret = PTR_ERR(xspi->regs); - goto remove_ctlr; + goto err_put_ctlr; } xspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); if (IS_ERR(xspi->pclk)) { dev_err(&pdev->dev, "pclk clock not found.\n"); ret = PTR_ERR(xspi->pclk); - goto remove_ctlr; + goto err_put_ctlr; } xspi->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi"); if (IS_ERR(xspi->rstc)) { ret = dev_err_probe(&pdev->dev, PTR_ERR(xspi->rstc), "Cannot get SPI reset.\n"); - goto remove_ctlr; + goto err_put_ctlr; } reset_control_assert(xspi->rstc); @@ -680,7 +680,7 @@ static int cdns_spi_probe(struct platform_device *pdev) if (IS_ERR(xspi->ref_clk)) { dev_err(&pdev->dev, "ref_clk clock not found.\n"); ret = PTR_ERR(xspi->ref_clk); - goto remove_ctlr; + goto err_put_ctlr; } if (!spi_controller_is_target(ctlr)) { @@ -710,7 +710,7 @@ static int cdns_spi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = irq; - goto clk_dis_all; + goto err_disable_rpm; } ret = devm_request_irq(&pdev->dev, irq, cdns_spi_irq, @@ -718,7 +718,7 @@ static int cdns_spi_probe(struct platform_device *pdev) if (ret != 0) { ret = -ENXIO; dev_err(&pdev->dev, "request_irq failed\n"); - goto clk_dis_all; + goto err_disable_rpm; } ctlr->use_gpio_descriptors = true; @@ -748,7 +748,7 @@ static int cdns_spi_probe(struct platform_device *pdev) ret = spi_register_controller(ctlr); if (ret) { dev_err(&pdev->dev, "spi_register_controller failed\n"); - goto clk_dis_all; + goto err_disable_rpm; } if (!spi_controller_is_target(ctlr)) @@ -756,14 +756,14 @@ static int cdns_spi_probe(struct platform_device *pdev) return ret; -clk_dis_all: +err_disable_rpm: if (!spi_controller_is_target(ctlr)) { pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); } -remove_ctlr: +err_put_ctlr: spi_controller_put(ctlr); return ret; } From bf7b648acd48ae5b9e265727c84b4e0a4a33727b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 21 Apr 2026 14:36:15 +0200 Subject: [PATCH 004/655] spi: cadence: clean up probe return value Drop the redundant initialisation and return explicit zero on successful probe to make the code more readable. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260421123615.1533617-5-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index f27586151ca9..d108e89fda22 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -635,7 +635,7 @@ static int cdns_target_abort(struct spi_controller *ctlr) */ static int cdns_spi_probe(struct platform_device *pdev) { - int ret = 0, irq; + int ret, irq; struct spi_controller *ctlr; struct cdns_spi *xspi; u32 num_cs; @@ -754,7 +754,7 @@ static int cdns_spi_probe(struct platform_device *pdev) if (!spi_controller_is_target(ctlr)) pm_runtime_put_autosuspend(&pdev->dev); - return ret; + return 0; err_disable_rpm: if (!spi_controller_is_target(ctlr)) { From edbaae583ead2c06aea756b0fafd5fa7a1e89fc1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 21 Apr 2026 14:53:53 +0200 Subject: [PATCH 005/655] spi: cadence-quadspi: clean up disable runtime pm quirk Commit 30dbc1c8d50f ("spi: cadence-qspi: defer runtime support on socfpga if reset bit is enabled") fixed a warm reset issue on SoCFPGA by disabling runtime PM on that platform. Clean up the quirk implementation by never dropping the runtime PM usage count on probe instead of sprinkling conditionals throughout the driver which makes the code unnecessarily hard to read and maintain. Cc: Khairul Anuar Romli Cc: Adrian Ng Ho Yin Cc: Niravkumar L Rabara Cc: Matthew Gerlach Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260421125354.1534871-6-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 47 +++++++++++++------------------ 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 057381e56a7f..348236ea503d 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1478,7 +1478,6 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) int ret; struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller); struct device *dev = &cqspi->pdev->dev; - const struct cqspi_driver_platdata *ddata = of_device_get_match_data(dev); if (refcount_read(&cqspi->inflight_ops) == 0) return -ENODEV; @@ -1494,18 +1493,15 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) return -EBUSY; } - if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { - ret = pm_runtime_resume_and_get(dev); - if (ret) { - dev_err(&mem->spi->dev, "resume failed with %d\n", ret); - goto dec_inflight_refcount; - } + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(&mem->spi->dev, "resume failed with %d\n", ret); + goto dec_inflight_refcount; } ret = cqspi_mem_process(mem, op); - if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) - pm_runtime_put_autosuspend(dev); + pm_runtime_put_autosuspend(dev); if (ret) dev_err(&mem->spi->dev, "operation failed with %d\n", ret); @@ -1957,13 +1953,11 @@ static int cqspi_probe(struct platform_device *pdev) cqspi->current_cs = -1; cqspi->sclk = 0; - if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { - pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); - pm_runtime_use_autosuspend(dev); - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } + pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(dev); + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); host->num_chipselect = cqspi->num_chipselect; @@ -1993,12 +1987,11 @@ release_dma_chan: if (cqspi->rx_chan) dma_release_channel(cqspi->rx_chan); disable_rpm: - if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); - pm_runtime_dont_use_autosuspend(dev); - } + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); + pm_runtime_dont_use_autosuspend(dev); + cqspi_controller_enable(cqspi, 0); disable_clks: clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); @@ -2033,12 +2026,10 @@ static void cqspi_remove(struct platform_device *pdev) clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); } - if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { - pm_runtime_disable(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); - } + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); } static int cqspi_runtime_suspend(struct device *dev) From 37c9dfa385db995e2c8b369a40c72a53dd644df1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 21 Apr 2026 14:53:54 +0200 Subject: [PATCH 006/655] spi: cadence-quadspi: drop redundant match data lookup Use the OF match data stored at probe instead of looking it up again on driver unbind. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260421125354.1534871-7-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 348236ea503d..aaba1a3ad577 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -2001,13 +2001,10 @@ disable_clks: static void cqspi_remove(struct platform_device *pdev) { - const struct cqspi_driver_platdata *ddata; struct cqspi_st *cqspi = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; + const struct cqspi_driver_platdata *ddata = cqspi->ddata; int ret = 0; - ddata = of_device_get_match_data(dev); - spi_unregister_controller(cqspi->host); refcount_set(&cqspi->refcount, 0); From 565bdf45125a05aa8f622f58f598283f46ba43f4 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Fri, 17 Apr 2026 00:27:54 +0800 Subject: [PATCH 007/655] spi: atcspi200: fix use-after-free when driver unbind DMA resource is initialized after SPI controller registration. So when driver unbind, this can trigger a use-after-free when DMA is torn down while the controller is still alive and triggers DMA transfers. Fixes: 34e3815ea459 ("spi: atcspi200: Add ATCSPI200 SPI controller driver") Signed-off-by: Felix Gu Link: https://patch.msgid.link/20260417-atcspi-v1-1-854831667d63@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-atcspi200.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-atcspi200.c b/drivers/spi/spi-atcspi200.c index 3832d9db3cbf..c5cf1aa2d674 100644 --- a/drivers/spi/spi-atcspi200.c +++ b/drivers/spi/spi-atcspi200.c @@ -575,12 +575,6 @@ static int atcspi_probe(struct platform_device *pdev) if (ret) goto free_controller; - ret = devm_spi_register_controller(&pdev->dev, host); - if (ret) { - dev_err_probe(spi->dev, ret, - "Failed to register SPI controller\n"); - goto free_controller; - } spi->use_dma = false; if (ATCSPI_DMA_SUPPORT) { ret = atcspi_configure_dma(spi); @@ -591,6 +585,13 @@ static int atcspi_probe(struct platform_device *pdev) spi->use_dma = true; } + ret = devm_spi_register_controller(&pdev->dev, host); + if (ret) { + dev_err_probe(spi->dev, ret, + "Failed to register SPI controller\n"); + goto free_controller; + } + return 0; free_controller: From aaea50c3bd768d03ee791b7428ac9b264777b6d7 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Fri, 17 Apr 2026 00:27:55 +0800 Subject: [PATCH 008/655] spi: atcspi200: switch to devm functions Switch to use devm_spi_alloc_host and devm_mutex_init to make code clean. Signed-off-by: Felix Gu Link: https://patch.msgid.link/20260417-atcspi-v1-2-854831667d63@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-atcspi200.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-atcspi200.c b/drivers/spi/spi-atcspi200.c index c5cf1aa2d674..6d4b6aeb3f5b 100644 --- a/drivers/spi/spi-atcspi200.c +++ b/drivers/spi/spi-atcspi200.c @@ -550,7 +550,7 @@ static int atcspi_probe(struct platform_device *pdev) struct resource *mem_res; int ret; - host = spi_alloc_host(&pdev->dev, sizeof(*spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi)); if (!host) return -ENOMEM; @@ -559,21 +559,23 @@ static int atcspi_probe(struct platform_device *pdev) spi->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, host); - mutex_init(&spi->mutex_lock); + ret = devm_mutex_init(&pdev->dev, &spi->mutex_lock); + if (ret) + return ret; ret = atcspi_init_resources(pdev, spi, &mem_res); if (ret) - goto free_controller; + return ret; ret = atcspi_enable_clk(spi); if (ret) - goto free_controller; + return ret; atcspi_init_controller(pdev, spi, host, mem_res); ret = atcspi_setup(spi); if (ret) - goto free_controller; + return ret; spi->use_dma = false; if (ATCSPI_DMA_SUPPORT) { @@ -586,18 +588,11 @@ static int atcspi_probe(struct platform_device *pdev) } ret = devm_spi_register_controller(&pdev->dev, host); - if (ret) { - dev_err_probe(spi->dev, ret, - "Failed to register SPI controller\n"); - goto free_controller; - } + if (ret) + return dev_err_probe(spi->dev, ret, + "Failed to register SPI controller\n"); return 0; - -free_controller: - mutex_destroy(&spi->mutex_lock); - spi_controller_put(host); - return ret; } static int atcspi_suspend(struct device *dev) From 97a7bd8c2c58a6d820df563d1d0f68aafec45477 Mon Sep 17 00:00:00 2001 From: Baolin Liu Date: Fri, 24 Apr 2026 17:06:54 +0800 Subject: [PATCH 009/655] Documentation: proc: fix section numbering in table of contents Commit e24ccaaf7ec4 ("block: remove last remaining traces of IDE documentation") removed the IDE section but left its table of contents entry behind. Fix the stale entry and renumber the following sections. Fixes: e24ccaaf7ec4 ("block: remove last remaining traces of IDE documentation") Signed-off-by: Baolin Liu Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260424090654.19229-1-liubaolin12138@163.com> --- Documentation/filesystems/proc.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index db6167befb7b..3c6e4f52f3e4 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -23,13 +23,13 @@ fixes/update part 1.1 Stefani Seibold June 9 2009 1 Collecting System Information 1.1 Process-Specific Subdirectories 1.2 Kernel data - 1.3 IDE devices in /proc/ide - 1.4 Networking info in /proc/net - 1.5 SCSI info - 1.6 Parallel port info in /proc/parport - 1.7 TTY info in /proc/tty - 1.8 Miscellaneous kernel statistics in /proc/stat - 1.9 Ext4 file system parameters + 1.3 Networking info in /proc/net + 1.4 SCSI info + 1.5 Parallel port info in /proc/parport + 1.6 TTY info in /proc/tty + 1.7 Miscellaneous kernel statistics in /proc/stat + 1.8 Ext4 file system parameters + 1.9 /proc/consoles - Shows registered system consoles 2 Modifying System Parameters From 1cf4830de25495c071a78f307fd66e83ddd586df Mon Sep 17 00:00:00 2001 From: Ninad Naik Date: Mon, 20 Apr 2026 00:15:27 +0530 Subject: [PATCH 010/655] Documentation: fix spelling mistake "stucture" -> "structure" Fixing a spelling mistake in Documentation/trace/histogram-design.rst. Signed-off-by: Ninad Naik Signed-off-by: Jonathan Corbet Message-ID: <20260419184527.779828-1-ninadnaik07@gmail.com> --- Documentation/trace/histogram-design.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/trace/histogram-design.rst b/Documentation/trace/histogram-design.rst index e92f56ebd0b5..41a726cd3536 100644 --- a/Documentation/trace/histogram-design.rst +++ b/Documentation/trace/histogram-design.rst @@ -247,7 +247,7 @@ field's size and offset, is used to grab that subkey's data from the current trace record. Note, the hist field function use to be a function pointer in the -hist_field stucture. Due to spectre mitigation, it was converted into +hist_field structure. Due to spectre mitigation, it was converted into a fn_num and hist_fn_call() is used to call the associated hist field function that corresponds to the fn_num of the hist_field structure. From 49984b903a92ccf9dafeca4ed4f18f86ee9adb72 Mon Sep 17 00:00:00 2001 From: Charlie Jenkins Date: Sat, 18 Apr 2026 17:08:49 -0400 Subject: [PATCH 011/655] Documentation/binfmt-misc.rst: Specify aux vector for "O" flag description Instead of replacing the file path in the argument vector, the file descriptor is passed as AT_EXECFD in the auxilary vector. This appears to have been the case at least since the git port, update the documentation to reflect this. Signed-off-by: Charlie Jenkins Signed-off-by: Jonathan Corbet Message-ID: <20260418-binfmt_misc_doc_update-v1-1-c2e9601ab868@gmail.com> --- Documentation/admin-guide/binfmt-misc.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/binfmt-misc.rst b/Documentation/admin-guide/binfmt-misc.rst index 59cd902e3549..c0a34fbf8022 100644 --- a/Documentation/admin-guide/binfmt-misc.rst +++ b/Documentation/admin-guide/binfmt-misc.rst @@ -68,10 +68,10 @@ Here is what the fields mean: Legacy behavior of binfmt_misc is to pass the full path of the binary to the interpreter as an argument. When this flag is included, binfmt_misc will open the file for reading and pass its - descriptor as an argument, instead of the full path, thus allowing - the interpreter to execute non-readable binaries. This feature - should be used with care - the interpreter has to be trusted not to - emit the contents of the non-readable binary. + descriptor into the auxilary vector with the key "AT_EXECFD", thus + allowing the interpreter to execute non-readable binaries. This + feature should be used with care - the interpreter has to be trusted + not to emit the contents of the non-readable binary. ``C`` - credentials Currently, the behavior of binfmt_misc is to calculate the credentials and security token of the new process according to From 6df140b2b156b0f7cda62ac93d50de7f8acd2d9b Mon Sep 17 00:00:00 2001 From: Zhang Xiaolei Date: Thu, 16 Apr 2026 18:58:53 +0800 Subject: [PATCH 012/655] docs: staging: fix various typos and grammar issues Fix a few typographical and grammatical issues across several staging documentation files to improve readability: - crc32.rst: replace "decide in" with "decide on" - lzo.rst: replace "independent on" with "independent of" - remoteproc.rst: fix word order in dependent clause - static-keys.rst: add hyphen to "low-level" Signed-off-by: Zhang Xiaolei Reviewed-by: Mathieu Poirier Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260416105854.788-1-zxl434815272@gmail.com> --- Documentation/staging/crc32.rst | 2 +- Documentation/staging/lzo.rst | 2 +- Documentation/staging/remoteproc.rst | 2 +- Documentation/staging/static-keys.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/staging/crc32.rst b/Documentation/staging/crc32.rst index 64f3dd430a6c..fc0d9564b99c 100644 --- a/Documentation/staging/crc32.rst +++ b/Documentation/staging/crc32.rst @@ -119,7 +119,7 @@ the byte-at-a-time table method, popularized by Dilip V. Sarwate, v.31 no.8 (August 1988) p. 1008-1013. Here, rather than just shifting one bit of the remainder to decide -in the correct multiple to subtract, we can shift a byte at a time. +on the correct multiple to subtract, we can shift a byte at a time. This produces a 40-bit (rather than a 33-bit) intermediate remainder, and the correct multiple of the polynomial to subtract is found using a 256-entry lookup table indexed by the high 8 bits. diff --git a/Documentation/staging/lzo.rst b/Documentation/staging/lzo.rst index f65b51523014..2d48b2667dd2 100644 --- a/Documentation/staging/lzo.rst +++ b/Documentation/staging/lzo.rst @@ -75,7 +75,7 @@ Description are called under the assumption that a certain number of bytes follow because it has already been guaranteed before parsing the instructions. They just have to "refill" this credit if they consume extra bytes. This - is an implementation design choice independent on the algorithm or + is an implementation design choice independent of the algorithm or encoding. Versions diff --git a/Documentation/staging/remoteproc.rst b/Documentation/staging/remoteproc.rst index 5c226fa076d6..c117b060e76c 100644 --- a/Documentation/staging/remoteproc.rst +++ b/Documentation/staging/remoteproc.rst @@ -24,7 +24,7 @@ handlers, and then all rpmsg drivers will then just work (for more information about the virtio-based rpmsg bus and its drivers, please read Documentation/staging/rpmsg.rst). Registration of other types of virtio devices is now also possible. Firmwares -just need to publish what kind of virtio devices do they support, and then +just need to publish what kind of virtio devices they support, and then remoteproc will add those devices. This makes it possible to reuse the existing virtio drivers with remote processor backends at a minimal development cost. diff --git a/Documentation/staging/static-keys.rst b/Documentation/staging/static-keys.rst index b0a519f456cf..e8dc3a87c381 100644 --- a/Documentation/staging/static-keys.rst +++ b/Documentation/staging/static-keys.rst @@ -90,7 +90,7 @@ out-of-line true branch. Thus, changing branch direction is expensive but branch selection is basically 'free'. That is the basic tradeoff of this optimization. -This lowlevel patching mechanism is called 'jump label patching', and it gives +This low-level patching mechanism is called 'jump label patching', and it gives the basis for the static keys facility. Static key label API, usage and examples From 8cfbcf36f97c5c9e70fe16c82a0f3782b8d67fe9 Mon Sep 17 00:00:00 2001 From: Hyeonjin Kim Date: Wed, 15 Apr 2026 09:12:04 +0900 Subject: [PATCH 013/655] docs: fix typos in kernel documentation reinitalizes => reinitializes unpriviledged => unprivileged sub-struture => sub-structure Signed-off-by: Hyeonjin Kim Signed-off-by: Jonathan Corbet Message-ID: <20260415001204.6428-1-fruitworld.planet@gmail.com> --- Documentation/block/data-integrity.rst | 2 +- Documentation/core-api/list.rst | 2 +- Documentation/gpu/drm-uapi.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/block/data-integrity.rst b/Documentation/block/data-integrity.rst index 99905e880a0e..b7b10c8abbcc 100644 --- a/Documentation/block/data-integrity.rst +++ b/Documentation/block/data-integrity.rst @@ -154,7 +154,7 @@ bio_free() will automatically free the bip. ---------------- Block devices can set up the integrity information in the integrity -sub-struture of the queue_limits structure. +sub-structure of the queue_limits structure. Layered block devices will need to pick a profile that's appropriate for all subdevices. queue_limits_stack_integrity() can help with that. DM diff --git a/Documentation/core-api/list.rst b/Documentation/core-api/list.rst index 241464ca0549..4819343a2706 100644 --- a/Documentation/core-api/list.rst +++ b/Documentation/core-api/list.rst @@ -752,7 +752,7 @@ This is because list_splice() did not reinitialize the list_head it took entries from, leaving its pointer pointing into what is now a different list. If we want to avoid this situation, list_splice_init() can be used. It does the -same thing as list_splice(), except reinitalizes the donor list_head after the +same thing as list_splice(), except reinitializes the donor list_head after the transplant. Concurrency considerations diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 579e87cb9ff7..8717744f0fec 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -568,7 +568,7 @@ ENOSPC: EPERM/EACCES: Returned for an operation that is valid, but needs more privileges. E.g. root-only or much more common, DRM master-only operations return - this when called by unpriviledged clients. There's no clear + this when called by unprivileged clients. There's no clear difference between EACCES and EPERM. ENODEV: From 713e899a683eb764b645eaeab79e7308cda497a7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 11 Apr 2026 16:35:26 -0700 Subject: [PATCH 014/655] docs: xforms_lists: allow __maybe_unused in func parameters Bart has a patch (not yet merged) that causes kernel-doc warnings: WARNING: ./include/linux/highmem.h:235 function parameter '__maybe_unused' not described in 'clear_user_pages' Documentation/mm/highmem:211: ./include/linux/highmem.h:222: WARNING: Error in declarator or parameters Handle this by adding "__maybe_unused" to the list of known function parameter modifiers. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202604120025.jtlnpWff-lkp@intel.com/ Signed-off-by: Randy Dunlap Cc: Bart Van Assche Reviewed-by: Bart Van Assche Signed-off-by: Jonathan Corbet Message-ID: <20260411233526.3909303-1-rdunlap@infradead.org> --- tools/lib/python/kdoc/xforms_lists.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/lib/python/kdoc/xforms_lists.py b/tools/lib/python/kdoc/xforms_lists.py index f6ea9efb11ae..496c52188273 100644 --- a/tools/lib/python/kdoc/xforms_lists.py +++ b/tools/lib/python/kdoc/xforms_lists.py @@ -93,6 +93,7 @@ class CTransforms: (CMatch("__weak"), ""), (CMatch("__sched"), ""), (CMatch("__always_unused"), ""), + (CMatch("__maybe_unused"), ""), (CMatch("__printf"), ""), (CMatch("__(?:re)?alloc_size"), ""), (CMatch("__diagnose_as"), ""), From 1804b8a1b43698853cb254dc5750c627591f2c43 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 27 Apr 2026 09:11:58 +0800 Subject: [PATCH 015/655] regulator: dt-bindings: qcom,rpmh: Add PMAU0102 support Add support for PMAU0102 PMIC used on Nord boards. Signed-off-by: Shawn Guo Link: https://patch.msgid.link/20260427011159.230698-2-shengchao.guo@oss.qualcomm.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/qcom,rpmh-regulator.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index 58bb0ad5dda4..d93594304651 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -51,6 +51,7 @@ description: | For PM8450, smps1 - smps6, ldo1 - ldo4 For PM8550, smps1 - smps6, ldo1 - ldo17, bob1 - bob2 For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 + For PMAU0102, smps1 - smps8, ldo1 - ldo3 For PMH0101, ldo1 - ldo18, bob1 - bob2 For PMH0104, smps1 - smps4 For PMH0110, smps1 - smps10, ldo1 - ldo4 @@ -87,6 +88,7 @@ properties: - qcom,pm8550ve-rpmh-regulators - qcom,pm8550vs-rpmh-regulators - qcom,pm8998-rpmh-regulators + - qcom,pmau0102-rpmh-regulators - qcom,pmc8180-rpmh-regulators - qcom,pmc8180c-rpmh-regulators - qcom,pmc8380-rpmh-regulators @@ -417,6 +419,7 @@ allOf: properties: compatible: enum: + - qcom,pmau0102-rpmh-regulators - qcom,pmc8380-rpmh-regulators - qcom,pm8550ve-rpmh-regulators then: From bb6ea5ae0b278c3f6e28565965ef4c12b7447665 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Mon, 27 Apr 2026 09:11:59 +0800 Subject: [PATCH 016/655] regulator: rpmh-regulator: Add RPMH regulator support for Nord Add support for PMAU0102 PMIC voltage regulators which are present on Nord boards. Signed-off-by: Kamal Wadhwa Signed-off-by: Shawn Guo Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260427011159.230698-3-shengchao.guo@oss.qualcomm.com Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 6e4cb2871fca..87cba629860c 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1100,6 +1100,21 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pmau0102_vreg_data[] = { + RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps527, "vdd-s1"), + RPMH_VREG("smps2", SMPS, 2, &pmic5_ftsmps527, "vdd-s2"), + RPMH_VREG("smps3", SMPS, 3, &pmic5_ftsmps527, "vdd-s3"), + RPMH_VREG("smps4", SMPS, 4, &pmic5_ftsmps527, "vdd-s4"), + RPMH_VREG("smps5", SMPS, 5, &pmic5_ftsmps527, "vdd-s5"), + RPMH_VREG("smps6", SMPS, 6, &pmic5_ftsmps527, "vdd-s6"), + RPMH_VREG("smps7", SMPS, 7, &pmic5_ftsmps527, "vdd-s7"), + RPMH_VREG("smps8", SMPS, 8, &pmic5_ftsmps527, "vdd-s8"), + RPMH_VREG("ldo1", LDO, 1, &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", LDO, 2, &pmic5_nldo515, "vdd-l2"), + RPMH_VREG("ldo3", LDO, 3, &pmic5_pldo515_mv, "vdd-l3"), + {} +}; + static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = { RPMH_VREG("smps1", SMPS, 1, &pmic5_ftsmps510, "vdd-s1"), {} @@ -1877,6 +1892,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pm8998-rpmh-regulators", .data = pm8998_vreg_data, }, + { + .compatible = "qcom,pmau0102-rpmh-regulators", + .data = pmau0102_vreg_data, + }, { .compatible = "qcom,pmg1110-rpmh-regulators", .data = pmg1110_vreg_data, From 4cf8806a637e98c9d83f4254f56e922e9a8714fd Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 28 Apr 2026 19:11:11 +0100 Subject: [PATCH 017/655] spi: microchip-core-qspi: report device on which timeout occured instead of which controller When prepare_message callbacks fail, the SPI core already reports which controller the failure happened on. The corresponding code in the mem_ops portion of the driver already reports the device a timeout occurred on, so make the regular part of the driver do the same. Signed-off-by: Conor Dooley Link: https://patch.msgid.link/20260428-porcupine-ninetieth-af00cb11b990@spud Signed-off-by: Mark Brown --- drivers/spi/spi-microchip-core-qspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c index eab059fb0bc2..c8b053c7c857 100644 --- a/drivers/spi/spi-microchip-core-qspi.c +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -604,7 +604,7 @@ static int mchp_coreqspi_prepare_message(struct spi_controller *ctlr, struct spi ret = mchp_coreqspi_wait_for_ready(qspi); if (ret) { mutex_unlock(&qspi->op_lock); - dev_err(&ctlr->dev, "Timeout waiting on QSPI ready.\n"); + dev_err(&m->spi->dev, "Timeout waiting on QSPI ready.\n"); return ret; } From 9c69bc6057a20642ee7db258b13f536c2e3214a2 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 28 Apr 2026 19:11:12 +0100 Subject: [PATCH 018/655] spi: microchip-core-qspi: remove an unused define I noticed this define was incorrect, it should be UpperAddress, but in renaming it it became clear there were actually no users. Just get rid of it. Signed-off-by: Conor Dooley Link: https://patch.msgid.link/20260428-viability-crepe-4e4c85e7c506@spud Signed-off-by: Mark Brown --- drivers/spi/spi-microchip-core-qspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c index c8b053c7c857..477a1bb390bb 100644 --- a/drivers/spi/spi-microchip-core-qspi.c +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -92,7 +92,6 @@ #define REG_IEN (0x0c) #define REG_STATUS (0x10) #define REG_DIRECT_ACCESS (0x14) -#define REG_UPPER_ACCESS (0x18) #define REG_RX_DATA (0x40) #define REG_TX_DATA (0x44) #define REG_X4_RX_DATA (0x48) From 54dac8230d9cbc26391ca61b45e1d6c2407c4daf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:23:01 +0200 Subject: [PATCH 019/655] spi: clean up controller registration return value Return explicit zero on successful controller registration to make the code more readable. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429092301.166375-1-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 104279858f56..5f57de24b9f7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3552,7 +3552,8 @@ int spi_register_controller(struct spi_controller *ctlr) /* Register devices from the device tree and ACPI */ of_register_spi_devices(ctlr); acpi_register_spi_devices(ctlr); - return status; + + return 0; del_ctrl: device_del(&ctlr->dev); @@ -3560,6 +3561,7 @@ free_bus_id: mutex_lock(&board_lock); idr_remove(&spi_controller_idr, ctlr->bus_num); mutex_unlock(&board_lock); + return status; } EXPORT_SYMBOL_GPL(spi_register_controller); From cb7083f9db3f634d22845c29b3af733bd751fc17 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sat, 2 May 2026 15:02:05 +0300 Subject: [PATCH 020/655] docs: Remove stale ISDN parameters The icn= and pcbit= parameters referenced drivers removed in commit 02bbd9802da7 ("staging: i4l: delete the whole thing"). Remove the stale parameter entries and the now-unused ISDN tag from the legend. Suggested-by: Randy Dunlap Signed-off-by: Costa Shulyupin Assisted-by: Claude:claude-opus-4-6 Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260502120206.1289126-1-costa.shul@redhat.com> --- Documentation/admin-guide/kernel-parameters.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 4d0f545fb3ec..319dfea30133 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -24,7 +24,6 @@ IP_PNP IP DHCP, BOOTP, or RARP is enabled. IPV6 IPv6 support is enabled. ISAPNP ISA PnP code is enabled. - ISDN Appropriate ISDN support is enabled. ISOL CPU Isolation is enabled. JOY Appropriate joystick support is enabled. KGDB Kernel debugger support is enabled. @@ -2245,9 +2244,6 @@ Kernel parameters syscalls, essentially overriding IA32_EMULATION_DEFAULT_DISABLED at boot time. When false, unconditionally disables IA32 emulation. - icn= [HW,ISDN] - Format: [,[,[,]]] - idle= [X86,EARLY] Format: idle=poll, idle=halt, idle=nomwait @@ -5037,8 +5033,6 @@ Kernel parameters the specified number of seconds. This is to be used if your oopses keep scrolling off the screen. - pcbit= [HW,ISDN] - pci=option[,option...] [PCI,EARLY] various PCI subsystem options. Some options herein operate on a specific device From 61e4155c81d1cc2b8a76344b65fd5fec41420cd6 Mon Sep 17 00:00:00 2001 From: Akiyoshi Kurita Date: Sat, 2 May 2026 16:01:43 +0900 Subject: [PATCH 021/655] docs/ja_JP: translate more of submitting-patches.rst Translate the "Separate your changes", "Style-check your changes", and "Select the recipients for your patch" sections in Documentation/translations/ja_JP/process/submitting-patches.rst. Keep the wording close to the English text and wrap lines to match the style used in the surrounding Japanese translation. Signed-off-by: Akiyoshi Kurita Acked-by: Akira Yokosawa Signed-off-by: Jonathan Corbet Message-ID: <20260502070143.1015416-1-weibu@redadmin.org> --- .../ja_JP/process/submitting-patches.rst | 127 +++++++++++++++++- 1 file changed, 120 insertions(+), 7 deletions(-) diff --git a/Documentation/translations/ja_JP/process/submitting-patches.rst b/Documentation/translations/ja_JP/process/submitting-patches.rst index 9d63220abd15..928e38a8d34d 100644 --- a/Documentation/translations/ja_JP/process/submitting-patches.rst +++ b/Documentation/translations/ja_JP/process/submitting-patches.rst @@ -83,19 +83,18 @@ Linux の多くの環境は、上流から特定のパッチだけを取り込 詳しく説明してください。コードが意図したとおりに動作していることを レビューアが確認できるよう、変更内容を平易な言葉で書き下すことが重要です。 -パッチの説明が Linux のソースコード管理システム ``git`` の「コミットログ」 -としてそのまま取り込める形で書かれていれば、メンテナは助かります。 -詳細は原文の該当節 ("The canonical patch format") を参照してください。 +パッチ説明を Linux のソースコード管理システム ``git`` の +「コミットログ」としてそのまま取り込める形で書けば、メンテナは +助かります。詳細は原文の該当節 ("The canonical patch format") を +参照してください。 .. TODO: Convert to file-local cross-reference when the destination is translated. 1 つのパッチでは 1 つの問題だけを解決してください。記述が長くなり -始めたら、それはパッチを分割すべきサインです。 -詳細は原文の該当節 ("Separate your changes") を参照してください。 +始めたら、パッチを分割すべきサインです。詳細は `変更を分割する`_ を +参照してください。 -.. TODO: Convert to file-local cross-reference when the destination is - translated. パッチまたはパッチシリーズを投稿/再投稿する際は、その完全な 説明と、それを正当化する理由を含めてください。単に「これはパッチ @@ -179,3 +178,117 @@ URL は禁止です。 $ git log -1 --pretty=fixes 54a4f0239f2e Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed") + +変更を分割する +-------------- + +各 **論理的な変更** は、個別のパッチに分けてください。 + +たとえば、単一のドライバに対する変更にバグ修正と性能改善の +両方が含まれるなら、それらは 2 つ以上のパッチに分けてください。 +変更に API の更新と、その新しい API を使う新しいドライバが +含まれるなら、それらは 2 つのパッチに分けてください。 + +一方、多数のファイルに対して単一の変更を行う場合は、それらを +1 つのパッチにまとめてください。つまり、1 つの論理的な変更は +1 つのパッチに含めるべきです。 + +覚えておくべき点は、各パッチがレビューアに理解しやすく、 +検証できる変更であるべきだということです。各パッチは、 +それ自体の妥当性で正当化できなければなりません。 + +変更を完成させるために、あるパッチが別のパッチに依存するなら、 +それでも構いません。単に、パッチの説明に +**"this patch depends on patch X"** と記してください。 + +変更を一連のパッチに分ける際は、シリーズ中の各パッチを +適用した後でも、カーネルが正しくビルドされ、正常に動作することを +特に注意して確認してください。問題の追跡に ``git bisect`` を +使う開発者は、あなたのパッチシリーズを任意の地点で分割する +ことがあります。途中でバグを持ち込めば、彼らに感謝されることは +ないでしょう。 + +パッチセットをこれ以上小さくできないなら、一度に投稿するのは +15 個程度までにして、レビューと統合を待ってください。 + + +変更のスタイルを確認する +------------------------ + +パッチに基本的なスタイル違反がないか確認してください。詳細は +Documentation/process/coding-style.rst を参照してください。 +これを怠ると、単にレビューアの時間を無駄にするだけでなく、 +パッチはおそらく読まれもせずに却下されます。 + +大きな例外が 1 つあります。コードをあるファイルから別の +ファイルへ移動する場合です。このときは、コードを移動する +その同じパッチの中で、移動したコードを一切変更してはいけません。 +そうすることで、コードの移動という行為と、あなたの変更とを +明確に区別できます。これは実際の差分のレビューを大いに助け、 +ツールがコード自体の履歴をより適切に追跡できるようにします。 + +提出前に、パッチスタイルチェッカー +(``scripts/checkpatch.pl``) でパッチを確認してください。 +ただし、スタイルチェッカーは指針として見るべきであり、 +人間の判断に取って代わるものではないことに注意してください。 +違反があっても、その方がコードの見栄えがよいなら、 +そのままにしておくのが最善でしょう。 + +チェッカーは 3 つのレベルで報告します: + + - ERROR: 間違っている可能性が非常に高いもの + - WARNING: 慎重なレビューを要するもの + - CHECK: 検討を要するもの + +パッチに残した違反については、すべて理由を説明できなければ +なりません。 + + +パッチの宛先を選択する +---------------------- + +各パッチでは、そのコードを保守する適切なサブシステムメンテナと +メーリングリストを、必ず Cc に入れてください。誰がその +メンテナかは、MAINTAINERS ファイルとソースコードの改訂履歴を +調べて確認してください。この段階では ``scripts/get_maintainer.pl`` +が非常に役立ちます(パッチへのパスを引数として +``scripts/get_maintainer.pl`` に渡してください)。作業中の +サブシステムのメンテナが見つからない場合は、Andrew Morton +(akpm@linux-foundation.org) が最後の手段となるメンテナです。 + +すべてのパッチでは、デフォルトで linux-kernel@vger.kernel.org を +使うべきですが、このリストの流量が多いため、目を通さなくなった +開発者も少なくありません。とはいえ、無関係なメーリングリストや +無関係な人々にスパムを送らないでください。 + +カーネル関連のメーリングリストの多くは kernel.org で運営されており、 +その一覧は https://subspace.kernel.org で確認できます。ただし、 +他所で運営されているカーネル関連のメーリングリストもあります。 + +Linux カーネルに採用されるすべての変更の最終的な裁定者は +Linus Torvalds です。彼のメールアドレスは + です。Linus は大量のメールを +受け取っており、現時点では彼に直接届くパッチはごくわずかなので、 +通常は彼にメールを送ることを極力避けてください。 + +悪用可能なセキュリティバグを修正するパッチがあるなら、 +そのパッチを security@kernel.org に送ってください。深刻なバグに +ついては、ディストリビュータがユーザーにパッチを配布できるよう、 +短期間の embargo が検討される場合があります。そのような場合、 +そのパッチを公開メーリングリストに送るべきではありません。 +Documentation/process/security-bugs.rst も参照してください。 + +リリース済みカーネルの深刻なバグを修正するパッチは、次のような行を +パッチの sign-off 欄に入れることで、stable メンテナへ向けてください:: + + Cc: stable@vger.kernel.org + +これはメールの受信者ではないことに注意してください。また、 +この文書に加えて Documentation/process/stable-kernel-rules.rst も +読んでください。 + +変更がユーザーランドとカーネルのインターフェースに影響する場合は、 +MAINTAINERS ファイルに記載されている MAN-PAGES メンテナに +man-pages パッチ、少なくとも変更の通知を送って、情報が +マニュアルページに反映されるようにしてください。ユーザー空間 API の +変更は、linux-api@vger.kernel.org にも Cc してください。 From e5ebf6278d06b55dadded317b92e351c03e05e6e Mon Sep 17 00:00:00 2001 From: Miles Krause Date: Wed, 29 Apr 2026 18:24:35 -0400 Subject: [PATCH 022/655] Documentation/scheduler: Fix duplicated word in sched-deadline The SCHED_DEADLINE documentation has a duplicated the in the CPU affinity section. Remove the extra word. Signed-off-by: Miles Krause Signed-off-by: Jonathan Corbet Message-ID: <20260429222435.2041-1-mileskrause5200@gmail.com> --- Documentation/scheduler/sched-deadline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/scheduler/sched-deadline.rst b/Documentation/scheduler/sched-deadline.rst index 3ad93cd7b59a..9019b66f6a5b 100644 --- a/Documentation/scheduler/sched-deadline.rst +++ b/Documentation/scheduler/sched-deadline.rst @@ -685,7 +685,7 @@ Deadline Task Scheduling Deadline tasks cannot have a cpu affinity mask smaller than the root domain they are created on. So, using ``sched_setaffinity(2)`` won't work. Instead, the - the deadline task should be created in a restricted root domain. This can be + deadline task should be created in a restricted root domain. This can be done using the cpuset controller of either cgroup v1 (deprecated) or cgroup v2. See :ref:`Documentation/admin-guide/cgroup-v1/cpusets.rst ` and :ref:`Documentation/admin-guide/cgroup-v2.rst ` for more information. From 7c6d969d5349c40348276d5c301b2d200afa623d Mon Sep 17 00:00:00 2001 From: Manuel Ebner Date: Wed, 29 Apr 2026 09:14:44 +0200 Subject: [PATCH 023/655] Documentation: adopt new coding style of type-aware kmalloc-family Update the documentation to reflect new type-aware kmalloc-family as suggested in commit 2932ba8d9c99 ("slab: Introduce kmalloc_obj() and family") ptr = kmalloc(sizeof(*ptr), gfp); -> ptr = kmalloc_obj(*ptr, gfp); ptr = kmalloc(sizeof(struct some_obj_name), gfp); -> ptr = kmalloc_obj(*ptr, gfp); ptr = kzalloc(sizeof(*ptr), gfp); -> ptr = kzalloc_obj(*ptr, gfp); ptr = kmalloc_array(count, sizeof(*ptr), gfp); -> ptr = kmalloc_objs(*ptr, count, gfp); ptr = kcalloc(count, sizeof(*ptr), gfp); -> ptr = kzalloc_objs(*ptr, count, gfp); Signed-off-by: Manuel Ebner Acked-by: SeongJae Park Acked-by: Vlastimil Babka (SUSE) Signed-off-by: Jonathan Corbet Message-ID: <20260429071445.309733-2-manuelebner@mailbox.org> --- Documentation/core-api/kref.rst | 4 ++-- Documentation/core-api/list.rst | 4 ++-- Documentation/driver-api/mailbox.rst | 4 ++-- Documentation/driver-api/media/v4l2-fh.rst | 2 +- Documentation/kernel-hacking/locking.rst | 4 ++-- Documentation/locking/locktypes.rst | 4 ++-- Documentation/process/coding-style.rst | 8 ++++---- .../sound/kernel-api/writing-an-alsa-driver.rst | 12 ++++++------ Documentation/spi/spi-summary.rst | 4 ++-- .../translations/it_IT/kernel-hacking/locking.rst | 4 ++-- .../translations/it_IT/locking/locktypes.rst | 4 ++-- .../translations/it_IT/process/coding-style.rst | 2 +- .../translations/sp_SP/process/coding-style.rst | 2 +- Documentation/translations/zh_CN/core-api/kref.rst | 4 ++-- .../translations/zh_CN/process/coding-style.rst | 2 +- .../zh_CN/video4linux/v4l2-framework.txt | 2 +- .../translations/zh_TW/process/coding-style.rst | 2 +- 17 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Documentation/core-api/kref.rst b/Documentation/core-api/kref.rst index 8db9ff03d952..233d52d2393d 100644 --- a/Documentation/core-api/kref.rst +++ b/Documentation/core-api/kref.rst @@ -40,7 +40,7 @@ kref_init as so:: struct my_data *data; - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kmalloc_obj(*data); if (!data) return -ENOMEM; kref_init(&data->refcount); @@ -100,7 +100,7 @@ thread to process:: int rv = 0; struct my_data *data; struct task_struct *task; - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kmalloc_obj(*data); if (!data) return -ENOMEM; kref_init(&data->refcount); diff --git a/Documentation/core-api/list.rst b/Documentation/core-api/list.rst index 4819343a2706..479aa91cc395 100644 --- a/Documentation/core-api/list.rst +++ b/Documentation/core-api/list.rst @@ -112,7 +112,7 @@ list: /* State 1 */ - grock = kzalloc(sizeof(*grock), GFP_KERNEL); + grock = kzalloc_obj(*grock); if (!grock) return -ENOMEM; grock->name = "Grock"; @@ -123,7 +123,7 @@ list: /* State 2 */ - dimitri = kzalloc(sizeof(*dimitri), GFP_KERNEL); + dimitri = kzalloc_obj(*dimitri); if (!dimitri) return -ENOMEM; dimitri->name = "Dimitri"; diff --git a/Documentation/driver-api/mailbox.rst b/Documentation/driver-api/mailbox.rst index 463dd032b96c..d46c60bd5df6 100644 --- a/Documentation/driver-api/mailbox.rst +++ b/Documentation/driver-api/mailbox.rst @@ -87,8 +87,8 @@ a message and a callback function to the API and return immediately). struct async_pkt ap; struct sync_pkt sp; - dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL); - dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL); + dc_sync = kzalloc_obj(*dc_sync); + dc_async = kzalloc_obj(*dc_async); /* Populate non-blocking mode client */ dc_async->cl.dev = &pdev->dev; diff --git a/Documentation/driver-api/media/v4l2-fh.rst b/Documentation/driver-api/media/v4l2-fh.rst index a934caa483a4..ff1fdd897504 100644 --- a/Documentation/driver-api/media/v4l2-fh.rst +++ b/Documentation/driver-api/media/v4l2-fh.rst @@ -42,7 +42,7 @@ Example: ... - my_fh = kzalloc(sizeof(*my_fh), GFP_KERNEL); + my_fh = kzalloc_obj(*my_fh); ... diff --git a/Documentation/kernel-hacking/locking.rst b/Documentation/kernel-hacking/locking.rst index dff0646a717b..c969c76ef7cb 100644 --- a/Documentation/kernel-hacking/locking.rst +++ b/Documentation/kernel-hacking/locking.rst @@ -442,7 +442,7 @@ to protect the cache and all the objects within it. Here's the code:: { struct object *obj; - if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL) + if ((obj = kmalloc_obj(*obj)) == NULL) return -ENOMEM; strscpy(obj->name, name, sizeof(obj->name)); @@ -517,7 +517,7 @@ which are taken away, and the ``+`` are lines which are added. struct object *obj; + unsigned long flags; - if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL) + if ((obj = kmalloc_obj(*obj)) == NULL) return -ENOMEM; @@ -63,30 +64,33 @@ obj->id = id; diff --git a/Documentation/locking/locktypes.rst b/Documentation/locking/locktypes.rst index 37b6a5670c2f..ac1ad722a9e7 100644 --- a/Documentation/locking/locktypes.rst +++ b/Documentation/locking/locktypes.rst @@ -498,7 +498,7 @@ allocating memory. Thus, on a non-PREEMPT_RT kernel the following code works perfectly:: raw_spin_lock(&lock); - p = kmalloc(sizeof(*p), GFP_ATOMIC); + p = kmalloc_obj(*p, GFP_ATOMIC); But this code fails on PREEMPT_RT kernels because the memory allocator is fully preemptible and therefore cannot be invoked from truly atomic @@ -507,7 +507,7 @@ while holding normal non-raw spinlocks because they do not disable preemption on PREEMPT_RT kernels:: spin_lock(&lock); - p = kmalloc(sizeof(*p), GFP_ATOMIC); + p = kmalloc_obj(*p, GFP_ATOMIC); bit spinlocks diff --git a/Documentation/process/coding-style.rst b/Documentation/process/coding-style.rst index 35b381230f6e..a3bf75dc7c88 100644 --- a/Documentation/process/coding-style.rst +++ b/Documentation/process/coding-style.rst @@ -936,7 +936,7 @@ used. --------------------- The kernel provides the following general purpose memory allocators: -kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc(), and +kmalloc(), kzalloc(), kmalloc_objs(), kzalloc_objs(), vmalloc(), and vzalloc(). Please refer to the API documentation for further information about them. :ref:`Documentation/core-api/memory-allocation.rst ` @@ -945,7 +945,7 @@ The preferred form for passing a size of a struct is the following: .. code-block:: c - p = kmalloc(sizeof(*p), ...); + p = kmalloc_obj(*p, ...); The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed @@ -959,13 +959,13 @@ The preferred form for allocating an array is the following: .. code-block:: c - p = kmalloc_array(n, sizeof(...), ...); + p = kmalloc_objs(*ptr, n, ...); The preferred form for allocating a zeroed array is the following: .. code-block:: c - p = kcalloc(n, sizeof(...), ...); + p = kzalloc_objs(*ptr, n, ...); Both forms check for overflow on the allocation size n * sizeof(...), and return NULL if that occurred. diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index 895752cbcedd..86b64de03140 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -266,7 +266,7 @@ to details explained in the following section. .... /* allocate a chip-specific data with zero filled */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc_obj(*chip); if (chip == NULL) return -ENOMEM; @@ -628,7 +628,7 @@ After allocating a card instance via :c:func:`snd_card_new()` err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, &card); ..... - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc_obj(*chip); The chip record should have the field to hold the card pointer at least, @@ -747,7 +747,7 @@ destructor and PCI entries. Example code is shown first, below:: return -ENXIO; } - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc_obj(*chip); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1737,7 +1737,7 @@ callback:: { struct my_pcm_data *data; .... - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kmalloc_obj(*data); substream->runtime->private_data = data; .... } @@ -3301,7 +3301,7 @@ You can then pass any pointer value to the ``private_data``. If you assign private data, you should define a destructor, too. The destructor function is set in the ``private_free`` field:: - struct mydata *p = kmalloc(sizeof(*p), GFP_KERNEL); + struct mydata *p = kmalloc_obj(*p); hw->private_data = p; hw->private_free = mydata_free; @@ -3833,7 +3833,7 @@ chip data individually:: err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, &card); .... - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc_obj(*chip); .... card->private_data = chip; .... diff --git a/Documentation/spi/spi-summary.rst b/Documentation/spi/spi-summary.rst index 6e21e6f86912..ee34796cfbb6 100644 --- a/Documentation/spi/spi-summary.rst +++ b/Documentation/spi/spi-summary.rst @@ -249,7 +249,7 @@ And SOC-specific utility code might look something like:: { struct mysoc_spi_data *pdata2; - pdata2 = kmalloc(sizeof *pdata2, GFP_KERNEL); + pdata2 = kmalloc_obj(*pdata2); *pdata2 = pdata; ... if (n == 2) { @@ -373,7 +373,7 @@ a bus (appearing under /sys/class/spi_master). return -ENODEV; /* get memory for driver's per-chip state */ - chip = kzalloc(sizeof *chip, GFP_KERNEL); + chip = kzalloc(*chip); if (!chip) return -ENOMEM; spi_set_drvdata(spi, chip); diff --git a/Documentation/translations/it_IT/kernel-hacking/locking.rst b/Documentation/translations/it_IT/kernel-hacking/locking.rst index 4c21cf60f775..205a232c98e2 100644 --- a/Documentation/translations/it_IT/kernel-hacking/locking.rst +++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst @@ -462,7 +462,7 @@ e tutti gli oggetti che contiene. Ecco il codice:: { struct object *obj; - if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL) + if ((obj = kmalloc_obj(*obj)) == NULL) return -ENOMEM; strscpy(obj->name, name, sizeof(obj->name)); @@ -537,7 +537,7 @@ sono quelle rimosse, mentre quelle ``+`` sono quelle aggiunte. struct object *obj; + unsigned long flags; - if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL) + if ((obj = kmalloc_obj(*obj)) == NULL) return -ENOMEM; @@ -63,30 +64,33 @@ obj->id = id; diff --git a/Documentation/translations/it_IT/locking/locktypes.rst b/Documentation/translations/it_IT/locking/locktypes.rst index 1c7056283b9d..d5fa36aa05cc 100644 --- a/Documentation/translations/it_IT/locking/locktypes.rst +++ b/Documentation/translations/it_IT/locking/locktypes.rst @@ -488,7 +488,7 @@ o rwlock_t. Per esempio, la sezione critica non deve fare allocazioni di memoria. Su un kernel non-PREEMPT_RT il seguente codice funziona perfettamente:: raw_spin_lock(&lock); - p = kmalloc(sizeof(*p), GFP_ATOMIC); + p = kmalloc_obj(*p, GFP_ATOMIC); Ma lo stesso codice non funziona su un kernel PREEMPT_RT perché l'allocatore di memoria può essere oggetto di prelazione e quindi non può essere chiamato in un @@ -497,7 +497,7 @@ trattiene un blocco *non-raw* perché non disabilitano la prelazione sui kernel PREEMPT_RT:: spin_lock(&lock); - p = kmalloc(sizeof(*p), GFP_ATOMIC); + p = kmalloc_obj(*p, GFP_ATOMIC); bit spinlocks diff --git a/Documentation/translations/it_IT/process/coding-style.rst b/Documentation/translations/it_IT/process/coding-style.rst index c0dc786b8474..2a499412a2e3 100644 --- a/Documentation/translations/it_IT/process/coding-style.rst +++ b/Documentation/translations/it_IT/process/coding-style.rst @@ -943,7 +943,7 @@ Il modo preferito per passare la dimensione di una struttura è il seguente: .. code-block:: c - p = kmalloc(sizeof(*p), ...); + p = kmalloc_obj(*p, ...); La forma alternativa, dove il nome della struttura viene scritto interamente, peggiora la leggibilità e introduce possibili bachi quando il tipo di diff --git a/Documentation/translations/sp_SP/process/coding-style.rst b/Documentation/translations/sp_SP/process/coding-style.rst index 7d63aa8426e6..44c93d5f6beb 100644 --- a/Documentation/translations/sp_SP/process/coding-style.rst +++ b/Documentation/translations/sp_SP/process/coding-style.rst @@ -955,7 +955,7 @@ La forma preferida para pasar el tamaño de una estructura es la siguiente: .. code-block:: c - p = kmalloc(sizeof(*p), ...); + p = kmalloc_obj(*p, ...); La forma alternativa donde se deletrea el nombre de la estructura perjudica la legibilidad, y presenta una oportunidad para un error cuando se cambia diff --git a/Documentation/translations/zh_CN/core-api/kref.rst b/Documentation/translations/zh_CN/core-api/kref.rst index b9902af310c5..8a0c030ec1d3 100644 --- a/Documentation/translations/zh_CN/core-api/kref.rst +++ b/Documentation/translations/zh_CN/core-api/kref.rst @@ -52,7 +52,7 @@ kref可以出现在数据结构体中的任何地方。 struct my_data *data; - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kmalloc_obj(*data); if (!data) return -ENOMEM; kref_init(&data->refcount); @@ -106,7 +106,7 @@ Kref规则 int rv = 0; struct my_data *data; struct task_struct *task; - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kmalloc_obj(*data); if (!data) return -ENOMEM; kref_init(&data->refcount); diff --git a/Documentation/translations/zh_CN/process/coding-style.rst b/Documentation/translations/zh_CN/process/coding-style.rst index 5a342a024c01..55d5da974d89 100644 --- a/Documentation/translations/zh_CN/process/coding-style.rst +++ b/Documentation/translations/zh_CN/process/coding-style.rst @@ -813,7 +813,7 @@ Documentation/translations/zh_CN/core-api/memory-allocation.rst 。 .. code-block:: c - p = kmalloc(sizeof(*p), ...); + p = kmalloc_obj(*p, ...); 另外一种传递方式中,sizeof 的操作数是结构体的名字,这样会降低可读性,并且可能 会引入 bug。有可能指针变量类型被改变时,而对应的传递给内存分配函数的 sizeof diff --git a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt index f0be21a60a0f..05414579efac 100644 --- a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt +++ b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt @@ -799,7 +799,7 @@ int my_open(struct file *file) ... - my_fh = kzalloc(sizeof(*my_fh), GFP_KERNEL); + my_fh = kzalloc_obj(*my_fh); ... diff --git a/Documentation/translations/zh_TW/process/coding-style.rst b/Documentation/translations/zh_TW/process/coding-style.rst index e2ba97b3d8bb..63c78982a1af 100644 --- a/Documentation/translations/zh_TW/process/coding-style.rst +++ b/Documentation/translations/zh_TW/process/coding-style.rst @@ -827,7 +827,7 @@ Documentation/translations/zh_CN/core-api/memory-allocation.rst 。 .. code-block:: c - p = kmalloc(sizeof(*p), ...); + p = kmalloc_obj(*p, ...); 另外一種傳遞方式中,sizeof 的操作數是結構體的名字,這樣會降低可讀性,並且可能 會引入 bug。有可能指針變量類型被改變時,而對應的傳遞給內存分配函數的 sizeof From f61bf5fdf77d8871391a8c25af75c4cad96012e9 Mon Sep 17 00:00:00 2001 From: Manuel Ebner Date: Wed, 29 Apr 2026 09:23:21 +0200 Subject: [PATCH 024/655] Documentation: RCU: adopt new coding style of type-aware kmalloc-family Update Documentation/RCU/* to reflect new type-aware kmalloc-family as suggested in commit 2932ba8d9c99 ("slab: Introduce kmalloc_obj() and family") ptr = kmalloc(sizeof(*ptr), gfp); -> ptr = kmalloc_obj(*ptr, gfp); Signed-off-by: Manuel Ebner Acked-by: Paul E. McKenney Acked-by: SeongJae Park Acked-by: Vlastimil Babka (SUSE) Signed-off-by: Jonathan Corbet Message-ID: <20260429072320.310817-2-manuelebner@mailbox.org> --- Documentation/RCU/Design/Requirements/Requirements.rst | 6 +++--- Documentation/RCU/listRCU.rst | 2 +- Documentation/RCU/whatisRCU.rst | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/RCU/Design/Requirements/Requirements.rst b/Documentation/RCU/Design/Requirements/Requirements.rst index 4d886e7c7a95..8a216e4a46a7 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.rst +++ b/Documentation/RCU/Design/Requirements/Requirements.rst @@ -206,7 +206,7 @@ non-\ ``NULL``, locklessly accessing the ``->a`` and ``->b`` fields. 1 bool add_gp_buggy(int a, int b) 2 { - 3 p = kmalloc(sizeof(*p), GFP_KERNEL); + 3 p = kmalloc_obj(*p); 4 if (!p) 5 return -ENOMEM; 6 spin_lock(&gp_lock); @@ -228,7 +228,7 @@ their rights to reorder this code as follows: 1 bool add_gp_buggy_optimized(int a, int b) 2 { - 3 p = kmalloc(sizeof(*p), GFP_KERNEL); + 3 p = kmalloc_obj(*p); 4 if (!p) 5 return -ENOMEM; 6 spin_lock(&gp_lock); @@ -264,7 +264,7 @@ shows an example of insertion: 1 bool add_gp(int a, int b) 2 { - 3 p = kmalloc(sizeof(*p), GFP_KERNEL); + 3 p = kmalloc_obj(*p); 4 if (!p) 5 return -ENOMEM; 6 spin_lock(&gp_lock); diff --git a/Documentation/RCU/listRCU.rst b/Documentation/RCU/listRCU.rst index d8bb98623c12..48c7272a4ccc 100644 --- a/Documentation/RCU/listRCU.rst +++ b/Documentation/RCU/listRCU.rst @@ -276,7 +276,7 @@ The RCU version of audit_upd_rule() is as follows:: list_for_each_entry(e, list, list) { if (!audit_compare_rule(rule, &e->rule)) { - ne = kmalloc(sizeof(*entry), GFP_ATOMIC); + ne = kmalloc_obj(*entry, GFP_ATOMIC); if (ne == NULL) return -ENOMEM; audit_copy_rule(&ne->rule, &e->rule); diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst index a1582bd653d1..e6767baff2d3 100644 --- a/Documentation/RCU/whatisRCU.rst +++ b/Documentation/RCU/whatisRCU.rst @@ -468,7 +468,7 @@ uses of RCU may be found in listRCU.rst and NMI-RCU.rst. struct foo *new_fp; struct foo *old_fp; - new_fp = kmalloc(sizeof(*new_fp), GFP_KERNEL); + new_fp = kmalloc_obj(*new_fp); spin_lock(&foo_mutex); old_fp = rcu_dereference_protected(gbl_foo, lockdep_is_held(&foo_mutex)); *new_fp = *old_fp; @@ -570,7 +570,7 @@ The foo_update_a() function might then be written as follows:: struct foo *new_fp; struct foo *old_fp; - new_fp = kmalloc(sizeof(*new_fp), GFP_KERNEL); + new_fp = kmalloc_obj(*new_fp); spin_lock(&foo_mutex); old_fp = rcu_dereference_protected(gbl_foo, lockdep_is_held(&foo_mutex)); *new_fp = *old_fp; From d957b4184aee15344ceb223248e09f6403b25967 Mon Sep 17 00:00:00 2001 From: Manuel Ebner Date: Wed, 29 Apr 2026 09:27:04 +0200 Subject: [PATCH 025/655] Documentation: deprecated.rst: kmalloc-family: mark argument as optional put the optional argument (gfp) in square brackets add default value = GFP_KERNEL eg. ptr = kmalloc_obj(*ptr, gfp); -> ptr = kmalloc_obj(*ptr [, gfp] ); Signed-off-by: Manuel Ebner Acked-by: SeongJae Park Acked-by: Vlastimil Babka (SUSE) Signed-off-by: Jonathan Corbet Message-ID: <20260429072704.311603-2-manuelebner@mailbox.org> --- Documentation/process/deprecated.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst index fed56864d036..ac75b7ecac47 100644 --- a/Documentation/process/deprecated.rst +++ b/Documentation/process/deprecated.rst @@ -392,13 +392,14 @@ allocations. For example, these open coded assignments:: become, respectively:: - ptr = kmalloc_obj(*ptr, gfp); - ptr = kzalloc_obj(*ptr, gfp); - ptr = kmalloc_objs(*ptr, count, gfp); - ptr = kzalloc_objs(*ptr, count, gfp); - ptr = kmalloc_flex(*ptr, flex_member, count, gfp); - __auto_type ptr = kmalloc_obj(struct foo, gfp); + ptr = kmalloc_obj(*ptr [, gfp] ); + ptr = kzalloc_obj(*ptr [, gfp] ); + ptr = kmalloc_objs(*ptr, count [, gfp] ); + ptr = kzalloc_objs(*ptr, count [, gfp] ); + ptr = kmalloc_flex(*ptr, flex_member, count [, gfp] ); + __auto_type ptr = kmalloc_obj(struct foo [, gfp] ); +The argument gfp is optional, the default value is GFP_KERNEL. If `ptr->flex_member` is annotated with __counted_by(), the allocation will automatically fail if `count` is larger than the maximum representable value that can be stored in the counter member associated From 45ef180629cb73324f3a2cb962bce5e9fe6f1aa6 Mon Sep 17 00:00:00 2001 From: Daniel Pereira Date: Tue, 28 Apr 2026 15:02:05 -0300 Subject: [PATCH 026/655] docs/pt_BR: process: link maintainer-kvm-x86 in maintainer-handbooks The Portuguese translation of maintainer-kvm-x86.rst exists in the directory, but it was not listed in the toctree of maintainer-handbooks.rst. Add the missing entry to ensure the document is properly indexed and reachable through the main maintainer handbook page. Signed-off-by: Daniel Pereira Signed-off-by: Jonathan Corbet Message-ID: <20260428180208.175472-1-danielmaraboo@gmail.com> --- .../translations/pt_BR/process/maintainer-handbooks.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/translations/pt_BR/process/maintainer-handbooks.rst b/Documentation/translations/pt_BR/process/maintainer-handbooks.rst index ba36df8eeaf1..bf7a381472e2 100644 --- a/Documentation/translations/pt_BR/process/maintainer-handbooks.rst +++ b/Documentation/translations/pt_BR/process/maintainer-handbooks.rst @@ -16,3 +16,4 @@ Conteúdos: maintainer-netdev maintainer-soc maintainer-soc-clean-dts + maintainer-kvm-x86 From 80647a62857ab530444c9bbb2f8aace17ff49b77 Mon Sep 17 00:00:00 2001 From: Myro Demma Date: Tue, 28 Apr 2026 15:30:01 +0200 Subject: [PATCH 027/655] docs: proc: fix minor grammar and formatting issues Fix missing "from" in "prevent being reused" and add spacing in vm_area_struct range notation for readability. No functional changes. Signed-off-by: Myro Demma Signed-off-by: Jonathan Corbet Message-ID: <20260428133001.11384-1-myro@myromyro.com> --- Documentation/filesystems/proc.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index 3c6e4f52f3e4..a4c2b22c08ef 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -118,7 +118,7 @@ PTRACE_MODE_ATTACH permissions; CAP_PERFMON capability does not grant access to /proc/PID/mem for other processes. Note that an open file descriptor to /proc/ or to any of its -contained files or subdirectories does not prevent being reused +contained files or subdirectories does not prevent from being reused for some other process in the event that exits. Operations on open /proc/ file descriptors corresponding to dead processes never act on any new process that the kernel may, through chance, have @@ -2211,7 +2211,7 @@ the process is maintaining. Example output:: | lr-------- 1 root root 64 Jan 27 11:24 400000-41a000 -> /usr/bin/ls The name of a link represents the virtual memory bounds of a mapping, i.e. -vm_area_struct::vm_start-vm_area_struct::vm_end. +vm_area_struct::vm_start - vm_area_struct::vm_end. The main purpose of the map_files is to retrieve a set of memory mapped files in a fast way instead of parsing /proc//maps or From 27e6bf7df26e1b5a54888c9f86fe7255861c530b Mon Sep 17 00:00:00 2001 From: Ilai Levin Date: Tue, 28 Apr 2026 12:45:55 +0000 Subject: [PATCH 028/655] docs: driver-api: eisa: add SPDX license identifier Add the missing SPDX-License-Identifier tag to the eisa.rst documentation file. Signed-off-by: Ilai Levin Acked-by: Marc Zyngier Signed-off-by: Jonathan Corbet Message-ID: <20260428124555.102039-1-levinilai972@gmail.com> --- Documentation/driver-api/eisa.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/driver-api/eisa.rst b/Documentation/driver-api/eisa.rst index 3563e5f7e98d..e98b21b60865 100644 --- a/Documentation/driver-api/eisa.rst +++ b/Documentation/driver-api/eisa.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + ================ EISA bus support ================ From 75ff0feaa2755ba8f064f2085a8afbf6139a5195 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 27 Apr 2026 17:07:39 +0200 Subject: [PATCH 029/655] Documentation/kernel-parameters: Remove "Deprecated" from isolcpus= The isolcpus= option has been marked as deprecated in 2017. Back then it was desired for the domain sub option to be configured dynamically at runtime instead using this boot command line which provides a static configuration. In the meantime this option was extended by other sub options which don't have runtime counterpart or it does not make sense to provide one. The deprecated part always referred to the default `domain' sub option but it was not obvious. Also the reasoning behind the deprecation is sort of dubious: There is nothing wrong with a static configuration if there is no desired to reconfigure. This is useful on systems which have one purpose and the CPU partition configuration is not changed for the entire lifetime. Remove the "Deprecated" note. Remove the part of the description which suggest to use cpuset.sched_load_balance and instead point to the documentation file which explains how to use cpusets to configure this at runtime. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Waiman Long Acked-by: Steven Rostedt Signed-off-by: Jonathan Corbet Message-ID: <20260427150739.bwVmmkj2@linutronix.de> --- Documentation/admin-guide/kernel-parameters.txt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 319dfea30133..b1e2e50d5c8d 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2751,7 +2751,6 @@ Kernel parameters Format: ,,, isolcpus= [KNL,SMP,ISOL] Isolate a given set of CPUs from disturbance. - [Deprecated - use cpusets instead] Format: [flag-list,] Specify one or more CPUs to isolate from disturbances @@ -2776,11 +2775,10 @@ Kernel parameters Isolate from the general SMP balancing and scheduling algorithms. Note that performing domain isolation this way is irreversible: it's not possible to bring back a CPU to - the domains once isolated through isolcpus. It's strongly - advised to use cpusets instead to disable scheduler load - balancing through the "cpuset.sched_load_balance" file. - It offers a much more flexible interface where CPUs can - move in and out of an isolated set anytime. + the domains once isolated through this boot time + configuration. Use cpusets for a dynamic configuration + which can be altered at runtime. For details see + Documentation/admin-guide/cpu-isolation.rst. You can move a process onto or off an "isolated" CPU via the CPU affinity syscalls or cpuset. From 49cbd359e4a7501e9d6694c072031d9ae6b2d1a5 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Mon, 27 Apr 2026 15:17:09 +0200 Subject: [PATCH 030/655] Documentation/rv: Replace stale website link The sched monitor page was linking to Daniel's website which is now down. The main purpose of the link was to point to a source for the models from the original author and that can be found also in his published paper. Replace the link with a reference to Daniel's "A thread synchronization model for the PREEMPT_RT Linux kernel" which can be found online and includes the models definitions as well as the work behind them (not the original patches but since they're based on a 5.0 kernel and are mostly included upstream, there's little value in keeping them in the docs). Fixes: 03abeaa63c08 ("Documentation/rv: Add docs for the sched monitors") Signed-off-by: Gabriele Monaco Acked-by: Matteo Martelli Tested-by: Matteo Martelli Tested-by: Randy Dunlap Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260427131709.170505-2-gmonaco@redhat.com> --- Documentation/trace/rv/monitor_sched.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/trace/rv/monitor_sched.rst b/Documentation/trace/rv/monitor_sched.rst index 0b96d6e147c6..d3ba7edc202f 100644 --- a/Documentation/trace/rv/monitor_sched.rst +++ b/Documentation/trace/rv/monitor_sched.rst @@ -36,7 +36,7 @@ Specifications -------------- The specifications included in sched are currently a work in progress, adapting the ones -defined in by Daniel Bristot in [1]. +defined by Daniel Bristot in [1]_. Currently we included the following: @@ -365,4 +365,7 @@ constraints when processing the events:: References ---------- -[1] - https://bristot.me/linux-task-model +.. [1] Daniel Bristot de Oliveira et al.: + `A thread synchronization model for the PREEMPT_RT Linux kernel + `_, + J. Syst. Archit., 2020. From 077f0972192390191279700194b6a230a5662127 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 22 Apr 2026 17:10:38 -0400 Subject: [PATCH 031/655] Documentation: filesystems: cramfs: correct stale hard-link and endianness claims Two paragraphs in cramfs.rst have been misleading for a long time: - "Hard links are supported, but hard linked files will still have a link count of 1": mkcramfs does not preserve hard links; it deduplicates by content (eliminate_doubles()). Two names for the same on-disk inode in the source tree become two separate (content-shared) entries in the image, and cramfs always reports a link count of 1. - "Currently, cramfs must be written and read with architectures of the same endianness ... PAGE_SIZE == 4096 ... is a bug, but it hasn't been decided what the best fix is": the endianness situation has been settled for years -- the kernel checks for CRAMFS_MAGIC_WEND in cramfs_fill_super() and refuses the mount, and mkcramfs has gained -B / -L for producing images of the opposite endianness from the build host (useful for cross-builds, but the reader still needs to match). Restate this accurately. Signed-off-by: Nicolas Pitre Signed-off-by: Jonathan Corbet Message-ID: <20260422211039.270552-1-nico@fluxnic.net> --- Documentation/filesystems/cramfs.rst | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/filesystems/cramfs.rst b/Documentation/filesystems/cramfs.rst index afbdbde98bd2..221c0bf91b9c 100644 --- a/Documentation/filesystems/cramfs.rst +++ b/Documentation/filesystems/cramfs.rst @@ -28,8 +28,10 @@ Only the low 8 bits of gid are stored. The current version of mkcramfs simply truncates to 8 bits, which is a potential security issue. -Hard links are supported, but hard linked files -will still have a link count of 1 in the cramfs image. +Hard links are not preserved. mkcramfs deduplicates files with +identical content, but two names for the same on-disk inode in the +source tree become two separate (content-shared) entries in the +image, and cramfs always reports a link count of 1. Cramfs directories have no ``.`` or ``..`` entries. Directories (like every other file on cramfs) always have a link count of 1. (There's @@ -40,12 +42,16 @@ No timestamps are stored in a cramfs, so these default to the epoch the update lasts only as long as the inode is cached in memory, after which the timestamp reverts to 1970, i.e. moves backwards in time. -Currently, cramfs must be written and read with architectures of the -same endianness, and can be read only by kernels with PAGE_SIZE -== 4096. At least the latter of these is a bug, but it hasn't been -decided what the best fix is. For the moment if you have larger pages -you can just change the #define in mkcramfs.c, so long as you don't -mind the filesystem becoming unreadable to future kernels. +The on-disk layout is host-endian: the kernel does not swab, and +refuses to mount an image whose endianness does not match the CPU. +For cross-builds, mkcramfs -B / -L forces the output endianness so +that a host of one endianness can produce an image for a target of +the other. + +The on-disk block size is fixed at 4096 bytes. On systems with a +larger PAGE_SIZE you can change the #define in mkcramfs.c, with the +caveat that the resulting image will only be readable on kernels +configured for the same PAGE_SIZE. Memory Mapped cramfs image From 2367ea8d9d62e8c40866f3a4f62d0cbb48c07822 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 22 Apr 2026 17:10:39 -0400 Subject: [PATCH 032/655] cramfs: drop obsolete Future Development notes and update tools URL fs/cramfs/README still carries a "Future Development" section written around the Linux 2.3.39 era discussing design decisions that have long since been settled: - Block size is 4096 and matches PAGE_SIZE on the reader. - Endianness is host-endian; mkcramfs -B / -L handles cross-builds. - Block-pointer extensions (CRAMFS_FLAG_EXT_BLOCK_POINTERS) ended up being the answer to layout flexibility rather than inode growth. Drop the stale forward-looking section -- the factual format description above remains accurate and is kept as-is. While here, replace the dead sourceforge URL in the "Tools" section with the current location of the user-space tools on github. Signed-off-by: Nicolas Pitre Signed-off-by: Jonathan Corbet Message-ID: <20260422211039.270552-2-nico@fluxnic.net> --- fs/cramfs/README | 92 +----------------------------------------------- 1 file changed, 1 insertion(+), 91 deletions(-) diff --git a/fs/cramfs/README b/fs/cramfs/README index 778df5c4d70b..c0052a11aa28 100644 --- a/fs/cramfs/README +++ b/fs/cramfs/README @@ -104,94 +104,4 @@ Tools ----- The cramfs user-space tools, including mkcramfs and cramfsck, are -located at . - - -Future Development -================== - -Block Size ----------- - -(Block size in cramfs refers to the size of input data that is -compressed at a time. It's intended to be somewhere around -PAGE_SIZE for cramfs_read_folio's convenience.) - -The superblock ought to indicate the block size that the fs was -written for, since comments in indicate that -PAGE_SIZE may grow in future (if I interpret the comment -correctly). - -Currently, mkcramfs #define's PAGE_SIZE as 4096 and uses that -for blksize, whereas Linux-2.3.39 uses its PAGE_SIZE, which in -turn is defined as PAGE_SIZE (which can be as large as 32KB on arm). -This discrepancy is a bug, though it's not clear which should be -changed. - -One option is to change mkcramfs to take its PAGE_SIZE from -. Personally I don't like this option, but it does -require the least amount of change: just change `#define -PAGE_SIZE (4096)' to `#include '. The disadvantage -is that the generated cramfs cannot always be shared between different -kernels, not even necessarily kernels of the same architecture if -PAGE_SIZE is subject to change between kernel versions -(currently possible with arm and ia64). - -The remaining options try to make cramfs more sharable. - -One part of that is addressing endianness. The two options here are -`always use little-endian' (like ext2fs) or `writer chooses -endianness; kernel adapts at runtime'. Little-endian wins because of -code simplicity and little CPU overhead even on big-endian machines. - -The cost of swabbing is changing the code to use the le32_to_cpu -etc. macros as used by ext2fs. We don't need to swab the compressed -data, only the superblock, inodes and block pointers. - - -The other part of making cramfs more sharable is choosing a block -size. The options are: - - 1. Always 4096 bytes. - - 2. Writer chooses blocksize; kernel adapts but rejects blocksize > - PAGE_SIZE. - - 3. Writer chooses blocksize; kernel adapts even to blocksize > - PAGE_SIZE. - -It's easy enough to change the kernel to use a smaller value than -PAGE_SIZE: just make cramfs_read_folio read multiple blocks. - -The cost of option 1 is that kernels with a larger PAGE_SIZE -value don't get as good compression as they can. - -The cost of option 2 relative to option 1 is that the code uses -variables instead of #define'd constants. The gain is that people -with kernels having larger PAGE_SIZE can make use of that if -they don't mind their cramfs being inaccessible to kernels with -smaller PAGE_SIZE values. - -Option 3 is easy to implement if we don't mind being CPU-inefficient: -e.g. get read_folio to decompress to a buffer of size MAX_BLKSIZE (which -must be no larger than 32KB) and discard what it doesn't need. -Getting read_folio to read into all the covered pages is harder. - -The main advantage of option 3 over 1, 2, is better compression. The -cost is greater complexity. Probably not worth it, but I hope someone -will disagree. (If it is implemented, then I'll re-use that code in -e2compr.) - - -Another cost of 2 and 3 over 1 is making mkcramfs use a different -block size, but that just means adding and parsing a -b option. - - -Inode Size ----------- - -Given that cramfs will probably be used for CDs etc. as well as just -silicon ROMs, it might make sense to expand the inode a little from -its current 12 bytes. Inodes other than the root inode are followed -by filename, so the expansion doesn't even have to be a multiple of 4 -bytes. +located at . From 551a7cf2158ce1f3f11e5fa092202fb656e6f8c3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 27 Feb 2026 17:03:58 -0800 Subject: [PATCH 033/655] docs: watchdog: mlx-wdt: small fixes Correct some grammar and spelling mistakes in mlx-wdt.rst. Signed-off-by: Randy Dunlap Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Corbet Message-ID: <20260228010402.2389343-2-rdunlap@infradead.org> --- Documentation/watchdog/mlx-wdt.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/watchdog/mlx-wdt.rst b/Documentation/watchdog/mlx-wdt.rst index 35e690dea9db..2da36c762890 100644 --- a/Documentation/watchdog/mlx-wdt.rst +++ b/Documentation/watchdog/mlx-wdt.rst @@ -28,7 +28,7 @@ Type 3: Same as Type 2 with extended maximum timeout period. Maximum timeout is 65535 sec. -Type 1 HW watchdog implementation exist in old systems and +Type 1 HW watchdog implementation exists in old systems and all new systems have type 2 HW watchdog. Two types of HW implementation have also different register map. @@ -48,7 +48,7 @@ which is optional. Watchdog can be started during a probe, in this case it will be pinged by watchdog core before watchdog device will be opened by user space application. -Watchdog can be initialised in nowayout way, i.e. oncse started +Watchdog can be initialised in nowayout mode, i.e. once started it can't be stopped. This mlx-wdt driver supports both HW watchdog implementations. From 996b4434be0364865e44d1ef3eed67df5fd8ce50 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 27 Feb 2026 17:03:59 -0800 Subject: [PATCH 034/655] docs: watchdog: pcwd: fix typo and driver info. Correct a typo and some technical info for the pcwd driver. Signed-off-by: Randy Dunlap Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Corbet Message-ID: <20260228010402.2389343-3-rdunlap@infradead.org> --- Documentation/watchdog/pcwd-watchdog.rst | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Documentation/watchdog/pcwd-watchdog.rst b/Documentation/watchdog/pcwd-watchdog.rst index 151505c856f6..5cd45abe246a 100644 --- a/Documentation/watchdog/pcwd-watchdog.rst +++ b/Documentation/watchdog/pcwd-watchdog.rst @@ -29,7 +29,7 @@ Documentation and Driver by Ken Hollis to run the program with an "&" to run it in the background!) If you want to write a program to be compatible with the PC Watchdog - driver, simply use of modify the watchdog test program: + driver, simply use or modify the watchdog test program: tools/testing/selftests/watchdog/watchdog-test.c @@ -37,16 +37,23 @@ Documentation and Driver by Ken Hollis WDIOC_GETSUPPORT This returns the support of the card itself. This - returns in structure "PCWDS" which returns: + returns in structure watchdog_info: + + identity = "PCWD" + + options = list of supported options:: + WDIOF_OVERHEAT + WDIOF_CARDRESET + WDIOF_KEEPALIVEPING + WDIOF_SETTIMEOUT + WDIOF_MAGICCLOSE - options = WDIOS_TEMPPANIC - (This card supports temperature) firmware_version = xxxx (Firmware version of the card) WDIOC_GETSTATUS This returns the status of the card, with the bits of - WDIOF_* bitwise-anded into the value. (The comments + WDIOF_* bitwise-ored into the value. (The comments are in include/uapi/linux/watchdog.h) WDIOC_GETBOOTSTATUS @@ -55,7 +62,7 @@ Documentation and Driver by Ken Hollis WDIOC_GETTEMP This returns the temperature of the card. (You can also - read /dev/watchdog, which gives a temperature update + read /dev/temperature, which gives a temperature update every second.) WDIOC_SETOPTIONS From 2a64c824d02331d41e6d4abd653ead05788c46c7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 27 Feb 2026 17:04:00 -0800 Subject: [PATCH 035/655] docs: watchdog-api: general cleaning Correct some grammar, punctuation, and capitalization mistakes. Drop extra words in printf() calls [likely a copy-paste error]. Signed-off-by: Randy Dunlap Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Corbet Message-ID: <20260228010402.2389343-4-rdunlap@infradead.org> --- Documentation/watchdog/watchdog-api.rst | 38 +++++++++++++------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Documentation/watchdog/watchdog-api.rst b/Documentation/watchdog/watchdog-api.rst index 78e228c272cf..983d4800d210 100644 --- a/Documentation/watchdog/watchdog-api.rst +++ b/Documentation/watchdog/watchdog-api.rst @@ -39,12 +39,12 @@ The simplest API All drivers support the basic mode of operation, where the watchdog activates as soon as /dev/watchdog is opened and will reboot unless -the watchdog is pinged within a certain time, this time is called the +the watchdog is pinged within a certain time; this time is called the timeout or margin. The simplest way to ping the watchdog is to write some data to the device. So a very simple watchdog daemon would look like this source file: see samples/watchdog/watchdog-simple.c -A more advanced driver could for example check that a HTTP server is +A more advanced driver could for example check that an HTTP server is still responding before doing the write call to ping the watchdog. When the device is closed, the watchdog is disabled, unless the "Magic @@ -87,13 +87,13 @@ replaced with:: sleep(10); } -the argument to the ioctl is ignored. +The argument to the ioctl is ignored. Setting and getting the timeout =============================== For some drivers it is possible to modify the watchdog timeout on the -fly with the SETTIMEOUT ioctl, those drivers have the WDIOF_SETTIMEOUT +fly with the SETTIMEOUT ioctl; those drivers have the WDIOF_SETTIMEOUT flag set in their option field. The argument is an integer representing the timeout in seconds. The driver returns the real timeout used in the same variable, and this timeout might differ from @@ -110,7 +110,7 @@ Starting with the Linux 2.4.18 kernel, it is possible to query the current timeout using the GETTIMEOUT ioctl:: ioctl(fd, WDIOC_GETTIMEOUT, &timeout); - printf("The timeout was is %d seconds\n", timeout); + printf("The timeout is %d seconds\n", timeout); Pretimeouts =========== @@ -133,7 +133,7 @@ seconds. Setting a pretimeout to zero disables it. There is also a get function for getting the pretimeout:: ioctl(fd, WDIOC_GETPRETIMEOUT, &timeout); - printf("The pretimeout was is %d seconds\n", timeout); + printf("The pretimeout is %d seconds\n", timeout); Not all watchdog drivers will support a pretimeout. @@ -145,13 +145,13 @@ before the system will reboot. The WDIOC_GETTIMELEFT is the ioctl that returns the number of seconds before reboot:: ioctl(fd, WDIOC_GETTIMELEFT, &timeleft); - printf("The timeout was is %d seconds\n", timeleft); + printf("The timeout is %d seconds\n", timeleft); Environmental monitoring ======================== -All watchdog drivers are required return more information about the system, -some do temperature, fan and power level monitoring, some can tell you +All watchdog drivers are required to return more information about the system. +Some do temperature, fan and power level monitoring; some can tell you the reason for the last reboot of the system. The GETSUPPORT ioctl is available to ask what the device can do:: @@ -166,7 +166,7 @@ the fields returned in the ident struct are: options a flags describing what the device supports ================ ============================================= -the options field can have the following bits set, and describes what +The options field can have the following bits set, and describes what kind of information that the GET_STATUS and GET_BOOT_STATUS ioctls can return. @@ -175,13 +175,13 @@ return. ================ ========================= The machine was last rebooted by the watchdog because the thermal limit was -exceeded: +exceeded. ============== ========== WDIOF_FANFAULT Fan failed ============== ========== -A system fan monitored by the watchdog card has failed +A system fan monitored by the watchdog card has failed. ============= ================ WDIOF_EXTERN1 External relay 1 @@ -195,26 +195,26 @@ a reset. WDIOF_EXTERN2 External relay 2 ============= ================ -External monitoring relay/source 2 was triggered +External monitoring relay/source 2 was triggered. ================ ===================== WDIOF_POWERUNDER Power bad/power fault ================ ===================== -The machine is showing an undervoltage status +The machine is showing an undervoltage status. =============== ============================= WDIOF_CARDRESET Card previously reset the CPU =============== ============================= -The last reboot was caused by the watchdog card +The last reboot was caused by the watchdog card. ================ ===================== WDIOF_POWEROVER Power over voltage ================ ===================== The machine is showing an overvoltage status. Note that if one level is -under and one over both bits will be set - this may seem odd but makes +under and one over, both bits will be set - this may seem odd but makes sense. =================== ===================== @@ -227,12 +227,14 @@ The watchdog saw a keepalive ping since it was last queried. WDIOF_SETTIMEOUT Can set/get the timeout ================ ======================= -The watchdog can do pretimeouts. +The watchdog can get/set the timeout. ================ ================================ WDIOF_PRETIMEOUT Pretimeout (in seconds), get/set ================ ================================ +The watchdog can do pretimeouts. + For those drivers that return any bits set in the option field, the GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current @@ -255,7 +257,7 @@ returned value is the temperature in degrees Fahrenheit:: ioctl(fd, WDIOC_GETTEMP, &temperature); Finally the SETOPTIONS ioctl can be used to control some aspects of -the cards operation:: +the card's operation:: int options = 0; ioctl(fd, WDIOC_SETOPTIONS, &options); From bb227ba68c0358fa5472aff54d66a6e5a541fdf9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 27 Feb 2026 17:04:01 -0800 Subject: [PATCH 036/655] docs: watchdog-kernel-api: general cleanups Fix grammar and punctuation. Add a missing struct member (pm_nb) and its description. Add a subheading for Helper Functions between the struct descriptions and just pure helper functions. Signed-off-by: Randy Dunlap Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Corbet Message-ID: <20260228010402.2389343-5-rdunlap@infradead.org> --- .../watchdog/watchdog-kernel-api.rst | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Documentation/watchdog/watchdog-kernel-api.rst b/Documentation/watchdog/watchdog-kernel-api.rst index 5649c54cf6fb..350e9037a69e 100644 --- a/Documentation/watchdog/watchdog-kernel-api.rst +++ b/Documentation/watchdog/watchdog-kernel-api.rst @@ -38,8 +38,8 @@ The watchdog_unregister_device routine deregisters a registered watchdog timer device. The parameter of this routine is the pointer to the registered watchdog_device structure. -The watchdog subsystem includes an registration deferral mechanism, -which allows you to register an watchdog as early as you wish during +The watchdog subsystem includes a registration deferral mechanism, +which allows you to register a watchdog as early as you wish during the boot process. The watchdog device structure looks like this:: @@ -60,13 +60,14 @@ The watchdog device structure looks like this:: unsigned int max_hw_heartbeat_ms; struct notifier_block reboot_nb; struct notifier_block restart_nb; + struct notifier_block pm_nb; void *driver_data; struct watchdog_core_data *wd_data; unsigned long status; struct list_head deferred; }; -It contains following fields: +It contains the following fields: * id: set by watchdog_register_device, id 0 is special. It has both a /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old @@ -105,6 +106,8 @@ It contains following fields: internal use only. If a watchdog is capable of restarting the machine, it should define ops->restart. Priority can be changed through watchdog_set_restart_priority. +* pm_nb: coordinates watchdog_dev_suspend/resume to cancel a ping worker + during suspend and restore it during resume. * bootstatus: status of the device after booting (reported with watchdog WDIOF_* status bits). * driver_data: a pointer to the drivers private data of a watchdog device. @@ -204,7 +207,7 @@ they are supported. These optional routines/operations are: If the watchdog driver does not have to perform any action but setting the watchdog_device.timeout, this callback can be omitted. - If set_timeout is not provided but, WDIOF_SETTIMEOUT is set, the watchdog + If set_timeout is not provided but WDIOF_SETTIMEOUT is set, the watchdog infrastructure updates the timeout value of the watchdog_device internally to the requested value. @@ -220,7 +223,7 @@ they are supported. These optional routines/operations are: the watchdog". A value of 0 disables pretimeout notification. (Note: the WDIOF_PRETIMEOUT needs to be set in the options field of the - watchdog's info structure). + watchdog's info structure.) If the watchdog driver does not have to perform any action but setting the watchdog_device.pretimeout, this callback can be omitted. That means if @@ -239,7 +242,7 @@ they are supported. These optional routines/operations are: The status bits should (preferably) be set with the set_bit and clear_bit alike bit-operations. The status bits that are defined are: -* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device +* WDOG_ACTIVE: this status bit indicates whether a watchdog timer device is active or not from user perspective. User space is expected to send heartbeat requests to the driver while this flag is set. * WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog. @@ -254,6 +257,9 @@ bit-operations. The status bits that are defined are: then opening /dev/watchdog will skip the start operation but send a keepalive request instead. +Helper Functions +~~~~~~~~~~~~~~~~ + To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog timer device) you can either: @@ -331,7 +337,7 @@ To raise a pretimeout notification, the following function should be used:: void watchdog_notify_pretimeout(struct watchdog_device *wdd) The function can be called in the interrupt context. If watchdog pretimeout -governor framework (kbuild CONFIG_WATCHDOG_PRETIMEOUT_GOV symbol) is enabled, +governor framework (kconfig CONFIG_WATCHDOG_PRETIMEOUT_GOV symbol) is enabled, an action is taken by a preconfigured pretimeout governor preassigned to the watchdog device. If watchdog pretimeout governor framework is not enabled, watchdog_notify_pretimeout() prints a notification message to From 6f8daf6670d3c33b45a5f0b1f78566385424519b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 27 Feb 2026 17:04:02 -0800 Subject: [PATCH 037/655] docs: watchdog-parameters: add missing watchdog_core parameters Add missing watchdog_core parameters (handle_boot_enabled and stop_on_reboot). Add default values for handle_boot_enabled and open_timeout. Signed-off-by: Randy Dunlap Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Corbet Message-ID: <20260228010402.2389343-6-rdunlap@infradead.org> --- Documentation/watchdog/watchdog-parameters.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/watchdog/watchdog-parameters.rst b/Documentation/watchdog/watchdog-parameters.rst index 773241ed9986..2359aa32e25d 100644 --- a/Documentation/watchdog/watchdog-parameters.rst +++ b/Documentation/watchdog/watchdog-parameters.rst @@ -14,13 +14,22 @@ modules. ------------------------------------------------- watchdog core: + handle_boot_enabled: + Watchdog core auto-updates boot-enabled watchdogs before userspace + takes over. Default is set by the kconfig option + CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED. + open_timeout: Maximum time, in seconds, for which the watchdog framework will take care of pinging a running hardware watchdog until userspace opens the corresponding /dev/watchdogN device. A value of 0 means an infinite timeout. Setting this to a non-zero value can be useful to ensure that either userspace comes up properly, or the board gets reset and allows - fallback logic in the bootloader to try something else. + fallback logic in the bootloader to try something else. Default is set + by the kconfig option CONFIG_WATCHDOG_OPEN_TIMEOUT. + + stop_on_reboot: + Stops watchdogs on reboot (0 = keep watching, 1 = stop). ------------------------------------------------- From 45a92c0b91d7d13434d0bc8f169abeb8a4519871 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:19 +0200 Subject: [PATCH 038/655] docs: maintainers: add SPDX license to the file While this file is really trivial, add a SPDX license line on it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/process/maintainers.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/process/maintainers.rst b/Documentation/process/maintainers.rst index 6174cfb4138f..5d1b1464c3ae 100644 --- a/Documentation/process/maintainers.rst +++ b/Documentation/process/maintainers.rst @@ -1 +1,3 @@ +.. SPDX-License-Identifier: GPL-2.0 + .. maintainers-include:: From 6b6d73de37581d1bc4f21e5bc1bd236caa66c7cf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:20 +0200 Subject: [PATCH 039/655] docs: maintainers_include: auto-generate maintainer profile TOC Add a feature to allow auto-generating media entry profiles from the corresponding field inside MAINTAINERS file(s). Suggested-by: Dan Williams Closes: https://lore.kernel.org/linux-doc/69dd6299440be_147c801005b@djbw-dev.notmuch/ Acked-by: Dan Williams Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Message-ID: <4e9512a3d05942c98361d06d60a118d7c78762b6.1776176108.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/sphinx/maintainers_include.py | 93 +++++++++++++++++---- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 519ad18685b2..1dac83bf1a65 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -21,6 +21,8 @@ import sys import re import os.path +from textwrap import indent + from docutils import statemachine from docutils.parsers.rst import Directive from docutils.parsers.rst.directives.misc import Include @@ -30,20 +32,11 @@ def ErrorString(exc): # Shamelessly stolen from docutils __version__ = '1.0' -def setup(app): - app.add_directive("maintainers-include", MaintainersInclude) - return dict( - version = __version__, - parallel_read_safe = True, - parallel_write_safe = True - ) +class MaintainersParser: + """Parse MAINTAINERS file(s) content""" -class MaintainersInclude(Include): - """MaintainersInclude (``maintainers-include``) directive""" - required_arguments = 0 - - def parse_maintainers(self, path): - """Parse all the MAINTAINERS lines into ReST for human-readability""" + def __init__(self, base_path, path): + self.profiles = list() result = list() result.append(".. _maintainers:") @@ -78,6 +71,12 @@ class MaintainersInclude(Include): # Drop needless input whitespace. line = line.rstrip() + match = re.match(r"P:\s*(Documentation/\S+)\.rst", line) + if match: + fname = os.path.relpath(match.group(1), base_path) + if fname not in self.profiles: + self.profiles.append(fname) + # Linkify all non-wildcard refs to ReST files in Documentation/. pat = r'(Documentation/([^\s\?\*]*)\.rst)' m = re.search(pat, line) @@ -165,12 +164,23 @@ class MaintainersInclude(Include): for separated in field_content.split('\n'): result.append(separated) - output = "\n".join(result) + self.output = "\n".join(result) + + # Create a TOC class + +class MaintainersInclude(Include): + """MaintainersInclude (``maintainers-include``) directive""" + required_arguments = 0 + + def emit(self, base_path, path): + """Parse all the MAINTAINERS lines into ReST for human-readability""" + + output = MaintainersParser(base_path, path).output + # For debugging the pre-rendered results... #print(output, file=open("/tmp/MAINTAINERS.rst", "w")) - self.state_machine.insert_input( - statemachine.string2lines(output), path) + self.state_machine.insert_input(statemachine.string2lines(output), path) def run(self): """Include the MAINTAINERS file as part of this reST file.""" @@ -186,12 +196,61 @@ class MaintainersInclude(Include): # Append "MAINTAINERS" path = os.path.join(path, "MAINTAINERS") + base_path = os.path.dirname(self.state.document.document.current_source) try: self.state.document.settings.record_dependencies.add(path) - lines = self.parse_maintainers(path) + lines = self.emit(base_path, path) except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) return [] + +class MaintainersProfile(Include): + required_arguments = 0 + + def emit(self, base_path, path): + """Parse all the MAINTAINERS lines looking for profile entries""" + + profiles = MaintainersParser(base_path, path).profiles + + output = ".. toctree::\n" + output += " :maxdepth: 2\n\n" + output += indent("\n".join(profiles), " ") + + self.state_machine.insert_input(statemachine.string2lines(output), path) + + def run(self): + """Include the MAINTAINERS file as part of this reST file.""" + if not self.state.document.settings.file_insertion_enabled: + raise self.warning('"%s" directive disabled.' % self.name) + + # Walk up source path directories to find Documentation/../ + path = self.state_machine.document.attributes['source'] + path = os.path.realpath(path) + tail = path + while tail != "Documentation" and tail != "": + (path, tail) = os.path.split(path) + + # Append "MAINTAINERS" + path = os.path.join(path, "MAINTAINERS") + base_path = os.path.dirname(self.state.document.document.current_source) + + try: + self.state.document.settings.record_dependencies.add(path) + lines = self.emit(base_path, path) + except IOError as error: + raise self.severe('Problems with "%s" directive path:\n%s.' % + (self.name, ErrorString(error))) + + return [] + +def setup(app): + app.add_directive("maintainers-include", MaintainersInclude) + app.add_directive("maintainers-profile-toc", MaintainersProfile) + return dict( + version = __version__, + parallel_read_safe = True, + parallel_write_safe = True + ) From 8eae6da5f56ca1b1fc8035daa11c85e156052c44 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:21 +0200 Subject: [PATCH 040/655] docs: auto-generate maintainer entry profile links Instead of manually creating a TOC tree for them, use the new tag to auto-generate its TOC. Co-developed-by: Dan Williams Signed-off-by: Dan Williams Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Message-ID: <9228f77b0339b8e5dea4a201ab6d4feb30cef5c2.1776176108.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: <65e3f1d51eda0984ac945f50128b593f848584bc.1777295258.git.mchehab+huawei@kernel.org> --- .../maintainer/maintainer-entry-profile.rst | 24 ++++--------------- .../process/maintainer-handbooks.rst | 19 ++++++++------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/Documentation/maintainer/maintainer-entry-profile.rst b/Documentation/maintainer/maintainer-entry-profile.rst index 6020d188e13d..58e2af333692 100644 --- a/Documentation/maintainer/maintainer-entry-profile.rst +++ b/Documentation/maintainer/maintainer-entry-profile.rst @@ -92,24 +92,8 @@ full series, or privately send a reminder email. This section might also list how review works for this code area and methods to get feedback that are not directly from the maintainer. -Existing profiles ------------------ +Maintainer Handbooks +-------------------- -For now, existing maintainer profiles are listed here; we will likely want -to do something different in the near future. - -.. toctree:: - :maxdepth: 1 - - ../doc-guide/maintainer-profile - ../nvdimm/maintainer-entry-profile - ../arch/riscv/patch-acceptance - ../process/maintainer-soc - ../process/maintainer-soc-clean-dts - ../driver-api/media/maintainer-entry-profile - ../process/maintainer-netdev - ../driver-api/vfio-pci-device-specific-driver-acceptance - ../nvme/feature-and-quirk-policy - ../filesystems/nfs/nfsd-maintainer-entry-profile - ../filesystems/xfs/xfs-maintainer-entry-profile - ../mm/damon/maintainer-profile +For examples of other subsystem handbooks see +Documentation/process/maintainer-handbooks.rst. diff --git a/Documentation/process/maintainer-handbooks.rst b/Documentation/process/maintainer-handbooks.rst index 3d72ad25fc6a..531985a0fae8 100644 --- a/Documentation/process/maintainer-handbooks.rst +++ b/Documentation/process/maintainer-handbooks.rst @@ -7,14 +7,15 @@ The purpose of this document is to provide subsystem specific information which is supplementary to the general development process handbook :ref:`Documentation/process `. +For developers, see below for all the known subsystem specific guides. +If the subsystem you are contributing to does not have a guide listed +here, it is fair to seek clarification of questions raised in +Documentation/maintainer/maintainer-entry-profile.rst. + +For maintainers, consider documenting additional requirements and +expectations if submissions routinely overlook specific submission +criteria. See Documentation/maintainer/maintainer-entry-profile.rst. + Contents: -.. toctree:: - :numbered: - :maxdepth: 2 - - maintainer-netdev - maintainer-soc - maintainer-soc-clean-dts - maintainer-tip - maintainer-kvm-x86 +.. maintainers-profile-toc:: From b01f7f29f71b4c1b0dc402d9b4e48e2f0ea541f8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:22 +0200 Subject: [PATCH 041/655] docs: maintainers_include: use a better title for profiles As we're picking the name of the subsystem from MAINTAINERS, also use its subsystem name for the titles. Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <8ce9c77c4d8c98e6bad37d838b0e359c8416040c.1777295258.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 1dac83bf1a65..cf428db7599c 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -36,7 +36,7 @@ class MaintainersParser: """Parse MAINTAINERS file(s) content""" def __init__(self, base_path, path): - self.profiles = list() + self.profiles = {} result = list() result.append(".. _maintainers:") @@ -54,6 +54,7 @@ class MaintainersParser: prev = None field_prev = "" field_content = "" + subsystem_name = None for line in open(path): # Have we reached the end of the preformatted Descriptions text? @@ -75,7 +76,10 @@ class MaintainersParser: if match: fname = os.path.relpath(match.group(1), base_path) if fname not in self.profiles: - self.profiles.append(fname) + if self.profiles.get(fname) is None: + self.profiles[fname] = subsystem_name + else: + self.profiles[fname] += f", {subsystem_name}" # Linkify all non-wildcard refs to ReST files in Documentation/. pat = r'(Documentation/([^\s\?\*]*)\.rst)' @@ -112,6 +116,8 @@ class MaintainersParser: output = field_content + "\n\n" field_content = "" + subsystem_name = line.title() + # Collapse whitespace in subsystem name. heading = re.sub(r"\s+", " ", line) output = output + "%s\n%s" % (heading, "~" * len(heading)) @@ -217,7 +223,13 @@ class MaintainersProfile(Include): output = ".. toctree::\n" output += " :maxdepth: 2\n\n" - output += indent("\n".join(profiles), " ") + + items = sorted(profiles.items(), key=lambda kv: (kv[1] or "", kv[0])) + for fname, profile in items: + if profile: + output += f" {profile} <{fname}>\n" + else: + output += f" {fname}\n" self.state_machine.insert_input(statemachine.string2lines(output), path) From a2560483c6cf1c0a8f2ad0887d3af87cf701150b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:23 +0200 Subject: [PATCH 042/655] docs: maintainers_include: add external profile URLs Some subsystem profiles are maintained elsewhere. Add them to the output. Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/sphinx/maintainers_include.py | 28 +++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index cf428db7599c..f1b8d4b00c2a 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -37,6 +37,7 @@ class MaintainersParser: def __init__(self, base_path, path): self.profiles = {} + self.profile_urls = {} result = list() result.append(".. _maintainers:") @@ -81,6 +82,16 @@ class MaintainersParser: else: self.profiles[fname] += f", {subsystem_name}" + match = re.match(r"P:\s*(https?://.*)", line) + if match: + url = match.group(1).strip() + if url not in self.profile_urls: + if self.profile_urls.get(url) is None: + self.profile_urls[url] = subsystem_name + else: + self.profile_urls[url] += f", {subsystem_name}" + + # Linkify all non-wildcard refs to ReST files in Documentation/. pat = r'(Documentation/([^\s\?\*]*)\.rst)' m = re.search(pat, line) @@ -219,18 +230,31 @@ class MaintainersProfile(Include): def emit(self, base_path, path): """Parse all the MAINTAINERS lines looking for profile entries""" - profiles = MaintainersParser(base_path, path).profiles + maint = MaintainersParser(base_path, path) output = ".. toctree::\n" output += " :maxdepth: 2\n\n" - items = sorted(profiles.items(), key=lambda kv: (kv[1] or "", kv[0])) + items = sorted(maint.profiles.items(), + key=lambda kv: (kv[1] or "", kv[0])) for fname, profile in items: if profile: output += f" {profile} <{fname}>\n" else: output += f" {fname}\n" + output += "\n**External profiles**\n\n" + + items = sorted(maint.profile_urls.items(), + key=lambda kv: (kv[1] or "", kv[0])) + for url, profile in items: + if profile: + output += f"- {profile} <{url}>\n" + else: + output += f"- {url}\n" + + output += "\n" + self.state_machine.insert_input(statemachine.string2lines(output), path) def run(self): From 66a40162db04f294845d41dfd1fb977c737fa744 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:24 +0200 Subject: [PATCH 043/655] docs: maintainers_include: preserve names for files under process/ When a maintainer's profile is stored outside process, they're already included on some other book and the name of the filesystem may not be there. That's why the logic picks the name from the subsystem's name. However, files directly placed together with maintainers-handbooks.rst (e.g. under Documentation/process/) is a different history: those aren't placed anywhere, so we can keep using their own names, letting Sphinx do his thing. Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <46961bc932be804cec19f06d202c23423d4aa12a.1777295258.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index f1b8d4b00c2a..948746b998a3 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -76,11 +76,13 @@ class MaintainersParser: match = re.match(r"P:\s*(Documentation/\S+)\.rst", line) if match: fname = os.path.relpath(match.group(1), base_path) - if fname not in self.profiles: + if fname.startswith("../"): if self.profiles.get(fname) is None: self.profiles[fname] = subsystem_name else: self.profiles[fname] += f", {subsystem_name}" + else: + self.profiles[fname] = None match = re.match(r"P:\s*(https?://.*)", line) if match: From bda185c3059332ed9d64209858292233b71df7e3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:25 +0200 Subject: [PATCH 044/655] docs: maintainers_include: Only show main entry for profiles Instead of showing as a "Contents:" with 2 identation levels, drop its title and show profiles as a list of entries. Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <387b42c523e7b9f33e61cdff6fadb1df265cf71d.1777295258.git.mchehab+huawei@kernel.org> --- Documentation/process/maintainer-handbooks.rst | 2 -- Documentation/sphinx/maintainers_include.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/process/maintainer-handbooks.rst b/Documentation/process/maintainer-handbooks.rst index 531985a0fae8..3821e78aefc0 100644 --- a/Documentation/process/maintainer-handbooks.rst +++ b/Documentation/process/maintainer-handbooks.rst @@ -16,6 +16,4 @@ For maintainers, consider documenting additional requirements and expectations if submissions routinely overlook specific submission criteria. See Documentation/maintainer/maintainer-entry-profile.rst. -Contents: - .. maintainers-profile-toc:: diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 948746b998a3..7ab921820612 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -235,7 +235,7 @@ class MaintainersProfile(Include): maint = MaintainersParser(base_path, path) output = ".. toctree::\n" - output += " :maxdepth: 2\n\n" + output += " :maxdepth: 1\n\n" items = sorted(maint.profiles.items(), key=lambda kv: (kv[1] or "", kv[0])) From 237abdfaa696b59b8fe750c915ec7d0f5233df90 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:26 +0200 Subject: [PATCH 045/655] docs: maintainers_include: improve its output There are three "types" of profiles: 1. Profiles already included inside subsystem-specific documentation. This is the most common case; 2. Profiles that are hosted externally; 3. Profiles that are at the same location as maintainer-handbooks.rst. For (3), we need to create a TOC, as they don't exist elsewhere. Change the logic to create TOC just for (3), prepending the content of maintainer-handbooks with a sorted entry of all types, before the TOC. With such change, we can have an unique sorted list of profiles, having the subsystem names used there listed. Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <10d06a3f530e07ad981aba93617a9a7f4d63c408.1777295258.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 76 +++++++++++---------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 7ab921820612..5413c1350bba 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -21,7 +21,7 @@ import sys import re import os.path -from textwrap import indent +from glob import glob from docutils import statemachine from docutils.parsers.rst import Directive @@ -36,8 +36,8 @@ class MaintainersParser: """Parse MAINTAINERS file(s) content""" def __init__(self, base_path, path): - self.profiles = {} - self.profile_urls = {} + self.profile_toc = set() + self.profile_entries = {} result = list() result.append(".. _maintainers:") @@ -73,26 +73,24 @@ class MaintainersParser: # Drop needless input whitespace. line = line.rstrip() + # + # Handle profile entries - either as files or as https refs + # match = re.match(r"P:\s*(Documentation/\S+)\.rst", line) if match: - fname = os.path.relpath(match.group(1), base_path) - if fname.startswith("../"): - if self.profiles.get(fname) is None: - self.profiles[fname] = subsystem_name - else: - self.profiles[fname] += f", {subsystem_name}" + entry = os.path.relpath(match.group(1), base_path) + if "*" in entry: + for e in glob(entry): + self.profile_toc.add(e) + self.profile_entries[subsystem_name] = e else: - self.profiles[fname] = None - - match = re.match(r"P:\s*(https?://.*)", line) - if match: - url = match.group(1).strip() - if url not in self.profile_urls: - if self.profile_urls.get(url) is None: - self.profile_urls[url] = subsystem_name - else: - self.profile_urls[url] += f", {subsystem_name}" - + self.profile_toc.add(entry) + self.profile_entries[subsystem_name] = entry + else: + match = re.match(r"P:\s*(https?://.*)", line) + if match: + entry = match.group(1).strip() + self.profile_entries[subsystem_name] = entry # Linkify all non-wildcard refs to ReST files in Documentation/. pat = r'(Documentation/([^\s\?\*]*)\.rst)' @@ -234,26 +232,32 @@ class MaintainersProfile(Include): maint = MaintainersParser(base_path, path) - output = ".. toctree::\n" - output += " :maxdepth: 1\n\n" + # + # Produce a list with all maintainer profiles, sorted by subsystem name + # + output = "" - items = sorted(maint.profiles.items(), - key=lambda kv: (kv[1] or "", kv[0])) - for fname, profile in items: - if profile: - output += f" {profile} <{fname}>\n" + for profile, entry in maint.profile_entries.items(): + if entry.startswith("http"): + if profile: + output += f"- `{profile} <{entry}>`_\n" + else: + output += f"- `<{entry}>_`\n" else: - output += f" {fname}\n" + if profile: + output += f"- :doc:`{profile} <{entry}>`\n" + else: + output += f"- :doc:`<{entry}>`\n" - output += "\n**External profiles**\n\n" + # + # Create a hidden TOC table with all profiles. That allows adding + # profiles without needing to add them on any index.rst file. + # + output += "\n.. toctree::\n" + output += " :hidden:\n\n" - items = sorted(maint.profile_urls.items(), - key=lambda kv: (kv[1] or "", kv[0])) - for url, profile in items: - if profile: - output += f"- {profile} <{url}>\n" - else: - output += f"- {url}\n" + for fname in maint.profile_toc: + output += f" {fname}\n" output += "\n" From 6aaf2e91a1db4b2ea5e84af633f4410853a04a70 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:27 +0200 Subject: [PATCH 046/655] docs: maintainers_include: fix support for O=dir os.path.relpath() will do the wrong thing with O=dir, as the build system uses "cd " internally. Solve it by using app.srcdir, which, on normal cases, point to Documentation/, or, when SPHINXDIRS=process, it will be set with Documentation/process. While here, remove a dead code while writing maintainer profiles, as now all entries should have both profile and entry. Reported-by: Randy Dunlap Closes: https://lore.kernel.org/linux-doc/88335220-3527-4b1f-9500-417f7ebb7a02@infradead.org/T/#m6854cbd8d30e2c5d3e8c4173bae1c3d6922ff970 Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <193792d73d08d9f8b9faa8b3df8a1a7439344a28.1777295258.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 71 +++++++++++++++------ 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 5413c1350bba..ae52e8198750 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -27,15 +27,24 @@ from docutils import statemachine from docutils.parsers.rst import Directive from docutils.parsers.rst.directives.misc import Include +# +# Base URL for intersphinx-like links to maintainer profiles +# +KERNELDOC_URL = "https://docs.kernel.org/" + def ErrorString(exc): # Shamelessly stolen from docutils return f'{exc.__class__.__name}: {exc}' __version__ = '1.0' +app_dir = "." + class MaintainersParser: """Parse MAINTAINERS file(s) content""" - def __init__(self, base_path, path): + def __init__(self, path): + global app_dir + self.profile_toc = set() self.profile_entries = {} @@ -57,6 +66,9 @@ class MaintainersParser: field_content = "" subsystem_name = None + base_dir, doc_dir, sphinx_dir = app_dir.partition("Documentation") + print("BASE DIR", base_dir) + for line in open(path): # Have we reached the end of the preformatted Descriptions text? if descriptions and line.startswith('Maintainers'): @@ -76,9 +88,25 @@ class MaintainersParser: # # Handle profile entries - either as files or as https refs # - match = re.match(r"P:\s*(Documentation/\S+)\.rst", line) + match = re.match(rf"P:\s*({doc_dir})(/\S+)\.rst", line) if match: - entry = os.path.relpath(match.group(1), base_path) + name = "".join(match.groups()) + entry = os.path.relpath(base_dir + name, app_dir) + + full_name = os.path.join(base_dir, name) + path = os.path.relpath(full_name, app_dir) + # + # When SPHINXDIRS is used, it will try to reference files + # outside srctree, causing warnings. To avoid that, point + # to the latest official documentation + # + if path.startswith("../"): + entry = KERNELDOC_URL + match.group(2) + ".html" + else: + entry = "/" + entry + + print(f"{name}: entry: {entry} FULL: {full_name} path: {path}") + if "*" in entry: for e in glob(entry): self.profile_toc.add(e) @@ -189,10 +217,10 @@ class MaintainersInclude(Include): """MaintainersInclude (``maintainers-include``) directive""" required_arguments = 0 - def emit(self, base_path, path): + def emit(self, path): """Parse all the MAINTAINERS lines into ReST for human-readability""" - output = MaintainersParser(base_path, path).output + output = MaintainersParser(path).output # For debugging the pre-rendered results... #print(output, file=open("/tmp/MAINTAINERS.rst", "w")) @@ -213,11 +241,10 @@ class MaintainersInclude(Include): # Append "MAINTAINERS" path = os.path.join(path, "MAINTAINERS") - base_path = os.path.dirname(self.state.document.document.current_source) try: self.state.document.settings.record_dependencies.add(path) - lines = self.emit(base_path, path) + lines = self.emit(path) except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) @@ -227,27 +254,20 @@ class MaintainersInclude(Include): class MaintainersProfile(Include): required_arguments = 0 - def emit(self, base_path, path): + def emit(self, path): """Parse all the MAINTAINERS lines looking for profile entries""" - maint = MaintainersParser(base_path, path) + maint = MaintainersParser(path) # # Produce a list with all maintainer profiles, sorted by subsystem name # output = "" - - for profile, entry in maint.profile_entries.items(): + for profile, entry in sorted(maint.profile_entries.items()): if entry.startswith("http"): - if profile: - output += f"- `{profile} <{entry}>`_\n" - else: - output += f"- `<{entry}>_`\n" + output += f"- `{profile} <{entry}>`_\n" else: - if profile: - output += f"- :doc:`{profile} <{entry}>`\n" - else: - output += f"- :doc:`<{entry}>`\n" + output += f"- :doc:`{profile} <{entry}>`\n" # # Create a hidden TOC table with all profiles. That allows adding @@ -261,6 +281,8 @@ class MaintainersProfile(Include): output += "\n" + print(output) + self.state_machine.insert_input(statemachine.string2lines(output), path) def run(self): @@ -277,11 +299,10 @@ class MaintainersProfile(Include): # Append "MAINTAINERS" path = os.path.join(path, "MAINTAINERS") - base_path = os.path.dirname(self.state.document.document.current_source) try: self.state.document.settings.record_dependencies.add(path) - lines = self.emit(base_path, path) + lines = self.emit(path) except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) @@ -289,6 +310,14 @@ class MaintainersProfile(Include): return [] def setup(app): + global app_dir + + # + # NOTE: we're using os.fspath() here because of a Sphinx warning: + # RemovedInSphinx90Warning: Sphinx 9 will drop support for representing paths as strings. Use "pathlib.Path" or "os.fspath" instead. + # + app_dir = os.fspath(app.srcdir) + app.add_directive("maintainers-include", MaintainersInclude) app.add_directive("maintainers-profile-toc", MaintainersProfile) return dict( From a2a2faa66e0271ead9c0c429f4bea9ae3bf43ab1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Apr 2026 16:22:28 +0200 Subject: [PATCH 047/655] docs: maintainers_include: parse MAINTAINERS just once Change the logic to parse MAINTAINERS file content just once, while still allowing using it multiple times. Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <8060589074f54a276e563db8cad124d3f88346c7.1777295258.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 61 +++++++-------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index ae52e8198750..436e7ac42ffc 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -37,14 +37,13 @@ def ErrorString(exc): # Shamelessly stolen from docutils __version__ = '1.0' -app_dir = "." +maint_parser = None class MaintainersParser: """Parse MAINTAINERS file(s) content""" - def __init__(self, path): - global app_dir - + def __init__(self, app_dir, path): + self.path = path self.profile_toc = set() self.profile_entries = {} @@ -67,7 +66,6 @@ class MaintainersParser: subsystem_name = None base_dir, doc_dir, sphinx_dir = app_dir.partition("Documentation") - print("BASE DIR", base_dir) for line in open(path): # Have we reached the end of the preformatted Descriptions text? @@ -105,8 +103,6 @@ class MaintainersParser: else: entry = "/" + entry - print(f"{name}: entry: {entry} FULL: {full_name} path: {path}") - if "*" in entry: for e in glob(entry): self.profile_toc.add(e) @@ -217,14 +213,17 @@ class MaintainersInclude(Include): """MaintainersInclude (``maintainers-include``) directive""" required_arguments = 0 - def emit(self, path): + def emit(self): """Parse all the MAINTAINERS lines into ReST for human-readability""" + global maint_parser - output = MaintainersParser(path).output + path = maint_parser.path + output = maint_parser.output # For debugging the pre-rendered results... #print(output, file=open("/tmp/MAINTAINERS.rst", "w")) + self.state.document.settings.record_dependencies.add(path) self.state_machine.insert_input(statemachine.string2lines(output), path) def run(self): @@ -232,19 +231,8 @@ class MaintainersInclude(Include): if not self.state.document.settings.file_insertion_enabled: raise self.warning('"%s" directive disabled.' % self.name) - # Walk up source path directories to find Documentation/../ - path = self.state_machine.document.attributes['source'] - path = os.path.realpath(path) - tail = path - while tail != "Documentation" and tail != "": - (path, tail) = os.path.split(path) - - # Append "MAINTAINERS" - path = os.path.join(path, "MAINTAINERS") - try: - self.state.document.settings.record_dependencies.add(path) - lines = self.emit(path) + lines = self.emit() except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) @@ -254,16 +242,17 @@ class MaintainersInclude(Include): class MaintainersProfile(Include): required_arguments = 0 - def emit(self, path): + def emit(self): """Parse all the MAINTAINERS lines looking for profile entries""" + global maint_parser - maint = MaintainersParser(path) + path = maint_parser.path # # Produce a list with all maintainer profiles, sorted by subsystem name # output = "" - for profile, entry in sorted(maint.profile_entries.items()): + for profile, entry in sorted(maint_parser.profile_entries.items()): if entry.startswith("http"): output += f"- `{profile} <{entry}>`_\n" else: @@ -276,13 +265,12 @@ class MaintainersProfile(Include): output += "\n.. toctree::\n" output += " :hidden:\n\n" - for fname in maint.profile_toc: + for fname in maint_parser.profile_toc: output += f" {fname}\n" output += "\n" - print(output) - + self.state.document.settings.record_dependencies.add(path) self.state_machine.insert_input(statemachine.string2lines(output), path) def run(self): @@ -290,19 +278,8 @@ class MaintainersProfile(Include): if not self.state.document.settings.file_insertion_enabled: raise self.warning('"%s" directive disabled.' % self.name) - # Walk up source path directories to find Documentation/../ - path = self.state_machine.document.attributes['source'] - path = os.path.realpath(path) - tail = path - while tail != "Documentation" and tail != "": - (path, tail) = os.path.split(path) - - # Append "MAINTAINERS" - path = os.path.join(path, "MAINTAINERS") - try: - self.state.document.settings.record_dependencies.add(path) - lines = self.emit(path) + lines = self.emit() except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) @@ -310,13 +287,17 @@ class MaintainersProfile(Include): return [] def setup(app): - global app_dir + global maint_parser # # NOTE: we're using os.fspath() here because of a Sphinx warning: # RemovedInSphinx90Warning: Sphinx 9 will drop support for representing paths as strings. Use "pathlib.Path" or "os.fspath" instead. # app_dir = os.fspath(app.srcdir) + srctree = os.path.abspath(os.environ["srctree"]) + path = os.path.join(srctree, "MAINTAINERS") + + maint_parser = MaintainersParser(app_dir, path) app.add_directive("maintainers-include", MaintainersInclude) app.add_directive("maintainers-profile-toc", MaintainersProfile) From 151d4c1b2fbf7d9604a5f4de1bcb80a53a9ead1c Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Mon, 27 Apr 2026 18:48:02 -0700 Subject: [PATCH 048/655] watchdog: remove driver for integrated WDT of ZFx86 486-based SoC The machzwd driver supports the integrated watchdog of the ZF Micro ZFx86 SoC, which contains a 486-compatible core [1]. Since 486 support was removed in commit 8b793a92d862 ("x86/cpu: Remove M486/M486SX/ELAN support"), the driver is no longer useful, Remove it. [1] https://www.zfmicro.com/zfx86.html Signed-off-by: Ethan Nelson-Moore Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260428014806.35400-1-enelsonmoore@gmail.com Signed-off-by: Guenter Roeck --- .../watchdog/watchdog-parameters.rst | 10 - drivers/watchdog/Kconfig | 13 - drivers/watchdog/Makefile | 1 - drivers/watchdog/machzwd.c | 452 ------------------ 4 files changed, 476 deletions(-) delete mode 100644 drivers/watchdog/machzwd.c diff --git a/Documentation/watchdog/watchdog-parameters.rst b/Documentation/watchdog/watchdog-parameters.rst index 773241ed9986..173adee71901 100644 --- a/Documentation/watchdog/watchdog-parameters.rst +++ b/Documentation/watchdog/watchdog-parameters.rst @@ -284,16 +284,6 @@ ixp4xx_wdt: ------------------------------------------------- -machzwd: - nowayout: - Watchdog cannot be stopped once started - (default=kernel config parameter) - action: - after watchdog resets, generate: - 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI - -------------------------------------------------- - max63xx_wdt: heartbeat: Watchdog heartbeat period in seconds from 1 to 60, default 60 diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index dc78729ba2a5..97e320721cff 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1712,19 +1712,6 @@ config W83977F_WDT To compile this driver as a module, choose M here: the module will be called w83977f_wdt. -config MACHZ_WDT - tristate "ZF MachZ Watchdog" - depends on (X86 || COMPILE_TEST) && HAS_IOPORT - help - If you are using a ZF Micro MachZ processor, say Y here, otherwise - N. This is the driver for the watchdog timer built-in on that - processor using ZF-Logic interface. This watchdog simply watches - your kernel to make sure it doesn't freeze, and if it does, it - reboots your computer after a certain amount of time. - - To compile this driver as a module, choose M here: the - module will be called machzwd. - config SBC_EPX_C3_WATCHDOG tristate "Winsystems SBC EPX-C3 watchdog" depends on (X86 || COMPILE_TEST) && HAS_IOPORT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index d2fb16b9f9ce..2961ca141c61 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -146,7 +146,6 @@ obj-$(CONFIG_VIA_WDT) += via_wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o -obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o obj-$(CONFIG_INTEL_OC_WATCHDOG) += intel_oc_wdt.o diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c deleted file mode 100644 index 0ae8e5bc10ae..000000000000 --- a/drivers/watchdog/machzwd.c +++ /dev/null @@ -1,452 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MachZ ZF-Logic Watchdog Timer driver for Linux - * - * The author does NOT admit liability nor provide warranty for - * any of this software. This material is provided "AS-IS" in - * the hope that it may be useful for others. - * - * Author: Fernando Fuganti - * - * Based on sbc60xxwdt.c by Jakob Oestergaard - * - * We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the - * following periods: - * wd#1 - 2 seconds; - * wd#2 - 7.2 ms; - * After the expiration of wd#1, it can generate a NMI, SCI, SMI, or - * a system RESET and it starts wd#2 that unconditionally will RESET - * the system when the counter reaches zero. - * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* ports */ -#define ZF_IOBASE 0x218 -#define INDEX 0x218 -#define DATA_B 0x219 -#define DATA_W 0x21A -#define DATA_D 0x21A - -/* indexes */ /* size */ -#define ZFL_VERSION 0x02 /* 16 */ -#define CONTROL 0x10 /* 16 */ -#define STATUS 0x12 /* 8 */ -#define COUNTER_1 0x0C /* 16 */ -#define COUNTER_2 0x0E /* 8 */ -#define PULSE_LEN 0x0F /* 8 */ - -/* controls */ -#define ENABLE_WD1 0x0001 -#define ENABLE_WD2 0x0002 -#define RESET_WD1 0x0010 -#define RESET_WD2 0x0020 -#define GEN_SCI 0x0100 -#define GEN_NMI 0x0200 -#define GEN_SMI 0x0400 -#define GEN_RESET 0x0800 - - -/* utilities */ - -#define WD1 0 -#define WD2 1 - -#define zf_writew(port, data) { outb(port, INDEX); outw(data, DATA_W); } -#define zf_writeb(port, data) { outb(port, INDEX); outb(data, DATA_B); } -#define zf_get_ZFL_version() zf_readw(ZFL_VERSION) - - -static unsigned short zf_readw(unsigned char port) -{ - outb(port, INDEX); - return inw(DATA_W); -} - - -MODULE_AUTHOR("Fernando Fuganti "); -MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver"); -MODULE_LICENSE("GPL"); - -static bool nowayout = WATCHDOG_NOWAYOUT; -module_param(nowayout, bool, 0); -MODULE_PARM_DESC(nowayout, - "Watchdog cannot be stopped once started (default=" - __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); - -#define PFX "machzwd" - -static const struct watchdog_info zf_info = { - .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, - .firmware_version = 1, - .identity = "ZF-Logic watchdog", -}; - - -/* - * action refers to action taken when watchdog resets - * 0 = GEN_RESET - * 1 = GEN_SMI - * 2 = GEN_NMI - * 3 = GEN_SCI - * defaults to GEN_RESET (0) - */ -static int action; -module_param(action, int, 0); -MODULE_PARM_DESC(action, "after watchdog resets, generate: " - "0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); - -static void zf_ping(struct timer_list *unused); - -static int zf_action = GEN_RESET; -static unsigned long zf_is_open; -static char zf_expect_close; -static DEFINE_SPINLOCK(zf_port_lock); -static DEFINE_TIMER(zf_timer, zf_ping); -static unsigned long next_heartbeat; - - -/* timeout for user land heart beat (10 seconds) */ -#define ZF_USER_TIMEO (HZ*10) - -/* timeout for hardware watchdog (~500ms) */ -#define ZF_HW_TIMEO (HZ/2) - -/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */ -#define ZF_CTIMEOUT 0xffff - -#ifndef ZF_DEBUG -#define dprintk(format, args...) -#else -#define dprintk(format, args...) \ - pr_debug(":%s:%d: " format, __func__, __LINE__ , ## args) -#endif - - -static inline void zf_set_status(unsigned char new) -{ - zf_writeb(STATUS, new); -} - - -/* CONTROL register functions */ - -static inline unsigned short zf_get_control(void) -{ - return zf_readw(CONTROL); -} - -static inline void zf_set_control(unsigned short new) -{ - zf_writew(CONTROL, new); -} - - -/* WD#? counter functions */ -/* - * Just set counter value - */ - -static inline void zf_set_timer(unsigned short new, unsigned char n) -{ - switch (n) { - case WD1: - zf_writew(COUNTER_1, new); - fallthrough; - case WD2: - zf_writeb(COUNTER_2, new > 0xff ? 0xff : new); - fallthrough; - default: - return; - } -} - -/* - * stop hardware timer - */ -static void zf_timer_off(void) -{ - unsigned int ctrl_reg = 0; - unsigned long flags; - - /* stop internal ping */ - timer_delete_sync(&zf_timer); - - spin_lock_irqsave(&zf_port_lock, flags); - /* stop watchdog timer */ - ctrl_reg = zf_get_control(); - ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */ - ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2); - zf_set_control(ctrl_reg); - spin_unlock_irqrestore(&zf_port_lock, flags); - - pr_info("Watchdog timer is now disabled\n"); -} - - -/* - * start hardware timer - */ -static void zf_timer_on(void) -{ - unsigned int ctrl_reg = 0; - unsigned long flags; - - spin_lock_irqsave(&zf_port_lock, flags); - - zf_writeb(PULSE_LEN, 0xff); - - zf_set_timer(ZF_CTIMEOUT, WD1); - - /* user land ping */ - next_heartbeat = jiffies + ZF_USER_TIMEO; - - /* start the timer for internal ping */ - mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); - - /* start watchdog timer */ - ctrl_reg = zf_get_control(); - ctrl_reg |= (ENABLE_WD1|zf_action); - zf_set_control(ctrl_reg); - spin_unlock_irqrestore(&zf_port_lock, flags); - - pr_info("Watchdog timer is now enabled\n"); -} - - -static void zf_ping(struct timer_list *unused) -{ - unsigned int ctrl_reg = 0; - unsigned long flags; - - zf_writeb(COUNTER_2, 0xff); - - if (time_before(jiffies, next_heartbeat)) { - dprintk("time_before: %ld\n", next_heartbeat - jiffies); - /* - * reset event is activated by transition from 0 to 1 on - * RESET_WD1 bit and we assume that it is already zero... - */ - - spin_lock_irqsave(&zf_port_lock, flags); - ctrl_reg = zf_get_control(); - ctrl_reg |= RESET_WD1; - zf_set_control(ctrl_reg); - - /* ...and nothing changes until here */ - ctrl_reg &= ~(RESET_WD1); - zf_set_control(ctrl_reg); - spin_unlock_irqrestore(&zf_port_lock, flags); - - mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); - } else - pr_crit("I will reset your machine\n"); -} - -static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) -{ - /* See if we got the magic character */ - if (count) { - /* - * no need to check for close confirmation - * no way to disable watchdog ;) - */ - if (!nowayout) { - size_t ofs; - /* - * note: just in case someone wrote the magic character - * five months ago... - */ - zf_expect_close = 0; - - /* now scan */ - for (ofs = 0; ofs != count; ofs++) { - char c; - if (get_user(c, buf + ofs)) - return -EFAULT; - if (c == 'V') { - zf_expect_close = 42; - dprintk("zf_expect_close = 42\n"); - } - } - } - - /* - * Well, anyhow someone wrote to us, - * we should return that favour - */ - next_heartbeat = jiffies + ZF_USER_TIMEO; - dprintk("user ping at %ld\n", jiffies); - } - return count; -} - -static long zf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int __user *p = argp; - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &zf_info, sizeof(zf_info))) - return -EFAULT; - break; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_KEEPALIVE: - zf_ping(NULL); - break; - default: - return -ENOTTY; - } - return 0; -} - -static int zf_open(struct inode *inode, struct file *file) -{ - if (test_and_set_bit(0, &zf_is_open)) - return -EBUSY; - if (nowayout) - __module_get(THIS_MODULE); - zf_timer_on(); - return stream_open(inode, file); -} - -static int zf_close(struct inode *inode, struct file *file) -{ - if (zf_expect_close == 42) - zf_timer_off(); - else { - timer_delete(&zf_timer); - pr_err("device file closed unexpectedly. Will not stop the WDT!\n"); - } - clear_bit(0, &zf_is_open); - zf_expect_close = 0; - return 0; -} - -/* - * Notifier for system down - */ - -static int zf_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - zf_timer_off(); - return NOTIFY_DONE; -} - -static const struct file_operations zf_fops = { - .owner = THIS_MODULE, - .write = zf_write, - .unlocked_ioctl = zf_ioctl, - .compat_ioctl = compat_ptr_ioctl, - .open = zf_open, - .release = zf_close, -}; - -static struct miscdevice zf_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &zf_fops, -}; - - -/* - * The device needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ -static struct notifier_block zf_notifier = { - .notifier_call = zf_notify_sys, -}; - -static void __init zf_show_action(int act) -{ - static const char * const str[] = { "RESET", "SMI", "NMI", "SCI" }; - - pr_info("Watchdog using action = %s\n", str[act]); -} - -static int __init zf_init(void) -{ - int ret; - - pr_info("MachZ ZF-Logic Watchdog driver initializing\n"); - - ret = zf_get_ZFL_version(); - if (!ret || ret == 0xffff) { - pr_warn("no ZF-Logic found\n"); - return -ENODEV; - } - - if (action <= 3 && action >= 0) - zf_action = zf_action >> action; - else - action = 0; - - zf_show_action(action); - - if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) { - pr_err("cannot reserve I/O ports at %d\n", ZF_IOBASE); - ret = -EBUSY; - goto no_region; - } - - ret = register_reboot_notifier(&zf_notifier); - if (ret) { - pr_err("can't register reboot notifier (err=%d)\n", ret); - goto no_reboot; - } - - ret = misc_register(&zf_miscdev); - if (ret) { - pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR); - goto no_misc; - } - - zf_set_status(0); - zf_set_control(0); - - return 0; - -no_misc: - unregister_reboot_notifier(&zf_notifier); -no_reboot: - release_region(ZF_IOBASE, 3); -no_region: - return ret; -} - - -static void __exit zf_exit(void) -{ - zf_timer_off(); - - misc_deregister(&zf_miscdev); - unregister_reboot_notifier(&zf_notifier); - release_region(ZF_IOBASE, 3); -} - -module_init(zf_init); -module_exit(zf_exit); From 3b3a80dacd6e730196b45cae142970aa46c87c50 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 22 Apr 2026 10:27:37 +0200 Subject: [PATCH 049/655] watchdog: qcom: Unify user-visible "Qualcomm" name Various names for Qualcomm as a company are used in user-visible config options: QCOM, Qualcomm and Qualcomm Technologies. Switch to unified "Qualcomm" so it will be easier for users to identify the options when for example running menuconfig. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260422082736.81981-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 97e320721cff..e19872c0ae61 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -882,7 +882,7 @@ config TEGRA_WATCHDOG module will be called tegra_wdt. config QCOM_WDT - tristate "QCOM watchdog" + tristate "Qualcomm watchdog" depends on HAS_IOMEM depends on ARCH_QCOM || COMPILE_TEST select WATCHDOG_CORE @@ -1093,7 +1093,7 @@ config SPRD_WATCHDOG by Spreadtrum system. config PM8916_WATCHDOG - tristate "QCOM PM8916 pmic watchdog" + tristate "Qualcomm PM8916 pmic watchdog" depends on OF && MFD_SPMI_PMIC select WATCHDOG_CORE help From ea333d1991e449b13a3b28812c4493d376492012 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Wed, 8 Apr 2026 14:54:37 +0530 Subject: [PATCH 050/655] dt-bindings: watchdog: qcom-wdt: Document sram property Document the "sram" property for the watchdog device on Qualcomm IPQ platforms. Use this property to extract the restart reason from IMEM, which is updated by XBL. Populate the watchdog's bootstatus sysFS entry with this information, when the system reboots due to a watchdog timeout. Describe this property for the IPQ5424 watchdog device and extend support to other targets subsequently. Reviewed-by: Rob Herring (Arm) Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20260408-wdt_reset_reason-v10-1-caf66786329f@oss.qualcomm.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 9f861045b71e..3ead00da3cd6 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -84,6 +84,12 @@ properties: minItems: 1 maxItems: 5 + sram: + maxItems: 1 + description: + A reference to an region residing in IMEM(on-chip SRAM), which contains + the system restart reason value populated by the bootloader. + required: - compatible - reg From 158dd300b07b0d39e9fb791a4ad1bc68c8588530 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Wed, 8 Apr 2026 14:54:38 +0530 Subject: [PATCH 051/655] watchdog: qcom: add support to get the bootstatus from IMEM When the system boots up after a watchdog reset, the EXPIRED_STATUS bit in the WDT_STS register is cleared. To identify if the system was restarted due to WDT expiry, XBL update the information in the IMEM region. Update the driver to read the restart reason from IMEM and populate the bootstatus accordingly. With the CONFIG_WATCHDOG_SYSFS enabled, user can extract the information as below: cat /sys/devices/platform/soc@0/f410000.watchdog/watchdog/watchdog0/bootstatus 32 For backward compatibility, keep the EXPIRED_STATUS bit check. Add a new function qcom_wdt_get_bootstatus() to read the restart reason from IMEM. Reviewed-by: Konrad Dybcio Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20260408-wdt_reset_reason-v10-2-caf66786329f@oss.qualcomm.com Signed-off-by: Guenter Roeck --- drivers/watchdog/qcom-wdt.c | 42 +++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index dfaac5995c84..49bd04841f0c 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ struct qcom_wdt_match_data { const u32 *offset; bool pretimeout; u32 max_tick_count; + u32 wdt_reason_val; }; struct qcom_wdt { @@ -185,6 +187,7 @@ static const struct qcom_wdt_match_data match_data_ipq5424 = { .offset = reg_offset_data_kpss, .pretimeout = true, .max_tick_count = 0xFFFFFU, + .wdt_reason_val = 5, }; static const struct qcom_wdt_match_data match_data_kpss = { @@ -193,6 +196,40 @@ static const struct qcom_wdt_match_data match_data_kpss = { .max_tick_count = 0xFFFFFU, }; +static int qcom_wdt_get_bootstatus(struct device *dev, struct qcom_wdt *wdt, + u32 val) +{ + struct device_node *imem; + struct resource res; + void __iomem *addr; + int ret; + + imem = of_parse_phandle(dev->of_node, "sram", 0); + if (!imem) { + /* Read the EXPIRED_STATUS bit as a fallback */ + if (readl(wdt_addr(wdt, WDT_STS)) & 1) + wdt->wdd.bootstatus = WDIOF_CARDRESET; + + return 0; + } + + ret = of_address_to_resource(imem, 0, &res); + of_node_put(imem); + if (ret) + return ret; + + addr = ioremap(res.start, resource_size(&res)); + if (!addr) + return -ENOMEM; + + if (readl(addr) == val) + wdt->wdd.bootstatus = WDIOF_CARDRESET; + + iounmap(addr); + + return 0; +} + static int qcom_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -273,8 +310,9 @@ static int qcom_wdt_probe(struct platform_device *pdev) wdt->wdd.parent = dev; wdt->layout = data->offset; - if (readl(wdt_addr(wdt, WDT_STS)) & 1) - wdt->wdd.bootstatus = WDIOF_CARDRESET; + ret = qcom_wdt_get_bootstatus(dev, wdt, data->wdt_reason_val); + if (ret) + dev_err(dev, "failed to get the bootstatus, %d\n", ret); /* * If 'timeout-sec' unspecified in devicetree, assume a 30 second From 066f6001fb58258269480547a920fc2812f37760 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Wed, 1 Apr 2026 18:14:42 +0530 Subject: [PATCH 052/655] dt-bindings: watchdog: qcom-wdt: Document Hawi watchdog compatible Add devicetree binding for watchdog present on Qualcomm Hawi SoC. Signed-off-by: Mukesh Ojha Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260401124442.591803-1-mukesh.ojha@oss.qualcomm.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 3ead00da3cd6..1d5d01c2547a 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -18,6 +18,7 @@ properties: - items: - enum: - qcom,apss-wdt-glymur + - qcom,apss-wdt-hawi - qcom,kpss-wdt-ipq4019 - qcom,apss-wdt-ipq5018 - qcom,apss-wdt-ipq5332 From 4f675f036cd5e9cfbe6df5f24f8338158af96a4b Mon Sep 17 00:00:00 2001 From: Yingjie Gao Date: Thu, 2 Apr 2026 15:16:17 +0800 Subject: [PATCH 053/655] watchdog: sp5100_tco: Use EFCH MMIO for newer Hygon FCH Commit 009637de1f65 ("watchdog: sp5100_tco: support Hygon FCH/SCH (Server Controller Hub)") added Hygon vendor matching to the efch layout selection, but newer Hygon 0x790b SMBus devices still need the efch_mmio path. The efch_mmio path enables EFCH_PM_DECODEEN_WDT_TMREN before probing the watchdog MMIO block. If firmware leaves that bit clear and the driver picks the legacy efch path instead, probe falls back to the alternate window and fails with "Watchdog hardware is disabled". Select efch_mmio for Hygon 0x790b devices with revision 0x51 or later, matching the equivalent AMD behavior and allowing the watchdog to initialize on those systems. Fixes: 009637de1f65 ("watchdog: sp5100_tco: support Hygon FCH/SCH (Server Controller Hub)") Signed-off-by: Yingjie Gao Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260402071617.634563-2-gaoyingjie@uniontech.com Signed-off-by: Guenter Roeck --- drivers/watchdog/sp5100_tco.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index 2bd3dc25cb03..7e99c3b1f367 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c @@ -92,7 +92,8 @@ static enum tco_reg_layout tco_reg_layout(struct pci_dev *dev) dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && dev->revision < 0x40) { return sp5100; - } else if (dev->vendor == PCI_VENDOR_ID_AMD && + } else if ((dev->vendor == PCI_VENDOR_ID_AMD || + dev->vendor == PCI_VENDOR_ID_HYGON) && sp5100_tco_pci->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS && sp5100_tco_pci->revision >= AMD_ZEN_SMBUS_PCI_REV) { return efch_mmio; From 07d690db9fc741649f98506e492d5c10d1060b80 Mon Sep 17 00:00:00 2001 From: "Herve Codina (Schneider Electric)" Date: Tue, 24 Mar 2026 12:48:45 +0100 Subject: [PATCH 054/655] watchdog: rzn1: Use dev_err_probe() In the probe() function the following pattern is present several times: if (err) { dev_err(dev, ...); return err; } Replace them by dev_err_probe() calls. Signed-off-by: Herve Codina (Schneider Electric) Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260324114849.242755-3-herve.codina@bootlin.com Signed-off-by: Guenter Roeck --- drivers/watchdog/rzn1_wdt.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/watchdog/rzn1_wdt.c b/drivers/watchdog/rzn1_wdt.c index 96fd04fbc2a2..0b57540692f9 100644 --- a/drivers/watchdog/rzn1_wdt.c +++ b/drivers/watchdog/rzn1_wdt.c @@ -122,22 +122,16 @@ static int rzn1_wdt_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, rzn1_wdt_irq, 0, np->name, wdt); - if (ret) { - dev_err(dev, "failed to request irq %d\n", irq); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(clk)) { - dev_err(dev, "failed to get the clock\n"); - return PTR_ERR(clk); - } + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get the clock\n"); clk_rate = clk_get_rate(clk); - if (!clk_rate) { - dev_err(dev, "failed to get the clock rate\n"); - return -EINVAL; - } + if (!clk_rate) + return dev_err_probe(dev, -EINVAL, "failed to get the clock rate\n"); wdt->clk_rate_khz = clk_rate / 1000; wdt->wdtdev.info = &rzn1_wdt_info; From cde09b031da871bc88ab693cf5ac503574a06639 Mon Sep 17 00:00:00 2001 From: "Herve Codina (Schneider Electric)" Date: Tue, 24 Mar 2026 12:48:44 +0100 Subject: [PATCH 055/655] watchdog: rzn1: Fix reverse xmas tree declaration Variables declared in probe() don't follow the reverse xmas tree convention. Fix the declaration in order to follow the convention. Signed-off-by: Herve Codina (Schneider Electric) Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260324114849.242755-2-herve.codina@bootlin.com Signed-off-by: Guenter Roeck --- drivers/watchdog/rzn1_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/rzn1_wdt.c b/drivers/watchdog/rzn1_wdt.c index 0b57540692f9..48d5afef62a5 100644 --- a/drivers/watchdog/rzn1_wdt.c +++ b/drivers/watchdog/rzn1_wdt.c @@ -101,10 +101,10 @@ static const struct watchdog_ops rzn1_wdt_ops = { static int rzn1_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct rzn1_watchdog *wdt; struct device_node *np = dev->of_node; - struct clk *clk; + struct rzn1_watchdog *wdt; unsigned long clk_rate; + struct clk *clk; int ret; int irq; From 2963bb3d5acf9f8478ed5a8b07ff8b8a211cc25d Mon Sep 17 00:00:00 2001 From: Jose Javier Rodriguez Barbarin Date: Mon, 23 Mar 2026 12:24:13 +0100 Subject: [PATCH 056/655] watchdog: menz069_wdt: drop unneeded MODULE_ALIAS Since commit 1f4ea4838b13 ("mcb: Add missing modpost build support") the MODULE_ALIAS() is redundant as the module alias is now automatically generated from the MODULE_DEVICE_TABLE(). Remove the explicit alias. No functional change intended. Reviewed-by: Jorge Sanjuan Garcia Signed-off-by: Jose Javier Rodriguez Barbarin Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260323112413.21923-2-dev-josejavier.rodriguez@duagon.com Signed-off-by: Guenter Roeck --- drivers/watchdog/menz69_wdt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/watchdog/menz69_wdt.c b/drivers/watchdog/menz69_wdt.c index 6e5e4e5c0b56..3fe23451135d 100644 --- a/drivers/watchdog/menz69_wdt.c +++ b/drivers/watchdog/menz69_wdt.c @@ -163,5 +163,4 @@ module_mcb_driver(men_z069_driver); MODULE_AUTHOR("Johannes Thumshirn "); MODULE_DESCRIPTION("Watchdog driver for the MEN z069 IP-Core"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("mcb:16z069"); MODULE_IMPORT_NS("MCB"); From d651a264536b30b423bd6478fc1a72eafb3e19e6 Mon Sep 17 00:00:00 2001 From: Eduard Bostina Date: Mon, 23 Mar 2026 19:59:44 +0200 Subject: [PATCH 057/655] dt-bindings: watchdog: Convert TS-4800 to DT schema Convert the Technologic Systems TS-4800 watchdog timer bindings to DT schema. Signed-off-by: Eduard Bostina Reviewed-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260323175948.302441-2-egbostina@gmail.com Signed-off-by: Guenter Roeck --- .../watchdog/technologic,ts4800-wdt.yaml | 40 +++++++++++++++++++ .../bindings/watchdog/ts4800-wdt.txt | 25 ------------ 2 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/watchdog/technologic,ts4800-wdt.yaml delete mode 100644 Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt diff --git a/Documentation/devicetree/bindings/watchdog/technologic,ts4800-wdt.yaml b/Documentation/devicetree/bindings/watchdog/technologic,ts4800-wdt.yaml new file mode 100644 index 000000000000..5c2541ac60cf --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/technologic,ts4800-wdt.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/technologic,ts4800-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Technologic Systems TS-4800 Watchdog + +maintainers: + - Eduard Bostina + +properties: + compatible: + const: technologic,ts4800-wdt + + syscon: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: Phandle to the FPGA's syscon + - description: Offset to the watchdog register + description: Phandle / integers array that points to the syscon node which + describes the FPGA's syscon registers. + +required: + - compatible + - syscon + +allOf: + - $ref: watchdog.yaml# + +unevaluatedProperties: false + +examples: + - | + watchdog { + compatible = "technologic,ts4800-wdt"; + syscon = <&syscon 0xe>; + timeout-sec = <10>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt b/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt deleted file mode 100644 index 8f6caad4258d..000000000000 --- a/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt +++ /dev/null @@ -1,25 +0,0 @@ -Technologic Systems Watchdog - -Required properties: -- compatible: must be "technologic,ts4800-wdt" -- syscon: phandle / integer array that points to the syscon node which - describes the FPGA's syscon registers. - - phandle to FPGA's syscon - - offset to the watchdog register - -Optional property: -- timeout-sec: contains the watchdog timeout in seconds. - -Example: - -syscon: syscon@b0010000 { - compatible = "syscon", "simple-mfd"; - reg = <0xb0010000 0x3d>; - reg-io-width = <2>; - - wdt@e { - compatible = "technologic,ts4800-wdt"; - syscon = <&syscon 0xe>; - timeout-sec = <10>; - }; -} From d8207d1e9a36b1a8a461581b2d4073ea28335603 Mon Sep 17 00:00:00 2001 From: Steve Wahl Date: Wed, 18 Mar 2026 10:50:05 -0500 Subject: [PATCH 058/655] watchdog/hpwdt: Refine hpwdt message for UV platform The watchdog hardware the hpwdt driver uses was added to the UV platform for UV_5, but the logging mentioned by this driver was not added to the BIOS. When the watchdog fires, the printed message had the administrators and developers looking for non-existent log files, and confused about whether a watchdog actually tripped. Change the message that prints on UV platforms so it doesn't send the user looking for non-existent logs. To aid in any future debugging, include all 8 bits of the NMISTAT register in the output, not just the two bits being used to determine this was "mynmi". And provide names to the bits in NMISTAT so the code is easier to understand. Signed-off-by: Steve Wahl Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260318155005.90271-1-steve.wahl@hpe.com Signed-off-by: Guenter Roeck --- drivers/watchdog/hpwdt.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 2a848c35c14d..8af1fad2de0b 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -23,6 +23,7 @@ #include #ifdef CONFIG_HPWDT_NMI_DECODING #include +#include #endif #include @@ -159,24 +160,31 @@ static int hpwdt_set_pretimeout(struct watchdog_device *wdd, unsigned int req) return 0; } -static int hpwdt_my_nmi(void) -{ - return ioread8(hpwdt_nmistat) & 0x6; -} +#define NMISTAT_EASR BIT(0) +#define NMISTAT_EWDOG BIT(1) +#define NMISTAT_RTRAP BIT(2) +#define NMISTAT_DBELL BIT(3) +#define NMISTAT_EMSWDG BIT(4) +#define NMISTAT_GPI BIT(5) +#define NMISTAT_NMIOUT BIT(7) /* * NMI Handler */ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) { - unsigned int mynmi = hpwdt_my_nmi(); - static char panic_msg[] = + u8 nmistat = ioread8(hpwdt_nmistat); + bool mynmi = (nmistat & (NMISTAT_EWDOG | NMISTAT_RTRAP)) != 0; + static char panic_msg_default[] = "00: An NMI occurred. Depending on your system the reason " "for the NMI is logged in any one of the following resources:\n" "1. Integrated Management Log (IML)\n" "2. OA Syslog\n" "3. OA Forward Progress Log\n" "4. iLO Event Log"; + static char panic_msg_uv[] = + "00: A watchdog NMI occurred."; + char *panic_msg = is_uv_system() ? panic_msg_uv : panic_msg_default; if (ulReason == NMI_UNKNOWN && !mynmi) return NMI_DONE; @@ -190,7 +198,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) hpwdt_ping_ticks(SECS_TO_TICKS(val)); } - hex_byte_pack(panic_msg, mynmi); + hex_byte_pack(panic_msg, nmistat); nmi_panic(regs, panic_msg); return NMI_HANDLED; From 5abb70c8f7582950e490823f4a94a3597ada9d83 Mon Sep 17 00:00:00 2001 From: Flavio Suligoi Date: Mon, 23 Mar 2026 13:52:04 +0100 Subject: [PATCH 059/655] watchdog: gpio_wdt: add ACPI support The gpio_wdt device driver uses the device property APIs, so it is firmware agnostic. For this reason we can now add the ACPI support in Kconfig. In this way it can be used seamlessly in ACPI and DT systems. For example, a typical GPIO watchdog device configuration, in an ACPI SSDT table, could be: Device (WDOG) { Name (_HID, "WDOG0001") Name (_CID, "PRP0001") Name (_UID, One) Name (_CRS, ResourceTemplate () { GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionOutputOnly, "\\_SB.GPI0", 0, ResourceConsumer, ,) { 3 } }) Method (_STA, 0, NotSerialized) { Return (0x0F) } Name (_DSD, Package (2) { ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package (5) { Package () { "compatible", Package() { "linux,wdt-gpio" } }, Package () { "hw_algo", "toggle" }, Package () { "gpios", Package () { ^WDOG, 0, 0, 0 } }, Package () { "hw_margin_ms", 2000 }, Package () { "always-running", 1 }, }, }) } Signed-off-by: Flavio Suligoi Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260323125204.164785-2-f.suligoi@asem.it Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e19872c0ae61..8de43b614bb7 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -250,7 +250,7 @@ config DA9062_WATCHDOG config GPIO_WATCHDOG tristate "Watchdog device controlled through GPIO-line" - depends on OF_GPIO + depends on (ACPI && GPIOLIB) || OF_GPIO select WATCHDOG_CORE help If you say yes here you get support for watchdog device From 63077abe9ca8356b6c15b3dfda6d2761337badaf Mon Sep 17 00:00:00 2001 From: Shubham Chakraborty Date: Wed, 11 Mar 2026 17:46:01 +0530 Subject: [PATCH 060/655] docs: watchdog: explain watchdog API options Replace FIXME comment with proper documentation for WDIOS_DISABLECARD, WDIOS_ENABLECARD, and WDIOS_TEMPPANIC options. Signed-off-by: Shubham Chakraborty Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260311121602.139967-1-chakrabortyshubham66@gmail.com Signed-off-by: Guenter Roeck --- Documentation/watchdog/watchdog-api.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/watchdog/watchdog-api.rst b/Documentation/watchdog/watchdog-api.rst index 78e228c272cf..984f7362d5fb 100644 --- a/Documentation/watchdog/watchdog-api.rst +++ b/Documentation/watchdog/watchdog-api.rst @@ -268,4 +268,13 @@ The following options are available: WDIOS_TEMPPANIC Kernel panic on temperature trip ================= ================================ -[FIXME -- better explanations] +The WDIOS_DISABLECARD option allows you to stop the watchdog timer via +software. Note that this will only work if the "nowayout" module parameter +(or CONFIG_WATCHDOG_NOWAYOUT) is not set. + +The WDIOS_ENABLECARD option turns on the watchdog timer. + +The WDIOS_TEMPPANIC option is used by some drivers (like the pcwd driver) +to trigger a system halt (typically a kernel panic or power off) when the +temperature trip point is reached. This ensures that the system is halted +immediately in case of an overheat condition. From ca316e145c35d59bf1c0b48ff4e38091e19b80a8 Mon Sep 17 00:00:00 2001 From: Hrishabh Rajput Date: Wed, 11 Mar 2026 11:16:31 +0530 Subject: [PATCH 061/655] watchdog: Add driver for Gunyah Watchdog On Qualcomm SoCs running under the Gunyah hypervisor, access to watchdog through MMIO is not available on all platforms. Depending on the hypervisor configuration, the watchdog is either fully emulated or exposed via ARM's SMC Calling Conventions (SMCCC) through the Vendor Specific Hypervisor Service Calls space. Add driver to support the SMC-based watchdog provided by the Gunyah Hypervisor. Device registration is done in the QCOM SCM driver after checks to restrict the watchdog initialization to Qualcomm devices running under Gunyah. Gunyah watchdog is not a hardware but an SMC-based vendor-specific hypervisor interface provided by the Gunyah hypervisor. The design involving QCOM SCM driver for registering the platform device has been devised to avoid adding non-hardware nodes to devicetree. Tested-by: Shivendra Pratap Tested-by: Neil Armstrong Tested-by: Mukesh Ojha Reviewed-by: Guenter Roeck Reviewed-by: Dmitry Baryshkov Signed-off-by: Hrishabh Rajput Signed-off-by: Pavankumar Kondeti Link: https://lore.kernel.org/r/20260311-gunyah_watchdog-v8-2-4c1c0689de22@oss.qualcomm.com Signed-off-by: Guenter Roeck --- MAINTAINERS | 1 + drivers/watchdog/Kconfig | 13 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/gunyah_wdt.c | 261 ++++++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 drivers/watchdog/gunyah_wdt.c diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..f35e1769fa72 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3337,6 +3337,7 @@ F: arch/arm64/boot/dts/qcom/ F: drivers/bus/qcom* F: drivers/firmware/qcom/ F: drivers/soc/qcom/ +F: drivers/watchdog/gunyah_wdt.c F: include/dt-bindings/arm/qcom,ids.h F: include/dt-bindings/firmware/qcom,scm.h F: include/dt-bindings/soc/qcom* diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 8de43b614bb7..3397c82ded9c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -2341,4 +2341,17 @@ config KEEMBAY_WATCHDOG To compile this driver as a module, choose M here: the module will be called keembay_wdt. +config GUNYAH_WATCHDOG + tristate "Qualcomm Gunyah Watchdog" + depends on ARCH_QCOM || COMPILE_TEST + depends on HAVE_ARM_SMCCC + select WATCHDOG_CORE + help + Say Y here to include support for watchdog timer provided by the + Gunyah hypervisor. The driver uses ARM SMC Calling Convention (SMCCC) + to interact with Gunyah Watchdog. + + To compile this driver as a module, choose M here: the + module will be called gunyah_wdt. + endif # WATCHDOG diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 2961ca141c61..ff1dc6fd5867 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o obj-$(CONFIG_MARVELL_GTI_WDT) += marvell_gti_wdt.o +obj-$(CONFIG_GUNYAH_WATCHDOG) += gunyah_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/watchdog/gunyah_wdt.c b/drivers/watchdog/gunyah_wdt.c new file mode 100644 index 000000000000..49dfef459e84 --- /dev/null +++ b/drivers/watchdog/gunyah_wdt.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GUNYAH_WDT_SMCCC_CALL_VAL(func_id) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32,\ + ARM_SMCCC_OWNER_VENDOR_HYP, func_id) + +/* SMCCC function IDs for watchdog operations */ +#define GUNYAH_WDT_CONTROL GUNYAH_WDT_SMCCC_CALL_VAL(0x0005) +#define GUNYAH_WDT_STATUS GUNYAH_WDT_SMCCC_CALL_VAL(0x0006) +#define GUNYAH_WDT_PING GUNYAH_WDT_SMCCC_CALL_VAL(0x0007) +#define GUNYAH_WDT_SET_TIME GUNYAH_WDT_SMCCC_CALL_VAL(0x0008) + +/* + * Control values for GUNYAH_WDT_CONTROL. + * Bit 0 is used to enable or disable the watchdog. If this bit is set, + * then the watchdog is enabled and vice versa. + * Bit 1 should always be set to 1 as this bit is reserved in Gunyah and + * it's expected to be 1. + */ +#define WDT_CTRL_ENABLE (BIT(1) | BIT(0)) +#define WDT_CTRL_DISABLE BIT(1) + +enum gunyah_error { + GUNYAH_ERROR_OK = 0, + GUNYAH_ERROR_UNIMPLEMENTED = -1, + GUNYAH_ERROR_ARG_INVAL = 1, +}; + +/** + * gunyah_error_remap() - Remap Gunyah hypervisor errors into a Linux error code + * @gunyah_error: Gunyah hypercall return value + */ +static inline int gunyah_error_remap(enum gunyah_error gunyah_error) +{ + switch (gunyah_error) { + case GUNYAH_ERROR_OK: + return 0; + case GUNYAH_ERROR_UNIMPLEMENTED: + return -EOPNOTSUPP; + default: + return -EINVAL; + } +} + +static int gunyah_wdt_call(unsigned long func_id, unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_smc(func_id, arg1, arg2, &res); + return gunyah_error_remap(res.a0); +} + +static int gunyah_wdt_start(struct watchdog_device *wdd) +{ + unsigned int timeout_ms; + struct device *dev = wdd->parent; + int ret; + + ret = gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_DISABLE, 0); + if (ret && watchdog_active(wdd)) { + dev_err(dev, "%s: Failed to stop gunyah wdt %d\n", __func__, ret); + return ret; + } + + timeout_ms = wdd->timeout * 1000; + ret = gunyah_wdt_call(GUNYAH_WDT_SET_TIME, timeout_ms, timeout_ms); + if (ret) { + dev_err(dev, "%s: Failed to set timeout for gunyah wdt %d\n", + __func__, ret); + return ret; + } + + ret = gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_ENABLE, 0); + if (ret) + dev_err(dev, "%s: Failed to start gunyah wdt %d\n", __func__, ret); + + return ret; +} + +static int gunyah_wdt_stop(struct watchdog_device *wdd) +{ + return gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_DISABLE, 0); +} + +static int gunyah_wdt_ping(struct watchdog_device *wdd) +{ + return gunyah_wdt_call(GUNYAH_WDT_PING, 0, 0); +} + +static int gunyah_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout_sec) +{ + wdd->timeout = timeout_sec; + + if (watchdog_active(wdd)) + return gunyah_wdt_start(wdd); + + return 0; +} + +static int gunyah_wdt_get_time_since_last_ping(void) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_smc(GUNYAH_WDT_STATUS, 0, 0, &res); + if (res.a0) + return gunyah_error_remap(res.a0); + + return res.a2 / 1000; +} + +static unsigned int gunyah_wdt_get_timeleft(struct watchdog_device *wdd) +{ + int seconds_since_last_ping; + + seconds_since_last_ping = gunyah_wdt_get_time_since_last_ping(); + if (seconds_since_last_ping < 0 || + seconds_since_last_ping > wdd->timeout) + return 0; + + return wdd->timeout - seconds_since_last_ping; +} + +static int gunyah_wdt_restart(struct watchdog_device *wdd, + unsigned long action, void *data) +{ + /* Set timeout to 1ms and send a ping */ + gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_DISABLE, 0); + gunyah_wdt_call(GUNYAH_WDT_SET_TIME, 1, 1); + gunyah_wdt_call(GUNYAH_WDT_CONTROL, WDT_CTRL_ENABLE, 0); + gunyah_wdt_call(GUNYAH_WDT_PING, 0, 0); + + /* Wait to make sure reset occurs */ + mdelay(100); + + return 0; +} + +static const struct watchdog_info gunyah_wdt_info = { + .identity = "Gunyah Watchdog", + .options = WDIOF_SETTIMEOUT + | WDIOF_KEEPALIVEPING + | WDIOF_MAGICCLOSE, +}; + +static const struct watchdog_ops gunyah_wdt_ops = { + .owner = THIS_MODULE, + .start = gunyah_wdt_start, + .stop = gunyah_wdt_stop, + .ping = gunyah_wdt_ping, + .set_timeout = gunyah_wdt_set_timeout, + .get_timeleft = gunyah_wdt_get_timeleft, + .restart = gunyah_wdt_restart +}; + +static int gunyah_wdt_probe(struct platform_device *pdev) +{ + struct watchdog_device *wdd; + struct device *dev = &pdev->dev; + int ret; + + ret = gunyah_wdt_call(GUNYAH_WDT_STATUS, 0, 0); + if (ret == -EOPNOTSUPP) + return -ENODEV; + + if (ret) + return dev_err_probe(dev, ret, "status check failed\n"); + + wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL); + if (!wdd) + return -ENOMEM; + + wdd->info = &gunyah_wdt_info; + wdd->ops = &gunyah_wdt_ops; + wdd->parent = dev; + + /* + * Although Gunyah expects 16-bit unsigned int values as timeout values + * in milliseconds, values above 0x8000 are reserved. This limits the + * max timeout value to 32 seconds. + */ + wdd->max_timeout = 32; /* seconds */ + wdd->min_timeout = 1; /* seconds */ + wdd->timeout = wdd->max_timeout; + + gunyah_wdt_stop(wdd); + platform_set_drvdata(pdev, wdd); + watchdog_set_restart_priority(wdd, 0); + + return devm_watchdog_register_device(dev, wdd); +} + +static void gunyah_wdt_remove(struct platform_device *pdev) +{ + struct watchdog_device *wdd = platform_get_drvdata(pdev); + + gunyah_wdt_stop(wdd); +} + +static int gunyah_wdt_suspend(struct device *dev) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + if (watchdog_active(wdd)) + gunyah_wdt_stop(wdd); + + return 0; +} + +static int gunyah_wdt_resume(struct device *dev) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + if (watchdog_active(wdd)) + gunyah_wdt_start(wdd); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(gunyah_wdt_pm_ops, gunyah_wdt_suspend, gunyah_wdt_resume); + +/* + * Gunyah watchdog is a vendor-specific hypervisor interface provided by the + * Gunyah hypervisor. Using QCOM SCM driver to detect Gunyah watchdog SMCCC + * hypervisor service and register platform device when the service is available + * allows this driver to operate independently of the devicetree and avoids + * adding the non-hardware nodes to the devicetree. + */ +static const struct platform_device_id gunyah_wdt_id[] = { + { .name = "gunyah-wdt" }, + {} +}; +MODULE_DEVICE_TABLE(platform, gunyah_wdt_id); + +static struct platform_driver gunyah_wdt_driver = { + .driver = { + .name = "gunyah-wdt", + .pm = pm_sleep_ptr(&gunyah_wdt_pm_ops), + }, + .id_table = gunyah_wdt_id, + .probe = gunyah_wdt_probe, + .remove = gunyah_wdt_remove, +}; + +module_platform_driver(gunyah_wdt_driver); + +MODULE_DESCRIPTION("Gunyah Watchdog Driver"); +MODULE_LICENSE("GPL"); From e8bc610b14a99d24b0916635102cc52ba41def9b Mon Sep 17 00:00:00 2001 From: Balakrishnan Sambath Date: Mon, 2 Mar 2026 17:03:09 +0530 Subject: [PATCH 062/655] watchdog: sama5d4_wdt: Fix WDDIS detection on SAM9X60 and SAMA7G5 The driver hardcoded AT91_WDT_WDDIS (bit 15) in wdt_enabled and the probe initial state readout. SAM9X60 and SAMA7G5 use bit 12 (AT91_SAM9X60_WDDIS), causing incorrect WDDIS detection. Introduce a per-device wddis_mask field to select the correct WDDIS bit based on the compatible string. Fixes: 266da53c35fc ("watchdog: sama5d4: readout initial state") Co-developed-by: Andrei Simion Signed-off-by: Andrei Simion Signed-off-by: Balakrishnan Sambath Reviewed-by: Alexandre Belloni Link: https://lore.kernel.org/r/20260302113310.133989-2-balakrishnan.s@microchip.com Signed-off-by: Guenter Roeck --- drivers/watchdog/sama5d4_wdt.c | 48 +++++++++++++++------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index 13e72918338a..704b786cc2ec 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c @@ -30,6 +30,7 @@ struct sama5d4_wdt { void __iomem *reg_base; u32 mr; u32 ir; + u32 wddis_mask; unsigned long last_ping; bool need_irq; bool sam9x60_support; @@ -48,7 +49,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -#define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS)) +static inline bool wdt_enabled(struct sama5d4_wdt *wdt) +{ + return !(wdt->mr & wdt->wddis_mask); +} #define wdt_read(wdt, field) \ readl_relaxed((wdt)->reg_base + (field)) @@ -81,12 +85,9 @@ static int sama5d4_wdt_start(struct watchdog_device *wdd) { struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); - if (wdt->sam9x60_support) { + if (wdt->sam9x60_support) writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IER); - wdt->mr &= ~AT91_SAM9X60_WDDIS; - } else { - wdt->mr &= ~AT91_WDT_WDDIS; - } + wdt->mr &= ~wdt->wddis_mask; wdt_write(wdt, AT91_WDT_MR, wdt->mr); return 0; @@ -96,12 +97,9 @@ static int sama5d4_wdt_stop(struct watchdog_device *wdd) { struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); - if (wdt->sam9x60_support) { + if (wdt->sam9x60_support) writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IDR); - wdt->mr |= AT91_SAM9X60_WDDIS; - } else { - wdt->mr |= AT91_WDT_WDDIS; - } + wdt->mr |= wdt->wddis_mask; wdt_write(wdt, AT91_WDT_MR, wdt->mr); return 0; @@ -117,7 +115,7 @@ static int sama5d4_wdt_ping(struct watchdog_device *wdd) } static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, - unsigned int timeout) + unsigned int timeout) { struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); u32 value = WDT_SEC2TICKS(timeout); @@ -140,8 +138,8 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, * If the watchdog is enabled, then the timeout can be updated. Else, * wait that the user enables it. */ - if (wdt_enabled) - wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS); + if (wdt_enabled(wdt)) + wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~wdt->wddis_mask); wdd->timeout = timeout; @@ -184,10 +182,7 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) { const char *tmp; - if (wdt->sam9x60_support) - wdt->mr = AT91_SAM9X60_WDDIS; - else - wdt->mr = AT91_WDT_WDDIS; + wdt->mr = wdt->wddis_mask; if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && !strcmp(tmp, "software")) @@ -213,15 +208,11 @@ static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) * If the watchdog is already running, we can safely update it. * Else, we have to disable it properly. */ - if (!wdt_enabled) { + if (!wdt_enabled(wdt)) { reg = wdt_read(wdt, AT91_WDT_MR); - if (wdt->sam9x60_support && (!(reg & AT91_SAM9X60_WDDIS))) + if (!(reg & wdt->wddis_mask)) wdt_write_nosleep(wdt, AT91_WDT_MR, - reg | AT91_SAM9X60_WDDIS); - else if (!wdt->sam9x60_support && - (!(reg & AT91_WDT_WDDIS))) - wdt_write_nosleep(wdt, AT91_WDT_MR, - reg | AT91_WDT_WDDIS); + reg | wdt->wddis_mask); } if (wdt->sam9x60_support) { @@ -273,6 +264,9 @@ static int sama5d4_wdt_probe(struct platform_device *pdev) of_device_is_compatible(dev->of_node, "microchip,sama7g5-wdt")) wdt->sam9x60_support = true; + wdt->wddis_mask = wdt->sam9x60_support ? AT91_SAM9X60_WDDIS + : AT91_WDT_WDDIS; + watchdog_set_drvdata(wdd, wdt); regs = devm_platform_ioremap_resource(pdev, 0); @@ -306,8 +300,8 @@ static int sama5d4_wdt_probe(struct platform_device *pdev) watchdog_init_timeout(wdd, wdt_timeout, dev); reg = wdt_read(wdt, AT91_WDT_MR); - if (!(reg & AT91_WDT_WDDIS)) { - wdt->mr &= ~AT91_WDT_WDDIS; + if (!(reg & wdt->wddis_mask)) { + wdt->mr &= ~wdt->wddis_mask; set_bit(WDOG_HW_RUNNING, &wdd->status); } From 882fc25d868fbd0d71751df4df49c4b55e3fa230 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 9 Mar 2026 21:20:40 -0300 Subject: [PATCH 063/655] dt-bindings: watchdog: rockchip: Add RV1103B compatible The RV1103B watchdog is compatible with the existing DesignWare Watchdog binding. Add the rockchip,rv1103b-wdt compatible string. Signed-off-by: Fabio Estevam Reviewed-by: Heiko Stuebner Acked-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260310002040.417424-1-festevam@gmail.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml index 609e98cdaaff..141c72909b15 100644 --- a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml @@ -33,6 +33,7 @@ properties: - rockchip,rk3568-wdt - rockchip,rk3576-wdt - rockchip,rk3588-wdt + - rockchip,rv1103b-wdt - rockchip,rv1108-wdt - rockchip,rv1126-wdt - const: snps,dw-wdt From f1ea97d64ba5c554b4e58d8b94a1440883ce9a70 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 2 Mar 2026 13:24:51 +0100 Subject: [PATCH 064/655] dt-bindings: watchdog: Drop SMARC-sAM67 support I was just informed that this product is discontinued (without being ever released to the market). Pull the plug and let's not waste any more maintainers time and revert commit 354f31e9d2a3 ("dt-bindings: watchdog: Add SMARC-sAM67 support"). Acked-by: Conor Dooley Signed-off-by: Michael Walle Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260302122540.1377444-7-mwalle@kernel.org Signed-off-by: Guenter Roeck --- .../devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml b/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml index 0821ba0e84a3..872a8471ef65 100644 --- a/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml @@ -18,12 +18,7 @@ allOf: properties: compatible: - oneOf: - - items: - - enum: - - kontron,sa67mcu-wdt - - const: kontron,sl28cpld-wdt - - const: kontron,sl28cpld-wdt + const: kontron,sl28cpld-wdt reg: maxItems: 1 From b5a8fc6b88f3d06ba20c0e056517fbeb9d251484 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 3 Feb 2026 12:42:45 +0000 Subject: [PATCH 065/655] dt-bindings: watchdog: renesas,r9a09g057-wdt: Rework example When the bindings for the Renesas RZ/V2H(P) SoC were factored out IP WDT0 was selected for the example, however the HW user manual states that only IP WDT1 can be used by Linux. This commit is part of a series that removes WDT{0,2,3} support from the kernel, therefore the example from the bindings has lost its meaning. Update the example accordingly. Signed-off-by: Fabrizio Castro Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20260203124247.7320-2-fabrizio.castro.jz@renesas.com Signed-off-by: Guenter Roeck --- .../bindings/watchdog/renesas,r9a09g057-wdt.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/renesas,r9a09g057-wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,r9a09g057-wdt.yaml index 099200c4f136..975c5aa4d747 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,r9a09g057-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,r9a09g057-wdt.yaml @@ -89,11 +89,11 @@ examples: - | #include - watchdog@11c00400 { + watchdog@14400000 { compatible = "renesas,r9a09g057-wdt"; - reg = <0x11c00400 0x400>; - clocks = <&cpg CPG_MOD 0x4b>, <&cpg CPG_MOD 0x4c>; + reg = <0x14400000 0x400>; + clocks = <&cpg CPG_MOD 0x4d>, <&cpg CPG_MOD 0x4e>; clock-names = "pclk", "oscclk"; - resets = <&cpg 0x75>; + resets = <&cpg 0x76>; power-domains = <&cpg>; }; From 587d5a3778e9fd25e327435b58b609487a692115 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 6 Feb 2026 11:22:25 +0000 Subject: [PATCH 066/655] dt-bindings: watchdog: renesas,wdt: Document RZ/G3L support Document the support for the watchdog IP available on RZ/G3L SoC. The watchdog IP available on RZ/G3L SoC is identical to the one found on RZ/G2L SoC. Signed-off-by: Biju Das Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20260206112227.233229-1-biju.das.jz@bp.renesas.com Signed-off-by: Guenter Roeck --- .../devicetree/bindings/watchdog/renesas,rzg2l-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/renesas,rzg2l-wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,rzg2l-wdt.yaml index a4d06c9c8b86..40b4fb26d9c5 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,rzg2l-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,rzg2l-wdt.yaml @@ -18,6 +18,7 @@ properties: - renesas,r9a07g044-wdt # RZ/G2{L,LC} - renesas,r9a07g054-wdt # RZ/V2L - renesas,r9a08g045-wdt # RZ/G3S + - renesas,r9a08g046-wdt # RZ/G3L - const: renesas,rzg2l-wdt - items: From bdd918c4e4516bd2eadac712b2d2e6d29445bd2e Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 2 Mar 2026 12:08:53 -0600 Subject: [PATCH 067/655] watchdog: bcm2835_wdt: Switch to new sys-off handler API Kernel now supports chained power-off handlers. Use devm_register_sys_off_handler() that registers a power-off handler. Legacy pm_power_off() will be removed once all drivers and archs are converted to the new sys-off API. Signed-off-by: Andrew Davis Reviewed-by: Guenter Roeck Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20260302180853.224112-1-afd@ti.com Signed-off-by: Guenter Roeck --- drivers/watchdog/bcm2835_wdt.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index 9fcfee63905b..6fd8b1b8e386 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -19,6 +19,7 @@ #include #include #include +#include #define PM_RSTC 0x1c #define PM_RSTS 0x20 @@ -49,8 +50,6 @@ struct bcm2835_wdt { spinlock_t lock; }; -static struct bcm2835_wdt *bcm2835_power_off_wdt; - static unsigned int heartbeat; static bool nowayout = WATCHDOG_NOWAYOUT; @@ -150,9 +149,9 @@ static struct watchdog_device bcm2835_wdt_wdd = { * indicate to bootcode.bin not to reboot, then most of the chip will be * powered off. */ -static void bcm2835_power_off(void) +static int bcm2835_power_off(struct sys_off_data *data) { - struct bcm2835_wdt *wdt = bcm2835_power_off_wdt; + struct bcm2835_wdt *wdt = data->cb_data; u32 val; /* @@ -166,6 +165,8 @@ static void bcm2835_power_off(void) /* Continue with normal reset mechanism */ __bcm2835_restart(wdt); + + return NOTIFY_DONE; } static int bcm2835_wdt_probe(struct platform_device *pdev) @@ -206,28 +207,17 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) if (err) return err; - if (of_device_is_system_power_controller(pdev->dev.parent->of_node)) { - if (!pm_power_off) { - pm_power_off = bcm2835_power_off; - bcm2835_power_off_wdt = wdt; - } else { - dev_info(dev, "Poweroff handler already present!\n"); - } - } + if (of_device_is_system_power_controller(pdev->dev.parent->of_node)) + devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + bcm2835_power_off, wdt); dev_info(dev, "Broadcom BCM2835 watchdog timer"); return 0; } -static void bcm2835_wdt_remove(struct platform_device *pdev) -{ - if (pm_power_off == bcm2835_power_off) - pm_power_off = NULL; -} - static struct platform_driver bcm2835_wdt_driver = { .probe = bcm2835_wdt_probe, - .remove = bcm2835_wdt_remove, .driver = { .name = "bcm2835-wdt", }, From 96b3cfc3b8ad0524d12fed1e08bc5df3ff345f64 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Mon, 23 Feb 2026 19:59:20 +0800 Subject: [PATCH 068/655] watchdog: sprd_wdt: Remove redundant sprd_wdt_disable() on register failure The driver uses devm_add_action_or_reset() to register sprd_wdt_disable() as a managed cleanup action. When devm_watchdog_register_device() fails, the devm core will invoke the cleanup action automatically. The explicit sprd_wdt_disable() call in the error path is therefore redundant and results in adouble cleanup. Fixes: 78d9bfad2e89 ("watchdog: sprd_wdt: Convert to use device managed functions and other improvements") Signed-off-by: Felix Gu Reviewed-by: Guenter Roeck Reviewed-by: Baolin Wang Link: https://lore.kernel.org/r/20260223-sprd_wdt-v1-1-2e71f9a76ecb@gmail.com Signed-off-by: Guenter Roeck --- drivers/watchdog/sprd_wdt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/sprd_wdt.c b/drivers/watchdog/sprd_wdt.c index 4e689b6ff141..aacf04616fef 100644 --- a/drivers/watchdog/sprd_wdt.c +++ b/drivers/watchdog/sprd_wdt.c @@ -320,10 +320,9 @@ static int sprd_wdt_probe(struct platform_device *pdev) watchdog_init_timeout(&wdt->wdd, 0, dev); ret = devm_watchdog_register_device(dev, &wdt->wdd); - if (ret) { - sprd_wdt_disable(wdt); + if (ret) return ret; - } + platform_set_drvdata(pdev, wdt); return 0; From 4bde3ad9ee7b92ef226e02cbd3b5c743ed8f781e Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:38 +0200 Subject: [PATCH 069/655] mtd: spinand: Drop a too strong limitation Since continuous reads may sometimes not be able to go past an erase block boundary, it has been decided not to attempt longer reads and if the user request is bigger, it will be split across eraseblocks. As these request will anyway be handled correctly, there is no reason to filter out cases where we would go over a target or a die, so drop this limitation which had a side effect: any request to read more than the content of an eraseblock would simply not benefit from the continuous read feature. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 8aa3753aaaa1..43df7d558b74 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -878,6 +878,12 @@ static int spinand_mtd_continuous_page_read(struct mtd_info *mtd, loff_t from, * Each data read must be a multiple of 4-bytes and full pages should be read; * otherwise, the data output might get out of sequence from one read command * to another. + * + * Continuous reads never cross LUN boundaries. Some devices don't + * support crossing planes boundaries. Some devices don't even support + * crossing blocks boundaries. The common case being to read through UBI, + * we will very rarely read two consequent blocks or more, so let's only enable + * continuous reads when reading within the same erase block. */ nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) { ret = spinand_select_target(spinand, iter.req.pos.target); @@ -968,19 +974,6 @@ static bool spinand_use_cont_read(struct mtd_info *mtd, loff_t from, nanddev_offs_to_pos(nand, from, &start_pos); nanddev_offs_to_pos(nand, from + ops->len - 1, &end_pos); - /* - * Continuous reads never cross LUN boundaries. Some devices don't - * support crossing planes boundaries. Some devices don't even support - * crossing blocks boundaries. The common case being to read through UBI, - * we will very rarely read two consequent blocks or more, so it is safer - * and easier (can be improved) to only enable continuous reads when - * reading within the same erase block. - */ - if (start_pos.target != end_pos.target || - start_pos.plane != end_pos.plane || - start_pos.eraseblock != end_pos.eraseblock) - return false; - return start_pos.page < end_pos.page; } From 22fa40c7ecdb11ddc1c95db88cce379408687962 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:39 +0200 Subject: [PATCH 070/655] mtd: spinand: Expose spinand_op_is_odtr() This helper is going to be needed in a vendor driver, so expose it. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 2 +- include/linux/mtd/spinand.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 43df7d558b74..a8247e5720c3 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1400,7 +1400,7 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand) return spinand->manufacturer->ops->cleanup(spinand); } -static bool spinand_op_is_odtr(const struct spi_mem_op *op) +bool spinand_op_is_odtr(const struct spi_mem_op *op) { return op->cmd.dtr && op->cmd.buswidth == 8; } diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 58abd306ebe3..e1f19664bb25 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -862,6 +862,8 @@ static inline void spinand_set_of_node(struct spinand_device *spinand, nanddev_set_of_node(&spinand->base, np); } +bool spinand_op_is_odtr(const struct spi_mem_op *op); + int spinand_match_and_init(struct spinand_device *spinand, const struct spinand_info *table, unsigned int table_size, From c952533f25e3dc9f121a612299bd54adc795b2ec Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:40 +0200 Subject: [PATCH 071/655] mtd: spinand: Drop ECC dirmaps Direct mappings are very static concepts, which allow us to reuse a template to perform reads or writes in a very efficient manner after a single initialization. With the introduction of pipelined ECC engines for SPI controllers, the need to differentiate between an operation with and without correction has arised. The chosen solution at that time has been to create new direct mappings for these operations, jumping from 2 to 4 dirmaps per target. Enabling ECC was done by choosing the correct dirmap. Today, we need to further parametrize dirmaps. With the goal to enable continuous reads on a wider range of devices, we will need more flexibility regarding the read from cache operation template to pick at run time, for instance to use shorter "continuous read from cache" variants. We could create other direct mappings, but it would increase the matrix by a power of two, bringing the theoretical number of dirmaps to 8 (read/write, ecc, shorter read variants) per target. This grow is not sustainable, so let's change how dirmaps work - a little bit. Operations already carry an ECC parameter, use it to indicate whether error correction is required or not. In practice this change happens only at the core level, SPI controller drivers do not care about the direct mapping structure in this case, they just pick whatever is in the template as a base. As a result, we allow the core to dynamically change the content of the templates. He who can do more can do less, so during the checking steps, make sure to enable the ECC requirement just for the time of the checks. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 52 ++++++++++++++----------------------- include/linux/mtd/spinand.h | 2 -- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index a8247e5720c3..0f154260e70f 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -487,10 +487,13 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, } } - if (req->mode == MTD_OPS_RAW) - rdesc = spinand->dirmaps[req->pos.plane].rdesc; + rdesc = spinand->dirmaps[req->pos.plane].rdesc; + + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && + req->mode != MTD_OPS_RAW) + rdesc->info.op_tmpl.data.ecc = true; else - rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc; + rdesc->info.op_tmpl.data.ecc = false; if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) column |= req->pos.plane << fls(nanddev_page_size(nand)); @@ -579,10 +582,13 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, req->ooblen); } - if (req->mode == MTD_OPS_RAW) - wdesc = spinand->dirmaps[req->pos.plane].wdesc; + wdesc = spinand->dirmaps[req->pos.plane].wdesc; + + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && + req->mode != MTD_OPS_RAW) + wdesc->info.op_tmpl.data.ecc = true; else - wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc; + wdesc->info.op_tmpl.data.ecc = false; if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) column |= req->pos.plane << fls(nanddev_page_size(nand)); @@ -1231,12 +1237,17 @@ static int spinand_create_dirmap(struct spinand_device *spinand, struct nand_device *nand = spinand_to_nand(spinand); struct spi_mem_dirmap_info info = { 0 }; struct spi_mem_dirmap_desc *desc; + bool enable_ecc = false; + + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED) + enable_ecc = true; /* The plane number is passed in MSB just above the column address */ info.offset = plane << fls(nand->memorg.pagesize); + /* Write descriptor */ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl = *spinand->op_templates->update_cache; + info.op_tmpl.data.ecc = enable_ecc; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); if (IS_ERR(desc)) @@ -1244,38 +1255,15 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc = desc; + /* Read descriptor */ info.op_tmpl = *spinand->op_templates->read_cache; + info.op_tmpl.data.ecc = enable_ecc; desc = spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); spinand->dirmaps[plane].rdesc = desc; - if (nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) { - spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc; - spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc; - - return 0; - } - - info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl = *spinand->op_templates->update_cache; - info.op_tmpl.data.ecc = true; - desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, - spinand->spimem, &info); - if (IS_ERR(desc)) - return PTR_ERR(desc); - - spinand->dirmaps[plane].wdesc_ecc = desc; - - info.op_tmpl = *spinand->op_templates->read_cache; - info.op_tmpl.data.ecc = true; - desc = spinand_create_rdesc(spinand, &info); - if (IS_ERR(desc)) - return PTR_ERR(desc); - - spinand->dirmaps[plane].rdesc_ecc = desc; - return 0; } diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index e1f19664bb25..896e9b5de0c4 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -684,8 +684,6 @@ struct spinand_info { struct spinand_dirmap { struct spi_mem_dirmap_desc *wdesc; struct spi_mem_dirmap_desc *rdesc; - struct spi_mem_dirmap_desc *wdesc_ecc; - struct spi_mem_dirmap_desc *rdesc_ecc; }; /** From 39d0ea33123ffe0214217b529830ad91574c8757 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:41 +0200 Subject: [PATCH 072/655] spi: spi-mem: Transform the read operation template As of now, we only use a single operation template when creating SPI memory direct mappings. With the idea to extend this possibility to 2, rename the template to reflect that we are currently setting the "primary" operation, and create a pointer in the same structure to point to it. From a user point of view, the op_tmpl name remains but becomes a pointer, leading to minor changes in both the SPI NAND and SPI NOR cores. There is no functional change. Acked-by: Mark Brown Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 15 ++++++++------- drivers/mtd/spi-nor/core.c | 22 ++++++++++++---------- drivers/spi/spi-airoha-snfi.c | 6 +++--- drivers/spi/spi-aspeed-smc.c | 4 ++-- drivers/spi/spi-intel.c | 6 +++--- drivers/spi/spi-mem.c | 15 ++++++++------- drivers/spi/spi-mxic.c | 18 +++++++++--------- drivers/spi/spi-npcm-fiu.c | 16 ++++++++-------- drivers/spi/spi-rpc-if.c | 8 ++++---- drivers/spi/spi-stm32-ospi.c | 6 +++--- drivers/spi/spi-stm32-qspi.c | 6 +++--- drivers/spi/spi-wpcm-fiu.c | 2 +- include/linux/spi/spi-mem.h | 3 ++- 13 files changed, 66 insertions(+), 61 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 0f154260e70f..b4c1410d5d8a 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -491,9 +491,9 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && req->mode != MTD_OPS_RAW) - rdesc->info.op_tmpl.data.ecc = true; + rdesc->info.op_tmpl->data.ecc = true; else - rdesc->info.op_tmpl.data.ecc = false; + rdesc->info.op_tmpl->data.ecc = false; if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) column |= req->pos.plane << fls(nanddev_page_size(nand)); @@ -586,9 +586,9 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && req->mode != MTD_OPS_RAW) - wdesc->info.op_tmpl.data.ecc = true; + wdesc->info.op_tmpl->data.ecc = true; else - wdesc->info.op_tmpl.data.ecc = false; + wdesc->info.op_tmpl->data.ecc = false; if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) column |= req->pos.plane << fls(nanddev_page_size(nand)); @@ -1247,7 +1247,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, /* Write descriptor */ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl.data.ecc = enable_ecc; + info.primary_op_tmpl = *spinand->op_templates->update_cache; + info.primary_op_tmpl.data.ecc = enable_ecc; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); if (IS_ERR(desc)) @@ -1256,8 +1257,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc = desc; /* Read descriptor */ - info.op_tmpl = *spinand->op_templates->read_cache; - info.op_tmpl.data.ecc = enable_ecc; + info.primary_op_tmpl = *spinand->op_templates->read_cache; + info.primary_op_tmpl.data.ecc = enable_ecc; desc = spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 5dd0b3cb5250..a7bc458edc5c 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3641,14 +3641,15 @@ EXPORT_SYMBOL_GPL(spi_nor_scan); static int spi_nor_create_read_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info = { - .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), - SPI_MEM_OP_DUMMY(nor->read_dummy, 0), - SPI_MEM_OP_DATA_IN(0, NULL, 0)), + .op_tmpl = &info.primary_op_tmpl, + .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), + SPI_MEM_OP_DUMMY(nor->read_dummy, 0), + SPI_MEM_OP_DATA_IN(0, NULL, 0)), .offset = 0, .length = nor->params->size, }; - struct spi_mem_op *op = &info.op_tmpl; + struct spi_mem_op *op = info.op_tmpl; spi_nor_spimem_setup_op(nor, op, nor->read_proto); @@ -3672,14 +3673,15 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor) static int spi_nor_create_write_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info = { - .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(0, NULL, 0)), + .op_tmpl = &info.primary_op_tmpl, + .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(0, NULL, 0)), .offset = 0, .length = nor->params->size, }; - struct spi_mem_op *op = &info.op_tmpl; + struct spi_mem_op *op = info.op_tmpl; if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) op->addr.nbytes = 0; diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c index 7b6c09f91fef..95bfde7c8e7f 100644 --- a/drivers/spi/spi-airoha-snfi.c +++ b/drivers/spi/spi-airoha-snfi.c @@ -546,7 +546,7 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) if (desc->info.length > SPI_NAND_CACHE_SIZE) return -E2BIG; - if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!airoha_snand_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; return 0; @@ -572,7 +572,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, * DUALIO and QUADIO opcodes are not supported by the spi controller, * replace them with supported opcodes. */ - opcode = desc->info.op_tmpl.cmd.opcode; + opcode = desc->info.op_tmpl->cmd.opcode; switch (opcode) { case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: @@ -761,7 +761,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, /* minimum oob size is 64 */ bytes = round_up(offs + len, 64); - opcode = desc->info.op_tmpl.cmd.opcode; + opcode = desc->info.op_tmpl->cmd.opcode; switch (opcode) { case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index c21323e07d3c..c20a33734f5c 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -697,7 +697,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) { struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller); struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)]; - struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_mem_op *op = desc->info.op_tmpl; u32 ctl_val; int ret = 0; @@ -769,7 +769,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, if (chip->ahb_window_size < offset + len || chip->force_user_mode) { int ret; - ret = aspeed_spi_read_user(chip, &desc->info.op_tmpl, offset, len, buf); + ret = aspeed_spi_read_user(chip, desc->info.op_tmpl, offset, len, buf); if (ret < 0) return ret; } else { diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c index 1775ad39e633..7494b921a743 100644 --- a/drivers/spi/spi-intel.c +++ b/drivers/spi/spi-intel.c @@ -814,7 +814,7 @@ static int intel_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); const struct intel_spi_mem_op *iop; - iop = intel_spi_match_mem_op(ispi, &desc->info.op_tmpl); + iop = intel_spi_match_mem_op(ispi, desc->info.op_tmpl); if (!iop) return -EOPNOTSUPP; @@ -827,7 +827,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, { struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); const struct intel_spi_mem_op *iop = desc->priv; - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; /* Fill in the gaps */ @@ -844,7 +844,7 @@ static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs { struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); const struct intel_spi_mem_op *iop = desc->priv; - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; op.addr.val = offs; diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index a09371a075d2..e2eaa1ba4ff6 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -647,7 +647,7 @@ EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration); static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; op.addr.val = desc->info.offset + offs; @@ -667,7 +667,7 @@ static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf) { - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; op.addr.val = desc->info.offset + offs; @@ -706,11 +706,11 @@ spi_mem_dirmap_create(struct spi_mem *mem, int ret = -ENOTSUPP; /* Make sure the number of address cycles is between 1 and 8 bytes. */ - if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8) + if (!info->primary_op_tmpl.addr.nbytes || info->primary_op_tmpl.addr.nbytes > 8) return ERR_PTR(-EINVAL); /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */ - if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA) + if (info->primary_op_tmpl.data.dir == SPI_MEM_NO_DATA) return ERR_PTR(-EINVAL); desc = kzalloc_obj(*desc); @@ -719,6 +719,7 @@ spi_mem_dirmap_create(struct spi_mem *mem, desc->mem = mem; desc->info = *info; + desc->info.op_tmpl = &desc->info.primary_op_tmpl; if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) { ret = spi_mem_access_start(mem); if (ret) { @@ -733,7 +734,7 @@ spi_mem_dirmap_create(struct spi_mem *mem, if (ret) { desc->nodirmap = true; - if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!spi_mem_supports_op(desc->mem, &desc->info.primary_op_tmpl)) ret = -EOPNOTSUPP; else ret = 0; @@ -857,7 +858,7 @@ ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, struct spi_controller *ctlr = desc->mem->spi->controller; ssize_t ret; - if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) return -EINVAL; if (!len) @@ -903,7 +904,7 @@ ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, struct spi_controller *ctlr = desc->mem->spi->controller; ssize_t ret; - if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_OUT) return -EINVAL; if (!len) diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index b0e7fc828a50..83b688e65284 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -403,20 +403,20 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.swap16), mxic->regs + HC_CFG); - writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), mxic->regs + LRD_CFG); writel(desc->info.offset + offs, mxic->regs + LRD_ADDR); len = min_t(size_t, len, mxic->linear.size); writel(len, mxic->regs + LRD_RANGE); - writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | LMODE_EN, mxic->regs + LRD_CTRL); - if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, NAND_PAGE_READ, mxic->linear.dma + offs); @@ -448,20 +448,20 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.swap16), mxic->regs + HC_CFG); - writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), mxic->regs + LWR_CFG); writel(desc->info.offset + offs, mxic->regs + LWR_ADDR); len = min_t(size_t, len, mxic->linear.size); writel(len, mxic->regs + LWR_RANGE); - writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | LMODE_EN, mxic->regs + LWR_CTRL); - if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, NAND_PAGE_WRITE, mxic->linear.dma + offs); @@ -509,7 +509,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; - if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!mxic_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; return 0; diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index 6617751009c3..4b825044038b 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -299,11 +299,11 @@ static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc, for (i = 0 ; i < len ; i++) *(buf_rx + i) = ioread8(src + i); } else { - if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth || - desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes || - desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode || - desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes) - npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); + if (desc->info.op_tmpl->addr.buswidth != fiu->drd_op.addr.buswidth || + desc->info.op_tmpl->dummy.nbytes != fiu->drd_op.dummy.nbytes || + desc->info.op_tmpl->cmd.opcode != fiu->drd_op.cmd.opcode || + desc->info.op_tmpl->addr.nbytes != fiu->drd_op.addr.nbytes) + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); memcpy_fromio(buf_rx, src, len); } @@ -609,7 +609,7 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) } if (!fiu->spix_mode && - desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) { + desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) { desc->nodirmap = true; return 0; } @@ -644,9 +644,9 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) NPCM_FIU_CFG_FIU_FIX); } - if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) { + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) { if (!fiu->spix_mode) - npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); else npcm_fiux_set_direct_rd(fiu); diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index 6edc0c4db854..1ef7bd91b3b3 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -83,7 +83,7 @@ static ssize_t xspi_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, if (offs + desc->info.offset + len > U32_MAX) return -EINVAL; - rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); return xspi_dirmap_write(rpc->dev, offs, len, buf); } @@ -97,7 +97,7 @@ static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, if (offs + desc->info.offset + len > U32_MAX) return -EINVAL; - rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); return rpcif_dirmap_read(rpc->dev, offs, len, buf); } @@ -110,13 +110,13 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; - if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!rpcif_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; if (!rpc->dirmap) return -EOPNOTSUPP; - if (!rpc->xspi && desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + if (!rpc->xspi && desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) return -EOPNOTSUPP; return 0; diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c index 4461c6e24b9e..5f5b3cd5d725 100644 --- a/drivers/spi/spi-stm32-ospi.c +++ b/drivers/spi/spi-stm32-ospi.c @@ -602,11 +602,11 @@ static int stm32_ospi_dirmap_create(struct spi_mem_dirmap_desc *desc) { struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller); - if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) return -EOPNOTSUPP; /* Should never happen, as mm_base == null is an error probe exit condition */ - if (!ospi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) + if (!ospi->mm_base && desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) return -EOPNOTSUPP; if (!ospi->mm_size) @@ -633,7 +633,7 @@ static ssize_t stm32_ospi_dirmap_read(struct spi_mem_dirmap_desc *desc, * spi_mem_op template with offs, len and *buf in order to get * all needed transfer information into struct spi_mem_op */ - memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); dev_dbg(ospi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); op.data.nbytes = len; diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index df1bbacec90a..e2a6a6eaf9b2 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -506,11 +506,11 @@ static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) { struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->controller); - if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) return -EOPNOTSUPP; /* should never happen, as mm_base == null is an error probe exit condition */ - if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) + if (!qspi->mm_base && desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) return -EOPNOTSUPP; if (!qspi->mm_size) @@ -536,7 +536,7 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, * spi_mem_op template with offs, len and *buf in order to get * all needed transfer information into struct spi_mem_op */ - memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); op.data.nbytes = len; diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 0e26ff178505..cd78e927953d 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -377,7 +377,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller); int cs = spi_get_chipselect(desc->mem->spi, 0); - if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) return -EOPNOTSUPP; /* diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index c8e207522223..9a96ddace3eb 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -237,7 +237,8 @@ struct spi_mem_op { * direction is directly encoded in the ->op_tmpl.data.dir field. */ struct spi_mem_dirmap_info { - struct spi_mem_op op_tmpl; + struct spi_mem_op *op_tmpl; + struct spi_mem_op primary_op_tmpl; u64 offset; u64 length; }; From 6f96f2fa152518d93ffeedbea781db50aef7f7dc Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:42 +0200 Subject: [PATCH 073/655] spi: spi-mem: Create a secondary read operation In some situations, direct mappings may need to use different operation templates. For instance, when enabling continuous reads, Winbond SPI NANDs no longer expect address cycles because they would be ignoring them otherwise. Hence, right after the command opcode, they start counting dummy cycles, followed by the data cycles as usual. This breaks the assumptions of "reads from cache" always being done identically once the best variant has been picked up, across the lifetime of the system. In order to support this feature, we must give direct mapping more than a single operation template to use, in order to switch to using secondary operations upon request by the upper layer. Create the concept of optional secondary operation template, which may or may not be fulfilled by the SPI NAND and SPI NOR cores. If the underlying SPI controller does not leverage any kind of direct mapping acceleration, the feature has no impact and can be freely used. Otherwise, the controller driver needs to opt-in for using this feature, if supported. The condition checked to know whether a secondary operation has been provided or not is to look for a non zero opcode to limit the creation of extra variables. In practice, the opcode 0x00 exist, but is not related to any cache related operation. Acked-by: Mark Brown Signed-off-by: Miquel Raynal --- drivers/spi/spi-mem.c | 17 +++++++++++++++++ include/linux/spi/spi-mem.h | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index e2eaa1ba4ff6..f64eda9bbd9f 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -713,6 +713,23 @@ spi_mem_dirmap_create(struct spi_mem *mem, if (info->primary_op_tmpl.data.dir == SPI_MEM_NO_DATA) return ERR_PTR(-EINVAL); + /* Apply similar constraints to the secondary template */ + if (info->secondary_op_tmpl.cmd.opcode) { + if (!info->secondary_op_tmpl.addr.nbytes || + info->secondary_op_tmpl.addr.nbytes > 8) + return ERR_PTR(-EINVAL); + + if (info->secondary_op_tmpl.data.dir == SPI_MEM_NO_DATA) + return ERR_PTR(-EINVAL); + + if (!spi_mem_supports_op(mem, &info->secondary_op_tmpl)) + return ERR_PTR(-EOPNOTSUPP); + + if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create && + !spi_mem_controller_is_capable(ctlr, secondary_op_tmpl)) + return ERR_PTR(-EOPNOTSUPP); + } + desc = kzalloc_obj(*desc); if (!desc) return ERR_PTR(-ENOMEM); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index 9a96ddace3eb..2012a3b2ef91 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -227,6 +227,8 @@ struct spi_mem_op { * struct spi_mem_dirmap_info - Direct mapping information * @op_tmpl: operation template that should be used by the direct mapping when * the memory device is accessed + * @secondary_op_tmpl: secondary template, may be used as an alternative to the + * primary template (decided by the upper layer) * @offset: absolute offset this direct mapping is pointing to * @length: length in byte of this direct mapping * @@ -239,6 +241,7 @@ struct spi_mem_op { struct spi_mem_dirmap_info { struct spi_mem_op *op_tmpl; struct spi_mem_op primary_op_tmpl; + struct spi_mem_op secondary_op_tmpl; u64 offset; u64 length; }; @@ -382,12 +385,14 @@ struct spi_controller_mem_ops { * @swap16: Supports swapping bytes on a 16 bit boundary when configured in * Octal DTR * @per_op_freq: Supports per operation frequency switching + * @secondary_op_tmpl: Supports leveraging a secondary memory operation template */ struct spi_controller_mem_caps { bool dtr; bool ecc; bool swap16; bool per_op_freq; + bool secondary_op_tmpl; }; #define spi_mem_controller_is_capable(ctlr, cap) \ From ae4ccd216dd3a9fa89a87a295380f6d62c4832ed Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:20:05 +0200 Subject: [PATCH 074/655] spi: at91-usart: drop dead runtime pm support Drop the dead runtime PM support which has never been enabled. Fixes: 96ed3ecde2c0 ("spi: at91-usart: add power management support") Cc: Radu Pirea Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429092005.166128-1-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-at91-usart.c | 39 ++++++++---------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index 79edc1cd13c0..dce879627091 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -16,7 +16,6 @@ #include #include #include -#include #include @@ -576,38 +575,18 @@ at91_usart_spi_probe_fail: return ret; } -__maybe_unused static int at91_usart_spi_runtime_suspend(struct device *dev) -{ - struct spi_controller *ctlr = dev_get_drvdata(dev); - struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr); - - clk_disable_unprepare(aus->clk); - pinctrl_pm_select_sleep_state(dev); - - return 0; -} - -__maybe_unused static int at91_usart_spi_runtime_resume(struct device *dev) -{ - struct spi_controller *ctrl = dev_get_drvdata(dev); - struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl); - - pinctrl_pm_select_default_state(dev); - - return clk_prepare_enable(aus->clk); -} - __maybe_unused static int at91_usart_spi_suspend(struct device *dev) { struct spi_controller *ctrl = dev_get_drvdata(dev); + struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl); int ret; ret = spi_controller_suspend(ctrl); if (ret) return ret; - if (!pm_runtime_suspended(dev)) - at91_usart_spi_runtime_suspend(dev); + clk_disable_unprepare(aus->clk); + pinctrl_pm_select_sleep_state(dev); return 0; } @@ -618,11 +597,11 @@ __maybe_unused static int at91_usart_spi_resume(struct device *dev) struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl); int ret; - if (!pm_runtime_suspended(dev)) { - ret = at91_usart_spi_runtime_resume(dev); - if (ret) - return ret; - } + pinctrl_pm_select_default_state(dev); + + ret = clk_prepare_enable(aus->clk); + if (ret) + return ret; at91_usart_spi_init(aus); @@ -646,8 +625,6 @@ static void at91_usart_spi_remove(struct platform_device *pdev) static const struct dev_pm_ops at91_usart_spi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(at91_usart_spi_suspend, at91_usart_spi_resume) - SET_RUNTIME_PM_OPS(at91_usart_spi_runtime_suspend, - at91_usart_spi_runtime_resume, NULL) }; static struct platform_driver at91_usart_spi_driver = { From 38fbe4b3f66e5b8e2f2ab8e7ca3d912e1e935fe2 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 26 Mar 2026 17:47:15 +0100 Subject: [PATCH 075/655] spi: spi-mem: Add a no_cs_assertion capability Some controllers are 'smart', and that's a problem. For instance, the Cadence quadspi controller is capable of deasserting the CS automatically whenever a too long period of time without any data to transfer elapses. This 'feature' combined with a loaded interconnect with arbitration, a "long" transfer may be split into smaller DMA transfers. In this case the controller may allow itself to deassert the CS between chunks. Deasserting the CS stops any ongoing continuous read. Reasserting it later to continue the reading will only result in the host getting garbage. In this case, the host controller driver has no control over the CS state, so we cannot reliably enable continuous reads. Flag this limitation through a spi-mem controller capability. The inversion in the flag name (starting with 'no_') is voluntary, in order to avoid the need to set this flag in all controller drivers. Only the broken controllers shall set this bit, the default being that the controller masters its CS fully. Reviewed-by: Mark Brown Signed-off-by: Miquel Raynal --- include/linux/spi/spi-mem.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index 2012a3b2ef91..722abd9aee3c 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -385,7 +385,10 @@ struct spi_controller_mem_ops { * @swap16: Supports swapping bytes on a 16 bit boundary when configured in * Octal DTR * @per_op_freq: Supports per operation frequency switching - * @secondary_op_tmpl: Supports leveraging a secondary memory operation template + * @no_cs_assertion: The controller may automatically deassert the CS if there + * is a pause in the transfer (eg. internal bus contention or + * DMA arbitration on an interconnect). Features such as NAND + * continuous reads shall not be leveraged. */ struct spi_controller_mem_caps { bool dtr; @@ -393,6 +396,7 @@ struct spi_controller_mem_caps { bool swap16; bool per_op_freq; bool secondary_op_tmpl; + bool no_cs_assertion; }; #define spi_mem_controller_is_capable(ctlr, cap) \ From 5113e23077103e6e92b21133065e5a4b5fd09c47 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:15 +0200 Subject: [PATCH 076/655] spi: at91-usart: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-2-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-at91-usart.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index dce879627091..77cad4118202 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -495,14 +495,13 @@ static int at91_usart_spi_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - ret = -ENOMEM; - controller = spi_alloc_host(&pdev->dev, sizeof(*aus)); + controller = devm_spi_alloc_host(&pdev->dev, sizeof(*aus)); if (!controller) - goto at91_usart_spi_probe_fail; + return -ENOMEM; ret = at91_usart_gpio_setup(pdev); if (ret) - goto at91_usart_spi_probe_fail; + return ret; controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; controller->dev.of_node = pdev->dev.parent->of_node; @@ -524,10 +523,8 @@ static int at91_usart_spi_probe(struct platform_device *pdev) aus->dev = &pdev->dev; aus->regs = devm_ioremap_resource(&pdev->dev, regs); - if (IS_ERR(aus->regs)) { - ret = PTR_ERR(aus->regs); - goto at91_usart_spi_probe_fail; - } + if (IS_ERR(aus->regs)) + return PTR_ERR(aus->regs); aus->irq = irq; aus->clk = clk; @@ -535,11 +532,11 @@ static int at91_usart_spi_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, at91_usart_spi_interrupt, 0, dev_name(&pdev->dev), controller); if (ret) - goto at91_usart_spi_probe_fail; + return ret; ret = clk_prepare_enable(clk); if (ret) - goto at91_usart_spi_probe_fail; + return ret; aus->spi_clk = clk_get_rate(clk); at91_usart_spi_init(aus); @@ -570,8 +567,7 @@ at91_usart_fail_register_controller: at91_usart_spi_release_dma(controller); at91_usart_fail_dma: clk_disable_unprepare(clk); -at91_usart_spi_probe_fail: - spi_controller_put(controller); + return ret; } @@ -613,14 +609,10 @@ static void at91_usart_spi_remove(struct platform_device *pdev) struct spi_controller *ctlr = platform_get_drvdata(pdev); struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr); - spi_controller_get(ctlr); - spi_unregister_controller(ctlr); at91_usart_spi_release_dma(ctlr); clk_disable_unprepare(aus->clk); - - spi_controller_put(ctlr); } static const struct dev_pm_ops at91_usart_spi_pm_ops = { From ebf99aebc458391893c598f1caddd42bfcc97fc5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:16 +0200 Subject: [PATCH 077/655] spi: atmel: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-3-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 42db85d7ff8e..25aa294631c8 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1528,7 +1528,7 @@ static int atmel_spi_probe(struct platform_device *pdev) return PTR_ERR(clk); /* setup spi core then atmel-specific driver state */ - host = spi_alloc_host(&pdev->dev, sizeof(*as)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*as)); if (!host) return -ENOMEM; @@ -1555,18 +1555,15 @@ static int atmel_spi_probe(struct platform_device *pdev) as->pdev = pdev; as->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ®s); - if (IS_ERR(as->regs)) { - ret = PTR_ERR(as->regs); - goto out_unmap_regs; - } + if (IS_ERR(as->regs)) + return PTR_ERR(as->regs); + as->phybase = regs->start; as->irq = irq; as->clk = clk; as->gclk = devm_clk_get_optional(&pdev->dev, "spi_gclk"); - if (IS_ERR(as->gclk)) { - ret = PTR_ERR(as->gclk); - goto out_unmap_regs; - } + if (IS_ERR(as->gclk)) + return PTR_ERR(as->gclk); init_completion(&as->xfer_completion); @@ -1576,11 +1573,10 @@ static int atmel_spi_probe(struct platform_device *pdev) as->use_pdc = false; if (as->caps.has_dma_support) { ret = atmel_spi_configure_dma(host, as); - if (ret == 0) { + if (ret == 0) as->use_dma = true; - } else if (ret == -EPROBE_DEFER) { - goto out_unmap_regs; - } + else if (ret == -EPROBE_DEFER) + return ret; } else if (as->caps.has_pdc_support) { as->use_pdc = true; } @@ -1620,12 +1616,12 @@ static int atmel_spi_probe(struct platform_device *pdev) 0, dev_name(&pdev->dev), host); } if (ret) - goto out_unmap_regs; + return ret; /* Initialize the hardware */ ret = clk_prepare_enable(clk); if (ret) - goto out_free_irq; + return ret; /* * In cases where the peripheral clock is higher,the FLEX_SPI_CSRx.SCBR @@ -1677,9 +1673,7 @@ out_free_dma: clk_disable_unprepare(as->gclk); out_disable_clk: clk_disable_unprepare(clk); -out_free_irq: -out_unmap_regs: - spi_controller_put(host); + return ret; } @@ -1688,8 +1682,6 @@ static void atmel_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct atmel_spi *as = spi_controller_get_devdata(host); - spi_controller_get(host); - pm_runtime_get_sync(&pdev->dev); spi_unregister_controller(host); @@ -1720,8 +1712,6 @@ static void atmel_spi_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); - - spi_controller_put(host); } static int atmel_spi_runtime_suspend(struct device *dev) From 414c359e7295d383e6bf2321eb7499f95008f1a8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:17 +0200 Subject: [PATCH 078/655] spi: bcm63xx: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-4-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 40cd7efc4b54..f8cfe535b2a3 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -541,11 +541,9 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) if (IS_ERR(reset)) return PTR_ERR(reset); - host = spi_alloc_host(dev, sizeof(*bs)); - if (!host) { - dev_err(dev, "out of memory\n"); + host = devm_spi_alloc_host(dev, sizeof(*bs)); + if (!host) return -ENOMEM; - } bs = spi_controller_get_devdata(host); init_completion(&bs->done); @@ -554,10 +552,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) bs->pdev = pdev; bs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &r); - if (IS_ERR(bs->regs)) { - ret = PTR_ERR(bs->regs); - goto out_err; - } + if (IS_ERR(bs->regs)) + return PTR_ERR(bs->regs); bs->irq = irq; bs->clk = clk; @@ -568,7 +564,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) pdev->name, host); if (ret) { dev_err(dev, "unable to request irq\n"); - goto out_err; + return ret; } host->bus_num = bus_num; @@ -587,7 +583,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) /* Initialize hardware */ ret = clk_prepare_enable(bs->clk); if (ret) - goto out_err; + return ret; ret = reset_control_reset(reset); if (ret) { @@ -615,8 +611,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) out_clk_disable: clk_disable_unprepare(clk); -out_err: - spi_controller_put(host); + return ret; } @@ -625,8 +620,6 @@ static void bcm63xx_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct bcm63xx_spi *bs = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); /* reset spi block */ @@ -634,8 +627,6 @@ static void bcm63xx_spi_remove(struct platform_device *pdev) /* HW shutdown */ clk_disable_unprepare(bs->clk); - - spi_controller_put(host); } static int bcm63xx_spi_suspend(struct device *dev) From fe010594a8575715b879956dfb970894431dd69f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:18 +0200 Subject: [PATCH 079/655] spi: bcm63xx-hsspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Acked-by: William Zhang Link: https://patch.msgid.link/20260429091333.165363-5-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx-hsspi.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index e935e8ab9cfd..58012e1b5ae7 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -783,7 +783,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) "failed get pll clk rate\n"); } - host = spi_alloc_host(&pdev->dev, sizeof(*bs)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*bs)); if (!host) return dev_err_probe(dev, -ENOMEM, "alloc host no mem\n"); @@ -796,10 +796,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0)); bs->wait_mode = HSSPI_WAIT_MODE_POLLING; bs->prepend_buf = devm_kzalloc(dev, HSSPI_BUFFER_LEN, GFP_KERNEL); - if (!bs->prepend_buf) { - ret = -ENOMEM; - goto out_put_host; - } + if (!bs->prepend_buf) + return -ENOMEM; mutex_init(&bs->bus_mutex); mutex_init(&bs->msg_mutex); @@ -845,7 +843,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) pdev->name, bs); if (ret) - goto out_put_host; + return ret; } pm_runtime_enable(&pdev->dev); @@ -869,8 +867,7 @@ out_sysgroup_disable: sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group); out_pm_disable: pm_runtime_disable(&pdev->dev); -out_put_host: - spi_controller_put(host); + return ret; } @@ -880,15 +877,11 @@ static void bcm63xx_hsspi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); /* reset the hardware and block queue progress */ __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG); sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group); - - spi_controller_put(host); } #ifdef CONFIG_PM_SLEEP From 83c4ded3917d0cf5bcb1899c2747cede8dc6ab14 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:19 +0200 Subject: [PATCH 080/655] spi: cadence: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-6-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index d108e89fda22..9b4e5b7013ae 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -643,9 +643,9 @@ static int cdns_spi_probe(struct platform_device *pdev) target = of_property_read_bool(pdev->dev.of_node, "spi-slave"); if (target) - ctlr = spi_alloc_target(&pdev->dev, sizeof(*xspi)); + ctlr = devm_spi_alloc_target(&pdev->dev, sizeof(*xspi)); else - ctlr = spi_alloc_host(&pdev->dev, sizeof(*xspi)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*xspi)); if (!ctlr) return -ENOMEM; @@ -654,23 +654,19 @@ static int cdns_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctlr); xspi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(xspi->regs)) { - ret = PTR_ERR(xspi->regs); - goto err_put_ctlr; - } + if (IS_ERR(xspi->regs)) + return PTR_ERR(xspi->regs); xspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); if (IS_ERR(xspi->pclk)) { dev_err(&pdev->dev, "pclk clock not found.\n"); - ret = PTR_ERR(xspi->pclk); - goto err_put_ctlr; + return PTR_ERR(xspi->pclk); } xspi->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi"); if (IS_ERR(xspi->rstc)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(xspi->rstc), - "Cannot get SPI reset.\n"); - goto err_put_ctlr; + return dev_err_probe(&pdev->dev, PTR_ERR(xspi->rstc), + "Cannot get SPI reset.\n"); } reset_control_assert(xspi->rstc); @@ -679,8 +675,7 @@ static int cdns_spi_probe(struct platform_device *pdev) xspi->ref_clk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); if (IS_ERR(xspi->ref_clk)) { dev_err(&pdev->dev, "ref_clk clock not found.\n"); - ret = PTR_ERR(xspi->ref_clk); - goto err_put_ctlr; + return PTR_ERR(xspi->ref_clk); } if (!spi_controller_is_target(ctlr)) { @@ -763,8 +758,7 @@ err_disable_rpm: pm_runtime_put_noidle(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); } -err_put_ctlr: - spi_controller_put(ctlr); + return ret; } @@ -785,8 +779,6 @@ static void cdns_spi_remove(struct platform_device *pdev) if (!spi_controller_is_target(ctlr)) ret = pm_runtime_get_sync(&pdev->dev); - spi_controller_get(ctlr); - spi_unregister_controller(ctlr); if (ret >= 0) @@ -798,8 +790,6 @@ static void cdns_spi_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); } - - spi_controller_put(ctlr); } /** From eab6ce941217cf12190945d6f8068306ccd4f6eb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:20 +0200 Subject: [PATCH 081/655] spi: octeon: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-7-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cavium-octeon.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c index b95bfa6a3013..28c922c72068 100644 --- a/drivers/spi/spi-cavium-octeon.c +++ b/drivers/spi/spi-cavium-octeon.c @@ -23,17 +23,15 @@ static int octeon_spi_probe(struct platform_device *pdev) struct octeon_spi *p; int err = -ENOENT; - host = spi_alloc_host(&pdev->dev, sizeof(struct octeon_spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct octeon_spi)); if (!host) return -ENOMEM; p = spi_controller_get_devdata(host); platform_set_drvdata(pdev, host); reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(reg_base)) { - err = PTR_ERR(reg_base); - goto fail; - } + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); p->register_base = reg_base; p->sys_freq = octeon_get_io_clock_rate(); @@ -57,15 +55,12 @@ static int octeon_spi_probe(struct platform_device *pdev) err = spi_register_controller(host); if (err) { dev_err(&pdev->dev, "register host failed: %d\n", err); - goto fail; + return err; } dev_info(&pdev->dev, "OCTEON SPI bus driver\n"); return 0; -fail: - spi_controller_put(host); - return err; } static void octeon_spi_remove(struct platform_device *pdev) @@ -73,14 +68,10 @@ static void octeon_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct octeon_spi *p = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); /* Clear the CSENA* and put everything in a known state. */ writeq(0, p->register_base + OCTEON_SPI_CFG(p)); - - spi_controller_put(host); } static const struct of_device_id octeon_spi_match[] = { From fcca78c086383c8b22aa1e529963eebab46d3f0c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:21 +0200 Subject: [PATCH 082/655] spi: cavium-thunderx: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-8-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cavium-thunderx.c | 32 ++++++++----------------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c index f1a9aa696c87..529b4066c922 100644 --- a/drivers/spi/spi-cavium-thunderx.c +++ b/drivers/spi/spi-cavium-thunderx.c @@ -24,7 +24,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev, struct octeon_spi *p; int ret; - host = spi_alloc_host(dev, sizeof(struct octeon_spi)); + host = devm_spi_alloc_host(dev, sizeof(struct octeon_spi)); if (!host) return -ENOMEM; @@ -32,17 +32,15 @@ static int thunderx_spi_probe(struct pci_dev *pdev, ret = pcim_enable_device(pdev); if (ret) - goto error; + return ret; ret = pcim_request_all_regions(pdev, DRV_NAME); if (ret) - goto error; + return ret; p->register_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0)); - if (!p->register_base) { - ret = -EINVAL; - goto error; - } + if (!p->register_base) + return -EINVAL; p->regs.config = 0x1000; p->regs.status = 0x1008; @@ -50,10 +48,8 @@ static int thunderx_spi_probe(struct pci_dev *pdev, p->regs.data = 0x1080; p->clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(p->clk)) { - ret = PTR_ERR(p->clk); - goto error; - } + if (IS_ERR(p->clk)) + return PTR_ERR(p->clk); p->sys_freq = clk_get_rate(p->clk); if (!p->sys_freq) @@ -70,15 +66,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, host); - ret = spi_register_controller(host); - if (ret) - goto error; - - return 0; - -error: - spi_controller_put(host); - return ret; + return spi_register_controller(host); } static void thunderx_spi_remove(struct pci_dev *pdev) @@ -90,14 +78,10 @@ static void thunderx_spi_remove(struct pci_dev *pdev) if (!p) return; - spi_controller_get(host); - spi_unregister_controller(host); /* Put everything in a known state. */ writeq(0, p->register_base + OCTEON_SPI_CFG(p)); - - spi_controller_put(host); } static const struct pci_device_id thunderx_spi_pci_id_table[] = { From 079c7a626c7d2a7f3841ce1195e4da09b8ca365b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:22 +0200 Subject: [PATCH 083/655] spi: coldfire-qspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-9-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index b45f44de85dc..3b175c1da36b 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -353,39 +353,33 @@ static int mcfqspi_probe(struct platform_device *pdev) return -EINVAL; } - host = spi_alloc_host(&pdev->dev, sizeof(*mcfqspi)); - if (host == NULL) { - dev_dbg(&pdev->dev, "spi_alloc_host failed\n"); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*mcfqspi)); + if (host == NULL) return -ENOMEM; - } mcfqspi = spi_controller_get_devdata(host); mcfqspi->iobase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(mcfqspi->iobase)) { - status = PTR_ERR(mcfqspi->iobase); - goto fail0; - } + if (IS_ERR(mcfqspi->iobase)) + return PTR_ERR(mcfqspi->iobase); mcfqspi->irq = platform_get_irq(pdev, 0); if (mcfqspi->irq < 0) { dev_dbg(&pdev->dev, "platform_get_irq failed\n"); - status = -ENXIO; - goto fail0; + return -ENXIO; } status = devm_request_irq(&pdev->dev, mcfqspi->irq, mcfqspi_irq_handler, 0, pdev->name, mcfqspi); if (status) { dev_dbg(&pdev->dev, "request_irq failed\n"); - goto fail0; + return status; } mcfqspi->clk = devm_clk_get_enabled(&pdev->dev, "qspi_clk"); if (IS_ERR(mcfqspi->clk)) { dev_dbg(&pdev->dev, "clk_get failed\n"); - status = PTR_ERR(mcfqspi->clk); - goto fail0; + return PTR_ERR(mcfqspi->clk); } host->bus_num = pdata->bus_num; @@ -395,7 +389,7 @@ static int mcfqspi_probe(struct platform_device *pdev) status = mcfqspi_cs_setup(mcfqspi); if (status) { dev_dbg(&pdev->dev, "error initializing cs_control\n"); - goto fail0; + return status; } init_waitqueue_head(&mcfqspi->waitq); @@ -423,8 +417,6 @@ static int mcfqspi_probe(struct platform_device *pdev) fail1: pm_runtime_disable(&pdev->dev); mcfqspi_cs_teardown(mcfqspi); -fail0: - spi_controller_put(host); dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n"); @@ -436,8 +428,6 @@ static void mcfqspi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct mcfqspi *mcfqspi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_disable(&pdev->dev); @@ -445,8 +435,6 @@ static void mcfqspi_remove(struct platform_device *pdev) mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR); mcfqspi_cs_teardown(mcfqspi); - - spi_controller_put(host); } #ifdef CONFIG_PM_SLEEP From 6bd505e710aa612cf57f7894a10d00c99d600226 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:23 +0200 Subject: [PATCH 084/655] spi: dln2: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-10-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-dln2.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c index 392f0d05f508..8333dda7d1e8 100644 --- a/drivers/spi/spi-dln2.c +++ b/drivers/spi/spi-dln2.c @@ -684,7 +684,7 @@ static int dln2_spi_probe(struct platform_device *pdev) struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret; - host = spi_alloc_host(&pdev->dev, sizeof(*dln2)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*dln2)); if (!host) return -ENOMEM; @@ -693,10 +693,8 @@ static int dln2_spi_probe(struct platform_device *pdev) dln2 = spi_controller_get_devdata(host); dln2->buf = devm_kmalloc(&pdev->dev, DLN2_SPI_BUF_SIZE, GFP_KERNEL); - if (!dln2->buf) { - ret = -ENOMEM; - goto exit_free_host; - } + if (!dln2->buf) + return -ENOMEM; dln2->host = host; dln2->pdev = pdev; @@ -709,13 +707,13 @@ static int dln2_spi_probe(struct platform_device *pdev) ret = dln2_spi_enable(dln2, false); if (ret < 0) { dev_err(&pdev->dev, "Failed to disable SPI module\n"); - goto exit_free_host; + return ret; } ret = dln2_spi_get_cs_num(dln2, &host->num_chipselect); if (ret < 0) { dev_err(&pdev->dev, "Failed to get number of CS pins\n"); - goto exit_free_host; + return ret; } ret = dln2_spi_get_speed_range(dln2, @@ -723,20 +721,20 @@ static int dln2_spi_probe(struct platform_device *pdev) &host->max_speed_hz); if (ret < 0) { dev_err(&pdev->dev, "Failed to read bus min/max freqs\n"); - goto exit_free_host; + return ret; } ret = dln2_spi_get_supported_frame_sizes(dln2, &host->bits_per_word_mask); if (ret < 0) { dev_err(&pdev->dev, "Failed to read supported frame sizes\n"); - goto exit_free_host; + return ret; } ret = dln2_spi_cs_enable_all(dln2, true); if (ret < 0) { dev_err(&pdev->dev, "Failed to enable CS pins\n"); - goto exit_free_host; + return ret; } host->bus_num = -1; @@ -749,7 +747,7 @@ static int dln2_spi_probe(struct platform_device *pdev) ret = dln2_spi_enable(dln2, true); if (ret < 0) { dev_err(&pdev->dev, "Failed to enable SPI module\n"); - goto exit_free_host; + return ret; } pm_runtime_set_autosuspend_delay(&pdev->dev, @@ -772,8 +770,6 @@ exit_register: if (dln2_spi_enable(dln2, false) < 0) dev_err(&pdev->dev, "Failed to disable SPI module\n"); -exit_free_host: - spi_controller_put(host); return ret; } @@ -783,16 +779,12 @@ static void dln2_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct dln2_spi *dln2 = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_disable(&pdev->dev); if (dln2_spi_enable(dln2, false) < 0) dev_err(&pdev->dev, "Failed to disable SPI module\n"); - - spi_controller_put(host); } #ifdef CONFIG_PM_SLEEP From 01500b2cb05ab60b6eb7b8a24a56bad45296227c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:24 +0200 Subject: [PATCH 085/655] spi: ep93xx: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-11-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index db50018050e5..d7e82d80c35a 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -629,7 +629,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev) if (irq < 0) return irq; - host = spi_alloc_host(&pdev->dev, sizeof(*espi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*espi)); if (!host) return -ENOMEM; @@ -654,8 +654,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev) espi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(espi->clk)) { dev_err(&pdev->dev, "unable to get spi clock\n"); - error = PTR_ERR(espi->clk); - goto fail_release_host; + return PTR_ERR(espi->clk); } /* @@ -666,22 +665,21 @@ static int ep93xx_spi_probe(struct platform_device *pdev) host->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256); espi->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(espi->mmio)) { - error = PTR_ERR(espi->mmio); - goto fail_release_host; - } + if (IS_ERR(espi->mmio)) + return PTR_ERR(espi->mmio); + espi->sspdr_phys = res->start + SSPDR; error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt, 0, "ep93xx-spi", host); if (error) { dev_err(&pdev->dev, "failed to request irq\n"); - goto fail_release_host; + return error; } error = ep93xx_spi_setup_dma(&pdev->dev, espi); if (error == -EPROBE_DEFER) - goto fail_release_host; + return error; if (error) dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n"); @@ -702,8 +700,6 @@ static int ep93xx_spi_probe(struct platform_device *pdev) fail_free_dma: ep93xx_spi_release_dma(espi); -fail_release_host: - spi_controller_put(host); return error; } @@ -713,13 +709,9 @@ static void ep93xx_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct ep93xx_spi *espi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); ep93xx_spi_release_dma(espi); - - spi_controller_put(host); } static const struct of_device_id ep93xx_spi_of_ids[] = { From 6afe041c2ce9068b2b6c64eddb5537911752050c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:25 +0200 Subject: [PATCH 086/655] spi: fsl: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-12-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 1252c41c206f..e45816ef7b65 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -535,7 +535,7 @@ static struct spi_controller *fsl_spi_probe(struct device *dev, u32 regval; int ret = 0; - host = spi_alloc_host(dev, sizeof(struct mpc8xxx_spi)); + host = devm_spi_alloc_host(dev, sizeof(struct mpc8xxx_spi)); if (host == NULL) { ret = -ENOMEM; goto err; @@ -559,7 +559,7 @@ static struct spi_controller *fsl_spi_probe(struct device *dev, ret = fsl_spi_cpm_init(mpc8xxx_spi); if (ret) - goto err_cpm_init; + goto err; mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); if (IS_ERR(mpc8xxx_spi->reg_base)) { @@ -625,8 +625,6 @@ static struct spi_controller *fsl_spi_probe(struct device *dev, err_probe: fsl_spi_cpm_free(mpc8xxx_spi); -err_cpm_init: - spi_controller_put(host); err: return ERR_PTR(ret); } @@ -705,13 +703,9 @@ static void of_fsl_spi_remove(struct platform_device *ofdev) struct spi_controller *host = platform_get_drvdata(ofdev); struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); fsl_spi_cpm_free(mpc8xxx_spi); - - spi_controller_put(host); } static struct platform_driver of_fsl_spi_driver = { @@ -757,13 +751,9 @@ static void plat_mpc8xxx_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); fsl_spi_cpm_free(mpc8xxx_spi); - - spi_controller_put(host); } MODULE_ALIAS("platform:mpc8xxx_spi"); From 9979501afa4a94e71e0c127bbbcd70bcdf397dbc Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:26 +0200 Subject: [PATCH 087/655] spi: fsl-espi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-13-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 45b9974ae911..f560bd537f7d 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -667,7 +667,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem, struct fsl_espi *espi; int ret; - host = spi_alloc_host(dev, sizeof(struct fsl_espi)); + host = devm_spi_alloc_host(dev, sizeof(struct fsl_espi)); if (!host) return -ENOMEM; @@ -690,8 +690,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem, espi->spibrg = fsl_get_sys_freq(); if (espi->spibrg == -1) { dev_err(dev, "Can't get sys frequency!\n"); - ret = -EINVAL; - goto err_probe; + return -EINVAL; } /* determined by clock divider fields DIV16/PM in register SPMODEx */ host->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16); @@ -700,15 +699,13 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem, init_completion(&espi->done); espi->reg_base = devm_ioremap_resource(dev, mem); - if (IS_ERR(espi->reg_base)) { - ret = PTR_ERR(espi->reg_base); - goto err_probe; - } + if (IS_ERR(espi->reg_base)) + return PTR_ERR(espi->reg_base); /* Register for SPI Interrupt */ ret = devm_request_irq(dev, irq, fsl_espi_irq, 0, "fsl_espi", espi); if (ret) - goto err_probe; + return ret; fsl_espi_init_regs(dev, true); @@ -732,8 +729,7 @@ err_pm: pm_runtime_put_noidle(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); -err_probe: - spi_controller_put(host); + return ret; } @@ -784,13 +780,9 @@ static void of_fsl_espi_remove(struct platform_device *dev) { struct spi_controller *host = platform_get_drvdata(dev); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_disable(&dev->dev); - - spi_controller_put(host); } #ifdef CONFIG_PM_SLEEP From 8015cac85a698d471f100ca8602c27448bee146b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:27 +0200 Subject: [PATCH 088/655] spi: img-spfi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-14-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-img-spfi.c | 40 ++++++++++++++------------------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 57625a3ce2f2..aec724e3f824 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -530,7 +530,7 @@ static int img_spfi_probe(struct platform_device *pdev) int ret; u32 max_speed_hz; - host = spi_alloc_host(&pdev->dev, sizeof(*spfi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*spfi)); if (!host) return -ENOMEM; platform_set_drvdata(pdev, host); @@ -541,36 +541,32 @@ static int img_spfi_probe(struct platform_device *pdev) spin_lock_init(&spfi->lock); spfi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(spfi->regs)) { - ret = PTR_ERR(spfi->regs); - goto put_spi; - } + if (IS_ERR(spfi->regs)) + return PTR_ERR(spfi->regs); + spfi->phys = res->start; spfi->irq = platform_get_irq(pdev, 0); - if (spfi->irq < 0) { - ret = spfi->irq; - goto put_spi; - } + if (spfi->irq < 0) + return spfi->irq; + ret = devm_request_irq(spfi->dev, spfi->irq, img_spfi_irq, IRQ_TYPE_LEVEL_HIGH, dev_name(spfi->dev), spfi); if (ret) - goto put_spi; + return ret; spfi->sys_clk = devm_clk_get(spfi->dev, "sys"); - if (IS_ERR(spfi->sys_clk)) { - ret = PTR_ERR(spfi->sys_clk); - goto put_spi; - } + if (IS_ERR(spfi->sys_clk)) + return PTR_ERR(spfi->sys_clk); + spfi->spfi_clk = devm_clk_get(spfi->dev, "spfi"); - if (IS_ERR(spfi->spfi_clk)) { - ret = PTR_ERR(spfi->spfi_clk); - goto put_spi; - } + if (IS_ERR(spfi->spfi_clk)) + return PTR_ERR(spfi->spfi_clk); ret = clk_prepare_enable(spfi->sys_clk); if (ret) - goto put_spi; + return ret; + ret = clk_prepare_enable(spfi->spfi_clk); if (ret) goto disable_pclk; @@ -658,8 +654,6 @@ disable_pm: clk_disable_unprepare(spfi->spfi_clk); disable_pclk: clk_disable_unprepare(spfi->sys_clk); -put_spi: - spi_controller_put(host); return ret; } @@ -669,8 +663,6 @@ static void img_spfi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct img_spfi *spfi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); if (spfi->tx_ch) @@ -683,8 +675,6 @@ static void img_spfi_remove(struct platform_device *pdev) clk_disable_unprepare(spfi->spfi_clk); clk_disable_unprepare(spfi->sys_clk); } - - spi_controller_put(host); } #ifdef CONFIG_PM From 8cecd707d5358b88bcd0ae49f2f38e143d6bf7da Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:28 +0200 Subject: [PATCH 089/655] spi: lantiq-ssc: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-15-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-lantiq-ssc.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index 75b9af8cb5db..ecae50a50b14 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -913,7 +913,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev) hwcfg = of_device_get_match_data(dev); - host = spi_alloc_host(dev, sizeof(struct lantiq_ssc_spi)); + host = devm_spi_alloc_host(dev, sizeof(struct lantiq_ssc_spi)); if (!host) return -ENOMEM; @@ -923,20 +923,16 @@ static int lantiq_ssc_probe(struct platform_device *pdev) spi->hwcfg = hwcfg; platform_set_drvdata(pdev, spi); spi->regbase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(spi->regbase)) { - err = PTR_ERR(spi->regbase); - goto err_host_put; - } + if (IS_ERR(spi->regbase)) + return PTR_ERR(spi->regbase); err = hwcfg->cfg_irq(pdev, spi); if (err) - goto err_host_put; + return err; spi->spi_clk = devm_clk_get_enabled(dev, "gate"); - if (IS_ERR(spi->spi_clk)) { - err = PTR_ERR(spi->spi_clk); - goto err_host_put; - } + if (IS_ERR(spi->spi_clk)) + return PTR_ERR(spi->spi_clk); /* * Use the old clk_get_fpi() function on Lantiq platform, till it @@ -947,10 +943,8 @@ static int lantiq_ssc_probe(struct platform_device *pdev) #else spi->fpi_clk = clk_get(dev, "freq"); #endif - if (IS_ERR(spi->fpi_clk)) { - err = PTR_ERR(spi->fpi_clk); - goto err_host_put; - } + if (IS_ERR(spi->fpi_clk)) + return PTR_ERR(spi->fpi_clk); num_cs = 8; of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); @@ -1006,8 +1000,6 @@ err_wq_destroy: destroy_workqueue(spi->wq); err_clk_put: clk_put(spi->fpi_clk); -err_host_put: - spi_controller_put(host); return err; } @@ -1016,8 +1008,6 @@ static void lantiq_ssc_remove(struct platform_device *pdev) { struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev); - spi_controller_get(spi->host); - spi_unregister_controller(spi->host); lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN); @@ -1028,8 +1018,6 @@ static void lantiq_ssc_remove(struct platform_device *pdev) destroy_workqueue(spi->wq); clk_put(spi->fpi_clk); - - spi_controller_put(spi->host); } static struct platform_driver lantiq_ssc_driver = { From 69fb8784c81e0699fbea2ee81f65d1a23bd11649 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:29 +0200 Subject: [PATCH 090/655] spi: meson-spicc: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-16-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 43 +++++++++++------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index b80f9f457b66..8ad2ad0c97e2 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -982,7 +982,7 @@ static int meson_spicc_probe(struct platform_device *pdev) struct meson_spicc_device *spicc; int ret, irq; - host = spi_alloc_host(&pdev->dev, sizeof(*spicc)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*spicc)); if (!host) { dev_err(&pdev->dev, "host allocation failed\n"); return -ENOMEM; @@ -993,8 +993,7 @@ static int meson_spicc_probe(struct platform_device *pdev) spicc->data = of_device_get_match_data(&pdev->dev); if (!spicc->data) { dev_err(&pdev->dev, "failed to get match data\n"); - ret = -EINVAL; - goto out_host; + return -EINVAL; } spicc->pdev = pdev; @@ -1005,8 +1004,7 @@ static int meson_spicc_probe(struct platform_device *pdev) spicc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(spicc->base)) { dev_err(&pdev->dev, "io resource mapping failed\n"); - ret = PTR_ERR(spicc->base); - goto out_host; + return PTR_ERR(spicc->base); } /* Set master mode and enable controller */ @@ -1017,39 +1015,33 @@ static int meson_spicc_probe(struct platform_device *pdev) writel_relaxed(0, spicc->base + SPICC_INTREG); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto out_host; - } + if (irq < 0) + return irq; ret = devm_request_irq(&pdev->dev, irq, meson_spicc_irq, 0, NULL, spicc); if (ret) { dev_err(&pdev->dev, "irq request failed\n"); - goto out_host; + return ret; } spicc->core = devm_clk_get_enabled(&pdev->dev, "core"); if (IS_ERR(spicc->core)) { dev_err(&pdev->dev, "core clock request failed\n"); - ret = PTR_ERR(spicc->core); - goto out_host; + return PTR_ERR(spicc->core); } if (spicc->data->has_pclk) { spicc->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); if (IS_ERR(spicc->pclk)) { dev_err(&pdev->dev, "pclk clock request failed\n"); - ret = PTR_ERR(spicc->pclk); - goto out_host; + return PTR_ERR(spicc->pclk); } } spicc->pinctrl = devm_pinctrl_get(&pdev->dev); - if (IS_ERR(spicc->pinctrl)) { - ret = PTR_ERR(spicc->pinctrl); - goto out_host; - } + if (IS_ERR(spicc->pinctrl)) + return PTR_ERR(spicc->pinctrl); device_reset_optional(&pdev->dev); @@ -1070,43 +1062,34 @@ static int meson_spicc_probe(struct platform_device *pdev) ret = meson_spicc_pow2_clk_init(spicc); if (ret) { dev_err(&pdev->dev, "pow2 clock registration failed\n"); - goto out_host; + return ret; } if (spicc->data->has_enhance_clk_div) { ret = meson_spicc_enh_clk_init(spicc); if (ret) { dev_err(&pdev->dev, "clock registration failed\n"); - goto out_host; + return ret; } } ret = spi_register_controller(host); if (ret) { dev_err(&pdev->dev, "spi registration failed\n"); - goto out_host; + return ret; } return 0; - -out_host: - spi_controller_put(host); - - return ret; } static void meson_spicc_remove(struct platform_device *pdev) { struct meson_spicc_device *spicc = platform_get_drvdata(pdev); - spi_controller_get(spicc->host); - spi_unregister_controller(spicc->host); /* Disable SPI */ writel(0, spicc->base + SPICC_CONREG); - - spi_controller_put(spicc->host); } static const struct meson_spicc_data meson_spicc_gx_data = { From f7c857559eb20a73d2ec6fe79808cdb1f4afabfa Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:30 +0200 Subject: [PATCH 091/655] spi: mxs: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-17-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 0164e04d59a1..fda1d260b296 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -563,7 +563,7 @@ static int mxs_spi_probe(struct platform_device *pdev) if (ret) clk_freq = clk_freq_default; - host = spi_alloc_host(&pdev->dev, sizeof(*spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi)); if (!host) return -ENOMEM; @@ -589,13 +589,12 @@ static int mxs_spi_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0, dev_name(&pdev->dev), ssp); if (ret) - goto out_host_free; + return ret; ssp->dmach = dma_request_chan(&pdev->dev, "rx-tx"); if (IS_ERR(ssp->dmach)) { dev_err(ssp->dev, "Failed to request DMA\n"); - ret = PTR_ERR(ssp->dmach); - goto out_host_free; + return PTR_ERR(ssp->dmach); } pm_runtime_enable(ssp->dev); @@ -635,8 +634,7 @@ out_pm_runtime_disable: pm_runtime_disable(ssp->dev); out_dma_release: dma_release_channel(ssp->dmach); -out_host_free: - spi_controller_put(host); + return ret; } @@ -650,8 +648,6 @@ static void mxs_spi_remove(struct platform_device *pdev) spi = spi_controller_get_devdata(host); ssp = &spi->ssp; - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_disable(&pdev->dev); @@ -659,8 +655,6 @@ static void mxs_spi_remove(struct platform_device *pdev) mxs_spi_runtime_suspend(&pdev->dev); dma_release_channel(ssp->dmach); - - spi_controller_put(host); } static struct platform_driver mxs_spi_driver = { From c0c6875f0b7de6094f15ffd5b1dcebb3cebe53e1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:31 +0200 Subject: [PATCH 092/655] spi: npcm-pspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-18-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-pspi.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index cffef0a5977d..a437a30d636c 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -345,7 +345,7 @@ static int npcm_pspi_probe(struct platform_device *pdev) int irq; int ret; - host = spi_alloc_host(&pdev->dev, sizeof(*priv)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*priv)); if (!host) return -ENOMEM; @@ -356,21 +356,18 @@ static int npcm_pspi_probe(struct platform_device *pdev) priv->is_save_param = false; priv->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->base)) { - ret = PTR_ERR(priv->base); - goto out_host_put; - } + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(priv->clk); - goto out_host_put; + return PTR_ERR(priv->clk); } ret = clk_prepare_enable(priv->clk); if (ret) - goto out_host_put; + return ret; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -424,8 +421,6 @@ static int npcm_pspi_probe(struct platform_device *pdev) out_disable_clk: clk_disable_unprepare(priv->clk); -out_host_put: - spi_controller_put(host); return ret; } @@ -434,14 +429,10 @@ static void npcm_pspi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct npcm_pspi *priv = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); npcm_pspi_reset_hw(priv); clk_disable_unprepare(priv->clk); - - spi_controller_put(host); } static const struct of_device_id npcm_pspi_match[] = { From bdab3707ddfdf89a054b2372a984316c84d3ce43 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 29 Apr 2026 11:13:33 +0200 Subject: [PATCH 093/655] spi: orion: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260429091333.165363-20-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 64bf215c1804..265708a94984 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -651,11 +651,9 @@ static int orion_spi_probe(struct platform_device *pdev) struct device_node *np; int status; - host = spi_alloc_host(&pdev->dev, sizeof(*spi)); - if (host == NULL) { - dev_dbg(&pdev->dev, "host allocation failed\n"); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi)); + if (host == NULL) return -ENOMEM; - } if (pdev->id != -1) host->bus_num = pdev->id; @@ -689,17 +687,14 @@ static int orion_spi_probe(struct platform_device *pdev) spi->devdata = devdata; spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); - if (IS_ERR(spi->clk)) { - status = PTR_ERR(spi->clk); - goto out; - } + if (IS_ERR(spi->clk)) + return PTR_ERR(spi->clk); /* The following clock is only used by some SoCs */ spi->axi_clk = devm_clk_get(&pdev->dev, "axi"); - if (PTR_ERR(spi->axi_clk) == -EPROBE_DEFER) { - status = -EPROBE_DEFER; - goto out; - } + if (PTR_ERR(spi->axi_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!IS_ERR(spi->axi_clk)) clk_prepare_enable(spi->axi_clk); @@ -796,8 +791,7 @@ out_rel_pm: pm_runtime_dont_use_autosuspend(&pdev->dev); out_rel_axi_clk: clk_disable_unprepare(spi->axi_clk); -out: - spi_controller_put(host); + return status; } @@ -807,15 +801,11 @@ static void orion_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct orion_spi *spi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_get_sync(&pdev->dev); clk_disable_unprepare(spi->axi_clk); - spi_controller_put(host); - pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); From caf2fd997bf36728661612c03a74bd2bf23de9e4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Apr 2026 14:01:58 +0200 Subject: [PATCH 094/655] spi: omap2-mcspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260430120200.249323-2-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 56b30ff58771..60c05eb91781 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1484,9 +1484,9 @@ static int omap2_mcspi_probe(struct platform_device *pdev) const struct of_device_id *match; if (of_property_read_bool(node, "spi-slave")) - ctlr = spi_alloc_target(&pdev->dev, sizeof(*mcspi)); + ctlr = devm_spi_alloc_target(&pdev->dev, sizeof(*mcspi)); else - ctlr = spi_alloc_host(&pdev->dev, sizeof(*mcspi)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*mcspi)); if (!ctlr) return -ENOMEM; @@ -1530,10 +1530,9 @@ static int omap2_mcspi_probe(struct platform_device *pdev) } mcspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); - if (IS_ERR(mcspi->base)) { - status = PTR_ERR(mcspi->base); - goto free_ctlr; - } + if (IS_ERR(mcspi->base)) + return PTR_ERR(mcspi->base); + mcspi->phys = r->start + regs_offset; mcspi->base += regs_offset; @@ -1544,10 +1543,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev) mcspi->dma_channels = devm_kcalloc(&pdev->dev, ctlr->num_chipselect, sizeof(struct omap2_mcspi_dma), GFP_KERNEL); - if (mcspi->dma_channels == NULL) { - status = -ENOMEM; - goto free_ctlr; - } + if (mcspi->dma_channels == NULL) + return -ENOMEM; for (i = 0; i < ctlr->num_chipselect; i++) { sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i); @@ -1604,7 +1601,7 @@ disable_pm: pm_runtime_disable(&pdev->dev); free_ctlr: omap2_mcspi_release_dma(ctlr); - spi_controller_put(ctlr); + return status; } @@ -1613,8 +1610,6 @@ static void omap2_mcspi_remove(struct platform_device *pdev) struct spi_controller *ctlr = platform_get_drvdata(pdev); struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); - spi_controller_get(ctlr); - spi_unregister_controller(ctlr); omap2_mcspi_release_dma(ctlr); @@ -1622,8 +1617,6 @@ static void omap2_mcspi_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(mcspi->dev); pm_runtime_put_sync(mcspi->dev); pm_runtime_disable(&pdev->dev); - - spi_controller_put(ctlr); } /* work with hotplug and coldplug */ From 186fda6ee1ac5f61b847ab8d65560252c8eae06f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Apr 2026 14:01:59 +0200 Subject: [PATCH 095/655] spi: omap2-mcspi: clean up error labels Clean up the error labels by adding a common prefix and naming them after what they do. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260430120200.249323-3-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 60c05eb91781..59ebdf7edbd2 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1553,26 +1553,27 @@ static int omap2_mcspi_probe(struct platform_device *pdev) status = omap2_mcspi_request_dma(mcspi, &mcspi->dma_channels[i]); if (status == -EPROBE_DEFER) - goto free_ctlr; + goto err_release_dma; } status = platform_get_irq(pdev, 0); if (status < 0) - goto free_ctlr; + goto err_release_dma; + init_completion(&mcspi->txdone); status = devm_request_irq(&pdev->dev, status, omap2_mcspi_irq_handler, 0, pdev->name, mcspi); if (status) { dev_err(&pdev->dev, "Cannot request IRQ"); - goto free_ctlr; + goto err_release_dma; } mcspi->ref_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); if (IS_ERR(mcspi->ref_clk)) { status = PTR_ERR(mcspi->ref_clk); dev_err_probe(&pdev->dev, status, "Failed to get ref_clk"); - goto free_ctlr; + goto err_release_dma; } if (mcspi->ref_clk) mcspi->ref_clk_hz = clk_get_rate(mcspi->ref_clk); @@ -1587,19 +1588,19 @@ static int omap2_mcspi_probe(struct platform_device *pdev) status = omap2_mcspi_controller_setup(mcspi); if (status < 0) - goto disable_pm; + goto err_disable_rpm; status = spi_register_controller(ctlr); if (status < 0) - goto disable_pm; + goto err_disable_rpm; return status; -disable_pm: +err_disable_rpm: pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); -free_ctlr: +err_release_dma: omap2_mcspi_release_dma(ctlr); return status; From 46bd1fafc494744cd099f605b364f6fbb097069e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Apr 2026 14:02:00 +0200 Subject: [PATCH 096/655] spi: omap2-mcspi: clean up probe return value Return explicit zero on successful probe to clearly separate the success and error paths and make the code more readable. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260430120200.249323-4-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 59ebdf7edbd2..d53f98aa0aac 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1594,7 +1594,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) if (status < 0) goto err_disable_rpm; - return status; + return 0; err_disable_rpm: pm_runtime_dont_use_autosuspend(&pdev->dev); From 0065dc1fed2a87f815065b1348732ba45469ea83 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Wed, 29 Apr 2026 22:31:36 +0530 Subject: [PATCH 097/655] spi: dt-bindings: qcom,spi-qcom-qspi: Add qcom,qcs615-qspi compatible Add support for the QSPI controller on QCS615 SoC. Move allOf section after required properties and add if:then constraint to require minimum 2 interconnects for qcs615 variant. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Viken Dadhaniya Link: https://patch.msgid.link/20260429-spi-nor-v5-1-993016c9711e@oss.qualcomm.com Signed-off-by: Mark Brown --- .../bindings/spi/qcom,spi-qcom-qspi.yaml | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml b/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml index 1696ac46a660..ee2199027e89 100644 --- a/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml +++ b/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml @@ -13,13 +13,11 @@ description: The QSPI controller allows SPI protocol communication in single, dual, or quad wire transmission modes for read/write access to slaves such as NOR flash. -allOf: - - $ref: /schemas/spi/spi-controller.yaml# - properties: compatible: items: - enum: + - qcom,qcs615-qspi - qcom,sc7180-qspi - qcom,sc7280-qspi - qcom,sdm845-qspi @@ -67,6 +65,23 @@ required: - clock-names - clocks +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + - if: + properties: + compatible: + contains: + const: qcom,qcs615-qspi + then: + properties: + interconnects: + minItems: 2 + interconnect-names: + minItems: 2 + required: + - interconnects + - interconnect-names + unevaluatedProperties: false examples: From d283d5d4d9f6d081ddb65e371be26fffeb611c42 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Wed, 29 Apr 2026 22:31:37 +0530 Subject: [PATCH 098/655] spi: spi-qcom-qspi: Fix incomplete error handling in runtime PM The runtime PM functions had incomplete error handling that could leave the system in an inconsistent state. If any operation failed midway through suspend or resume, some resources would be left in the wrong state while others were already changed, leading to potential clock/power imbalances. Reorder the suspend/resume sequences to avoid brownout risk by ensuring the performance state is set appropriately before clocks are enabled and clocks are disabled before dropping the performance state. Fix by adding proper error checking for all operations and using goto-based cleanup to ensure all successfully acquired resources are properly released on any error. Signed-off-by: Viken Dadhaniya Link: https://patch.msgid.link/20260429-spi-nor-v5-2-993016c9711e@oss.qualcomm.com Signed-off-by: Mark Brown --- drivers/spi/spi-qcom-qspi.c | 44 ++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 7e39038160e0..edfbf0b5d1fa 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -818,20 +818,34 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) struct qcom_qspi *ctrl = spi_controller_get_devdata(host); int ret; - /* Drop the performance state vote */ - dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks); ret = icc_disable(ctrl->icc_path_cpu_to_qspi); if (ret) { dev_err_ratelimited(ctrl->dev, "%s: ICC disable failed for cpu: %d\n", __func__, ret); - return ret; + goto err_enable_clk; } - pinctrl_pm_select_sleep_state(dev); + ret = pinctrl_pm_select_sleep_state(dev); + if (ret) + goto err_enable_icc; + + /* Drop the performance state vote */ + ret = dev_pm_opp_set_rate(dev, 0); + if (ret) + goto err_select_default_state; return 0; + +err_select_default_state: + pinctrl_pm_select_default_state(dev); +err_enable_icc: + icc_enable(ctrl->icc_path_cpu_to_qspi); +err_enable_clk: + if (clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks)) + dev_err_ratelimited(ctrl->dev, "Failed to re-enable clocks\n"); + return ret; } static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev) @@ -840,20 +854,34 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev) struct qcom_qspi *ctrl = spi_controller_get_devdata(host); int ret; - pinctrl_pm_select_default_state(dev); + ret = dev_pm_opp_set_rate(dev, ctrl->last_speed * 4); + if (ret) + return ret; + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + goto err_opp_set_rate_zero; ret = icc_enable(ctrl->icc_path_cpu_to_qspi); if (ret) { dev_err_ratelimited(ctrl->dev, "%s: ICC enable failed for cpu: %d\n", __func__, ret); - return ret; + goto err_select_sleep_state; } ret = clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks); if (ret) - return ret; + goto err_disable_icc; - return dev_pm_opp_set_rate(dev, ctrl->last_speed * 4); + return 0; + +err_disable_icc: + icc_disable(ctrl->icc_path_cpu_to_qspi); +err_select_sleep_state: + pinctrl_pm_select_sleep_state(dev); +err_opp_set_rate_zero: + dev_pm_opp_set_rate(dev, 0); + return ret; } static int __maybe_unused qcom_qspi_suspend(struct device *dev) From 104b5e9b85c00c3fe552032164bf5bbd78e0f0b4 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Wed, 29 Apr 2026 22:31:38 +0530 Subject: [PATCH 099/655] spi: spi-qcom-qspi: Add interconnect support for memory path The QSPI controller has two interconnect paths: 1. qspi-config: CPU to QSPI controller for register access 2. qspi-memory: QSPI controller to memory for DMA operations Currently, the driver only manages the qspi-config path. Add support for the qspi-memory path to ensure proper bandwidth allocation for QSPI data transfers to/from memory. Enable and disable both paths during runtime PM transitions. Signed-off-by: Viken Dadhaniya Link: https://patch.msgid.link/20260429-spi-nor-v5-3-993016c9711e@oss.qualcomm.com Signed-off-by: Mark Brown --- drivers/spi/spi-qcom-qspi.c | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index edfbf0b5d1fa..caf55a6f70b3 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -174,6 +174,7 @@ struct qcom_qspi { void *virt_cmd_desc[QSPI_MAX_SG]; unsigned int n_cmd_desc; struct icc_path *icc_path_cpu_to_qspi; + struct icc_path *icc_path_mem; unsigned long last_speed; /* Lock to protect data accessed by IRQs */ spinlock_t lock; @@ -272,7 +273,7 @@ static void qcom_qspi_handle_err(struct spi_controller *host, static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) { int ret; - unsigned int avg_bw_cpu; + unsigned int avg_bw_cpu, avg_bw_mem; if (speed_hz == ctrl->last_speed) return 0; @@ -285,7 +286,7 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) } /* - * Set BW quota for CPU. + * Set BW quota for CPU and memory paths. * We don't have explicit peak requirement so keep it equal to avg_bw. */ avg_bw_cpu = Bps_to_icc(speed_hz); @@ -296,6 +297,13 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) return ret; } + avg_bw_mem = Bps_to_icc(speed_hz); + ret = icc_set_bw(ctrl->icc_path_mem, avg_bw_mem, avg_bw_mem); + if (ret) { + dev_err(ctrl->dev, "ICC BW voting failed for memory: %d\n", ret); + return ret; + } + ctrl->last_speed = speed_hz; return 0; @@ -729,6 +737,14 @@ static int qcom_qspi_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(ctrl->icc_path_cpu_to_qspi), "Failed to get cpu path\n"); + ctrl->icc_path_mem = devm_of_icc_get(dev, "qspi-memory"); + if (IS_ERR(ctrl->icc_path_mem)) { + if (PTR_ERR(ctrl->icc_path_mem) != -ENODATA) + return dev_err_probe(dev, PTR_ERR(ctrl->icc_path_mem), + "Failed to get memory path\n"); + ctrl->icc_path_mem = NULL; + } + /* Set BW vote for register access */ ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, Bps_to_icc(1000), Bps_to_icc(1000)); @@ -827,9 +843,15 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) goto err_enable_clk; } + ret = icc_disable(ctrl->icc_path_mem); + if (ret) { + dev_err_ratelimited(ctrl->dev, "ICC disable failed for memory: %d\n", ret); + goto err_enable_icc_cpu; + } + ret = pinctrl_pm_select_sleep_state(dev); if (ret) - goto err_enable_icc; + goto err_enable_icc_mem; /* Drop the performance state vote */ ret = dev_pm_opp_set_rate(dev, 0); @@ -840,7 +862,9 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) err_select_default_state: pinctrl_pm_select_default_state(dev); -err_enable_icc: +err_enable_icc_mem: + icc_enable(ctrl->icc_path_mem); +err_enable_icc_cpu: icc_enable(ctrl->icc_path_cpu_to_qspi); err_enable_clk: if (clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks)) @@ -869,13 +893,21 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev) goto err_select_sleep_state; } + ret = icc_enable(ctrl->icc_path_mem); + if (ret) { + dev_err_ratelimited(ctrl->dev, "ICC enable failed for memory: %d\n", ret); + goto err_disable_icc_cpu; + } + ret = clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks); if (ret) - goto err_disable_icc; + goto err_disable_icc_mem; return 0; -err_disable_icc: +err_disable_icc_mem: + icc_disable(ctrl->icc_path_mem); +err_disable_icc_cpu: icc_disable(ctrl->icc_path_cpu_to_qspi); err_select_sleep_state: pinctrl_pm_select_sleep_state(dev); From b610d5333c4b93389240b62d1b6299e7e2ee2e65 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 2 May 2026 21:30:51 -0400 Subject: [PATCH 100/655] spi: dt-bindings: add SpacemiT K1 SPI support Add support for the SPI controller implemented by the SpacemiT K1 SoC. Acked-by: Conor Dooley Acked-by: Troy Mitchell Reviewed-by: Rob Herring (Arm) Signed-off-by: Alex Elder Signed-off-by: Guodong Xu Link: https://patch.msgid.link/20260502-spi-spacemit-k1-v10-1-f412e1ae8a34@riscstar.com Signed-off-by: Mark Brown --- .../bindings/spi/spacemit,k1-spi.yaml | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml diff --git a/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml b/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml new file mode 100644 index 000000000000..e82c7f8d0b98 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spacemit,k1-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K1 SoC Serial Peripheral Interface (SPI) + +maintainers: + - Alex Elder + +description: + The SpacemiT K1 SoC implements a SPI controller that has two 32-entry + FIFOs, for transmit and receive. Details are currently available in + section 18.2.1 of the K1 User Manual, found in the SpacemiT Keystone + K1 Documentation[1]. The controller transfers words using PIO. DMA + transfers are supported as well, if both TX and RX DMA channels are + specified, + + [1] https://developer.spacemit.com/documentation + +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + +properties: + compatible: + const: spacemit,k1-spi + + reg: + maxItems: 1 + + clocks: + items: + - description: Core clock + - description: Bus clock + + clock-names: + items: + - const: core + - const: bus + + resets: + maxItems: 1 + + interrupts: + maxItems: 1 + + dmas: + items: + - description: RX DMA channel + - description: TX DMA channel + + dma-names: + items: + - const: rx + - const: tx + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - interrupts + +unevaluatedProperties: false + +examples: + - | + + #include + spi@d401c000 { + compatible = "spacemit,k1-spi"; + reg = <0xd401c000 0x30>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&syscon_apbc CLK_SSP3>, + <&syscon_apbc CLK_SSP3_BUS>; + clock-names = "core", "bus"; + resets = <&syscon_apbc RESET_SSP3>; + interrupts = <55>; + dmas = <&pdma 20>, <&pdma 19>; + dma-names = "rx", "tx"; + }; From efcd8b9d111177d48c841d09beca43b15d5b9e5f Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 2 May 2026 21:30:52 -0400 Subject: [PATCH 101/655] spi: spacemit: introduce SpacemiT K1 SPI controller driver This patch introduces the driver for the SPI controller found in the SpacemiT K1 SoC. Currently the driver supports master mode only. The SPI hardware implements RX and TX FIFOs, 32 entries each, and supports both PIO and DMA mode transfers. Signed-off-by: Alex Elder Signed-off-by: Guodong Xu Link: https://patch.msgid.link/20260502-spi-spacemit-k1-v10-2-f412e1ae8a34@riscstar.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 + drivers/spi/spi-spacemit-k1.c | 789 ++++++++++++++++++++++++++++++++++ 3 files changed, 799 insertions(+) create mode 100644 drivers/spi/spi-spacemit-k1.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b563f49e2197..8782514bb89b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -1085,6 +1085,15 @@ config SPI_SG2044_NOR also supporting 3Byte address devices and 4Byte address devices. +config SPI_SPACEMIT_K1 + tristate "K1 SPI Controller" + depends on ARCH_SPACEMIT || COMPILE_TEST + depends on OF + imply MMP_PDMA if ARCH_SPACEMIT + default m if ARCH_SPACEMIT + help + Enable support for the SpacemiT K1 SPI controller. + config SPI_SPRD tristate "Spreadtrum SPI controller" depends on ARCH_SPRD || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 9d36190a9884..9fa12498ce8c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -143,6 +143,7 @@ obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o obj-$(CONFIG_SPI_SN_F_OSPI) += spi-sn-f-ospi.o obj-$(CONFIG_SPI_SG2044_NOR) += spi-sg2044-nor.o +obj-$(CONFIG_SPI_SPACEMIT_K1) += spi-spacemit-k1.o obj-$(CONFIG_SPI_SPRD) += spi-sprd.o obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o obj-$(CONFIG_SPI_STM32) += spi-stm32.o diff --git a/drivers/spi/spi-spacemit-k1.c b/drivers/spi/spi-spacemit-k1.c new file mode 100644 index 000000000000..99db429db0b2 --- /dev/null +++ b/drivers/spi/spi-spacemit-k1.c @@ -0,0 +1,789 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// SpacemiT K1 SPI controller driver +// +// Copyright (C) 2026, RISCstar Solutions Corporation +// Copyright (C) 2023, SpacemiT Corporation + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internals.h" + +/* This is the range of transfer rates supported by the K1 SoC */ +#define K1_SPI_MIN_SPEED_HZ 6250 +#define K1_SPI_MAX_SPEED_HZ 51200000 + +/* DMA constraints */ +#define K1_SPI_DMA_ALIGNMENT 64 +#define K1_SPI_MAX_DMA_LEN SZ_512K + +/* SSP Top Control Register */ +#define SSP_TOP_CTRL 0x00 +#define TOP_SSE BIT(0) /* Enable port */ +#define TOP_FRF_MASK GENMASK(2, 1) /* Frame format */ +#define TOP_FRF_MOTOROLA 0 /* Motorola SPI */ +#define TOP_DSS_MASK GENMASK(9, 5) /* Data size (1-32) */ +#define TOP_SPO BIT(10) /* Polarity: 0=low */ +#define TOP_SPH BIT(11) /* Half-cycle phase */ +#define TOP_LBM BIT(12) /* Loopback mode */ +#define TOP_TRAIL BIT(13) /* Trailing bytes */ +#define TOP_HOLD_FRAME_LOW BIT(14) /* Chip select */ + +/* SSP FIFO Control Register */ +#define SSP_FIFO_CTRL 0x04 +#define FIFO_TFT_MASK GENMASK(4, 0) /* TX FIFO threshold */ +#define FIFO_RFT_MASK GENMASK(9, 5) /* RX FIFO threshold */ +#define FIFO_TSRE BIT(10) /* TX service request */ +#define FIFO_RSRE BIT(11) /* RX service request */ + +/* SSP Interrupt Enable Register */ +#define SSP_INT_EN 0x08 +#define SSP_INT_EN_TINTE BIT(1) /* RX timeout */ +#define SSP_INT_EN_RIE BIT(2) /* RX FIFO */ +#define SSP_INT_EN_TIE BIT(3) /* TX FIFO */ +#define SSP_INT_EN_RIM BIT(4) /* RX FIFO overrun */ +#define SSP_INT_EN_TIM BIT(5) /* TX FIFO underrun */ +#define SSP_INT_EN_EBCEI BIT(6) /* Bit count error */ + +/* TX interrupts, RX interrupts, and error interrupts */ +#define SSP_INT_EN_TX SSP_INT_EN_TIE +#define SSP_INT_EN_RX \ + (SSP_INT_EN_TINTE | SSP_INT_EN_RIE) +#define SSP_INT_EN_ERROR \ + (SSP_INT_EN_RIM | SSP_INT_EN_TIM | SSP_INT_EN_EBCEI) + +/* SSP Time Out Register */ +#define SSP_TIMEOUT 0x0c +#define SSP_TIMEOUT_MASK GENMASK(23, 0) + +/* SSP Data Register */ +#define SSP_DATAR 0x10 + +/* SSP Status Register */ +#define SSP_STATUS 0x14 +#define SSP_STATUS_BSY BIT(0) /* SPI/I2S busy */ +#define SSP_STATUS_TNF BIT(6) /* TX FIFO not full */ +#define SSP_STATUS_TFL GENMASK(11, 7) /* TX FIFO level */ +#define SSP_STATUS_TUR BIT(12) /* TX FIFO underrun */ +#define SSP_STATUS_RNE BIT(14) /* RX FIFO not empty */ +#define SSP_STATUS_RFL GENMASK(19, 15) /* RX FIFO level */ +#define SSP_STATUS_ROR BIT(20) /* RX FIFO overrun */ +#define SSP_STATUS_BCE BIT(21) /* Bit count error */ + +/* Error status mask */ +#define SSP_STATUS_ERROR \ + (SSP_STATUS_TUR | SSP_STATUS_ROR | SSP_STATUS_BCE) + +/* The FIFO sizes and thresholds are the same for RX and TX */ +#define K1_SPI_FIFO_SIZE 32 +#define K1_SPI_THRESH (K1_SPI_FIFO_SIZE / 2) + +struct k1_spi_driver_data { + struct spi_controller *host; + void __iomem *base; + phys_addr_t base_addr; + unsigned long bus_rate; + struct clk *clk; + unsigned long rate; + int irq; + + /* Current transfer information; not valid if message is null */ + u32 bytes; /* Bytes used for bits_per_word */ + unsigned int rx_resid; /* RX bytes left in transfer */ + unsigned int tx_resid; /* TX bytes left in transfer */ + struct spi_transfer *transfer; /* Current transfer */ + + bool dma_enabled; +}; + +/* Set our registers to a known initial state */ +static void +k1_spi_register_reset(struct k1_spi_driver_data *drv_data, bool initial) +{ + u32 val = 0; + + writel(0, drv_data->base + SSP_TOP_CTRL); + + if (initial) { + /* + * The TX and RX FIFO thresholds are the same no matter + * what the speed or bits per word, so we can just set + * them once. The thresholds are one more than the values + * in the register. + */ + val = FIELD_PREP(FIFO_RFT_MASK, K1_SPI_THRESH - 1); + val |= FIELD_PREP(FIFO_TFT_MASK, K1_SPI_THRESH - 1); + } + writel(val, drv_data->base + SSP_FIFO_CTRL); + + writel(0, drv_data->base + SSP_INT_EN); + writel(0, drv_data->base + SSP_TIMEOUT); + + /* Clear any pending interrupt conditions */ + writel(~0, drv_data->base + SSP_STATUS); +} + +/* + * The client can call the setup function multiple times, and each call + * can specify a different SPI mode (and transfer speed). Each transfer + * can specify its own speed though, and the core code ensures each + * transfer's speed is set to something nonzero and supported by both + * the controller and the device. We just set the speed for each transfer. + */ +static int k1_spi_setup(struct spi_device *spi) +{ + struct k1_spi_driver_data *drv_data; + u32 val; + + drv_data = spi_controller_get_devdata(spi->controller); + + /* + * Configure the message format for this device. We only + * support Motorola SPI format in master mode. + */ + val = FIELD_PREP(TOP_FRF_MASK, TOP_FRF_MOTOROLA); + + /* Translate the mode into the value used to program the hardware. */ + if (spi->mode & SPI_CPHA) + val |= TOP_SPH; /* 1/2 cycle */ + if (spi->mode & SPI_CPOL) + val |= TOP_SPO; /* active low */ + if (spi->mode & SPI_LOOP) + val |= TOP_LBM; /* enable loopback */ + writel(val, drv_data->base + SSP_TOP_CTRL); + + return 0; +} + +static void k1_spi_cleanup(struct spi_device *spi) +{ + struct k1_spi_driver_data *drv_data; + + drv_data = spi_controller_get_devdata(spi->controller); + k1_spi_register_reset(drv_data, false); +} + +static bool k1_spi_can_dma(struct spi_controller *host, struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host); + u32 burst_size; + + if (!drv_data->dma_enabled) + return false; + + if (transfer->len > SZ_2K) + return false; + + /* Don't bother with DMA if we can't do even a single burst */ + burst_size = K1_SPI_THRESH * spi_bpw_to_bytes(transfer->bits_per_word); + + return transfer->len >= burst_size; +} + +static void k1_spi_dma_callback(void *param) +{ + struct k1_spi_driver_data *drv_data = param; + u32 val; + + val = readl(drv_data->base + SSP_FIFO_CTRL); + val &= ~(FIFO_TSRE | FIFO_RSRE); + writel(val, drv_data->base + SSP_FIFO_CTRL); + + val = readl(drv_data->base + SSP_TOP_CTRL); + val &= ~TOP_TRAIL; + writel(val, drv_data->base + SSP_TOP_CTRL); + + /* Check for any error conditions */ + val = readl(drv_data->base + SSP_STATUS); + if (val & SSP_STATUS_ERROR) + drv_data->transfer->error |= SPI_TRANS_FAIL_IO; + + /* Disable the port */ + val = readl(drv_data->base + SSP_TOP_CTRL); + val &= ~TOP_SSE; + writel(val, drv_data->base + SSP_TOP_CTRL); + + drv_data->transfer = NULL; + + spi_finalize_current_transfer(drv_data->host); +} + +/* Prepare a descriptor for TX or RX DMA */ +static struct dma_async_tx_descriptor * +k1_spi_dma_prep(struct k1_spi_driver_data *drv_data, + struct spi_transfer *transfer, bool tx) +{ + phys_addr_t addr = drv_data->base_addr + SSP_DATAR; + u32 burst_size = K1_SPI_THRESH * drv_data->bytes; + struct dma_slave_config cfg = { }; + enum dma_transfer_direction dir; + enum dma_slave_buswidth width; + struct dma_chan *chan; + struct sg_table *sgt; + + switch (drv_data->bytes) { + case 1: + width = DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case 2: + width = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + default: /* bytes == 4 */ + width = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + } + + if (tx) { + chan = drv_data->host->dma_tx; + sgt = &transfer->tx_sg; + dir = DMA_MEM_TO_DEV; + + cfg.dst_addr = addr; + cfg.dst_addr_width = width; + cfg.dst_maxburst = burst_size; + } else { + chan = drv_data->host->dma_rx; + sgt = &transfer->rx_sg; + dir = DMA_DEV_TO_MEM; + + cfg.src_addr = addr; + cfg.src_addr_width = width; + cfg.src_maxburst = burst_size; + } + cfg.direction = dir; + + if (dmaengine_slave_config(chan, &cfg)) + return NULL; + + return dmaengine_prep_slave_sg(chan, sgt->sgl, sgt->nents, dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + +} + +static int k1_spi_dma_one(struct spi_controller *host, struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host); + struct dma_async_tx_descriptor *desc; + u32 val; + + /* Prepare the TX descriptor and submit it */ + desc = k1_spi_dma_prep(drv_data, transfer, true); + if (!desc) + goto fallback; + dmaengine_submit(desc); + + /* Prepare the RX descriptor and submit it */ + desc = k1_spi_dma_prep(drv_data, transfer, false); + if (!desc) + goto fallback; + + /* When RX is complete we also know TX has completed */ + desc->callback = k1_spi_dma_callback; + desc->callback_param = drv_data; + + dmaengine_submit(desc); + + val = readl(drv_data->base + SSP_TOP_CTRL); + val |= TOP_TRAIL; /* Trailing bytes handled by DMA */ + writel(val, drv_data->base + SSP_TOP_CTRL); + + val = readl(drv_data->base + SSP_FIFO_CTRL); + val |= FIFO_TSRE | FIFO_RSRE; + writel(val, drv_data->base + SSP_FIFO_CTRL); + + /* Start RX first so we're ready the instant we start transmitting */ + dma_async_issue_pending(host->dma_rx); + dma_async_issue_pending(host->dma_tx); + + return 1; +fallback: + transfer->error |= SPI_TRANS_FAIL_NO_START; + + return -EAGAIN; +} + +/* Flush the RX FIFO of any leftover data before processing a message */ +static int k1_spi_prepare_message(struct spi_controller *host, + struct spi_message *message) +{ + struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host); + u32 val = readl(drv_data->base + SSP_STATUS); + u32 count; + + /* If there's nothing in the FIFO, we're done */ + if (!(val & SSP_STATUS_RNE)) + return 0; + + /* Read and discard what's there (one more than what the field says) */ + count = FIELD_GET(SSP_STATUS_RFL, val) + 1; + do + (void)readl(drv_data->base + SSP_DATAR); + while (--count); + + return 0; +} + +/* Set logic level of chip select line (high=true means CS deasserted) */ +static void k1_spi_set_cs(struct spi_device *spi, bool high) +{ + struct k1_spi_driver_data *drv_data; + u32 val; + + drv_data = spi_controller_get_devdata(spi->controller); + + val = readl(drv_data->base + SSP_TOP_CTRL); + if (high) + val &= ~TOP_HOLD_FRAME_LOW; + else + val |= TOP_HOLD_FRAME_LOW; + writel(val, drv_data->base + SSP_TOP_CTRL); +} + +/* Set the transfer speed; the SPI core code ensures it is supported */ +static int k1_spi_set_speed(struct k1_spi_driver_data *drv_data, + struct spi_transfer *transfer) +{ + struct clk *clk = drv_data->clk; + u64 nsec_per_word; + u64 bus_ticks; + u32 timeout; + u32 val; + int ret; + + ret = clk_set_rate(clk, transfer->speed_hz); + if (ret) + return ret; + + drv_data->rate = clk_get_rate(clk); + + /* No need for RX FIFO timeout if we're not receiving anything */ + if (!transfer->rx_buf) + return 0; + + /* + * Compute the RX FIFO inactivity timeout value that should be used. + * The inactivity timer restarts with each word that lands in the + * FIFO. If several "word transfer times" pass without any new data + * in the RX FIFO, we might as well read what's there. + * + * The rate at which words land in the FIFO is determined by the + * word size and the transfer rate. One bit is transferred per + * clock tick, and 8 (or 16 or 32) bits are transferred per word. + * + * So we can get word transfer time (in nanoseconds) from: + * nsec_per_tick = NSEC_PER_SEC / drv_data->rate; + * ticks_per_word = BITS_PER_BYTE * drv_data->bytes; + * We do the divide last for better accuracy. + */ + nsec_per_word = NSEC_PER_SEC * BITS_PER_BYTE * drv_data->bytes; + nsec_per_word = DIV_ROUND_UP_ULL(nsec_per_word, drv_data->rate); + + /* + * The timeout (which we'll set to three word transfer times) is + * expressed as a number of APB clock ticks. + * bus_ticks = 3 * nsec * (drv_data->bus_rate / NSEC_PER_SEC) + */ + bus_ticks = 3 * nsec_per_word * drv_data->bus_rate; + timeout = DIV_ROUND_UP_ULL(bus_ticks, NSEC_PER_SEC); + + /* Set the RX timeout period (required for both DMA and PIO) */ + val = FIELD_PREP(SSP_TIMEOUT_MASK, timeout); + writel(val, drv_data->base + SSP_TIMEOUT); + + return 0; +} + +static int k1_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host); + u32 ctrl; + u32 val; + int ret; + + /* Bits per word can change on a per-transfer basis */ + drv_data->bytes = spi_bpw_to_bytes(transfer->bits_per_word); + + /* Each transfer can also specify a different rate */ + ret = k1_spi_set_speed(drv_data, transfer); + if (ret) { + dev_err(&host->dev, + "failed to set transfer speed: %d\n", ret); + return ret; + } + + drv_data->rx_resid = transfer->len; + drv_data->tx_resid = transfer->len; + + drv_data->transfer = transfer; + + /* Clear any existing interrupt conditions */ + writel(~0, drv_data->base + SSP_STATUS); + + /* Set the data (word) size, and enable the port */ + ctrl = readl(drv_data->base + SSP_TOP_CTRL); + ctrl &= ~TOP_DSS_MASK; + ctrl |= FIELD_PREP(TOP_DSS_MASK, transfer->bits_per_word - 1); + ctrl |= TOP_SSE; + writel(ctrl, drv_data->base + SSP_TOP_CTRL); + + if (spi_xfer_is_dma_mapped(host, spi, transfer)) + return k1_spi_dma_one(host, spi, transfer); + + /* An interrupt will initiate the transfer */ + val = SSP_INT_EN_TX | SSP_INT_EN_RX | SSP_INT_EN_ERROR; + writel(val, drv_data->base + SSP_INT_EN); + + return 1; /* We will call spi_finalize_current_transfer() */ +} + +static void +k1_spi_handle_err(struct spi_controller *host, struct spi_message *message) +{ + struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host); + + if (drv_data->dma_enabled) { + dmaengine_terminate_sync(host->dma_rx); + dmaengine_terminate_sync(host->dma_tx); + } +} + +static void k1_spi_write_word(struct k1_spi_driver_data *drv_data) +{ + struct spi_transfer *transfer = drv_data->transfer; + u32 bytes = drv_data->bytes; + u32 val; + + if (transfer->tx_buf) { + const void *buf; + + buf = transfer->tx_buf + (transfer->len - drv_data->tx_resid); + if (bytes == 1) + val = *(u8 *)buf; + else if (bytes == 2) + val = *(u16 *)buf; + else /* bytes == 4 */ + val = *(u32 *)buf; + } else { + val = 0; /* Null writer; write 1, 2, or 4 zero bytes */ + } + /* Fill the next TX FIFO entry */ + writel(val, drv_data->base + SSP_DATAR); + + drv_data->tx_resid -= bytes; +} + +/* The last-read status value is provided; we know SSP_STATUS_TNF is set */ +static bool k1_spi_write(struct k1_spi_driver_data *drv_data, u32 val) +{ + unsigned int count; + + /* Get the number of open slots in the FIFO; zero means all */ + count = FIELD_GET(SSP_STATUS_TFL, val) ? : K1_SPI_FIFO_SIZE; + + /* + * Limit how much we try to send at a time, to reduce the + * chance the other side can overrun our RX FIFO. + */ + count = min3(count, K1_SPI_THRESH, drv_data->tx_resid / drv_data->bytes); + do + k1_spi_write_word(drv_data); + while (--count); + + return !drv_data->tx_resid; +} + +static void k1_spi_read_word(struct k1_spi_driver_data *drv_data) +{ + struct spi_transfer *transfer = drv_data->transfer; + u32 bytes = drv_data->bytes; + u32 val; + + /* Consume the next RX FIFO entry */ + val = readl(drv_data->base + SSP_DATAR); + if (transfer->rx_buf) { + void *buf; + + buf = transfer->rx_buf + (transfer->len - drv_data->rx_resid); + + if (bytes == 1) + *(u8 *)buf = val; + else if (bytes == 2) + *(u16 *)buf = val; + else /* bytes == 4 */ + *(u32 *)buf = val; + } /* Otherwise null reader: discard the data */ + + drv_data->rx_resid -= bytes; +} + +/* The last-read status value is provided; we know SSP_STATUS_RNE is set */ +static bool k1_spi_read(struct k1_spi_driver_data *drv_data, u32 val) +{ + do { + unsigned int count = FIELD_GET(SSP_STATUS_RFL, val) + 1; + + /* Only read what we need */ + count = min(count, drv_data->rx_resid / drv_data->bytes); + do + k1_spi_read_word(drv_data); + while (--count); + + /* If there's no more to read, we're done */ + if (!drv_data->rx_resid) + return true; + + /* Check again in case more became available to read */ + val = readl(drv_data->base + SSP_STATUS); + if (val & SSP_STATUS_RNE) + writel(SSP_STATUS_RNE, drv_data->base + SSP_STATUS); + else + return false; + } while (true); +} + +static irqreturn_t k1_spi_ssp_isr(int irq, void *dev_id) +{ + struct k1_spi_driver_data *drv_data = dev_id; + u32 status; + u32 top_ctrl; + + /* Get status and clear pending interrupts */ + status = readl(drv_data->base + SSP_STATUS); + writel(status, drv_data->base + SSP_STATUS); + + /* If no actionable status bits are set, this is not our interrupt */ + if (!(status & (SSP_STATUS_ERROR | SSP_STATUS_TNF | SSP_STATUS_RNE))) + return IRQ_NONE; + + /* Check for any error conditions first */ + if (status & SSP_STATUS_ERROR) { + if (drv_data->transfer) + drv_data->transfer->error |= SPI_TRANS_FAIL_IO; + goto done; + } + + /* + * For SPI, bytes are transferred in both directions equally, and + * RX always follows TX. Start by writing if there is anything to + * write, then read. Once there's no more to read, we're done. + */ + if (drv_data->tx_resid && (status & SSP_STATUS_TNF)) { + /* If we finish writing, disable TX interrupts */ + if (k1_spi_write(drv_data, status)) + writel(SSP_INT_EN_RX | SSP_INT_EN_ERROR, + drv_data->base + SSP_INT_EN); + } + + /* We're not done unless we've read all that was requested */ + if (drv_data->rx_resid) { + /* Read more if the FIFO is not empty */ + if (status & SSP_STATUS_RNE) + if (k1_spi_read(drv_data, status)) + goto done; + + return IRQ_HANDLED; + } +done: + /* Disable the port */ + top_ctrl = readl(drv_data->base + SSP_TOP_CTRL); + top_ctrl &= ~TOP_SSE; + writel(top_ctrl, drv_data->base + SSP_TOP_CTRL); + + /* Disable all interrupts */ + writel(0, drv_data->base + SSP_INT_EN); + + if (drv_data->transfer) { + drv_data->transfer = NULL; + spi_finalize_current_transfer(drv_data->host); + } + + return IRQ_HANDLED; +} + +static int +k1_spi_dma_setup(struct k1_spi_driver_data *drv_data, struct device *dev) +{ + struct spi_controller *host = drv_data->host; + struct dma_chan *chan; + + chan = dma_request_chan(dev, "tx"); + if (IS_ERR(chan)) + return PTR_ERR(chan); + host->dma_tx = chan; + + chan = dma_request_chan(dev, "rx"); + if (IS_ERR(chan)) { + dma_release_channel(host->dma_tx); + host->dma_tx = NULL; + return PTR_ERR(chan); + } + host->dma_rx = chan; + + drv_data->dma_enabled = true; + + return 0; +} + +static void k1_spi_dma_cleanup(struct device *dev, void *res) +{ + struct k1_spi_driver_data **ptr = res; + struct k1_spi_driver_data *drv_data = *ptr; + struct spi_controller *host = drv_data->host; + + if (!drv_data->dma_enabled) + return; + + drv_data->dma_enabled = false; + + dma_release_channel(host->dma_rx); + host->dma_rx = NULL; + dma_release_channel(host->dma_tx); + host->dma_tx = NULL; +} + +static int +devm_k1_spi_dma_setup(struct k1_spi_driver_data *drv_data, struct device *dev) +{ + struct k1_spi_driver_data **ptr; + int ret; + + if (!IS_ENABLED(CONFIG_MMP_PDMA)) { + dev_info(dev, "DMA not available; using PIO\n"); + return 0; + } + + ptr = devres_alloc(k1_spi_dma_cleanup, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = k1_spi_dma_setup(drv_data, dev); + if (ret) { + devres_free(ptr); + return ret; + } + + *ptr = drv_data; + devres_add(dev, ptr); + + return 0; +} + +static int k1_spi_probe(struct platform_device *pdev) +{ + struct k1_spi_driver_data *drv_data; + struct device *dev = &pdev->dev; + struct reset_control *reset; + struct spi_controller *host; + struct resource *iores; + struct clk *clk_bus; + int ret; + + host = devm_spi_alloc_host(dev, sizeof(*drv_data)); + if (!host) + return -ENOMEM; + drv_data = spi_controller_get_devdata(host); + drv_data->host = host; + platform_set_drvdata(pdev, drv_data); + + ret = devm_k1_spi_dma_setup(drv_data, dev); + if (ret == -EPROBE_DEFER) + return ret; + if (ret) + dev_warn(dev, "DMA setup failed (%d), falling back to PIO\n", ret); + + drv_data->base = devm_platform_get_and_ioremap_resource(pdev, 0, + &iores); + if (IS_ERR(drv_data->base)) + return dev_err_probe(dev, PTR_ERR(drv_data->base), + "error mapping memory\n"); + drv_data->base_addr = iores->start; + + clk_bus = devm_clk_get_enabled(dev, "bus"); + if (IS_ERR(clk_bus)) + return dev_err_probe(dev, PTR_ERR(clk_bus), + "error getting/enabling bus clock\n"); + drv_data->bus_rate = clk_get_rate(clk_bus); + + drv_data->clk = devm_clk_get_enabled(dev, "core"); + if (IS_ERR(drv_data->clk)) + return dev_err_probe(dev, PTR_ERR(drv_data->clk), + "error getting/enabling core clock\n"); + + reset = devm_reset_control_get_exclusive_deasserted(dev, NULL); + if (IS_ERR(reset)) + return dev_err_probe(dev, PTR_ERR(reset), + "error getting/deasserting reset\n"); + + k1_spi_register_reset(drv_data, true); + + drv_data->irq = platform_get_irq(pdev, 0); + if (drv_data->irq < 0) + return dev_err_probe(dev, drv_data->irq, "error getting IRQ\n"); + + ret = devm_request_irq(dev, drv_data->irq, k1_spi_ssp_isr, + IRQF_SHARED, dev_name(dev), drv_data); + if (ret < 0) + return dev_err_probe(dev, ret, "error requesting IRQ\n"); + + /* Initialize the host structure, then register it */ + host->dev.of_node = dev_of_node(dev); + host->dev.parent = dev; + host->num_chipselect = 1; + if (drv_data->dma_enabled) + host->dma_alignment = K1_SPI_DMA_ALIGNMENT; + host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; + host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + host->min_speed_hz = K1_SPI_MIN_SPEED_HZ; + host->max_speed_hz = K1_SPI_MAX_SPEED_HZ; + host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; + host->max_dma_len = K1_SPI_MAX_DMA_LEN; + + host->setup = k1_spi_setup; + host->cleanup = k1_spi_cleanup; + host->can_dma = k1_spi_can_dma; + host->prepare_message = k1_spi_prepare_message; + host->set_cs = k1_spi_set_cs; + host->transfer_one = k1_spi_transfer_one; + host->handle_err = k1_spi_handle_err; + + ret = devm_spi_register_controller(dev, host); + if (ret) + dev_err(dev, "error registering controller\n"); + + return ret; +} + +static const struct of_device_id k1_spi_dt_ids[] = { + { .compatible = "spacemit,k1-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, k1_spi_dt_ids); + +static struct platform_driver k1_spi_driver = { + .probe = k1_spi_probe, + .driver = { + .name = "k1-spi", + .of_match_table = k1_spi_dt_ids, + }, +}; +module_platform_driver(k1_spi_driver); + +MODULE_DESCRIPTION("SpacemiT K1 SPI controller driver"); +MODULE_LICENSE("GPL"); From 3fa7816d0fff0c1212c88faf1e3f05cdaff6aba3 Mon Sep 17 00:00:00 2001 From: Rakesh Kota Date: Wed, 29 Apr 2026 18:56:18 +0530 Subject: [PATCH 102/655] regulator: dt-bindings: qcom,smd-rpm-regulator: Document PM8150 IC Document the pm8150 compatible string and available regulators in the QCOM SMD RPM regulator documentation. Signed-off-by: Rakesh Kota Link: https://patch.msgid.link/20260429-add_pm8150_regulators-v1-1-9879c0967cf0@oss.qualcomm.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml index b7241ce975b9..0fa0db7eef23 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml @@ -35,6 +35,9 @@ description: For pm660l s1, s2, s3, s5, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, bob + For pm8150, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, l1, l2, l3, l4, l5, l6, + l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18 + For pm8226, s1, s2, s3, s4, s5, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, lvs1 @@ -91,6 +94,7 @@ properties: - qcom,rpm-pm6125-regulators - qcom,rpm-pm660-regulators - qcom,rpm-pm660l-regulators + - qcom,rpm-pm8150-regulators - qcom,rpm-pm8226-regulators - qcom,rpm-pm8841-regulators - qcom,rpm-pm8909-regulators From abc004841af8f19e301bd372415b53fd184d8710 Mon Sep 17 00:00:00 2001 From: Rakesh Kota Date: Wed, 29 Apr 2026 18:56:19 +0530 Subject: [PATCH 103/655] regulator: qcom_smd: Add PM8150 regulators The PM8150 is found on boards with shikra SoCs and It provides 10 SMPS and 18 LDO regulators. Signed-off-by: Rakesh Kota Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260429-add_pm8150_regulators-v1-2-9879c0967cf0@oss.qualcomm.com Signed-off-by: Mark Brown --- drivers/regulator/qcom_smd-regulator.c | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 25ed9f713974..3ee7f5d0c694 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -913,6 +913,38 @@ static const struct rpm_regulator_data rpm_pm660l_regulators[] = { { } }; +static const struct rpm_regulator_data rpm_pm8150_regulators[] = { + { "s1", QCOM_SMD_RPM_SMPA, 1, &pmic5_ftsmps520, "vdd-s1" }, + { "s2", QCOM_SMD_RPM_SMPA, 2, &pmic5_ftsmps520, "vdd-s2" }, + { "s3", QCOM_SMD_RPM_SMPA, 3, &pmic5_ftsmps520, "vdd-s3" }, + { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8998_hfsmps, "vdd-s4" }, + { "s5", QCOM_SMD_RPM_SMPA, 5, &pm8998_hfsmps, "vdd-s5" }, + { "s6", QCOM_SMD_RPM_SMPA, 6, &pmic5_ftsmps520, "vdd-s6" }, + { "s7", QCOM_SMD_RPM_SMPA, 7, &pmic5_ftsmps520, "vdd-s7" }, + { "s8", QCOM_SMD_RPM_SMPA, 8, &pmic5_ftsmps520, "vdd-s8" }, + { "s9", QCOM_SMD_RPM_SMPA, 9, &pmic5_ftsmps520, "vdd-s9" }, + { "s10", QCOM_SMD_RPM_SMPA, 10, &pmic5_ftsmps520, "vdd-s10" }, + { "l1", QCOM_SMD_RPM_LDOA, 1, &pm660_nldo660, "vdd-l1-l8-l11" }, + { "l2", QCOM_SMD_RPM_LDOA, 2, &pm660_pldo660, "vdd-l2-l10" }, + { "l3", QCOM_SMD_RPM_LDOA, 3, &pm660_nldo660, "vdd-l3-l4-l5-l18" }, + { "l4", QCOM_SMD_RPM_LDOA, 4, &pm660_nldo660, "vdd-l3-l4-l5-l18" }, + { "l5", QCOM_SMD_RPM_LDOA, 5, &pm660_nldo660, "vdd-l3-l4-l5-l18" }, + { "l6", QCOM_SMD_RPM_LDOA, 6, &pm660_nldo660, "vdd-l6-l9" }, + { "l7", QCOM_SMD_RPM_LDOA, 7, &pm660_pldo660, "vdd-l7-l12-l14-l15" }, + { "l8", QCOM_SMD_RPM_LDOA, 8, &pm660_nldo660, "vdd-l1-l8-l11" }, + { "l9", QCOM_SMD_RPM_LDOA, 9, &pm660_nldo660, "vdd-l6-l9" }, + { "l10", QCOM_SMD_RPM_LDOA, 10, &pm660_pldo660, "vdd-l2-l10" }, + { "l11", QCOM_SMD_RPM_LDOA, 11, &pm660_nldo660, "vdd-l1-l8-l11" }, + { "l12", QCOM_SMD_RPM_LDOA, 12, &pm660_ht_lvpldo, "vdd-l7-l12-l14-l15" }, + { "l13", QCOM_SMD_RPM_LDOA, 13, &pm660_pldo660, "vdd-l13-l16-l17" }, + { "l14", QCOM_SMD_RPM_LDOA, 14, &pm660_ht_lvpldo, "vdd-l7-l12-l14-l15" }, + { "l15", QCOM_SMD_RPM_LDOA, 15, &pm660_ht_lvpldo, "vdd-l7-l12-l14-l15" }, + { "l16", QCOM_SMD_RPM_LDOA, 16, &pm660_pldo660, "vdd-l13-l16-l17" }, + { "l17", QCOM_SMD_RPM_LDOA, 17, &pm660_pldo660, "vdd-l13-l16-l17" }, + { "l18", QCOM_SMD_RPM_LDOA, 18, &pm660_nldo660, "vdd-l3-l4-l5-l18" }, + { } +}; + static const struct rpm_regulator_data rpm_pm8226_regulators[] = { { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8226_hfsmps, "vdd_s1" }, { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8226_ftsmps, "vdd_s2" }, @@ -1358,6 +1390,7 @@ static const struct of_device_id rpm_of_match[] = { { .compatible = "qcom,rpm-pm6125-regulators", .data = &rpm_pm6125_regulators }, { .compatible = "qcom,rpm-pm660-regulators", .data = &rpm_pm660_regulators }, { .compatible = "qcom,rpm-pm660l-regulators", .data = &rpm_pm660l_regulators }, + { .compatible = "qcom,rpm-pm8150-regulators", .data = &rpm_pm8150_regulators }, { .compatible = "qcom,rpm-pm8226-regulators", .data = &rpm_pm8226_regulators }, { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators }, { .compatible = "qcom,rpm-pm8909-regulators", .data = &rpm_pm8909_regulators }, From e4358093816df69b574a5632051801a881663d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 4 May 2026 16:21:17 +0200 Subject: [PATCH 104/655] spi: Consistently define pci_device_ids using named initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .driver_data member of the various struct pci_device_id arrays were initialized by list expressions. This isn't easily readable if you're not into PCI. Using named initializers is more explicit and thus easier to parse. Also skip explicit assignments of 0 (which the compiler then takes care of). This change doesn't introduce changes to the compiled pci_device_id arrays. Tested on x86 and arm64. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/20260504142117.2116978-2-u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 14 ++++---- drivers/spi/spi-intel-pci.c | 66 +++++++++++++++++----------------- drivers/spi/spi-pci1xxxx.c | 42 +++++++++++----------- drivers/spi/spi-topcliff-pch.c | 8 ++--- 4 files changed, 65 insertions(+), 65 deletions(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 72d9f5bc87f7..7f002d5e5b88 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -185,15 +185,15 @@ static const struct pci_device_id dw_spi_pci_ids[] = { * exclusively used by SCU to communicate with MSIC. */ /* Intel MID platform SPI controller 1 */ - { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&dw_spi_pci_mid_desc_1}, + { PCI_VDEVICE(INTEL, 0x0800), .driver_data = (kernel_ulong_t)&dw_spi_pci_mid_desc_1 }, /* Intel MID platform SPI controller 2 */ - { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&dw_spi_pci_mid_desc_2}, + { PCI_VDEVICE(INTEL, 0x0812), .driver_data = (kernel_ulong_t)&dw_spi_pci_mid_desc_2 }, /* Intel Elkhart Lake PSE SPI controllers */ - { PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, - { PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, - { PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, - { PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, - {}, + { PCI_VDEVICE(INTEL, 0x4b84), .driver_data = (kernel_ulong_t)&dw_spi_pci_ehl_desc }, + { PCI_VDEVICE(INTEL, 0x4b85), .driver_data = (kernel_ulong_t)&dw_spi_pci_ehl_desc }, + { PCI_VDEVICE(INTEL, 0x4b86), .driver_data = (kernel_ulong_t)&dw_spi_pci_ehl_desc }, + { PCI_VDEVICE(INTEL, 0x4b87), .driver_data = (kernel_ulong_t)&dw_spi_pci_ehl_desc }, + { }, }; MODULE_DEVICE_TABLE(pci, dw_spi_pci_ids); diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c index d8ef8f89330a..8c429c832ddd 100644 --- a/drivers/spi/spi-intel-pci.c +++ b/drivers/spi/spi-intel-pci.c @@ -66,39 +66,39 @@ static int intel_spi_pci_probe(struct pci_dev *pdev, } static const struct pci_device_id intel_spi_pci_ids[] = { - { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x38a4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x4d23), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x5794), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x5825), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x6e24), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x7723), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x7f24), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x9d24), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x9da4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, - { PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa823), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xd323), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xe323), (unsigned long)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xe423), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x02a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x06a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x18e0), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x19e0), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x1bca), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x34a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x38a4), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x43a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x4b24), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x4d23), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x4da4), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x51a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x54a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x5794), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x5825), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x6e24), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x7723), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x7a24), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x7aa4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x7e23), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x7f24), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x9d24), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x9da4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa1a4), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa224), .driver_data = (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0xa2a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa324), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa3a4), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa823), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xd323), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xe323), .driver_data = (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xe423), .driver_data = (unsigned long)&cnl_info }, { }, }; MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c index 8577a19705de..af6ed78493e3 100644 --- a/drivers/spi/spi-pci1xxxx.c +++ b/drivers/spi/spi-pci1xxxx.c @@ -173,27 +173,27 @@ struct pci1xxxx_spi { }; static const struct pci_device_id pci1xxxx_spi_pci_id_table[] = { - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, - { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, - { 0, } + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0001), .driver_data = 0x02 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0002), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0003), .driver_data = 0x11 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, PCI_ANY_ID), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0001), .driver_data = 0x02 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0002), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0003), .driver_data = 0x11 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, PCI_ANY_ID), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0001), .driver_data = 0x02 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0002), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0003), .driver_data = 0x11 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, PCI_ANY_ID), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0001), .driver_data = 0x02 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0002), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0003), .driver_data = 0x11 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, PCI_ANY_ID), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0001), .driver_data = 0x02 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0002), .driver_data = 0x01 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0003), .driver_data = 0x11 }, + { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, PCI_ANY_ID), .driver_data = 0x01 }, + { } }; MODULE_DEVICE_TABLE(pci, pci1xxxx_spi_pci_id_table); diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 14d11450e86d..02ced638d8b4 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -207,10 +207,10 @@ struct pch_pd_dev_save { }; static const struct pci_device_id pch_spi_pcidev_id[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI), 1, }, - { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, }, - { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), 1, }, - { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_SPI), 1, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI), .driver_data = 1 }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), .driver_data = 2 }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), .driver_data = 1 }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_SPI), .driver_data = 1 }, { } }; From 00cef7eb08c8b9af0978f667c77c6a30b71b7e22 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Tue, 5 May 2026 09:53:34 -0400 Subject: [PATCH 105/655] spi: spacemit: add u64 cast to NSEC_PER_SEC to avoid 32-bit overflow NSEC_PER_SEC expands to the long constant 1000000000L, so NSEC_PER_SEC * BITS_PER_BYTE (8 * 10^9) overflows on 32-bit-long architectures before the result reaches the u64 nsec_per_word. Promote the multiplication to u64 by casting the first operand, which is NSEC_PER_SEC. Fixes: efcd8b9d1111 ("spi: spacemit: introduce SpacemiT K1 SPI controller driver") Suggested-by: Alex Elder Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605050437.RS6mmV2b-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202605050317.Tf9j487w-lkp@intel.com/ Signed-off-by: Guodong Xu Link: https://patch.msgid.link/20260505-spi-spacemit-k1-fix-overflow-v1-1-77564c2e4e86@riscstar.com Signed-off-by: Mark Brown --- drivers/spi/spi-spacemit-k1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-spacemit-k1.c b/drivers/spi/spi-spacemit-k1.c index 99db429db0b2..215fe66d27b4 100644 --- a/drivers/spi/spi-spacemit-k1.c +++ b/drivers/spi/spi-spacemit-k1.c @@ -390,7 +390,7 @@ static int k1_spi_set_speed(struct k1_spi_driver_data *drv_data, * ticks_per_word = BITS_PER_BYTE * drv_data->bytes; * We do the divide last for better accuracy. */ - nsec_per_word = NSEC_PER_SEC * BITS_PER_BYTE * drv_data->bytes; + nsec_per_word = (u64)NSEC_PER_SEC * BITS_PER_BYTE * drv_data->bytes; nsec_per_word = DIV_ROUND_UP_ULL(nsec_per_word, drv_data->rate); /* From ffa13d4fdb0dedbde009df10a8af485c123566eb Mon Sep 17 00:00:00 2001 From: Julian Braha Date: Tue, 31 Mar 2026 13:22:14 +0100 Subject: [PATCH 106/655] keys: cleanup dead code in Kconfig for FIPS_SIGNATURE_SELFTEST There is already an 'if ASYMMETRIC_KEY_TYPE' condition wrapping FIPS_SIGNATURE_SELFTEST, making the 'depends on' statement a duplicate dependency (dead code). I propose leaving the outer 'if ASYMMETRIC_KEY_TYPE...endif' and removing the individual 'depends on' statement. This dead code was found by kconfirm, a static analysis tool for Kconfig. Signed-off-by: Julian Braha Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index e50bd9b3e27b..6a2f664046ef 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -95,7 +95,6 @@ config FIPS_SIGNATURE_SELFTEST verification code, using some built in data. This is required for FIPS. depends on KEYS - depends on ASYMMETRIC_KEY_TYPE depends on PKCS7_MESSAGE_PARSER=X509_CERTIFICATE_PARSER depends on X509_CERTIFICATE_PARSER depends on CRYPTO_RSA From 52d167bb09181452a8358163b034bb038b1d26dc Mon Sep 17 00:00:00 2001 From: Alexander Koskovich Date: Mon, 6 Apr 2026 02:10:07 +0000 Subject: [PATCH 107/655] dt-bindings: crypto: qcom-qce: Document the Milos crypto engine Document the crypto engine on the Milos platform. Signed-off-by: Alexander Koskovich Reviewed-by: Krzysztof Kozlowski Reviewed-by: Kuldeep Singh Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom-qce.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index 79d5be2548bc..74a121d8b2a5 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -46,6 +46,7 @@ properties: - items: - enum: - qcom,kaanapali-qce + - qcom,milos-qce - qcom,qcs615-qce - qcom,qcs8300-qce - qcom,sa8775p-qce From 2e96024632b386c86860aa78639940fc96d6fcc9 Mon Sep 17 00:00:00 2001 From: Damian Muszynski Date: Tue, 7 Apr 2026 12:04:26 +0200 Subject: [PATCH 108/655] crypto: qat - fix heartbeat error injection The current implementation of the heartbeat error injection uses adf_disable_arb_thd() to stop a specific accelerator engine thread from processing requests. This does not reliably prevent the device from generating responses. Fix the error injection by disabling the device arbiter through exit_arb() instead. This properly simulates a device failure by stopping all arbitration, which results in missing responses for sent requests. Remove the now unused adf_disable_arb_thd() function and its declaration. Fixes: e2b67859ab6e ("crypto: qat - add heartbeat error simulator") Signed-off-by: Damian Muszynski Reviewed-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../intel/qat/qat_common/adf_common_drv.h | 1 - .../qat/qat_common/adf_heartbeat_inject.c | 6 ++--- .../intel/qat/qat_common/adf_hw_arbiter.c | 25 ------------------- 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index 7b8b295ac459..fb0fd46a79b0 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -92,7 +92,6 @@ void adf_exit_aer(void); int adf_init_arb(struct adf_accel_dev *accel_dev); void adf_exit_arb(struct adf_accel_dev *accel_dev); void adf_update_ring_arb(struct adf_etr_ring_data *ring); -int adf_disable_arb_thd(struct adf_accel_dev *accel_dev, u32 ae, u32 thr); int adf_dev_get(struct adf_accel_dev *accel_dev); void adf_dev_put(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c index a3b474bdef6c..023c5f1e78b0 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c +++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_inject.c @@ -64,10 +64,8 @@ int adf_heartbeat_inject_error(struct adf_accel_dev *accel_dev) if (ret) return ret; - /* Configure worker threads to stop processing any packet */ - ret = adf_disable_arb_thd(accel_dev, rand_ae, rand_thr); - if (ret) - return ret; + /* Disable arbiter to stop processing any packet */ + hw_device->exit_arb(accel_dev); /* Change HB counters memory to simulate a hang */ adf_set_hb_counters_fail(accel_dev, rand_ae, rand_thr); diff --git a/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c b/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c index f93d9cca70ce..dd9a31c20bc9 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c +++ b/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c @@ -99,28 +99,3 @@ void adf_exit_arb(struct adf_accel_dev *accel_dev) csr_ops->write_csr_ring_srv_arb_en(csr, i, 0); } EXPORT_SYMBOL_GPL(adf_exit_arb); - -int adf_disable_arb_thd(struct adf_accel_dev *accel_dev, u32 ae, u32 thr) -{ - void __iomem *csr = accel_dev->transport->banks[0].csr_addr; - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - const u32 *thd_2_arb_cfg; - struct arb_info info; - u32 ae_thr_map; - - if (ADF_AE_STRAND0_THREAD == thr || ADF_AE_STRAND1_THREAD == thr) - thr = ADF_AE_ADMIN_THREAD; - - hw_data->get_arb_info(&info); - thd_2_arb_cfg = hw_data->get_arb_mapping(accel_dev); - if (!thd_2_arb_cfg) - return -EFAULT; - - /* Disable scheduling for this particular AE and thread */ - ae_thr_map = *(thd_2_arb_cfg + ae); - ae_thr_map &= ~(GENMASK(3, 0) << (thr * BIT(2))); - - WRITE_CSR_ARB_WT2SAM(csr, info.arb_offset, info.wt2sam_offset, ae, - ae_thr_map); - return 0; -} From 1b475aaee4cbf4d2f7d8ac69ce84ff2e22953d30 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Apr 2026 15:51:42 +0200 Subject: [PATCH 109/655] dt-bindings: crypto: qcom-qce: Add Qualcomm Eliza QCE Document the QCE crypto engine on Qualcomm Eliza SoC, fully compatible with earlier generations. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Harshal Dev Reviewed-by: Kuldeep Singh Acked-by: Rob Herring (Arm) Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom-qce.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index 74a121d8b2a5..e6c0aa5dabfc 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -45,6 +45,7 @@ properties: - items: - enum: + - qcom,eliza-qce - qcom,kaanapali-qce - qcom,milos-qce - qcom,qcs615-qce From c6bd6642c6498eb6a7eaf085a0b82c07ed6142f9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 May 2026 12:27:35 +0200 Subject: [PATCH 110/655] regulator: palmas: Move MODULE_DEVICE_TABLE next to the table itself By convention MODULE_DEVICE_TABLE() immediately follows the ID table it exports, because this is easier to read and verify. It also makes more sense since #ifdef for ACPI or OF could hide both of them. Most of the privers already have this correctly placed, so adjust the missing ones. No functional impact. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260505102734.180464-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 60656a815b9e..f82618a70106 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1590,6 +1590,7 @@ static const struct of_device_id of_palmas_match_tbl[] = { }, { /* end */ } }; +MODULE_DEVICE_TABLE(of, of_palmas_match_tbl); static int palmas_regulators_probe(struct platform_device *pdev) { @@ -1684,4 +1685,3 @@ MODULE_AUTHOR("Graeme Gregory "); MODULE_DESCRIPTION("Palmas voltage regulator driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:palmas-pmic"); -MODULE_DEVICE_TABLE(of, of_palmas_match_tbl); From 88f731e7962945614a477a8a86c2517d87fd6b02 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 6 May 2026 10:51:44 -0700 Subject: [PATCH 111/655] spi: s3c64xx: fix all kernel-doc warnings Add kernel-doc for one struct member and use the correct function name to eliminate kernel-doc warnings: Warning: include/linux/platform_data/spi-s3c64xx.h:40 struct member 'polling' not described in 's3c64xx_spi_info' Warning: include/linux/platform_data/spi-s3c64xx.h:51 expecting prototype for s3c64xx_spi_set_platdata(). Prototype was for s3c64xx_spi0_set_platdata() instead Signed-off-by: Randy Dunlap Reviewed-by: Krzysztof Kozlowski Reviewed-by: Tudor Ambarus Link: https://patch.msgid.link/20260506175144.449364-1-rdunlap@infradead.org Signed-off-by: Mark Brown --- include/linux/platform_data/spi-s3c64xx.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h index 1d6e6c424fc6..f92bb4a1213b 100644 --- a/include/linux/platform_data/spi-s3c64xx.h +++ b/include/linux/platform_data/spi-s3c64xx.h @@ -30,6 +30,7 @@ struct s3c64xx_spi_csinfo { * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field. * @num_cs: Number of CS this controller emulates. * @no_cs: Used when CS line is not connected. + * @polling: Using polling mode when %true (no 'dmas' property in devicetree) * @cfg_gpio: Configure pins for this SPI controller. */ struct s3c64xx_spi_info { @@ -41,7 +42,7 @@ struct s3c64xx_spi_info { }; /** - * s3c64xx_spi_set_platdata - SPI Controller configure callback by the board + * s3c64xx_spi0_set_platdata - SPI Controller configure callback by the board * initialization code. * @src_clk_nr: Clock the SPI controller is to use to generate SPI clocks. * @num_cs: Number of elements in the 'cs' array. From 4a76a164ba1617f60d1c8a2fd754466c9d9e48e9 Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Wed, 8 Apr 2026 08:32:56 -0600 Subject: [PATCH 112/655] crypto: ccp - Reverse the cleanup order in psp_dev_destroy() Before SNP x86 shutdown [1], all HV_FIXED pages were always leaked on module unload. Now pages can be reclaimed if they are freed before SNP shutdown. The SFS driver does sfs_dev_destroy() -> snp_free_hv_fixed_pages(), marking the command buffer as free. But this happens after sev_dev_destroy() in psp_dev_destroy(), so the pages are always leaked. Rearrange psp_dev_destroy() to destroy things in the reverse order from psp_init(), so that any dependencies can be unwound accordingly. This lets SFS free the page and the subsequent SNP shutdown release it. This was identified with use of Chris Mason's review-prompts: https://github.com/masoncl/review-prompts [1]: https://lore.kernel.org/all/20260324161301.1353976-1-tycho@kernel.org/ Fixes: 648dbccc03a0 ("crypto: ccp - Add AMD Seamless Firmware Servicing (SFS) driver") Reported-by: review-prompts Assisted-by: Claude:claude-4.6-opus Suggested-by: Tom Lendacky Signed-off-by: Tycho Andersen (AMD) Reviewed-by: Ashish Kalra Signed-off-by: Herbert Xu --- drivers/crypto/ccp/psp-dev.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index 5c7f7e02a7d8..b14ce51065d5 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -316,16 +316,16 @@ void psp_dev_destroy(struct sp_device *sp) if (!psp) return; - sev_dev_destroy(psp); - - tee_dev_destroy(psp); - - sfs_dev_destroy(psp); - dbc_dev_destroy(psp); platform_access_dev_destroy(psp); + sfs_dev_destroy(psp); + + tee_dev_destroy(psp); + + sev_dev_destroy(psp); + sp_free_psp_irq(sp, psp); if (sp->clear_psp_master_device) From 1b864b6cb213bbd7b406e9b2e98c962077f300df Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Wed, 8 Apr 2026 08:32:57 -0600 Subject: [PATCH 113/655] crypto: ccp - Fix snp_filter_reserved_mem_regions() off-by-one Sashiko notes: > regarding the bounds check in snp_filter_reserved_mem_regions() > called via walk_iomem_res_desc(): does the check > if ((range_list->num_elements * 16 + 8) > PAGE_SIZE) > allow an off-by-one heap buffer overflow? > > If range_list->num_elements is 255, 255 * 16 + 8 = 4088, which is <= 4096. > Writing range->base (8 bytes) fills 4088-4095, but writing range->page_count > (4 bytes) would write to 4096-4099, overflowing the kzalloc-allocated > PAGE_SIZE buffer. Fix this by accounting for the entry about to be written to, in addition to the entries that are already allocated. Fixes: 1ca5614b84ee ("crypto: ccp: Add support to initialize the AMD-SP for SEV-SNP") Reported-by: Sashiko Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org Signed-off-by: Tycho Andersen (AMD) Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index d1e9e0ac63b6..9f3434ffba4f 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1328,10 +1328,11 @@ static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) size_t size; /* - * Ensure the list of HV_FIXED pages that will be passed to firmware - * do not exceed the page-sized argument buffer. + * Ensure the list of HV_FIXED pages passed to the firmware including + * the one about to be written to do not exceed the page-sized argument + * buffer. */ - if ((range_list->num_elements * sizeof(struct sev_data_range) + + if (((range_list->num_elements + 1) * sizeof(struct sev_data_range) + sizeof(struct sev_data_range_list)) > PAGE_SIZE) return -E2BIG; From a8d5370eef00eca132a292b1901c9914c817e385 Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Wed, 8 Apr 2026 08:32:58 -0600 Subject: [PATCH 114/655] crypto: ccp - Check for page allocation failure correctly in TIO Sashiko notes: > if __snp_alloc_firmware_pages() returns NULL under memory pressure, is it > safe to pass it directly to page_address()? > > On architectures without HASHED_PAGE_VIRTUAL, page_address(NULL) might > compute a deterministic but invalid, non-zero virtual address. The > subsequent if (tio_status) check would then evaluate to true, and > sev_tsm_init_locked() would dereference the invalid pointer. Indeed, page_address(NULL) will return non-NULL garbage here. Fix this by checking the page allocation itself for NULL, not the resulting virtual address. Fixes: 4be423572da1 ("crypto/ccp: Implement SEV-TIO PCIe IDE (phase1)") Reported-by: Sashiko Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org Signed-off-by: Tycho Andersen (AMD) Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 9f3434ffba4f..48caeffcc217 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1488,6 +1488,8 @@ static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) &snp_panic_notifier); if (data.tio_en) { + struct page *page; + /* * This executes with the sev_cmd_mutex held so down the stack * snp_reclaim_pages(locked=false) might be needed (which is extremely @@ -1495,12 +1497,14 @@ static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) * Instead of exporting __snp_alloc_firmware_pages(), allocate a page * for this one call here. */ - void *tio_status = page_address(__snp_alloc_firmware_pages( - GFP_KERNEL_ACCOUNT | __GFP_ZERO, 0, true)); + page = __snp_alloc_firmware_pages(GFP_KERNEL_ACCOUNT | __GFP_ZERO, + 0, true); + if (page) { + void *tio_status = page_address(page); - if (tio_status) { sev_tsm_init_locked(sev, tio_status); - __snp_free_firmware_pages(virt_to_page(tio_status), 0, true); + + __snp_free_firmware_pages(page, 0, true); } } From fed613c1230277105bb512bce6e1fda8f316d178 Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Wed, 8 Apr 2026 08:32:59 -0600 Subject: [PATCH 115/655] crypto: ccp - Initialize data during __sev_snp_init_locked() Sashiko notes: > is the stack variable data left uninitialized when taking the else branch? > Since data.tio_en is later evaluated unconditionally, could stack garbage > cause it to evaluate to true, leading to erroneous attempts to allocate > pages and initialize SEV-TIO on unsupported hardware? If the firmware is too old to support SEV_INIT_EX, data is left uninitialized but used in the debug logging about whether TIO is enabled or not. Fixes: 4be423572da1 ("crypto/ccp: Implement SEV-TIO PCIe IDE (phase1)") Reported-by: Sashiko Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org Signed-off-by: Tycho Andersen (AMD) Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 48caeffcc217..8a85439cfa76 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1356,7 +1356,7 @@ static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) { struct sev_data_range_list *snp_range_list __free(kfree) = NULL; struct psp_device *psp = psp_master; - struct sev_data_snp_init_ex data; + struct sev_data_snp_init_ex data = {}; struct sev_device *sev; void *arg = &data; int cmd, rc = 0; @@ -1420,8 +1420,6 @@ static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) */ snp_add_hv_fixed_pages(sev, snp_range_list); - memset(&data, 0, sizeof(data)); - if (max_snp_asid) { data.ciphertext_hiding_en = 1; data.max_snp_asid = max_snp_asid; From b668edaf8dcc8d09f6f1e71797422b44d4bd22a3 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 12 Apr 2026 11:56:43 +0200 Subject: [PATCH 116/655] crypto: atmel-ecc - add support for atecc608b Tested on hardware with an ATECC608B at 0x60. The device binds successfully, passes the driver's sanity check, and registers the ecdh-nist-p256 KPP algorithm. The hardware ECDH path was also exercised using a minimal KPP test module, covering private key generation, public key derivation, and shared secret computation. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-ecc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 9c380351d2f9..3738a4eb8701 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -372,6 +372,8 @@ static void atmel_ecc_remove(struct i2c_client *client) static const struct of_device_id atmel_ecc_dt_ids[] = { { .compatible = "atmel,atecc508a", + }, { + .compatible = "atmel,atecc608b", }, { /* sentinel */ } @@ -381,6 +383,7 @@ MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids); static const struct i2c_device_id atmel_ecc_id[] = { { "atecc508a" }, + { "atecc608b" }, { } }; MODULE_DEVICE_TABLE(i2c, atmel_ecc_id); From 59ed9e187f81bef5c8c7c952ea7566e900a13b95 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 12 Apr 2026 11:56:45 +0200 Subject: [PATCH 117/655] dt-bindings: trivial-devices: add atmel,atecc608b Add entry for ATECC608B. Update the ATECC508A comment for consistency. Acked-by: Rob Herring (Arm) Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/trivial-devices.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 23fd4513933a..a5d5296d76af 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -67,8 +67,10 @@ properties: - arduino,unoq-mcu # Temperature monitoring of Astera Labs PT5161L PCIe retimer - asteralabs,pt5161l - # i2c h/w elliptic curve crypto module + # ATECC508A - i2c h/w elliptic curve crypto module - atmel,atecc508a + # ATECC608B - i2c h/w elliptic curve crypto module + - atmel,atecc608b # ATSHA204 - i2c h/w symmetric crypto module - atmel,atsha204 # ATSHA204A - i2c h/w symmetric crypto module From edcc5d486ac69d019d32e694c83e7f24a1003123 Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Thu, 16 Apr 2026 18:37:20 +0530 Subject: [PATCH 118/655] dt-bindings: crypto: qcom-qce: Document the Glymur crypto engine Document the crypto engine on Glymur platform. Signed-off-by: Harshal Dev Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom-qce.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index e6c0aa5dabfc..69101cead3bc 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -46,6 +46,7 @@ properties: - items: - enum: - qcom,eliza-qce + - qcom,glymur-qce - qcom,kaanapali-qce - qcom,milos-qce - qcom,qcs615-qce From 39a31ad9e2a5ed7e9c9c6f711dca96c8c8f5f26b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:45 -0700 Subject: [PATCH 119/655] crypto: drbg - Fix returning success on failure in CTR_DRBG drbg_ctr_generate() sometimes returns success when it fails, leaving the output buffer uninitialized. Fix it. Fixes: cde001e4c3c3 ("crypto: rng - RNGs must return 0 in success case") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 9204e6edb426..e4eb78ed222b 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -377,7 +377,7 @@ static int drbg_ctr_generate(struct drbg_state *drbg, if (addtl && !list_empty(addtl)) { ret = drbg_ctr_update(drbg, addtl, 2); if (ret) - return 0; + return ret; } /* 10.2.1.5.2 step 4.1 */ From ddc4dedb9ba3c8eecbc8c050fffd46d1b7e75c21 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:46 -0700 Subject: [PATCH 120/655] crypto: drbg - Fix misaligned writes in CTR_DRBG and HASH_DRBG drbg_cpu_to_be32() is being used to do a plain write to a byte array, which doesn't have any alignment guarantee. This can cause a misaligned write. Replace it with the correct function, put_unaligned_be32(). Fixes: 72f3e00dd67e ("crypto: drbg - replace int2byte with cpu_to_be") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/df_sp80090a.c | 7 ++++--- crypto/drbg.c | 3 ++- include/crypto/internal/drbg.h | 18 ------------------ 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/crypto/df_sp80090a.c b/crypto/df_sp80090a.c index b8134be6f7ad..f4bb7be016e8 100644 --- a/crypto/df_sp80090a.c +++ b/crypto/df_sp80090a.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -141,10 +142,10 @@ int crypto_drbg_ctr_df(struct aes_enckey *aeskey, /* 10.4.2 step 2 -- calculate the entire length of all input data */ list_for_each_entry(seed, seedlist, list) inputlen += seed->len; - drbg_cpu_to_be32(inputlen, &L_N[0]); + put_unaligned_be32(inputlen, &L_N[0]); /* 10.4.2 step 3 */ - drbg_cpu_to_be32(bytes_to_return, &L_N[4]); + put_unaligned_be32(bytes_to_return, &L_N[4]); /* 10.4.2 step 5: length is L_N, input_string, one byte, padding */ padlen = (inputlen + sizeof(L_N) + 1) % (blocklen_bytes); @@ -175,7 +176,7 @@ int crypto_drbg_ctr_df(struct aes_enckey *aeskey, * holds zeros after allocation -- even the increment of i * is irrelevant as the increment remains within length of i */ - drbg_cpu_to_be32(i, iv); + put_unaligned_be32(i, iv); /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ drbg_ctr_bcc(aeskey, temp + templen, K, &bcc_list, blocklen_bytes, keylen); diff --git a/crypto/drbg.c b/crypto/drbg.c index e4eb78ed222b..de4c69032155 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -103,6 +103,7 @@ #include #include #include +#include /*************************************************************** * Backend cipher definitions available to DRBG @@ -601,7 +602,7 @@ static int drbg_hash_df(struct drbg_state *drbg, /* 10.4.1 step 3 */ input[0] = 1; - drbg_cpu_to_be32((outlen * 8), &input[1]); + put_unaligned_be32(outlen * 8, &input[1]); /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ drbg_string_fill(&data, input, 5); diff --git a/include/crypto/internal/drbg.h b/include/crypto/internal/drbg.h index 371e52dcee6c..b4e5ef0be602 100644 --- a/include/crypto/internal/drbg.h +++ b/include/crypto/internal/drbg.h @@ -9,24 +9,6 @@ #ifndef _INTERNAL_DRBG_H #define _INTERNAL_DRBG_H -/* - * Convert an integer into a byte representation of this integer. - * The byte representation is big-endian - * - * @val value to be converted - * @buf buffer holding the converted integer -- caller must ensure that - * buffer size is at least 32 bit - */ -static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf) -{ - struct s { - __be32 conv; - }; - struct s *conversion = (struct s *)buf; - - conversion->conv = cpu_to_be32(val); -} - /* * Concatenation Helper and string operation helper * From 040ad83b0e8aa065fd2fc641cacba8491a8b186d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:47 -0700 Subject: [PATCH 121/655] crypto: drbg - Fix ineffective sanity check Fix drbg_healthcheck_sanity() to correctly check the return value of drbg_generate(). drbg_generate() returns 0 on success, or a negative errno value on failure. drbg_healthcheck_sanity() incorrectly assumed that it returned a positive value on success. This didn't make the sanity check fail, but it made it ineffective. Fixes: cde001e4c3c3 ("crypto: rng - RNGs must return 0 in success case") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index de4c69032155..f23b431bd490 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1737,7 +1737,6 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, */ static inline int __init drbg_healthcheck_sanity(void) { - int len = 0; #define OUTBUFLEN 16 unsigned char buf[OUTBUFLEN]; struct drbg_state *drbg = NULL; @@ -1782,11 +1781,11 @@ static inline int __init drbg_healthcheck_sanity(void) max_request_bytes = drbg_max_request_bytes(drbg); drbg_string_fill(&addtl, buf, max_addtllen + 1); /* overflow addtllen with additional info string */ - len = drbg_generate(drbg, buf, OUTBUFLEN, &addtl); - BUG_ON(0 < len); + ret = drbg_generate(drbg, buf, OUTBUFLEN, &addtl); + BUG_ON(ret == 0); /* overflow max_bits */ - len = drbg_generate(drbg, buf, (max_request_bytes + 1), NULL); - BUG_ON(0 < len); + ret = drbg_generate(drbg, buf, max_request_bytes + 1, NULL); + BUG_ON(ret == 0); /* overflow max addtllen with personalization string */ ret = drbg_seed(drbg, &addtl, false); From 6f49f00c981bbb9ef602966f19bfdbef46b681d2 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:48 -0700 Subject: [PATCH 122/655] crypto: drbg - Fix drbg_max_addtl() on 64-bit kernels On 64-bit kernels, drbg_max_addtl() returns 2**35 bytes. That's too large, for two reasons: 1. SP800-90A says the maximum limit is 2**35 *bits*, not 2**35 bytes. So the implemented limit has confused bits and bytes. 2. When drbg_kcapi_hash() calls crypto_shash_update() on the additional information string, the length is implicitly cast to 'unsigned int'. That truncates the additional information string to U32_MAX bytes. Fix the maximum additional information string length to always be U32_MAX - 1, causing an error to be returned for any longer lengths. Fixes: 541af946fe13 ("crypto: drbg - SP800-90A Deterministic Random Bit Generator") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- include/crypto/drbg.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index 2d42518cbdce..c11eaf757ed0 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -148,19 +148,15 @@ static inline size_t drbg_max_request_bytes(struct drbg_state *drbg) return (1 << 16); } +/* + * SP800-90A allows implementations to support additional info / personalization + * strings of up to 2**35 bits. Implementations can have a smaller maximum. We + * use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a + * size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. + */ static inline size_t drbg_max_addtl(struct drbg_state *drbg) { - /* SP800-90A requires 2**35 bytes additional info str / pers str */ -#if (__BITS_PER_LONG == 32) - /* - * SP800-90A allows smaller maximum numbers to be returned -- we - * return SIZE_MAX - 1 to allow the verification of the enforcement - * of this value in drbg_healthcheck_sanity. - */ - return (SIZE_MAX - 1); -#else - return (1UL<<35); -#endif + return U32_MAX - 1; } static inline size_t drbg_max_requests(struct drbg_state *drbg) From a8a1f93080efc83a9ff8452954429ae379e9e614 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:49 -0700 Subject: [PATCH 123/655] crypto: drbg - Fix the fips_enabled priority boost When fips_enabled=1, it seems to have been intended for one of the algorithms defined in crypto/drbg.c to be the highest priority "stdrng" algorithm, so that it is what is used by "stdrng" users. However, the code only boosts the priority to 400, which is less than the priority 500 used in drivers/crypto/caam/caamprng.c. Thus, the CAAM RNG could be used instead. Fix this by boosting the priority by 2000 instead of 200. Fixes: 541af946fe13 ("crypto: drbg - SP800-90A Deterministic Random Bit Generator") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index f23b431bd490..e3065fb9541b 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1832,7 +1832,7 @@ static inline void __init drbg_fill_array(struct rng_alg *alg, * it is selected. */ if (fips_enabled) - alg->base.cra_priority += 200; + alg->base.cra_priority += 2000; alg->base.cra_ctxsize = sizeof(struct drbg_state); alg->base.cra_module = THIS_MODULE; From f01d721cb809cb47db1afcf629d57e2aa18ae3c6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:50 -0700 Subject: [PATCH 124/655] crypto: drbg - Remove always-enabled symbol CRYPTO_DRBG_HMAC The kconfig symbol CRYPTO_DRBG_HMAC is always enabled when CRYPTO_DRBG_MENU is enabled, and all checks for CRYPTO_DRBG_HMAC are in code conditional on CRYPTO_DRBG_MENU. Thus, the only purpose of the CRYPTO_DRBG_HMAC symbol is to select CRYPTO_HMAC and CRYPTO_SHA512. Move those two selections to CRYPTO_DRBG_MENU, remove the checks for CRYPTO_DRBG_HMAC, and remove the CRYPTO_DRBG_HMAC symbol itself. Note that this also fixes an issue where CRYPTO_HMAC and CRYPTO_SHA512 were unnecessarily being forced to built-in when CRYPTO_DRBG=m. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/Kconfig | 10 +++------- crypto/drbg.c | 15 --------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 103d1f58cb7c..34da01c153d6 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1122,12 +1122,6 @@ menuconfig CRYPTO_DRBG_MENU if CRYPTO_DRBG_MENU -config CRYPTO_DRBG_HMAC - bool - default y - select CRYPTO_HMAC - select CRYPTO_SHA512 - config CRYPTO_DRBG_HASH bool "Hash_DRBG" select CRYPTO_SHA256 @@ -1147,8 +1141,10 @@ config CRYPTO_DRBG_CTR config CRYPTO_DRBG tristate default CRYPTO_DRBG_MENU - select CRYPTO_RNG + select CRYPTO_HMAC select CRYPTO_JITTERENTROPY + select CRYPTO_RNG + select CRYPTO_SHA512 endif # if CRYPTO_DRBG_MENU diff --git a/crypto/drbg.c b/crypto/drbg.c index e3065fb9541b..f6bff275c31b 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -161,7 +161,6 @@ static const struct drbg_core drbg_cores[] = { .backend_cra_name = "sha256", }, #endif /* CONFIG_CRYPTO_DRBG_HASH */ -#ifdef CONFIG_CRYPTO_DRBG_HMAC { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 48, /* block length of cipher */ @@ -181,7 +180,6 @@ static const struct drbg_core drbg_cores[] = { .cra_name = "hmac_sha512", .backend_cra_name = "hmac(sha512)", }, -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ }; static int drbg_uninstantiate(struct drbg_state *drbg); @@ -406,16 +404,13 @@ static const struct drbg_state_ops drbg_ctr_ops = { * HMAC DRBG callback functions ******************************************************************/ -#if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC) static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, const struct list_head *in); static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, const unsigned char *key); static int drbg_init_hash_kernel(struct drbg_state *drbg); static int drbg_fini_hash_kernel(struct drbg_state *drbg); -#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */ -#ifdef CONFIG_CRYPTO_DRBG_HMAC #define CRYPTO_DRBG_HMAC_STRING "HMAC " MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); @@ -527,7 +522,6 @@ static const struct drbg_state_ops drbg_hmac_ops = { .crypto_init = drbg_init_hash_kernel, .crypto_fini = drbg_fini_hash_kernel, }; -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ /****************************************************************** * Hash DRBG callback functions @@ -1046,11 +1040,9 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) unsigned int sb_size = 0; switch (drbg->core->flags & DRBG_TYPE_MASK) { -#ifdef CONFIG_CRYPTO_DRBG_HMAC case DRBG_HMAC: drbg->d_ops = &drbg_hmac_ops; break; -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ #ifdef CONFIG_CRYPTO_DRBG_HASH case DRBG_HASH: drbg->d_ops = &drbg_hash_ops; @@ -1431,7 +1423,6 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, * Kernel crypto API cipher invocations requested by DRBG ***************************************************************/ -#if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC) struct sdesc { struct shash_desc shash; }; @@ -1491,7 +1482,6 @@ static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, crypto_shash_update(&sdesc->shash, input->buf, input->len); return crypto_shash_final(&sdesc->shash, outval); } -#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */ #ifdef CONFIG_CRYPTO_DRBG_CTR static int drbg_fini_sym_kernel(struct drbg_state *drbg) @@ -1757,9 +1747,7 @@ static inline int __init drbg_healthcheck_sanity(void) #ifdef CONFIG_CRYPTO_DRBG_HASH drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); #endif -#ifdef CONFIG_CRYPTO_DRBG_HMAC drbg_convert_tfm_core("drbg_nopr_hmac_sha512", &coreref, &pr); -#endif drbg = kzalloc_obj(struct drbg_state); if (!drbg) @@ -1887,9 +1875,6 @@ module_exit(drbg_exit); #ifndef CRYPTO_DRBG_HASH_STRING #define CRYPTO_DRBG_HASH_STRING "" #endif -#ifndef CRYPTO_DRBG_HMAC_STRING -#define CRYPTO_DRBG_HMAC_STRING "" -#endif #ifndef CRYPTO_DRBG_CTR_STRING #define CRYPTO_DRBG_CTR_STRING "" #endif From 1c4f7235112934232975e6ed08a896a4caa71dd9 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:51 -0700 Subject: [PATCH 125/655] crypto: drbg - Remove broken commented-out code This commented-out code doesn't compile. Even if it did, it wouldn't actually do what it was apparently intended to do, seeing as the "test" for "drbg_pr_hmac_sha512" and "drbg_pr_ctr_aes256" is alg_test_null(). Just delete it to avoid keeping broken code around, and so that there isn't any perceived need to try to update it as the DRBG code is refactored. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index f6bff275c31b..bb8ddc090307 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1219,36 +1219,7 @@ static int drbg_generate(struct drbg_state *drbg, * In this case, the entire kernel operation is questionable and it * is unlikely that the integrity violation only affects the * correct operation of the DRBG. - * - * Albeit the following code is commented out, it is provided in - * case somebody has a need to implement the test of 11.3.3. */ -#if 0 - if (drbg->reseed_ctr && !(drbg->reseed_ctr % 4096)) { - int err = 0; - pr_devel("DRBG: start to perform self test\n"); - if (drbg->core->flags & DRBG_HMAC) - err = alg_test("drbg_pr_hmac_sha512", - "drbg_pr_hmac_sha512", 0, 0); - else if (drbg->core->flags & DRBG_CTR) - err = alg_test("drbg_pr_ctr_aes256", - "drbg_pr_ctr_aes256", 0, 0); - else - err = alg_test("drbg_pr_sha256", - "drbg_pr_sha256", 0, 0); - if (err) { - pr_err("DRBG: periodical self test failed\n"); - /* - * uninstantiate implies that from now on, only errors - * are returned when reusing this DRBG cipher handle - */ - drbg_uninstantiate(drbg); - return 0; - } else { - pr_devel("DRBG: self test successful\n"); - } - } -#endif /* * All operations were successful, return 0 as mandated by From 06dc3f01e789cdad4d99b99eba35acb26d227f53 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:52 -0700 Subject: [PATCH 126/655] crypto: drbg - Remove unhelpful helper functions Fold the contents of the inline functions crypto_drbg_get_bytes_addtl(), crypto_drbg_get_bytes_addtl_test(), and crypto_drbg_reset_test() into their only caller in drbg_cavs_test(). It ends up being much simpler. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 15 +++------ crypto/testmgr.c | 34 ++++++------------- include/crypto/drbg.h | 76 ------------------------------------------- 3 files changed, 15 insertions(+), 110 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index bb8ddc090307..83cb6c1bbac0 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -55,7 +55,7 @@ * char data[DATALEN]; * * drng = crypto_alloc_rng(drng_name, 0, 0); - * err = crypto_rng_get_bytes(drng, &data, DATALEN); + * err = crypto_rng_get_bytes(drng, data, DATALEN); * crypto_free_rng(drng); * * @@ -64,15 +64,13 @@ * struct crypto_rng *drng; * int err; * char data[DATALEN]; - * struct drbg_string pers; * char personalization[11] = "some-string"; * - * drbg_string_fill(&pers, personalization, strlen(personalization)); * drng = crypto_alloc_rng(drng_name, 0, 0); * // The reset completely re-initializes the DRBG with the provided * // personalization string - * err = crypto_rng_reset(drng, &personalization, strlen(personalization)); - * err = crypto_rng_get_bytes(drng, &data, DATALEN); + * err = crypto_rng_reset(drng, personalization, strlen(personalization)); + * err = crypto_rng_get_bytes(drng, data, DATALEN); * crypto_free_rng(drng); * * @@ -82,13 +80,10 @@ * int err; * char data[DATALEN]; * char addtl_string[11] = "some-string"; - * string drbg_string addtl; * - * drbg_string_fill(&addtl, addtl_string, strlen(addtl_string)); * drng = crypto_alloc_rng(drng_name, 0, 0); - * // The following call is a wrapper to crypto_rng_get_bytes() and returns - * // the same error codes. - * err = crypto_drbg_get_bytes_addtl(drng, &data, DATALEN, &addtl); + * err = crypto_rng_generate(drng, addtl_string, strlen(addtl_string), + data, DATALEN); * crypto_free_rng(drng); * * diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 4d86efae65b2..35ff2b50e3c2 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3487,8 +3487,6 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr, { int ret = -EAGAIN; struct crypto_rng *drng; - struct drbg_test_data test_data; - struct drbg_string addtl, pers, testentropy; unsigned char *buf = kzalloc(test->expectedlen, GFP_KERNEL); if (!buf) @@ -3504,39 +3502,27 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr, return PTR_ERR(drng); } - test_data.testentropy = &testentropy; - drbg_string_fill(&testentropy, test->entropy, test->entropylen); - drbg_string_fill(&pers, test->pers, test->perslen); - ret = crypto_drbg_reset_test(drng, &pers, &test_data); + crypto_rng_set_entropy(drng, test->entropy, test->entropylen); + ret = crypto_rng_reset(drng, test->pers, test->perslen); if (ret) { printk(KERN_ERR "alg: drbg: Failed to reset rng\n"); goto outbuf; } - drbg_string_fill(&addtl, test->addtla, test->addtllen); - if (pr) { - drbg_string_fill(&testentropy, test->entpra, test->entprlen); - ret = crypto_drbg_get_bytes_addtl_test(drng, - buf, test->expectedlen, &addtl, &test_data); - } else { - ret = crypto_drbg_get_bytes_addtl(drng, - buf, test->expectedlen, &addtl); - } + if (pr) + crypto_rng_set_entropy(drng, test->entpra, test->entprlen); + ret = crypto_rng_generate(drng, test->addtla, test->addtllen, + buf, test->expectedlen); if (ret < 0) { printk(KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n", driver); goto outbuf; } - drbg_string_fill(&addtl, test->addtlb, test->addtllen); - if (pr) { - drbg_string_fill(&testentropy, test->entprb, test->entprlen); - ret = crypto_drbg_get_bytes_addtl_test(drng, - buf, test->expectedlen, &addtl, &test_data); - } else { - ret = crypto_drbg_get_bytes_addtl(drng, - buf, test->expectedlen, &addtl); - } + if (pr) + crypto_rng_set_entropy(drng, test->entprb, test->entprlen); + ret = crypto_rng_generate(drng, test->addtlb, test->addtllen, + buf, test->expectedlen); if (ret < 0) { printk(KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n", driver); diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index c11eaf757ed0..486aa793688e 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -78,10 +78,6 @@ struct drbg_state_ops { }; -struct drbg_test_data { - struct drbg_string *testentropy; /* TEST PARAMETER: test entropy */ -}; - enum drbg_seed_state { DRBG_SEED_STATE_UNSEEDED, DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ @@ -165,78 +161,6 @@ static inline size_t drbg_max_requests(struct drbg_state *drbg) return (1<<20); } -/* - * This is a wrapper to the kernel crypto API function of - * crypto_rng_generate() to allow the caller to provide additional data. - * - * @drng DRBG handle -- see crypto_rng_get_bytes - * @outbuf output buffer -- see crypto_rng_get_bytes - * @outlen length of output buffer -- see crypto_rng_get_bytes - * @addtl_input additional information string input buffer - * @addtllen length of additional information string buffer - * - * return - * see crypto_rng_get_bytes - */ -static inline int crypto_drbg_get_bytes_addtl(struct crypto_rng *drng, - unsigned char *outbuf, unsigned int outlen, - struct drbg_string *addtl) -{ - return crypto_rng_generate(drng, addtl->buf, addtl->len, - outbuf, outlen); -} - -/* - * TEST code - * - * This is a wrapper to the kernel crypto API function of - * crypto_rng_generate() to allow the caller to provide additional data and - * allow furnishing of test_data - * - * @drng DRBG handle -- see crypto_rng_get_bytes - * @outbuf output buffer -- see crypto_rng_get_bytes - * @outlen length of output buffer -- see crypto_rng_get_bytes - * @addtl_input additional information string input buffer - * @addtllen length of additional information string buffer - * @test_data filled test data - * - * return - * see crypto_rng_get_bytes - */ -static inline int crypto_drbg_get_bytes_addtl_test(struct crypto_rng *drng, - unsigned char *outbuf, unsigned int outlen, - struct drbg_string *addtl, - struct drbg_test_data *test_data) -{ - crypto_rng_set_entropy(drng, test_data->testentropy->buf, - test_data->testentropy->len); - return crypto_rng_generate(drng, addtl->buf, addtl->len, - outbuf, outlen); -} - -/* - * TEST code - * - * This is a wrapper to the kernel crypto API function of - * crypto_rng_reset() to allow the caller to provide test_data - * - * @drng DRBG handle -- see crypto_rng_reset - * @pers personalization string input buffer - * @perslen length of additional information string buffer - * @test_data filled test data - * - * return - * see crypto_rng_reset - */ -static inline int crypto_drbg_reset_test(struct crypto_rng *drng, - struct drbg_string *pers, - struct drbg_test_data *test_data) -{ - crypto_rng_set_entropy(drng, test_data->testentropy->buf, - test_data->testentropy->len); - return crypto_rng_reset(drng, pers->buf, pers->len); -} - /* DRBG type flags */ #define DRBG_CTR ((drbg_flag_t)1<<0) #define DRBG_HMAC ((drbg_flag_t)1<<1) From f4919bbca03c8d130a46eba99535b5730edd89a6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:53 -0700 Subject: [PATCH 127/655] crypto: drbg - Remove obsolete FIPS 140-2 continuous test FIPS 140-2 required that a continuous test for repeated outputs be done on both "Approved RNGs" and "Non-Approved RNGs". That's apparently why crypto/drbg.c does such a test on the bytes it pulls from get_random_bytes(), despite get_random_bytes() being a "Non-Approved RNG" that is credited with zero entropy for FIPS purposes. (From FIPS's point of view, the "Approved RNG" is jitterentropy.) FIPS 140-3 "modernized" the continuous RNG test requirements. They're now a bit more sophisticated, requiring both an "Adaptive Proportion Test" and a "Repetition Count Test". At the same time, FIPS 140-3 doesn't require continuous RNG tests on "Non-Approved RNGs" if a "vetted conditioning component" is used. The SP800-90A DRBGs are exactly such a vetted conditioning component, by their design. (In the case of HASH_DRBG and CTR_DRBG, the derivation function does have to be implemented. But the kernel does that.) In other words: from FIPS 140-3's point of view, get_random_bytes() still produces zero entropy, but the way the DRBG combines those bytes with the jitterentropy bytes preserves all the "approved" entropy from jitterentropy. Thus no test for get_random_bytes() is required. Seeing as FIPS 140-2 certificates stopped being issued in 2021 in favor of FIPS 140-3, this means this code is obsolete. Remove it. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 78 ++----------------------------------------- include/crypto/drbg.h | 2 -- 2 files changed, 2 insertions(+), 78 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 83cb6c1bbac0..66d7739469c6 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -205,55 +205,6 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags) } } -/* - * FIPS 140-2 continuous self test for the noise source - * The test is performed on the noise source input data. Thus, the function - * implicitly knows the size of the buffer to be equal to the security - * strength. - * - * Note, this function disregards the nonce trailing the entropy data during - * initial seeding. - * - * drbg->drbg_mutex must have been taken. - * - * @drbg DRBG handle - * @entropy buffer of seed data to be checked - * - * return: - * %true on success - * %false when the CTRNG is not yet primed - */ -static bool drbg_fips_continuous_test(struct drbg_state *drbg, - const unsigned char *entropy) - __must_hold(&drbg->drbg_mutex) -{ - unsigned short entropylen = drbg_sec_strength(drbg->core->flags); - - if (!IS_ENABLED(CONFIG_CRYPTO_FIPS)) - return true; - - /* skip test if we test the overall system */ - if (list_empty(&drbg->test_data.list)) - return true; - /* only perform test in FIPS mode */ - if (!fips_enabled) - return true; - - if (!drbg->fips_primed) { - /* Priming of FIPS test */ - memcpy(drbg->prev, entropy, entropylen); - drbg->fips_primed = true; - /* priming: another round is needed */ - return false; - } - if (!memcmp(drbg->prev, entropy, entropylen)) - panic("DRBG continuous self test failed\n"); - memcpy(drbg->prev, entropy, entropylen); - - /* the test shall pass when the two values are not equal */ - return true; -} - /****************************************************************** * CTR DRBG callback functions ******************************************************************/ @@ -833,16 +784,6 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, return ret; } -static inline void drbg_get_random_bytes(struct drbg_state *drbg, - unsigned char *entropy, - unsigned int entropylen) - __must_hold(&drbg->drbg_mutex) -{ - do - get_random_bytes(entropy, entropylen); - while (!drbg_fips_continuous_test(drbg, entropy)); -} - static int drbg_seed_from_random(struct drbg_state *drbg) __must_hold(&drbg->drbg_mutex) { @@ -858,7 +799,7 @@ static int drbg_seed_from_random(struct drbg_state *drbg) drbg_string_fill(&data, entropy, entropylen); list_add_tail(&data.list, &seedlist); - drbg_get_random_bytes(drbg, entropy, entropylen); + get_random_bytes(entropy, entropylen); ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); @@ -937,7 +878,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, if (!rng_is_initialized()) new_seed_state = DRBG_SEED_STATE_PARTIAL; - drbg_get_random_bytes(drbg, entropy, entropylen); + get_random_bytes(entropy, entropylen); if (!drbg->jent) { drbg_string_fill(&data1, entropy, entropylen); @@ -1018,11 +959,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) drbg->reseed_ctr = 0; drbg->d_ops = NULL; drbg->core = NULL; - if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) { - kfree_sensitive(drbg->prev); - drbg->prev = NULL; - drbg->fips_primed = false; - } } /* @@ -1088,16 +1024,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1); } - if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) { - drbg->prev = kzalloc(drbg_sec_strength(drbg->core->flags), - GFP_KERNEL); - if (!drbg->prev) { - ret = -ENOMEM; - goto fini; - } - drbg->fips_primed = false; - } - return 0; fini: diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index 486aa793688e..4fafc69a8ee6 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -109,8 +109,6 @@ struct drbg_state { enum drbg_seed_state seeded; /* DRBG fully seeded? */ unsigned long last_seed_time; bool pr; /* Prediction resistance enabled? */ - bool fips_primed; /* Continuous test primed? */ - unsigned char *prev; /* FIPS 140-2 continuous test value */ struct crypto_rng *jent; const struct drbg_state_ops *d_ops; const struct drbg_core *core; From 262ec4782cf4ae3b661b30ff11d3af86f667c69c Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:54 -0700 Subject: [PATCH 128/655] crypto: drbg - Fold include/crypto/drbg.h into crypto/drbg.c include/crypto/drbg.h no longer contains anything that is used externally to crypto/drbg.c. Therefore, fold it into crypto/drbg.c. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 132 ++++++++++++- crypto/testmgr.c | 3 +- include/crypto/drbg.h | 181 ------------------ .../crypto/chacha20-s390/test-cipher.c | 1 - 4 files changed, 132 insertions(+), 185 deletions(-) delete mode 100644 include/crypto/drbg.h diff --git a/crypto/drbg.c b/crypto/drbg.c index 66d7739469c6..fd1d75addaf7 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -92,14 +92,144 @@ * Just mix both scenarios above. */ -#include #include #include +#include +#include +#include +#include +#include #include #include +#include +#include +#include #include #include +struct drbg_state; +typedef uint32_t drbg_flag_t; + +struct drbg_core { + drbg_flag_t flags; /* flags for the cipher */ + __u8 statelen; /* maximum state length */ + __u8 blocklen_bytes; /* block size of output in bytes */ + char cra_name[CRYPTO_MAX_ALG_NAME]; /* mapping to kernel crypto API */ + /* kernel crypto API backend cipher name */ + char backend_cra_name[CRYPTO_MAX_ALG_NAME]; +}; + +struct drbg_state_ops { + int (*update)(struct drbg_state *drbg, struct list_head *seed, + int reseed); + int (*generate)(struct drbg_state *drbg, + unsigned char *buf, unsigned int buflen, + struct list_head *addtl); + int (*crypto_init)(struct drbg_state *drbg); + int (*crypto_fini)(struct drbg_state *drbg); + +}; + +enum drbg_seed_state { + DRBG_SEED_STATE_UNSEEDED, + DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ + DRBG_SEED_STATE_FULL, +}; + +struct drbg_state { + struct mutex drbg_mutex; /* lock around DRBG */ + unsigned char *V; /* internal state 10.1.1.1 1a) */ + unsigned char *Vbuf; + /* hash: static value 10.1.1.1 1b) hmac / ctr: key */ + unsigned char *C; + unsigned char *Cbuf; + /* Number of RNG requests since last reseed -- 10.1.1.1 1c) */ + size_t reseed_ctr; + size_t reseed_threshold; + /* some memory the DRBG can use for its operation */ + unsigned char *scratchpad; + unsigned char *scratchpadbuf; + void *priv_data; /* Cipher handle */ + + struct crypto_skcipher *ctr_handle; /* CTR mode cipher handle */ + struct skcipher_request *ctr_req; /* CTR mode request handle */ + __u8 *outscratchpadbuf; /* CTR mode output scratchpad */ + __u8 *outscratchpad; /* CTR mode aligned outbuf */ + struct crypto_wait ctr_wait; /* CTR mode async wait obj */ + struct scatterlist sg_in, sg_out; /* CTR mode SGLs */ + + enum drbg_seed_state seeded; /* DRBG fully seeded? */ + unsigned long last_seed_time; + bool pr; /* Prediction resistance enabled? */ + struct crypto_rng *jent; + const struct drbg_state_ops *d_ops; + const struct drbg_core *core; + struct drbg_string test_data; +}; + +static inline __u8 drbg_statelen(struct drbg_state *drbg) +{ + if (drbg && drbg->core) + return drbg->core->statelen; + return 0; +} + +static inline __u8 drbg_blocklen(struct drbg_state *drbg) +{ + if (drbg && drbg->core) + return drbg->core->blocklen_bytes; + return 0; +} + +static inline __u8 drbg_keylen(struct drbg_state *drbg) +{ + if (drbg && drbg->core) + return (drbg->core->statelen - drbg->core->blocklen_bytes); + return 0; +} + +static inline size_t drbg_max_request_bytes(struct drbg_state *drbg) +{ + /* SP800-90A requires the limit 2**19 bits, but we return bytes */ + return (1 << 16); +} + +/* + * SP800-90A allows implementations to support additional info / personalization + * strings of up to 2**35 bits. Implementations can have a smaller maximum. We + * use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a + * size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. + */ +static inline size_t drbg_max_addtl(struct drbg_state *drbg) +{ + return U32_MAX - 1; +} + +static inline size_t drbg_max_requests(struct drbg_state *drbg) +{ + /* SP800-90A requires 2**48 maximum requests before reseeding */ + return (1<<20); +} + +/* DRBG type flags */ +#define DRBG_CTR ((drbg_flag_t)1<<0) +#define DRBG_HMAC ((drbg_flag_t)1<<1) +#define DRBG_HASH ((drbg_flag_t)1<<2) +#define DRBG_TYPE_MASK (DRBG_CTR | DRBG_HMAC | DRBG_HASH) +/* DRBG strength flags */ +#define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) +#define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) +#define DRBG_STRENGTH256 ((drbg_flag_t)1<<5) +#define DRBG_STRENGTH_MASK (DRBG_STRENGTH128 | DRBG_STRENGTH192 | \ + DRBG_STRENGTH256) + +enum drbg_prefixes { + DRBG_PREFIX0 = 0x00, + DRBG_PREFIX1, + DRBG_PREFIX2, + DRBG_PREFIX3 +}; + /*************************************************************** * Backend cipher definitions available to DRBG ***************************************************************/ diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 35ff2b50e3c2..480368a41cc0 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -28,13 +28,12 @@ #include #include #include -#include -#include #include #include #include #include #include +#include #include #include "internal.h" diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h deleted file mode 100644 index 4fafc69a8ee6..000000000000 --- a/include/crypto/drbg.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * DRBG based on NIST SP800-90A - * - * Copyright Stephan Mueller , 2014 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -#ifndef _DRBG_H -#define _DRBG_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct drbg_state; -typedef uint32_t drbg_flag_t; - -struct drbg_core { - drbg_flag_t flags; /* flags for the cipher */ - __u8 statelen; /* maximum state length */ - __u8 blocklen_bytes; /* block size of output in bytes */ - char cra_name[CRYPTO_MAX_ALG_NAME]; /* mapping to kernel crypto API */ - /* kernel crypto API backend cipher name */ - char backend_cra_name[CRYPTO_MAX_ALG_NAME]; -}; - -struct drbg_state_ops { - int (*update)(struct drbg_state *drbg, struct list_head *seed, - int reseed); - int (*generate)(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct list_head *addtl); - int (*crypto_init)(struct drbg_state *drbg); - int (*crypto_fini)(struct drbg_state *drbg); - -}; - -enum drbg_seed_state { - DRBG_SEED_STATE_UNSEEDED, - DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ - DRBG_SEED_STATE_FULL, -}; - -struct drbg_state { - struct mutex drbg_mutex; /* lock around DRBG */ - unsigned char *V; /* internal state 10.1.1.1 1a) */ - unsigned char *Vbuf; - /* hash: static value 10.1.1.1 1b) hmac / ctr: key */ - unsigned char *C; - unsigned char *Cbuf; - /* Number of RNG requests since last reseed -- 10.1.1.1 1c) */ - size_t reseed_ctr; - size_t reseed_threshold; - /* some memory the DRBG can use for its operation */ - unsigned char *scratchpad; - unsigned char *scratchpadbuf; - void *priv_data; /* Cipher handle */ - - struct crypto_skcipher *ctr_handle; /* CTR mode cipher handle */ - struct skcipher_request *ctr_req; /* CTR mode request handle */ - __u8 *outscratchpadbuf; /* CTR mode output scratchpad */ - __u8 *outscratchpad; /* CTR mode aligned outbuf */ - struct crypto_wait ctr_wait; /* CTR mode async wait obj */ - struct scatterlist sg_in, sg_out; /* CTR mode SGLs */ - - enum drbg_seed_state seeded; /* DRBG fully seeded? */ - unsigned long last_seed_time; - bool pr; /* Prediction resistance enabled? */ - struct crypto_rng *jent; - const struct drbg_state_ops *d_ops; - const struct drbg_core *core; - struct drbg_string test_data; -}; - -static inline __u8 drbg_statelen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return drbg->core->statelen; - return 0; -} - -static inline __u8 drbg_blocklen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return drbg->core->blocklen_bytes; - return 0; -} - -static inline __u8 drbg_keylen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return (drbg->core->statelen - drbg->core->blocklen_bytes); - return 0; -} - -static inline size_t drbg_max_request_bytes(struct drbg_state *drbg) -{ - /* SP800-90A requires the limit 2**19 bits, but we return bytes */ - return (1 << 16); -} - -/* - * SP800-90A allows implementations to support additional info / personalization - * strings of up to 2**35 bits. Implementations can have a smaller maximum. We - * use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a - * size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. - */ -static inline size_t drbg_max_addtl(struct drbg_state *drbg) -{ - return U32_MAX - 1; -} - -static inline size_t drbg_max_requests(struct drbg_state *drbg) -{ - /* SP800-90A requires 2**48 maximum requests before reseeding */ - return (1<<20); -} - -/* DRBG type flags */ -#define DRBG_CTR ((drbg_flag_t)1<<0) -#define DRBG_HMAC ((drbg_flag_t)1<<1) -#define DRBG_HASH ((drbg_flag_t)1<<2) -#define DRBG_TYPE_MASK (DRBG_CTR | DRBG_HMAC | DRBG_HASH) -/* DRBG strength flags */ -#define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) -#define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) -#define DRBG_STRENGTH256 ((drbg_flag_t)1<<5) -#define DRBG_STRENGTH_MASK (DRBG_STRENGTH128 | DRBG_STRENGTH192 | \ - DRBG_STRENGTH256) - -enum drbg_prefixes { - DRBG_PREFIX0 = 0x00, - DRBG_PREFIX1, - DRBG_PREFIX2, - DRBG_PREFIX3 -}; - -#endif /* _DRBG_H */ diff --git a/tools/testing/crypto/chacha20-s390/test-cipher.c b/tools/testing/crypto/chacha20-s390/test-cipher.c index 827507844e8f..9f61454ed077 100644 --- a/tools/testing/crypto/chacha20-s390/test-cipher.c +++ b/tools/testing/crypto/chacha20-s390/test-cipher.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include From f2e5cd7baea4f1d6fc9fe1a0472b9316eb29b396 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:55 -0700 Subject: [PATCH 129/655] crypto: drbg - Remove import of crypto_cipher functions The inclusion of and the import of the internal crypto namespace became unnecessary in commit ba0570bdf1d9 ("crypto: drbg - Replace AES cipher calls with library calls"). Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index fd1d75addaf7..9dedc6186b42 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -93,7 +93,6 @@ */ #include -#include #include #include #include @@ -1908,4 +1907,3 @@ MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG) " CRYPTO_DRBG_HMAC_STRING CRYPTO_DRBG_CTR_STRING); MODULE_ALIAS_CRYPTO("stdrng"); -MODULE_IMPORT_NS("CRYPTO_INTERNAL"); From 6f88f41eeb7d4ef34e4ddb133d10779a316da67f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:56 -0700 Subject: [PATCH 130/655] crypto: drbg - Remove support for CTR_DRBG Remove the support for CTR_DRBG. It's likely unused code, seeing as HMAC_DRBG is always enabled and prioritized over it unless NETLINK_CRYPTO is used to change the algorithm priorities. There's also no compelling reason to support more than one of [HMAC_DRBG, HASH_DRBG, CTR_DRBG]. By definition, callers cannot tell any difference in their outputs. And all are FIPS-certifiable, which is the only point of the kernel's NIST DRBGs anyway. Switching to CTR_DRBG doesn't seem all that compelling, either. While it's often the fastest NIST DRBG, it has several disadvantages: - CTR_DRBG uses AES. Some platforms don't have AES acceleration at all, causing a fallback to the table-based AES code which is very slow and can be vulnerable to cache-timing attacks. In contrast, HMAC_DRBG uses primitives that are consistently constant-time. - CTR_DRBG is usually considered to be somewhat less cryptographically robust than HMAC_DRBG. Granted, HMAC_DRBG isn't all that great either, e.g. given the negative result from Woodage & Shumow (2018) (https://eprint.iacr.org/2018/349.pdf), but that can be worked around. - CTR_DRBG is more complex than HMAC_DRBG, risking bugs. Indeed, while reviewing the CTR_DRBG code, I found two bugs, including one where it can return success while leaving the output buffer uninitialized. - The kernel's implementation of CTR_DRBG uses an "ctr(aes)" crypto_skcipher and relies on it returning the next counter value. That's fragile, and indeed historically many "ctr(aes)" crypto_skcipher implementations haven't done that. E.g. see commit 511306b2d075 ("crypto: arm/aes-ce - update IV after partial final CTR block"), commit fa5fd3afc7e6 ("crypto: arm64/aes-blk - update IV after partial final CTR block"), commit 371731ec2179 ("crypto: atmel-aes - Fix saving of IV for CTR mode"), commit 25baaf8e2c93 ("crypto: crypto4xx - fix ctr-aes missing output IV"), commit 334d37c9e263 ("crypto: caam - update IV using HW support"), commit 0a4491d3febe ("crypto: chelsio - count incomplete block in IV"), commit e8e3c1ca57d4 ("crypto: s5p - update iv after AES-CBC op end"). I.e., there were many years where the kernel's CTR_DRBG code (if it were to have actually been used) repeated outputs on some platforms. AES-CTR also uses a 128-bit counter, which creates overflow edge cases that are sometimes gotten wrong. E.g. see commit 009b30ac7444 ("crypto: vmx - CTR: always increment IV as quadword"). So, while switching to CTR_DRBG for performance reasons isn't completely out of the question (notably BoringSSL uses it), it would take quite a bit more work to create a solid implementation of it in the kernel, including a more solid implementation of AES-CTR itself (in lib/crypto/, with a scalar bit-sliced fallback, etc). Since HMAC_DRBG has always been the default NIST DRBG variant in the kernel and is in a better state, let's just standardize on it for now. Signed-off-by: Eric Biggers Acked-by: Geert Uytterhoeven # m68k Signed-off-by: Herbert Xu --- arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 - arch/mips/configs/decstation_64_defconfig | 1 - arch/mips/configs/decstation_defconfig | 1 - arch/mips/configs/decstation_r4k_defconfig | 1 - crypto/Kconfig | 8 - crypto/drbg.c | 332 +-------------------- crypto/testmgr.c | 37 --- crypto/testmgr.h | 252 ---------------- include/crypto/internal/drbg.h | 3 + 20 files changed, 9 insertions(+), 638 deletions(-) diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 47e48c18e55c..a8ca9023caf3 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -551,7 +551,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 161586d611ab..5c6610d9e80a 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -506,7 +506,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index c13c6deeac22..4d080f6f3ddf 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -528,7 +528,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index d4f3f94b61ff..c61fc9d13d30 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -498,7 +498,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 58288f83349d..2bc20cfdfcf6 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -508,7 +508,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index abb369fd1f55..e03877efc7e6 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -527,7 +527,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index cb8de979700f..d613bfedee8a 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -614,7 +614,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index 176540bd5074..fe343a8f69f5 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -498,7 +498,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index 8b2e5cf4d2f2..c5803f67f30b 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -499,7 +499,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index d48f3cf5285b..619518c30e0b 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -517,7 +517,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 0b96428f25d4..530fa722e3b2 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -496,7 +496,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index 6140e18244a1..f282e05bc8f9 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -496,7 +496,6 @@ CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/mips/configs/decstation_64_defconfig b/arch/mips/configs/decstation_64_defconfig index 7c43352fac6b..6712143a2842 100644 --- a/arch/mips/configs/decstation_64_defconfig +++ b/arch/mips/configs/decstation_64_defconfig @@ -200,7 +200,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y # CONFIG_CRYPTO_HW is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index aee10274f048..1a31bbb99839 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -195,7 +195,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y diff --git a/arch/mips/configs/decstation_r4k_defconfig b/arch/mips/configs/decstation_r4k_defconfig index a1698049aa7a..8ff71ca43bfb 100644 --- a/arch/mips/configs/decstation_r4k_defconfig +++ b/arch/mips/configs/decstation_r4k_defconfig @@ -195,7 +195,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_DRBG_HASH=y -CONFIG_CRYPTO_DRBG_CTR=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y diff --git a/crypto/Kconfig b/crypto/Kconfig index 34da01c153d6..b16a1aa95c46 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1130,14 +1130,6 @@ config CRYPTO_DRBG_HASH This uses the SHA-1, SHA-256, SHA-384, or SHA-512 hash algorithms. -config CRYPTO_DRBG_CTR - bool "CTR_DRBG" - select CRYPTO_DF80090A - help - CTR_DRBG variant as defined in NIST SP800-90A. - - This uses the AES cipher algorithm with the counter block mode. - config CRYPTO_DRBG tristate default CRYPTO_DRBG_MENU diff --git a/crypto/drbg.c b/crypto/drbg.c index 9dedc6186b42..b29090bb59bc 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -2,7 +2,6 @@ * DRBG: Deterministic Random Bits Generator * Based on NIST Recommended DRBG from NIST SP800-90A with the following * properties: - * * CTR DRBG with DF with AES-128, AES-192, AES-256 cores * * Hash DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores * * with and without prediction resistance @@ -92,17 +91,14 @@ * Just mix both scenarios above. */ -#include #include #include #include -#include #include #include #include #include #include -#include #include #include @@ -139,7 +135,7 @@ struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ unsigned char *V; /* internal state 10.1.1.1 1a) */ unsigned char *Vbuf; - /* hash: static value 10.1.1.1 1b) hmac / ctr: key */ + /* hash: static value 10.1.1.1 1b) hmac: key */ unsigned char *C; unsigned char *Cbuf; /* Number of RNG requests since last reseed -- 10.1.1.1 1c) */ @@ -150,13 +146,6 @@ struct drbg_state { unsigned char *scratchpadbuf; void *priv_data; /* Cipher handle */ - struct crypto_skcipher *ctr_handle; /* CTR mode cipher handle */ - struct skcipher_request *ctr_req; /* CTR mode request handle */ - __u8 *outscratchpadbuf; /* CTR mode output scratchpad */ - __u8 *outscratchpad; /* CTR mode aligned outbuf */ - struct crypto_wait ctr_wait; /* CTR mode async wait obj */ - struct scatterlist sg_in, sg_out; /* CTR mode SGLs */ - enum drbg_seed_state seeded; /* DRBG fully seeded? */ unsigned long last_seed_time; bool pr; /* Prediction resistance enabled? */ @@ -180,13 +169,6 @@ static inline __u8 drbg_blocklen(struct drbg_state *drbg) return 0; } -static inline __u8 drbg_keylen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return (drbg->core->statelen - drbg->core->blocklen_bytes); - return 0; -} - static inline size_t drbg_max_request_bytes(struct drbg_state *drbg) { /* SP800-90A requires the limit 2**19 bits, but we return bytes */ @@ -211,10 +193,9 @@ static inline size_t drbg_max_requests(struct drbg_state *drbg) } /* DRBG type flags */ -#define DRBG_CTR ((drbg_flag_t)1<<0) #define DRBG_HMAC ((drbg_flag_t)1<<1) #define DRBG_HASH ((drbg_flag_t)1<<2) -#define DRBG_TYPE_MASK (DRBG_CTR | DRBG_HMAC | DRBG_HASH) +#define DRBG_TYPE_MASK (DRBG_HMAC | DRBG_HASH) /* DRBG strength flags */ #define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) #define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) @@ -238,32 +219,9 @@ enum drbg_prefixes { * as stdrng. Each DRBG receives an increasing cra_priority values the later * they are defined in this array (see drbg_fill_array). * - * HMAC DRBGs are favored over Hash DRBGs over CTR DRBGs, and the - * HMAC-SHA512 / SHA256 / AES 256 over other ciphers. Thus, the - * favored DRBGs are the latest entries in this array. + * Thus, the favored DRBGs are the latest entries in this array. */ static const struct drbg_core drbg_cores[] = { -#ifdef CONFIG_CRYPTO_DRBG_CTR - { - .flags = DRBG_CTR | DRBG_STRENGTH128, - .statelen = 32, /* 256 bits as defined in 10.2.1 */ - .blocklen_bytes = 16, - .cra_name = "ctr_aes128", - .backend_cra_name = "aes", - }, { - .flags = DRBG_CTR | DRBG_STRENGTH192, - .statelen = 40, /* 320 bits as defined in 10.2.1 */ - .blocklen_bytes = 16, - .cra_name = "ctr_aes192", - .backend_cra_name = "aes", - }, { - .flags = DRBG_CTR | DRBG_STRENGTH256, - .statelen = 48, /* 384 bits as defined in 10.2.1 */ - .blocklen_bytes = 16, - .cra_name = "ctr_aes256", - .backend_cra_name = "aes", - }, -#endif /* CONFIG_CRYPTO_DRBG_CTR */ #ifdef CONFIG_CRYPTO_DRBG_HASH { .flags = DRBG_HASH | DRBG_STRENGTH256, @@ -334,147 +292,6 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags) } } -/****************************************************************** - * CTR DRBG callback functions - ******************************************************************/ - -#ifdef CONFIG_CRYPTO_DRBG_CTR -#define CRYPTO_DRBG_CTR_STRING "CTR " -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes256"); -MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes256"); -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes192"); -MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes192"); -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes128"); -MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes128"); - -static int drbg_init_sym_kernel(struct drbg_state *drbg); -static int drbg_fini_sym_kernel(struct drbg_state *drbg); -static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, - u8 *inbuf, u32 inbuflen, - u8 *outbuf, u32 outlen); -#define DRBG_OUTSCRATCHLEN 256 - -static int drbg_ctr_df(struct drbg_state *drbg, - unsigned char *df_data, size_t bytes_to_return, - struct list_head *seedlist) -{ - return crypto_drbg_ctr_df(drbg->priv_data, df_data, drbg_statelen(drbg), - seedlist, drbg_blocklen(drbg), drbg_statelen(drbg)); -} - -/* - * update function of CTR DRBG as defined in 10.2.1.2 - * - * The reseed variable has an enhanced meaning compared to the update - * functions of the other DRBGs as follows: - * 0 => initial seed from initialization - * 1 => reseed via drbg_seed - * 2 => first invocation from drbg_ctr_update when addtl is present. In - * this case, the df_data scratchpad is not deleted so that it is - * available for another calls to prevent calling the DF function - * again. - * 3 => second invocation from drbg_ctr_update. When the update function - * was called with addtl, the df_data memory already contains the - * DFed addtl information and we do not need to call DF again. - */ -static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) -{ - int ret = -EFAULT; - /* 10.2.1.2 step 1 */ - unsigned char *temp = drbg->scratchpad; - unsigned char *df_data = drbg->scratchpad + drbg_statelen(drbg) + - drbg_blocklen(drbg); - - if (3 > reseed) - memset(df_data, 0, drbg_statelen(drbg)); - - if (!reseed) { - /* - * The DRBG uses the CTR mode of the underlying AES cipher. The - * CTR mode increments the counter value after the AES operation - * but SP800-90A requires that the counter is incremented before - * the AES operation. Hence, we increment it at the time we set - * it by one. - */ - crypto_inc(drbg->V, drbg_blocklen(drbg)); - - ret = crypto_skcipher_setkey(drbg->ctr_handle, drbg->C, - drbg_keylen(drbg)); - if (ret) - goto out; - } - - /* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */ - if (seed) { - ret = drbg_ctr_df(drbg, df_data, drbg_statelen(drbg), seed); - if (ret) - goto out; - } - - ret = drbg_kcapi_sym_ctr(drbg, df_data, drbg_statelen(drbg), - temp, drbg_statelen(drbg)); - if (ret) - return ret; - - /* 10.2.1.2 step 5 */ - ret = crypto_skcipher_setkey(drbg->ctr_handle, temp, - drbg_keylen(drbg)); - if (ret) - goto out; - /* 10.2.1.2 step 6 */ - memcpy(drbg->V, temp + drbg_keylen(drbg), drbg_blocklen(drbg)); - /* See above: increment counter by one to compensate timing of CTR op */ - crypto_inc(drbg->V, drbg_blocklen(drbg)); - ret = 0; - -out: - memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg)); - if (2 != reseed) - memset(df_data, 0, drbg_statelen(drbg)); - return ret; -} - -/* - * scratchpad use: drbg_ctr_update is called independently from - * drbg_ctr_extract_bytes. Therefore, the scratchpad is reused - */ -/* Generate function of CTR DRBG as defined in 10.2.1.5.2 */ -static int drbg_ctr_generate(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct list_head *addtl) -{ - int ret; - int len = min_t(int, buflen, INT_MAX); - - /* 10.2.1.5.2 step 2 */ - if (addtl && !list_empty(addtl)) { - ret = drbg_ctr_update(drbg, addtl, 2); - if (ret) - return ret; - } - - /* 10.2.1.5.2 step 4.1 */ - ret = drbg_kcapi_sym_ctr(drbg, NULL, 0, buf, len); - if (ret) - return ret; - - /* 10.2.1.5.2 step 6 */ - ret = drbg_ctr_update(drbg, NULL, 3); - if (ret) - len = ret; - - return len; -} - -static const struct drbg_state_ops drbg_ctr_ops = { - .update = drbg_ctr_update, - .generate = drbg_ctr_generate, - .crypto_init = drbg_init_sym_kernel, - .crypto_fini = drbg_fini_sym_kernel, -}; -#endif /* CONFIG_CRYPTO_DRBG_CTR */ - /****************************************************************** * HMAC DRBG callback functions ******************************************************************/ @@ -1108,11 +925,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) drbg->d_ops = &drbg_hash_ops; break; #endif /* CONFIG_CRYPTO_DRBG_HASH */ -#ifdef CONFIG_CRYPTO_DRBG_CTR - case DRBG_CTR: - drbg->d_ops = &drbg_ctr_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_CTR */ default: ret = -EOPNOTSUPP; goto err; @@ -1134,13 +946,9 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) goto fini; } drbg->C = PTR_ALIGN(drbg->Cbuf, ret + 1); - /* scratchpad is only generated for CTR and Hash */ + /* scratchpad is only generated for Hash */ if (drbg->core->flags & DRBG_HMAC) sb_size = 0; - else if (drbg->core->flags & DRBG_CTR) - sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg) + /* temp */ - crypto_drbg_ctr_df_datalen(drbg_statelen(drbg), - drbg_blocklen(drbg)); else sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg); @@ -1253,7 +1061,7 @@ static int drbg_generate(struct drbg_state *drbg, /* 9.3.1 step 8 and 10 */ len = drbg->d_ops->generate(drbg, buf, buflen, &addtllist); - /* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */ + /* 10.1.1.4 step 6, 10.1.2.5 step 7 */ drbg->reseed_ctr++; if (0 >= len) goto err; @@ -1504,127 +1312,6 @@ static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, return crypto_shash_final(&sdesc->shash, outval); } -#ifdef CONFIG_CRYPTO_DRBG_CTR -static int drbg_fini_sym_kernel(struct drbg_state *drbg) -{ - struct aes_enckey *aeskey = drbg->priv_data; - - kfree(aeskey); - drbg->priv_data = NULL; - - if (drbg->ctr_handle) - crypto_free_skcipher(drbg->ctr_handle); - drbg->ctr_handle = NULL; - - if (drbg->ctr_req) - skcipher_request_free(drbg->ctr_req); - drbg->ctr_req = NULL; - - kfree(drbg->outscratchpadbuf); - drbg->outscratchpadbuf = NULL; - - return 0; -} - -static int drbg_init_sym_kernel(struct drbg_state *drbg) -{ - struct aes_enckey *aeskey; - struct crypto_skcipher *sk_tfm; - struct skcipher_request *req; - unsigned int alignmask; - char ctr_name[CRYPTO_MAX_ALG_NAME]; - - aeskey = kzalloc_obj(*aeskey); - if (!aeskey) - return -ENOMEM; - drbg->priv_data = aeskey; - - if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", - drbg->core->backend_cra_name) >= CRYPTO_MAX_ALG_NAME) { - drbg_fini_sym_kernel(drbg); - return -EINVAL; - } - sk_tfm = crypto_alloc_skcipher(ctr_name, 0, 0); - if (IS_ERR(sk_tfm)) { - pr_info("DRBG: could not allocate CTR cipher TFM handle: %s\n", - ctr_name); - drbg_fini_sym_kernel(drbg); - return PTR_ERR(sk_tfm); - } - drbg->ctr_handle = sk_tfm; - crypto_init_wait(&drbg->ctr_wait); - - req = skcipher_request_alloc(sk_tfm, GFP_KERNEL); - if (!req) { - pr_info("DRBG: could not allocate request queue\n"); - drbg_fini_sym_kernel(drbg); - return -ENOMEM; - } - drbg->ctr_req = req; - skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &drbg->ctr_wait); - - alignmask = crypto_skcipher_alignmask(sk_tfm); - drbg->outscratchpadbuf = kmalloc(DRBG_OUTSCRATCHLEN + alignmask, - GFP_KERNEL); - if (!drbg->outscratchpadbuf) { - drbg_fini_sym_kernel(drbg); - return -ENOMEM; - } - drbg->outscratchpad = (u8 *)PTR_ALIGN(drbg->outscratchpadbuf, - alignmask + 1); - - sg_init_table(&drbg->sg_in, 1); - sg_init_one(&drbg->sg_out, drbg->outscratchpad, DRBG_OUTSCRATCHLEN); - - return alignmask; -} - -static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, - u8 *inbuf, u32 inlen, - u8 *outbuf, u32 outlen) -{ - struct scatterlist *sg_in = &drbg->sg_in, *sg_out = &drbg->sg_out; - u32 scratchpad_use = min_t(u32, outlen, DRBG_OUTSCRATCHLEN); - int ret; - - if (inbuf) { - /* Use caller-provided input buffer */ - sg_set_buf(sg_in, inbuf, inlen); - } else { - /* Use scratchpad for in-place operation */ - inlen = scratchpad_use; - memset(drbg->outscratchpad, 0, scratchpad_use); - sg_set_buf(sg_in, drbg->outscratchpad, scratchpad_use); - } - - while (outlen) { - u32 cryptlen = min3(inlen, outlen, (u32)DRBG_OUTSCRATCHLEN); - - /* Output buffer may not be valid for SGL, use scratchpad */ - skcipher_request_set_crypt(drbg->ctr_req, sg_in, sg_out, - cryptlen, drbg->V); - ret = crypto_wait_req(crypto_skcipher_encrypt(drbg->ctr_req), - &drbg->ctr_wait); - if (ret) - goto out; - - crypto_init_wait(&drbg->ctr_wait); - - memcpy(outbuf, drbg->outscratchpad, cryptlen); - memzero_explicit(drbg->outscratchpad, cryptlen); - - outlen -= cryptlen; - outbuf += cryptlen; - } - ret = 0; - -out: - return ret; -} -#endif /* CONFIG_CRYPTO_DRBG_CTR */ - /*************************************************************** * Kernel crypto API interface to register DRBG ***************************************************************/ @@ -1762,9 +1449,6 @@ static inline int __init drbg_healthcheck_sanity(void) if (!fips_enabled) return 0; -#ifdef CONFIG_CRYPTO_DRBG_CTR - drbg_convert_tfm_core("drbg_nopr_ctr_aes256", &coreref, &pr); -#endif #ifdef CONFIG_CRYPTO_DRBG_HASH drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); #endif @@ -1896,14 +1580,10 @@ module_exit(drbg_exit); #ifndef CRYPTO_DRBG_HASH_STRING #define CRYPTO_DRBG_HASH_STRING "" #endif -#ifndef CRYPTO_DRBG_CTR_STRING -#define CRYPTO_DRBG_CTR_STRING "" -#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Stephan Mueller "); MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG) " "using following cores: " CRYPTO_DRBG_HASH_STRING - CRYPTO_DRBG_HMAC_STRING - CRYPTO_DRBG_CTR_STRING); + CRYPTO_DRBG_HMAC_STRING); MODULE_ALIAS_CRYPTO("stdrng"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 480368a41cc0..dbc1e1fb4bd0 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4638,27 +4638,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "digest_null", .test = alg_test_null, - }, { - .alg = "drbg_nopr_ctr_aes128", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_ctr_aes128_tv_template) - } - }, { - .alg = "drbg_nopr_ctr_aes192", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_ctr_aes192_tv_template) - } - }, { - .alg = "drbg_nopr_ctr_aes256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_ctr_aes256_tv_template) - } }, { .alg = "drbg_nopr_hmac_sha256", .test = alg_test_drbg, @@ -4697,22 +4676,6 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_nopr_sha512", .fips_allowed = 1, .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes128", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_ctr_aes128_tv_template) - } - }, { - /* covered by drbg_pr_ctr_aes128 test */ - .alg = "drbg_pr_ctr_aes192", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes256", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_hmac_sha256", .test = alg_test_drbg, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 9b4d7e11c9fd..a86275b61b6a 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -23746,122 +23746,6 @@ static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { }, }; -static const struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { - { - .entropy = (unsigned char *) - "\xd1\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" - "\x94\xd7\x28\x9c\x43\x77\x19\x29\x1a\x6d\xc3\xa2", - .entropylen = 24, - .entpra = (unsigned char *) - "\x96\xd8\x9e\x45\x32\xc9\xd2\x08\x7a\x6d\x97\x15" - "\xb4\xec\x80\xb1", - .entprb = (unsigned char *) - "\x8b\xb6\x72\xb5\x24\x0b\x98\x65\x95\x95\xe9\xc9" - "\x28\x07\xeb\xc2", - .entprlen = 16, - .expected = (unsigned char *) - "\x70\x19\xd0\x4c\x45\x78\xd6\x68\xa9\x9a\xaa\xfe" - "\xc1\xdf\x27\x9a\x1c\x0d\x0d\xf7\x24\x75\x46\xcc" - "\x77\x6b\xdf\x89\xc6\x94\xdc\x74\x50\x10\x70\x18" - "\x9b\xdc\x96\xb4\x89\x23\x40\x1a\xce\x09\x87\xce" - "\xd2\xf3\xd5\xe4\x51\x67\x74\x11\x5a\xcc\x8b\x3b" - "\x8a\xf1\x23\xa8", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x8e\x83\xe0\xeb\x37\xea\x3e\x53\x5e\x17\x6e\x77" - "\xbd\xb1\x53\x90\xfc\xdc\xc1\x3c\x9a\x88\x22\x94", - .entropylen = 24, - .entpra = (unsigned char *) - "\x6a\x85\xe7\x37\xc8\xf1\x04\x31\x98\x4f\xc8\x73" - "\x67\xd1\x08\xf8", - .entprb = (unsigned char *) - "\xd7\xa4\x68\xe2\x12\x74\xc3\xd9\xf1\xb7\x05\xbc" - "\xd4\xba\x04\x58", - .entprlen = 16, - .expected = (unsigned char *) - "\x78\xd6\xa6\x70\xff\xd1\x82\xf5\xa2\x88\x7f\x6d" - "\x3d\x8c\x39\xb1\xa8\xcb\x2c\x91\xab\x14\x7e\xbc" - "\x95\x45\x9f\x24\xb8\x20\xac\x21\x23\xdb\x72\xd7" - "\x12\x8d\x48\x95\xf3\x19\x0c\x43\xc6\x19\x45\xfc" - "\x8b\xac\x40\x29\x73\x00\x03\x45\x5e\x12\xff\x0c" - "\xc1\x02\x41\x82", - .expectedlen = 64, - .addtla = (unsigned char *) - "\xa2\xd9\x38\xcf\x8b\x29\x67\x5b\x65\x62\x6f\xe8" - "\xeb\xb3\x01\x76", - .addtlb = (unsigned char *) - "\x59\x63\x1e\x81\x8a\x14\xa8\xbb\xa1\xb8\x41\x25" - "\xd0\x7f\xcc\x43", - .addtllen = 16, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x04\xd9\x49\xa6\xdc\xe8\x6e\xbb\xf1\x08\x77\x2b" - "\x9e\x08\xca\x92\x65\x16\xda\x99\xa2\x59\xf3\xe8", - .entropylen = 24, - .entpra = (unsigned char *) - "\x38\x7e\x3f\x6b\x51\x70\x7b\x20\xec\x53\xd0\x66" - "\xc3\x0f\xe3\xb0", - .entprb = (unsigned char *) - "\xe0\x86\xa6\xaa\x5f\x72\x2f\xad\xf7\xef\x06\xb8" - "\xd6\x9c\x9d\xe8", - .entprlen = 16, - .expected = (unsigned char *) - "\xc9\x0a\xaf\x85\x89\x71\x44\x66\x4f\x25\x0b\x2b" - "\xde\xd8\xfa\xff\x52\x5a\x1b\x32\x5e\x41\x7a\x10" - "\x1f\xef\x1e\x62\x23\xe9\x20\x30\xc9\x0d\xad\x69" - "\xb4\x9c\x5b\xf4\x87\x42\xd5\xae\x5e\x5e\x43\xcc" - "\xd9\xfd\x0b\x93\x4a\xe3\xd4\x06\x37\x36\x0f\x3f" - "\x72\x82\x0c\xcf", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xbf\xa4\x9a\x8f\x7b\xd8\xb1\x7a\x9d\xfa\x45\xed" - "\x21\x52\xb3\xad", - .perslen = 16, - }, { - .entropy = (unsigned char *) - "\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06" - "\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97", - .entropylen = 24, - .entpra = (unsigned char *) - "\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7" - "\xc4\x2c\xe8\x10", - .entprb = (unsigned char *) - "\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22" - "\x08\xf7\xa5\x01", - .entprlen = 16, - .expected = (unsigned char *) - "\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71" - "\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28" - "\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45" - "\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08" - "\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4" - "\x23\xc5\x1f\x68", - .expectedlen = 64, - .addtla = (unsigned char *) - "\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59" - "\x23\x6d\xad\x1d", - .addtlb = (unsigned char *) - "\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12" - "\xbc\x59\x31\x8c", - .addtllen = 16, - .pers = (unsigned char *) - "\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4" - "\x37\x3c\x5c\x0b", - .perslen = 16, - }, -}; - /* * SP800-90A DRBG Test vectors from * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip @@ -24163,142 +24047,6 @@ static const struct drbg_testvec drbg_nopr_hmac_sha512_tv_template[] = { } }; -static const struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { - { - .entropy = (unsigned char *) - "\xc3\x5c\x2f\xa2\xa8\x9d\x52\xa1\x1f\xa3\x2a\xa9" - "\x6c\x95\xb8\xf1\xc9\xa8\xf9\xcb\x24\x5a\x8b\x40" - "\xf3\xa6\xe5\xa7\xfb\xd9\xd3\xc6\x8e\x27\x7b\xa9" - "\xac\x9b\xbb\x00", - .entropylen = 40, - .expected = (unsigned char *) - "\x8c\x2e\x72\xab\xfd\x9b\xb8\x28\x4d\xb7\x9e\x17" - "\xa4\x3a\x31\x46\xcd\x76\x94\xe3\x52\x49\xfc\x33" - "\x83\x91\x4a\x71\x17\xf4\x13\x68\xe6\xd4\xf1\x48" - "\xff\x49\xbf\x29\x07\x6b\x50\x15\xc5\x9f\x45\x79" - "\x45\x66\x2e\x3d\x35\x03\x84\x3f\x4a\xa5\xa3\xdf" - "\x9a\x9d\xf1\x0d", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, -}; - -static const struct drbg_testvec drbg_nopr_ctr_aes256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x36\x40\x19\x40\xfa\x8b\x1f\xba\x91\xa1\x66\x1f" - "\x21\x1d\x78\xa0\xb9\x38\x9a\x74\xe5\xbc\xcf\xec" - "\xe8\xd7\x66\xaf\x1a\x6d\x3b\x14\x49\x6f\x25\xb0" - "\xf1\x30\x1b\x4f\x50\x1b\xe3\x03\x80\xa1\x37\xeb", - .entropylen = 48, - .expected = (unsigned char *) - "\x58\x62\xeb\x38\xbd\x55\x8d\xd9\x78\xa6\x96\xe6" - "\xdf\x16\x47\x82\xdd\xd8\x87\xe7\xe9\xa6\xc9\xf3" - "\xf1\xfb\xaf\xb7\x89\x41\xb5\x35\xa6\x49\x12\xdf" - "\xd2\x24\xc6\xdc\x74\x54\xe5\x25\x0b\x3d\x97\x16" - "\x5e\x16\x26\x0c\x2f\xaf\x1c\xc7\x73\x5c\xb7\x5f" - "\xb4\xf0\x7e\x1d", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, -}; - -static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { - { - .entropy = (unsigned char *) - "\x87\xe1\xc5\x32\x99\x7f\x57\xa3\x5c\x28\x6d\xe8" - "\x64\xbf\xf2\x64\xa3\x9e\x98\xdb\x6c\x10\x78\x7f", - .entropylen = 24, - .expected = (unsigned char *) - "\x2c\x14\x7e\x24\x11\x9a\xd8\xd4\xb2\xed\x61\xc1" - "\x53\xd0\x50\xc9\x24\xff\x59\x75\x15\xf1\x17\x3a" - "\x3d\xf4\x4b\x2c\x84\x28\xef\x89\x0e\xb9\xde\xf3" - "\xe4\x78\x04\xb2\xfd\x9b\x35\x7f\xe1\x3f\x8a\x3e" - "\x10\xc8\x67\x0a\xf9\xdf\x2d\x6c\x96\xfb\xb2\xb8" - "\xcb\x2d\xd6\xb0", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x71\xbd\xce\x35\x42\x7d\x20\xbf\x58\xcf\x17\x74" - "\xce\x72\xd8\x33\x34\x50\x2d\x8f\x5b\x14\xc4\xdd", - .entropylen = 24, - .expected = (unsigned char *) - "\x97\x33\xe8\x20\x12\xe2\x7b\xa1\x46\x8f\xf2\x34" - "\xb3\xc9\xb6\x6b\x20\xb2\x4f\xee\x27\xd8\x0b\x21" - "\x8c\xff\x63\x73\x69\x29\xfb\xf3\x85\xcd\x88\x8e" - "\x43\x2c\x71\x8b\xa2\x55\xd2\x0f\x1d\x7f\xe3\xe1" - "\x2a\xa3\xe9\x2c\x25\x89\xc7\x14\x52\x99\x56\xcc" - "\xc3\xdf\xb3\x81", - .expectedlen = 64, - .addtla = (unsigned char *) - "\x66\xef\x42\xd6\x9a\x8c\x3d\x6d\x4a\x9e\x95\xa6" - "\x91\x4d\x81\x56", - .addtlb = (unsigned char *) - "\xe3\x18\x83\xd9\x4b\x5e\xc4\xcc\xaa\x61\x2f\xbb" - "\x4a\x55\xd1\xc6", - .addtllen = 16, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xca\x4b\x1e\xfa\x75\xbd\x69\x36\x38\x73\xb8\xf9" - "\xdb\x4d\x35\x0e\x47\xbf\x6c\x37\x72\xfd\xf7\xa9", - .entropylen = 24, - .expected = (unsigned char *) - "\x59\xc3\x19\x79\x1b\xb1\xf3\x0e\xe9\x34\xae\x6e" - "\x8b\x1f\xad\x1f\x74\xca\x25\x45\x68\xb8\x7f\x75" - "\x12\xf8\xf2\xab\x4c\x23\x01\x03\x05\xe1\x70\xee" - "\x75\xd8\xcb\xeb\x23\x4c\x7a\x23\x6e\x12\x27\xdb" - "\x6f\x7a\xac\x3c\x44\xb7\x87\x4b\x65\x56\x74\x45" - "\x34\x30\x0c\x3d", - .expectedlen = 64, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xeb\xaa\x60\x2c\x4d\xbe\x33\xff\x1b\xef\xbf\x0a" - "\x0b\xc6\x97\x54", - .perslen = 16, - }, { - .entropy = (unsigned char *) - "\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98" - "\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6", - .entropylen = 24, - .expected = (unsigned char *) - "\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a" - "\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95" - "\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f" - "\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a" - "\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a" - "\x2b\x49\x1e\x5c", - .expectedlen = 64, - .addtla = (unsigned char *) - "\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2" - "\x44\x85\xe7\xfe", - .addtlb = (unsigned char *) - "\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4" - "\x82\x16\x62\x7f", - .addtllen = 16, - .pers = (unsigned char *) - "\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f" - "\x8e\xcf\xe0\x02", - .perslen = 16, - }, -}; - /* Cast5 test vectors from RFC 2144 */ static const struct cipher_testvec cast5_tv_template[] = { { diff --git a/include/crypto/internal/drbg.h b/include/crypto/internal/drbg.h index b4e5ef0be602..5d4174cc6a53 100644 --- a/include/crypto/internal/drbg.h +++ b/include/crypto/internal/drbg.h @@ -9,6 +9,9 @@ #ifndef _INTERNAL_DRBG_H #define _INTERNAL_DRBG_H +#include +#include + /* * Concatenation Helper and string operation helper * From e227be3ffde0ec8063c9967062a43237a5545581 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:57 -0700 Subject: [PATCH 131/655] crypto: drbg - Remove support for HASH_DRBG Remove the support for HASH_DRBG. It's likely unused code, seeing as HMAC_DRBG is always enabled and prioritized over it unless NETLINK_CRYPTO is used to change the algorithm priorities. There's also no compelling reason to support more than one of [HMAC_DRBG, HASH_DRBG, CTR_DRBG]. By definition, callers cannot tell any difference in their outputs. And all are FIPS-certifiable, which is the only point of the kernel's NIST DRBGs anyway. Switching to HASH_DRBG doesn't seem all that compelling, either. For one, it's more complex than HMAC_DRBG. Thus, let's just drop HASH_DRBG support and focus on HMAC_DRBG. Signed-off-by: Eric Biggers Acked-by: Geert Uytterhoeven # m68k Signed-off-by: Herbert Xu --- Documentation/crypto/api-samples.rst | 2 +- Documentation/crypto/userspace-if.rst | 2 +- arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 - arch/mips/configs/decstation_64_defconfig | 1 - arch/mips/configs/decstation_defconfig | 1 - arch/mips/configs/decstation_r4k_defconfig | 1 - crypto/Kconfig | 8 - crypto/drbg.c | 348 +-------------------- crypto/testmgr.c | 32 -- crypto/testmgr.h | 296 ------------------ 21 files changed, 8 insertions(+), 695 deletions(-) diff --git a/Documentation/crypto/api-samples.rst b/Documentation/crypto/api-samples.rst index e923f17bc2bd..388bb7d7a460 100644 --- a/Documentation/crypto/api-samples.rst +++ b/Documentation/crypto/api-samples.rst @@ -159,7 +159,7 @@ Code Example For Random Number Generator Usage static int get_random_numbers(u8 *buf, unsigned int len) { struct crypto_rng *rng = NULL; - char *drbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */ + char *drbg = "stdrng"; int ret; if (!buf || !len) { diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst index 021759198fe7..a3b13ff83cb3 100644 --- a/Documentation/crypto/userspace-if.rst +++ b/Documentation/crypto/userspace-if.rst @@ -297,7 +297,7 @@ follows: struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "rng", /* this selects the random number generator */ - .salg_name = "drbg_nopr_sha256" /* this is the RNG name */ + .salg_name = "stdrng" /* this is the RNG name */ }; diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index a8ca9023caf3..a886494c5a30 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -550,7 +550,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 5c6610d9e80a..14c6298b1175 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -505,7 +505,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 4d080f6f3ddf..86a5c69b3655 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -527,7 +527,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index c61fc9d13d30..b3828dc6ee25 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -497,7 +497,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 2bc20cfdfcf6..6b890c6bcf35 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -507,7 +507,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index e03877efc7e6..1a7694486c08 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -526,7 +526,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index d613bfedee8a..468f0dab58ad 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -613,7 +613,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index fe343a8f69f5..ef6e94e5abcd 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -497,7 +497,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index c5803f67f30b..cdb8cb030c33 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -498,7 +498,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index 619518c30e0b..a6af67707e9e 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -516,7 +516,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 530fa722e3b2..1d8233ebb454 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -495,7 +495,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index f282e05bc8f9..8366a1d850b0 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -495,7 +495,6 @@ CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m CONFIG_CRYPTO_ZSTD=m -CONFIG_CRYPTO_DRBG_HASH=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m diff --git a/arch/mips/configs/decstation_64_defconfig b/arch/mips/configs/decstation_64_defconfig index 6712143a2842..509515cf4751 100644 --- a/arch/mips/configs/decstation_64_defconfig +++ b/arch/mips/configs/decstation_64_defconfig @@ -199,7 +199,6 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m -CONFIG_CRYPTO_DRBG_HASH=y # CONFIG_CRYPTO_HW is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_FTRACE is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index 1a31bbb99839..3a17c080292f 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -194,7 +194,6 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m -CONFIG_CRYPTO_DRBG_HASH=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y diff --git a/arch/mips/configs/decstation_r4k_defconfig b/arch/mips/configs/decstation_r4k_defconfig index 8ff71ca43bfb..7f5823663702 100644 --- a/arch/mips/configs/decstation_r4k_defconfig +++ b/arch/mips/configs/decstation_r4k_defconfig @@ -194,7 +194,6 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_842=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m -CONFIG_CRYPTO_DRBG_HASH=y # CONFIG_CRYPTO_HW is not set CONFIG_FRAME_WARN=2048 CONFIG_MAGIC_SYSRQ=y diff --git a/crypto/Kconfig b/crypto/Kconfig index b16a1aa95c46..14519474a67b 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1122,14 +1122,6 @@ menuconfig CRYPTO_DRBG_MENU if CRYPTO_DRBG_MENU -config CRYPTO_DRBG_HASH - bool "Hash_DRBG" - select CRYPTO_SHA256 - help - Hash_DRBG variant as defined in NIST SP800-90A. - - This uses the SHA-1, SHA-256, SHA-384, or SHA-512 hash algorithms. - config CRYPTO_DRBG tristate default CRYPTO_DRBG_MENU diff --git a/crypto/drbg.c b/crypto/drbg.c index b29090bb59bc..6301eb2e304c 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -2,7 +2,6 @@ * DRBG: Deterministic Random Bits Generator * Based on NIST Recommended DRBG from NIST SP800-90A with the following * properties: - * * Hash DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores * * with and without prediction resistance * @@ -133,17 +132,13 @@ enum drbg_seed_state { struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ - unsigned char *V; /* internal state 10.1.1.1 1a) */ + unsigned char *V; /* internal state -- 10.1.2.1 1a */ unsigned char *Vbuf; - /* hash: static value 10.1.1.1 1b) hmac: key */ - unsigned char *C; + unsigned char *C; /* current key -- 10.1.2.1 1b */ unsigned char *Cbuf; - /* Number of RNG requests since last reseed -- 10.1.1.1 1c) */ + /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr; size_t reseed_threshold; - /* some memory the DRBG can use for its operation */ - unsigned char *scratchpad; - unsigned char *scratchpadbuf; void *priv_data; /* Cipher handle */ enum drbg_seed_state seeded; /* DRBG fully seeded? */ @@ -194,8 +189,7 @@ static inline size_t drbg_max_requests(struct drbg_state *drbg) /* DRBG type flags */ #define DRBG_HMAC ((drbg_flag_t)1<<1) -#define DRBG_HASH ((drbg_flag_t)1<<2) -#define DRBG_TYPE_MASK (DRBG_HMAC | DRBG_HASH) +#define DRBG_TYPE_MASK DRBG_HMAC /* DRBG strength flags */ #define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) #define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) @@ -206,8 +200,6 @@ static inline size_t drbg_max_requests(struct drbg_state *drbg) enum drbg_prefixes { DRBG_PREFIX0 = 0x00, DRBG_PREFIX1, - DRBG_PREFIX2, - DRBG_PREFIX3 }; /*************************************************************** @@ -222,27 +214,6 @@ enum drbg_prefixes { * Thus, the favored DRBGs are the latest entries in this array. */ static const struct drbg_core drbg_cores[] = { -#ifdef CONFIG_CRYPTO_DRBG_HASH - { - .flags = DRBG_HASH | DRBG_STRENGTH256, - .statelen = 111, /* 888 bits */ - .blocklen_bytes = 48, - .cra_name = "sha384", - .backend_cra_name = "sha384", - }, { - .flags = DRBG_HASH | DRBG_STRENGTH256, - .statelen = 111, /* 888 bits */ - .blocklen_bytes = 64, - .cra_name = "sha512", - .backend_cra_name = "sha512", - }, { - .flags = DRBG_HASH | DRBG_STRENGTH256, - .statelen = 55, /* 440 bits */ - .blocklen_bytes = 32, - .cra_name = "sha256", - .backend_cra_name = "sha256", - }, -#endif /* CONFIG_CRYPTO_DRBG_HASH */ { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 48, /* block length of cipher */ @@ -303,7 +274,6 @@ static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, static int drbg_init_hash_kernel(struct drbg_state *drbg); static int drbg_fini_hash_kernel(struct drbg_state *drbg); -#define CRYPTO_DRBG_HMAC_STRING "HMAC " MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha384"); @@ -415,280 +385,6 @@ static const struct drbg_state_ops drbg_hmac_ops = { .crypto_fini = drbg_fini_hash_kernel, }; -/****************************************************************** - * Hash DRBG callback functions - ******************************************************************/ - -#ifdef CONFIG_CRYPTO_DRBG_HASH -#define CRYPTO_DRBG_HASH_STRING "HASH " -MODULE_ALIAS_CRYPTO("drbg_pr_sha512"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha512"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha384"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha384"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha256"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha256"); - -/* - * Increment buffer - * - * @dst buffer to increment - * @add value to add - */ -static inline void drbg_add_buf(unsigned char *dst, size_t dstlen, - const unsigned char *add, size_t addlen) -{ - /* implied: dstlen > addlen */ - unsigned char *dstptr; - const unsigned char *addptr; - unsigned int remainder = 0; - size_t len = addlen; - - dstptr = dst + (dstlen-1); - addptr = add + (addlen-1); - while (len) { - remainder += *dstptr + *addptr; - *dstptr = remainder & 0xff; - remainder >>= 8; - len--; dstptr--; addptr--; - } - len = dstlen - addlen; - while (len && remainder > 0) { - remainder = *dstptr + 1; - *dstptr = remainder & 0xff; - remainder >>= 8; - len--; dstptr--; - } -} - -/* - * scratchpad usage: as drbg_hash_update and drbg_hash_df are used - * interlinked, the scratchpad is used as follows: - * drbg_hash_update - * start: drbg->scratchpad - * length: drbg_statelen(drbg) - * drbg_hash_df: - * start: drbg->scratchpad + drbg_statelen(drbg) - * length: drbg_blocklen(drbg) - * - * drbg_hash_process_addtl uses the scratchpad, but fully completes - * before either of the functions mentioned before are invoked. Therefore, - * drbg_hash_process_addtl does not need to be specifically considered. - */ - -/* Derivation Function for Hash DRBG as defined in 10.4.1 */ -static int drbg_hash_df(struct drbg_state *drbg, - unsigned char *outval, size_t outlen, - struct list_head *entropylist) -{ - int ret = 0; - size_t len = 0; - unsigned char input[5]; - unsigned char *tmp = drbg->scratchpad + drbg_statelen(drbg); - struct drbg_string data; - - /* 10.4.1 step 3 */ - input[0] = 1; - put_unaligned_be32(outlen * 8, &input[1]); - - /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ - drbg_string_fill(&data, input, 5); - list_add(&data.list, entropylist); - - /* 10.4.1 step 4 */ - while (len < outlen) { - short blocklen = 0; - /* 10.4.1 step 4.1 */ - ret = drbg_kcapi_hash(drbg, tmp, entropylist); - if (ret) - goto out; - /* 10.4.1 step 4.2 */ - input[0]++; - blocklen = (drbg_blocklen(drbg) < (outlen - len)) ? - drbg_blocklen(drbg) : (outlen - len); - memcpy(outval + len, tmp, blocklen); - len += blocklen; - } - -out: - memset(tmp, 0, drbg_blocklen(drbg)); - return ret; -} - -/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */ -static int drbg_hash_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) -{ - int ret = 0; - struct drbg_string data1, data2; - LIST_HEAD(datalist); - LIST_HEAD(datalist2); - unsigned char *V = drbg->scratchpad; - unsigned char prefix = DRBG_PREFIX1; - - if (!seed) - return -EINVAL; - - if (reseed) { - /* 10.1.1.3 step 1 */ - memcpy(V, drbg->V, drbg_statelen(drbg)); - drbg_string_fill(&data1, &prefix, 1); - list_add_tail(&data1.list, &datalist); - drbg_string_fill(&data2, V, drbg_statelen(drbg)); - list_add_tail(&data2.list, &datalist); - } - list_splice_tail(seed, &datalist); - - /* 10.1.1.2 / 10.1.1.3 step 2 and 3 */ - ret = drbg_hash_df(drbg, drbg->V, drbg_statelen(drbg), &datalist); - if (ret) - goto out; - - /* 10.1.1.2 / 10.1.1.3 step 4 */ - prefix = DRBG_PREFIX0; - drbg_string_fill(&data1, &prefix, 1); - list_add_tail(&data1.list, &datalist2); - drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg)); - list_add_tail(&data2.list, &datalist2); - /* 10.1.1.2 / 10.1.1.3 step 4 */ - ret = drbg_hash_df(drbg, drbg->C, drbg_statelen(drbg), &datalist2); - -out: - memset(drbg->scratchpad, 0, drbg_statelen(drbg)); - return ret; -} - -/* processing of additional information string for Hash DRBG */ -static int drbg_hash_process_addtl(struct drbg_state *drbg, - struct list_head *addtl) -{ - int ret = 0; - struct drbg_string data1, data2; - LIST_HEAD(datalist); - unsigned char prefix = DRBG_PREFIX2; - - /* 10.1.1.4 step 2 */ - if (!addtl || list_empty(addtl)) - return 0; - - /* 10.1.1.4 step 2a */ - drbg_string_fill(&data1, &prefix, 1); - drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg)); - list_add_tail(&data1.list, &datalist); - list_add_tail(&data2.list, &datalist); - list_splice_tail(addtl, &datalist); - ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist); - if (ret) - goto out; - - /* 10.1.1.4 step 2b */ - drbg_add_buf(drbg->V, drbg_statelen(drbg), - drbg->scratchpad, drbg_blocklen(drbg)); - -out: - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); - return ret; -} - -/* Hashgen defined in 10.1.1.4 */ -static int drbg_hash_hashgen(struct drbg_state *drbg, - unsigned char *buf, - unsigned int buflen) -{ - int len = 0; - int ret = 0; - unsigned char *src = drbg->scratchpad; - unsigned char *dst = drbg->scratchpad + drbg_statelen(drbg); - struct drbg_string data; - LIST_HEAD(datalist); - - /* 10.1.1.4 step hashgen 2 */ - memcpy(src, drbg->V, drbg_statelen(drbg)); - - drbg_string_fill(&data, src, drbg_statelen(drbg)); - list_add_tail(&data.list, &datalist); - while (len < buflen) { - unsigned int outlen = 0; - /* 10.1.1.4 step hashgen 4.1 */ - ret = drbg_kcapi_hash(drbg, dst, &datalist); - if (ret) { - len = ret; - goto out; - } - outlen = (drbg_blocklen(drbg) < (buflen - len)) ? - drbg_blocklen(drbg) : (buflen - len); - /* 10.1.1.4 step hashgen 4.2 */ - memcpy(buf + len, dst, outlen); - len += outlen; - /* 10.1.1.4 hashgen step 4.3 */ - if (len < buflen) - crypto_inc(src, drbg_statelen(drbg)); - } - -out: - memset(drbg->scratchpad, 0, - (drbg_statelen(drbg) + drbg_blocklen(drbg))); - return len; -} - -/* generate function for Hash DRBG as defined in 10.1.1.4 */ -static int drbg_hash_generate(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct list_head *addtl) -{ - int len = 0; - int ret = 0; - union { - unsigned char req[8]; - __be64 req_int; - } u; - unsigned char prefix = DRBG_PREFIX3; - struct drbg_string data1, data2; - LIST_HEAD(datalist); - - /* 10.1.1.4 step 2 */ - ret = drbg_hash_process_addtl(drbg, addtl); - if (ret) - return ret; - /* 10.1.1.4 step 3 */ - len = drbg_hash_hashgen(drbg, buf, buflen); - - /* this is the value H as documented in 10.1.1.4 */ - /* 10.1.1.4 step 4 */ - drbg_string_fill(&data1, &prefix, 1); - list_add_tail(&data1.list, &datalist); - drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg)); - list_add_tail(&data2.list, &datalist); - ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist); - if (ret) { - len = ret; - goto out; - } - - /* 10.1.1.4 step 5 */ - drbg_add_buf(drbg->V, drbg_statelen(drbg), - drbg->scratchpad, drbg_blocklen(drbg)); - drbg_add_buf(drbg->V, drbg_statelen(drbg), - drbg->C, drbg_statelen(drbg)); - u.req_int = cpu_to_be64(drbg->reseed_ctr); - drbg_add_buf(drbg->V, drbg_statelen(drbg), u.req, 8); - -out: - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); - return len; -} - -/* - * scratchpad usage: as update and generate are used isolated, both - * can use the scratchpad - */ -static const struct drbg_state_ops drbg_hash_ops = { - .update = drbg_hash_update, - .generate = drbg_hash_generate, - .crypto_init = drbg_init_hash_kernel, - .crypto_fini = drbg_fini_hash_kernel, -}; -#endif /* CONFIG_CRYPTO_DRBG_HASH */ - /****************************************************************** * Functions common for DRBG implementations ******************************************************************/ @@ -703,7 +399,6 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, drbg->seeded = new_seed_state; drbg->last_seed_time = jiffies; - /* 10.1.1.2 / 10.1.1.3 step 5 */ drbg->reseed_ctr = 1; switch (drbg->seeded) { @@ -900,8 +595,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) kfree_sensitive(drbg->Cbuf); drbg->Cbuf = NULL; drbg->C = NULL; - kfree_sensitive(drbg->scratchpadbuf); - drbg->scratchpadbuf = NULL; drbg->reseed_ctr = 0; drbg->d_ops = NULL; drbg->core = NULL; @@ -914,17 +607,11 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) static inline int drbg_alloc_state(struct drbg_state *drbg) { int ret = -ENOMEM; - unsigned int sb_size = 0; switch (drbg->core->flags & DRBG_TYPE_MASK) { case DRBG_HMAC: drbg->d_ops = &drbg_hmac_ops; break; -#ifdef CONFIG_CRYPTO_DRBG_HASH - case DRBG_HASH: - drbg->d_ops = &drbg_hash_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_HASH */ default: ret = -EOPNOTSUPP; goto err; @@ -946,20 +633,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) goto fini; } drbg->C = PTR_ALIGN(drbg->Cbuf, ret + 1); - /* scratchpad is only generated for Hash */ - if (drbg->core->flags & DRBG_HMAC) - sb_size = 0; - else - sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg); - - if (0 < sb_size) { - drbg->scratchpadbuf = kzalloc(sb_size + ret, GFP_KERNEL); - if (!drbg->scratchpadbuf) { - ret = -ENOMEM; - goto fini; - } - drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1); - } return 0; @@ -1061,7 +734,7 @@ static int drbg_generate(struct drbg_state *drbg, /* 9.3.1 step 8 and 10 */ len = drbg->d_ops->generate(drbg, buf, buflen, &addtllist); - /* 10.1.1.4 step 6, 10.1.2.5 step 7 */ + /* 10.1.2.5 step 7 */ drbg->reseed_ctr++; if (0 >= len) goto err; @@ -1449,9 +1122,6 @@ static inline int __init drbg_healthcheck_sanity(void) if (!fips_enabled) return 0; -#ifdef CONFIG_CRYPTO_DRBG_HASH - drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); -#endif drbg_convert_tfm_core("drbg_nopr_hmac_sha512", &coreref, &pr); drbg = kzalloc_obj(struct drbg_state); @@ -1577,13 +1247,7 @@ static void __exit drbg_exit(void) module_init(drbg_init); module_exit(drbg_exit); -#ifndef CRYPTO_DRBG_HASH_STRING -#define CRYPTO_DRBG_HASH_STRING "" -#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Stephan Mueller "); -MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG) " - "using following cores: " - CRYPTO_DRBG_HASH_STRING - CRYPTO_DRBG_HMAC_STRING); +MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG)"); MODULE_ALIAS_CRYPTO("stdrng"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index dbc1e1fb4bd0..fdc5051b73c5 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4660,22 +4660,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) } - }, { - .alg = "drbg_nopr_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_sha256_tv_template) - } - }, { - /* covered by drbg_nopr_sha256 test */ - .alg = "drbg_nopr_sha384", - .test = alg_test_null, - .fips_allowed = 1 - }, { - .alg = "drbg_nopr_sha512", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_hmac_sha256", .test = alg_test_drbg, @@ -4692,22 +4676,6 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_pr_hmac_sha512", .test = alg_test_null, .fips_allowed = 1, - }, { - .alg = "drbg_pr_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_sha256_tv_template) - } - }, { - /* covered by drbg_pr_sha256 test */ - .alg = "drbg_pr_sha384", - .test = alg_test_null, - .fips_allowed = 1 - }, { - .alg = "drbg_pr_sha512", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "ecb(aes)", .generic_driver = "ecb(aes-lib)", diff --git a/crypto/testmgr.h b/crypto/testmgr.h index a86275b61b6a..d44a4c1e7313 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -23422,172 +23422,6 @@ static const struct aead_testvec aegis128_tv_template[] = { }, }; -/* - * SP800-90A DRBG Test vectors from - * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip - * - * Test vectors for DRBG with prediction resistance. All types of DRBGs - * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and - * w/o personalization string, w/ and w/o additional input string). - */ -static const struct drbg_testvec drbg_pr_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x72\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" - "\xc1\xeb\xd2\x4e\x36\x14\xab\x18\xc4\x9c\xc9\xcf" - "\x1a\xe8\xf7\x7b\x02\x49\x73\xd7\xf1\x42\x7d\xc6" - "\x3f\x29\x2d\xec\xd3\x66\x51\x3f\x1d\x8d\x5b\x4e", - .entropylen = 48, - .entpra = (unsigned char *) - "\x38\x9c\x91\xfa\xc2\xa3\x46\x89\x56\x08\x3f\x62" - "\x73\xd5\x22\xa9\x29\x63\x3a\x1d\xe5\x5d\x5e\x4f" - "\x67\xb0\x67\x7a\x5e\x9e\x0c\x62", - .entprb = (unsigned char *) - "\xb2\x8f\x36\xb2\xf6\x8d\x39\x13\xfa\x6c\x66\xcf" - "\x62\x8a\x7e\x8c\x12\x33\x71\x9c\x69\xe4\xa5\xf0" - "\x8c\xee\xeb\x9c\xf5\x31\x98\x31", - .entprlen = 32, - .expected = (unsigned char *) - "\x52\x7b\xa3\xad\x71\x77\xa4\x49\x42\x04\x61\xc7" - "\xf0\xaf\xa5\xfd\xd3\xb3\x0d\x6a\x61\xba\x35\x49" - "\xbb\xaa\xaf\xe4\x25\x7d\xb5\x48\xaf\x5c\x18\x3d" - "\x33\x8d\x9d\x45\xdf\x98\xd5\x94\xa8\xda\x92\xfe" - "\xc4\x3c\x94\x2a\xcf\x7f\x7b\xf2\xeb\x28\xa9\xf1" - "\xe0\x86\x30\xa8\xfe\xf2\x48\x90\x91\x0c\x75\xb5" - "\x3c\x00\xf0\x4d\x09\x4f\x40\xa7\xa2\x8c\x52\xdf" - "\x52\xef\x17\xbf\x3d\xd1\xa2\x31\xb4\xb8\xdc\xe6" - "\x5b\x0d\x1f\x78\x36\xb4\xe6\x4b\xa7\x11\x25\xd5" - "\x94\xc6\x97\x36\xab\xf0\xe5\x31\x28\x6a\xbb\xce" - "\x30\x81\xa6\x8f\x27\x14\xf8\x1c", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d" - "\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0" - "\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1" - "\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6", - .entropylen = 48, - .entpra = (unsigned char *) - "\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb" - "\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13" - "\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15", - .entprb = (unsigned char *) - "\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09" - "\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde" - "\x76\xaa\x55\x04\x8b\x0a\x72\x95", - .entprlen = 32, - .expected = (unsigned char *) - "\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32" - "\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c" - "\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18" - "\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb" - "\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81" - "\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4" - "\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6" - "\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13" - "\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9" - "\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60" - "\x50\x47\xa3\x63\x81\x16\xaf\x19", - .expectedlen = 128, - .addtla = (unsigned char *) - "\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d" - "\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad" - "\xa9\xd0\x1d\x59\x02\xc4\xff\x70", - .addtlb = (unsigned char *) - "\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31" - "\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41" - "\x9f\xeb\xe4\x38\xfe\x67\x00\xcd", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xc6\x1c\xaf\x83\xa2\x56\x38\xf9\xb0\xbc\xd9\x85" - "\xf5\x2e\xc4\x46\x9c\xe1\xb9\x40\x98\x70\x10\x72" - "\xd7\x7d\x15\x85\xa1\x83\x5a\x97\xdf\xc8\xa8\xe8" - "\x03\x4c\xcb\x70\x35\x8b\x90\x94\x46\x8a\x6e\xa1", - .entropylen = 48, - .entpra = (unsigned char *) - "\xc9\x05\xa4\xcf\x28\x80\x4b\x93\x0f\x8b\xc6\xf9" - "\x09\x41\x58\x74\xe9\xec\x28\xc7\x53\x0a\x73\x60" - "\xba\x0a\xde\x57\x5b\x4b\x9f\x29", - .entprb = (unsigned char *) - "\x4f\x31\xd2\xeb\xac\xfa\xa8\xe2\x01\x7d\xf3\xbd" - "\x42\xbd\x20\xa0\x30\x65\x74\xd5\x5d\xd2\xad\xa4" - "\xa9\xeb\x1f\x4d\xf6\xfd\xb8\x26", - .entprlen = 32, - .expected = (unsigned char *) - "\xf6\x13\x05\xcb\x83\x60\x16\x42\x49\x1d\xc6\x25" - "\x3b\x8c\x31\xa3\xbe\x8b\xbd\x1c\xe2\xec\x1d\xde" - "\xbb\xbf\xa1\xac\xa8\x9f\x50\xce\x69\xce\xef\xd5" - "\xd6\xf2\xef\x6a\xf7\x81\x38\xdf\xbc\xa7\x5a\xb9" - "\xb2\x42\x65\xab\xe4\x86\x8d\x2d\x9d\x59\x99\x2c" - "\x5a\x0d\x71\x55\x98\xa4\x45\xc2\x8d\xdb\x05\x5e" - "\x50\x21\xf7\xcd\xe8\x98\x43\xce\x57\x74\x63\x4c" - "\xf3\xb1\xa5\x14\x1e\x9e\x01\xeb\x54\xd9\x56\xae" - "\xbd\xb6\x6f\x1a\x47\x6b\x3b\x44\xe4\xa2\xe9\x3c" - "\x6c\x83\x12\x30\xb8\x78\x7f\x8e\x54\x82\xd4\xfe" - "\x90\x35\x0d\x4c\x4d\x85\xe7\x13", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xa5\xbf\xac\x4f\x71\xa1\xbb\x67\x94\xc6\x50\xc7" - "\x2a\x45\x9e\x10\xa8\xed\xf7\x52\x4f\xfe\x21\x90" - "\xa4\x1b\xe1\xe2\x53\xcc\x61\x47", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xb6\xc1\x8d\xdf\x99\x54\xbe\x95\x10\x48\xd9\xf6" - "\xd7\x48\xa8\x73\x2d\x74\xde\x1e\xde\x57\x7e\xf4" - "\x7b\x7b\x64\xef\x88\x7a\xa8\x10\x4b\xe1\xc1\x87" - "\xbb\x0b\xe1\x39\x39\x50\xaf\x68\x9c\xa2\xbf\x5e", - .entropylen = 48, - .entpra = (unsigned char *) - "\xdc\x81\x0a\x01\x58\xa7\x2e\xce\xee\x48\x8c\x7c" - "\x77\x9e\x3c\xf1\x17\x24\x7a\xbb\xab\x9f\xca\x12" - "\x19\xaf\x97\x2d\x5f\xf9\xff\xfc", - .entprb = (unsigned char *) - "\xaf\xfc\x4f\x98\x8b\x93\x95\xc1\xb5\x8b\x7f\x73" - "\x6d\xa6\xbe\x6d\x33\xeb\x2c\x82\xb1\xaf\xc1\xb6" - "\xb6\x05\xe2\x44\xaa\xfd\xe7\xdb", - .entprlen = 32, - .expected = (unsigned char *) - "\x51\x79\xde\x1c\x0f\x58\xf3\xf4\xc9\x57\x2e\x31" - "\xa7\x09\xa1\x53\x64\x63\xa2\xc5\x1d\x84\x88\x65" - "\x01\x1b\xc6\x16\x3c\x49\x5b\x42\x8e\x53\xf5\x18" - "\xad\x94\x12\x0d\x4f\x55\xcc\x45\x5c\x98\x0f\x42" - "\x28\x2f\x47\x11\xf9\xc4\x01\x97\x6b\xa0\x94\x50" - "\xa9\xd1\x5e\x06\x54\x3f\xdf\xbb\xc4\x98\xee\x8b" - "\xba\xa9\xfa\x49\xee\x1d\xdc\xfb\x50\xf6\x51\x9f" - "\x6c\x4a\x9a\x6f\x63\xa2\x7d\xad\xaf\x3a\x24\xa0" - "\xd9\x9f\x07\xeb\x15\xee\x26\xe0\xd5\x63\x39\xda" - "\x3c\x59\xd6\x33\x6c\x02\xe8\x05\x71\x46\x68\x44" - "\x63\x4a\x68\x72\xe9\xf5\x55\xfe", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x15\x20\x2f\xf6\x98\x28\x63\xa2\xc4\x4e\xbb\x6c" - "\xb2\x25\x92\x61\x79\xc9\x22\xc4\x61\x54\x96\xff" - "\x4a\x85\xca\x80\xfe\x0d\x1c\xd0", - .addtlb = (unsigned char *) - "\xde\x29\x8e\x03\x42\x61\xa3\x28\x5e\xc8\x80\xc2" - "\x6d\xbf\xad\x13\xe1\x8d\x2a\xc7\xe8\xc7\x18\x89" - "\x42\x58\x9e\xd6\xcc\xad\x7b\x1e", - .addtllen = 32, - .pers = (unsigned char *) - "\x84\xc3\x73\x9e\xce\xb3\xbc\x89\xf7\x62\xb3\xe1" - "\xd7\x48\x45\x8a\xa9\xcc\xe9\xed\xd5\x81\x84\x52" - "\x82\x4c\xdc\x19\xb8\xf8\x92\x5c", - .perslen = 32, - }, -}; - static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { { .entropy = (unsigned char *) @@ -23746,136 +23580,6 @@ static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { }, }; -/* - * SP800-90A DRBG Test vectors from - * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip - * - * Test vectors for DRBG without prediction resistance. All types of DRBGs - * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and - * w/o personalization string, w/ and w/o additional input string). - */ -static const struct drbg_testvec drbg_nopr_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\xa6\x5a\xd0\xf3\x45\xdb\x4e\x0e\xff\xe8\x75\xc3" - "\xa2\xe7\x1f\x42\xc7\x12\x9d\x62\x0f\xf5\xc1\x19" - "\xa9\xef\x55\xf0\x51\x85\xe0\xfb\x85\x81\xf9\x31" - "\x75\x17\x27\x6e\x06\xe9\x60\x7d\xdb\xcb\xcc\x2e", - .entropylen = 48, - .expected = (unsigned char *) - "\xd3\xe1\x60\xc3\x5b\x99\xf3\x40\xb2\x62\x82\x64" - "\xd1\x75\x10\x60\xe0\x04\x5d\xa3\x83\xff\x57\xa5" - "\x7d\x73\xa6\x73\xd2\xb8\xd8\x0d\xaa\xf6\xa6\xc3" - "\x5a\x91\xbb\x45\x79\xd7\x3f\xd0\xc8\xfe\xd1\x11" - "\xb0\x39\x13\x06\x82\x8a\xdf\xed\x52\x8f\x01\x81" - "\x21\xb3\xfe\xbd\xc3\x43\xe7\x97\xb8\x7d\xbb\x63" - "\xdb\x13\x33\xde\xd9\xd1\xec\xe1\x77\xcf\xa6\xb7" - "\x1f\xe8\xab\x1d\xa4\x66\x24\xed\x64\x15\xe5\x1c" - "\xcd\xe2\xc7\xca\x86\xe2\x83\x99\x0e\xea\xeb\x91" - "\x12\x04\x15\x52\x8b\x22\x95\x91\x02\x81\xb0\x2d" - "\xd4\x31\xf4\xc9\xf7\x04\x27\xdf", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c" - "\x8a\x93\x17\xae\x19\xc3\x4c\xc3\xd6\xca\xa3\x2d" - "\x16\xfc\x42\xd2\x2d\xd5\x6f\x56\xcc\x1d\x30\xff" - "\x9e\x06\x3e\x09\xce\x58\xe6\x9a\x35\xb3\xa6\x56", - .entropylen = 48, - .expected = (unsigned char *) - "\x71\x7b\x93\x46\x1a\x40\xaa\x35\xa4\xaa\xc5\xe7" - "\x6d\x5b\x5b\x8a\xa0\xdf\x39\x7d\xae\x71\x58\x5b" - "\x3c\x7c\xb4\xf0\x89\xfa\x4a\x8c\xa9\x5c\x54\xc0" - "\x40\xdf\xbc\xce\x26\x81\x34\xf8\xba\x7d\x1c\xe8" - "\xad\x21\xe0\x74\xcf\x48\x84\x30\x1f\xa1\xd5\x4f" - "\x81\x42\x2f\xf4\xdb\x0b\x23\xf8\x73\x27\xb8\x1d" - "\x42\xf8\x44\x58\xd8\x5b\x29\x27\x0a\xf8\x69\x59" - "\xb5\x78\x44\xeb\x9e\xe0\x68\x6f\x42\x9a\xb0\x5b" - "\xe0\x4e\xcb\x6a\xaa\xe2\xd2\xd5\x33\x25\x3e\xe0" - "\x6c\xc7\x6a\x07\xa5\x03\x83\x9f\xe2\x8b\xd1\x1c" - "\x70\xa8\x07\x59\x97\xeb\xf6\xbe", - .expectedlen = 128, - .addtla = (unsigned char *) - "\xf4\xd5\x98\x3d\xa8\xfc\xfa\x37\xb7\x54\x67\x73" - "\xc7\xc3\xdd\x47\x34\x71\x02\x5d\xc1\xa0\xd3\x10" - "\xc1\x8b\xbd\xf5\x66\x34\x6f\xdd", - .addtlb = (unsigned char *) - "\xf7\x9e\x6a\x56\x0e\x73\xe9\xd9\x7a\xd1\x69\xe0" - "\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d" - "\xa8\xc0\x85\xd1\x5a\x0c\x59\x40", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x2a\x85\xa9\x8b\xd0\xda\x83\xd6\xad\xab\x9f\xbb" - "\x54\x31\x15\x95\x1c\x4d\x49\x9f\x6a\x15\xf6\xe4" - "\x15\x50\x88\x06\x29\x0d\xed\x8d\xb9\x6f\x96\xe1" - "\x83\x9f\xf7\x88\xda\x84\xbf\x44\x28\xd9\x1d\xaa", - .entropylen = 48, - .expected = (unsigned char *) - "\x2d\x55\xde\xc9\xed\x05\x47\x07\x3d\x04\xfc\x28" - "\x0f\x92\xf0\x4d\xd8\x00\x32\x47\x0a\x1b\x1c\x4b" - "\xef\xd9\x97\xa1\x17\x67\xda\x26\x6c\xfe\x76\x46" - "\x6f\xbc\x6d\x82\x4e\x83\x8a\x98\x66\x6c\x01\xb6" - "\xe6\x64\xe0\x08\x10\x6f\xd3\x5d\x90\xe7\x0d\x72" - "\xa6\xa7\xe3\xbb\x98\x11\x12\x56\x23\xc2\x6d\xd1" - "\xc8\xa8\x7a\x39\xf3\x34\xe3\xb8\xf8\x66\x00\x77" - "\x7d\xcf\x3c\x3e\xfa\xc9\x0f\xaf\xe0\x24\xfa\xe9" - "\x84\xf9\x6a\x01\xf6\x35\xdb\x5c\xab\x2a\xef\x4e" - "\xac\xab\x55\xb8\x9b\xef\x98\x68\xaf\x51\xd8\x16" - "\xa5\x5e\xae\xf9\x1e\xd2\xdb\xe6", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xa8\x80\xec\x98\x30\x98\x15\xd2\xc6\xc4\x68\xf1" - "\x3a\x1c\xbf\xce\x6a\x40\x14\xeb\x36\x99\x53\xda" - "\x57\x6b\xce\xa4\x1c\x66\x3d\xbc", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\x69\xed\x82\xa9\xc5\x7b\xbf\xe5\x1d\x2f\xcb\x7a" - "\xd3\x50\x7d\x96\xb4\xb9\x2b\x50\x77\x51\x27\x74" - "\x33\x74\xba\xf1\x30\xdf\x8e\xdf\x87\x1d\x87\xbc" - "\x96\xb2\xc3\xa7\xed\x60\x5e\x61\x4e\x51\x29\x1a", - .entropylen = 48, - .expected = (unsigned char *) - "\xa5\x71\x24\x31\x11\xfe\x13\xe1\xa8\x24\x12\xfb" - "\x37\xa1\x27\xa5\xab\x77\xa1\x9f\xae\x8f\xaf\x13" - "\x93\xf7\x53\x85\x91\xb6\x1b\xab\xd4\x6b\xea\xb6" - "\xef\xda\x4c\x90\x6e\xef\x5f\xde\xe1\xc7\x10\x36" - "\xd5\x67\xbd\x14\xb6\x89\x21\x0c\xc9\x92\x65\x64" - "\xd0\xf3\x23\xe0\x7f\xd1\xe8\x75\xc2\x85\x06\xea" - "\xca\xc0\xcb\x79\x2d\x29\x82\xfc\xaa\x9a\xc6\x95" - "\x7e\xdc\x88\x65\xba\xec\x0e\x16\x87\xec\xa3\x9e" - "\xd8\x8c\x80\xab\x3a\x64\xe0\xcb\x0e\x45\x98\xdd" - "\x7c\x6c\x6c\x26\x11\x13\xc8\xce\xa9\x47\xa6\x06" - "\x57\xa2\x66\xbb\x2d\x7f\xf3\xc1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x74\xd3\x6d\xda\xe8\xd6\x86\x5f\x63\x01\xfd\xf2" - "\x7d\x06\x29\x6d\x94\xd1\x66\xf0\xd2\x72\x67\x4e" - "\x77\xc5\x3d\x9e\x03\xe3\xa5\x78", - .addtlb = (unsigned char *) - "\xf6\xb6\x3d\xf0\x7c\x26\x04\xc5\x8b\xcd\x3e\x6a" - "\x9f\x9c\x3a\x2e\xdb\x47\x87\xe5\x8e\x00\x5e\x2b" - "\x74\x7f\xa6\xf6\x80\xcd\x9b\x21", - .addtllen = 32, - .pers = (unsigned char *) - "\x74\xa6\xe0\x08\xf9\x27\xee\x1d\x6e\x3c\x28\x20" - "\x87\xdd\xd7\x54\x31\x47\x78\x4b\xe5\x6d\xa3\x73" - "\xa9\x65\xb1\x10\xc1\xdc\x77\x7c", - .perslen = 32, - }, -}; - static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { { .entropy = (unsigned char *) From 5dd76c87e47879ca2ef70479962bca01263a5428 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:58 -0700 Subject: [PATCH 132/655] crypto: drbg - Flatten the DRBG menu Now that the menuconfig CRYPTO_DRBG_MENU has no options in it other than the hidden symbol CRYPTO_DRBG, remove it and move CRYPTO_DRBG to its parent menu. Give CRYPTO_DRBG an appropriate prompt and help text. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/Kconfig | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 14519474a67b..1abb3d356458 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1113,24 +1113,17 @@ endmenu menu "Random number generation" -menuconfig CRYPTO_DRBG_MENU - tristate "NIST SP800-90A DRBG (Deterministic Random Bit Generator)" - help - DRBG (Deterministic Random Bit Generator) (NIST SP800-90A) - - In the following submenu, one or more of the DRBG types must be selected. - -if CRYPTO_DRBG_MENU - config CRYPTO_DRBG - tristate - default CRYPTO_DRBG_MENU + tristate "NIST SP800-90A DRBG (Deterministic Random Bit Generator)" select CRYPTO_HMAC select CRYPTO_JITTERENTROPY select CRYPTO_RNG select CRYPTO_SHA512 + help + DRBG (Deterministic Random Bit Generator) (NIST SP800-90A) -endif # if CRYPTO_DRBG_MENU + Enable this only if you need it for a FIPS 140 certification. + It's otherwise redundant with the kernel's regular RNG. config CRYPTO_JITTERENTROPY tristate "CPU Jitter Non-Deterministic RNG (Random Number Generator)" From ca952c7504707495ab8cf2fdd958ee10cf41f48f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:33:59 -0700 Subject: [PATCH 133/655] crypto: testmgr - Add test for drbg_pr_hmac_sha512 Add a test for drbg_pr_hmac_sha512, which previously didn't have a test. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/testmgr.c | 5 +- crypto/testmgr.h | 199 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 1 deletion(-) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index fdc5051b73c5..5a984b3b9a9b 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4674,8 +4674,11 @@ static const struct alg_test_desc alg_test_descs[] = { .fips_allowed = 1 }, { .alg = "drbg_pr_hmac_sha512", - .test = alg_test_null, + .test = alg_test_drbg, .fips_allowed = 1, + .suite = { + .drbg = __VECS(drbg_pr_hmac_sha512_tv_template) + } }, { .alg = "ecb(aes)", .generic_driver = "ecb(aes-lib)", diff --git a/crypto/testmgr.h b/crypto/testmgr.h index d44a4c1e7313..77935a457313 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -23702,6 +23702,205 @@ static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { }, }; +static const struct drbg_testvec drbg_pr_hmac_sha512_tv_template[] = { + /* + * Borrowed from the first applicable test vector from ACVP: + * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/prompt.json#L1161 + * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/expectedResults.json#L271 + */ + { + /* .entropy = ACVP entropyInput || nonce */ + .entropy = "\x9B\xE9\xB2\x87\xA3\x9A\x08\x44\x1D\x67\x82\x20" + "\xC9\x53\xFB\xEB\xA4\xB9\x0F\x44\x0B\x98\x33\x18" + "\xAC\x6E\x25\x4A\x85\x83\x2D\x26\x21\x9F\x93\x64" + "\xC8\x5A\x5F\x72\xDB\x88\x45\x96\x71\x41\xF4\xBF" + "\x6E\xA7\x98\x00\x9D\xD1\x0C\x2E\x4D\x7A\xE2\x03" + "\x0D\xE3\xCD\x62\xFE\xF3\x62\xBD\x12\x69\x92\x3D" + "\xBA\xAC\x15\x17\xC7\x80\x93\x8E\x72\x32\x2D\x52" + "\xE5\x2C\x19\x84\x5C\xA5\xCE\x5B\x98\x19\x1F\xF1" + "\x9F\x0C\x17\x04\xD0\x66\xF1\x9B\xFA\x7E\x2C\xB6" + "\x55\x68\xD4\x1B\xD6\x7A\x1D\x2C\xD4\x6D\x6E\x15" + "\xF7\x32\x23\x04\x05\x8C\xBB\xE6\x63\x6B\x80\x9B" + "\x9C\x69\x09\x8F\x5F\x02\xBF\x53\x42\x11\xB7\x80" + "\xAA\xD4\xE8\x54\x00\x83\x5C\x20\xA8\xB3\x6E\xD9" + "\xF5\x51\x9E\xB9\xD1\x6E\xC7\x0C\xE9\x7F\xF0\xBF" + "\xCE\x1D\xB0\x31\x8D\x16\xC9\x65\x0C\x18\x55\xA4" + "\x46\x8D\x54\x2B\x78\x69\x1B\x8C\x29\xD7\xAC\x0F" + "\x34\x4D\x69\x0B\x76\xC3\x98\x00\x78\x2F\xE2\x54" + "\xAF\xD5\x8A\xC3\x40\x97\xB1\xA2\x60\xD3\x07\x3B" + "\x7A\x3E\xD0\x82\x80\x68\xEE\xB0\x72\x5F\x07\x17" + "\xD9\x0A\xFC\xBD\xBA\xB6\x77\x4E\xC9\xCE\x6A\x48" + "\xEB\x9C\xF5\x18\x88\x1E\x6E\x3B\x65\x43\x16\x73" + "\x80\x53\xB7\xF0\x7E\xAB\x23\x19\x1E\x75\x60\x36" + "\xAF\x39\xC0\xCF\x0F\x6D\x7F\x90\xB2\x50\xD5\x37" + "\x58\x6D\x5C\x95\x78\x25\x8D\x3A\x40\xAB\xF6\x7B" + "\x85\x86\xBB\x48\x5E\x1C\x99\xC1\xD3\x4E\x85\xE5" + "\xB4\xE7\x61\xF3\x7D\x56\x1F\x77\xCF\x3C\x76\x3A" + "\xF4\x82\x36\xB7\x37\x33\x84\x34\xBA\x0E\xE2\xE1" + "\xAF\x0C\xD2\xAE\x97\x5C\x80\xD4\xD2\xFD\x37\x71" + "\xC8\x70\x04\x29\x8B\x44\xB9\xD7\xC9\x8F\xE7\x99" + "\x94\x9E\xFC\x49\x66\x24\xCB\x8B\x41\x40\x66\xC5" + "\xA4\x00\xD5\x3F\x68\xDD\xB5\xA5\x62\x96\x7C\xAC" + "\x63\x58\x95\x85\x99\x24\x21\x15\xD2\x76\xAF\x6D", + .entropylen = 384, + .pers = "\xDD\x07\x10\x10\x17\x34\xD5\xBD\x43\xAF\x03\x79\xE4" + "\x64\x2C\x58\x06\xEA\xE0\x39\xDA\x42\x96\x16\x0B\xF9" + "\xB8\xCE\x57\x7D\x53\x67\xBF\xF8\x0C\x40\x02\xB2\x77" + "\x16\xD5\x23\x75\x9F\x6A\x42\x0E\xE8\xCC\xD0\x9F\x40" + "\x64\xE9\x3B\xE9\x48\x13\xC3\x8E\x4B\xAB\xE1\xB9\x4F" + "\x6D\xBB\xF2\x4C\xF8\x29\xA5\x2B\x44\x23\x15\x2C\xDE" + "\x2A\xCF\x88\x04\x7A\x38\x37\xA2\xD5\x7B\xEA\x59\x39" + "\x2C\x58\xA2\x5B\xF9\x39\xA2\x7E\x94\x11\x97\xEC\x47" + "\x08\xD6\xE2\x39\x65\x26\x43\x81\x3F\x1B\x31\xA6\xA4" + "\x1A\x5C\xCD\x02\xCC\x89\x38\x3F\x32\x7C\x0E\x7E\x88" + "\x3B\x6F\x60\x69\xEA\xBA\xAA\x1F\x53\x93\x70\xD7\x48" + "\x74\x91\x79\x5E\xD4\xB0\xD9\x82\x74\x12\xDE\xFE\xFB" + "\x51\x96\x66\x5C\x6A\x53\x11\xAD\x9A\xD4\xFA\x9D\xF0" + "\xE2\x7F\x26\x8F\x6F\xAC\x00\xC8\xDB\xCF\xA5\x8E\xE6" + "\x61\x8F\x36\xD6\x44\x5B\x07\xDA\x9C\x2A\x46\xE3\x03" + "\x1C\xD8\x11\x4F\x61\x1F\xEC\xBA\x12\x68\xB9\x4B\x57" + "\x39\x05\xD6\xEE\xC1\xAC\x3F\x6D\x6F\xE9\xBF\xEA\x36" + "\x1A\x8A\xAA\xF4\xE8\xE0\xDB\xC6\xE5\x06\x9F\xC9\x91" + "\x52\xCD\x53\xD0\x78\xF6\xC1\x7B\x75\x91\x85\x91\x13" + "\x26\xBE\xC9\x02\xDE\xB0\x19\xF2\x71", + .perslen = 256, + + .entpra = "\xDB\xBA\x25\xC7\x02\x0D\x3D\x95\x9C\xEB\xF5\x42" + "\x52\x3A\x6B\xDA\xE8\xAF\xE9\x3D\x76\x2A\x9E\xB5" + "\xD7\xE7\x5D\xC9\xB8\x1F\x3A\xC2\x91\x95\x9D\xFD" + "\xE5\x48\x5F\x63\xD8\x84\x44\x82\x6A\x71\xF9\xDD" + "\xAF\x4B\xE2\x28\xB4\x30\xCF\x78\xB7\x0B\x0F\x61" + "\x71\x16\x1A\xE0\x6D\x5F\xB4\x4B\x17\x1A\x26\xCA" + "\xD8\x9D\x6D\x46\xA3\x56\xC0\xE7\x49\xCF\xE0\xD2" + "\xFF\xA8\x22\x45\xE0\xB4\x18\x0B\x13\x37\x01\x46" + "\xCB\xE7\xD8\x2A\x59\x43\xAD\x90\x1E\xE1\xD0\xD7" + "\x76\xB0\x2D\xCF\x17\x23\x99\x73\x5D\xE5\xC7\x46" + "\x8A\x0D\x8E\xC4\xAB\x45\xAC\xA8\x74\xE4\xF7\xD0" + "\x26\xD7\x0A\xE2\x43\x3D\xB8\xC7\xEE\xAD\x53\x6F" + "\x78\xC3\x51\xC0\xE0\x76\x2A\xC2\xB7\xFE\x02\x64" + "\x25\xF0\xCE\xD7\xA9\xBF\x85\xCA\x20\xA6\x93\x68" + "\xE3\x79\xE9\x88\xA8\x7F\x45\x8D\x71\xB4\xB4\x79" + "\x1C\x56\x68\xF9\xAE\x18\x76\xB9\x3F\xEE\x5B\x2C" + "\xC6\x61\x47\x34\x3B\xC5\x24\x2D\x3C\x6D\x16\x48" + "\x70\xD9\xDB\x2E\xB8\x42\x52\x81\x1C\x94\x39\xF0" + "\xF4\xC0\x8F\x44\xD3\xCF\xD5\xF9\xC1\x59\x61\x83" + "\xAE\xFD\xD0\xC4\x35\xD1\x0E\x55\x46\x5C\xBA\x3D" + "\x5C\x4A\x89\x15\xE8\x1D\x86\x28\xE5\xF5\x31\x0B" + "\x89\x59\xFE\x4A\xC3\x5D\xA5\x2A\x16\x37\x78\x41" + "\x58\x3A\x9E\xA3\xBD\x1F\xE6\x25\xCC\x18\x9E\xD2" + "\x1A\x99\x56\x66\x83\x78\xBB\x27\x3E\x28\xFE\xD4" + "\x74\xCB\x75\x2D\x82\x86\x55\xFB\x1C\xA4\xAF\x3F" + "\x84\x0A\xA0\xA1\x1C\x70\x34\x87\x2E\x73\x15\x38" + "\x8A\x27\xB1\x6C\x33\x95\xE5\x07", + .entprb = "\x38\xF2\xC4\x8F\x4B\x9C\x2F\x03\x67\x8C\x8A\x47" + "\xE1\xF2\x18\xC5\xB8\x4C\x05\x77\x77\x15\xA8\x94" + "\x1F\x1F\x45\x6D\xD0\xEF\x60\x67\x63\x12\x5D\x38" + "\x89\x22\x76\xF5\xF2\xC4\xE1\x15\x26\x7E\x8F\x52" + "\x79\x1E\x96\x71\xCD\xE7\x32\x95\x2B\x4E\xB2\xC2" + "\x92\x21\xC7\x48\xA2\xB1\xC5\x71\x44\x91\xE4\x4F" + "\xBE\xD3\x5E\xA9\xAB\xD3\xE2\xD1\xE2\xD8\x8F\x98" + "\x38\x03\x18\x29\x84\xA2\xCA\x6E\x72\x34\xC9\x51" + "\x6D\x8C\xE8\x09\x50\x71\x2A\x08\xB7\xCF\x74\xE6" + "\x11\xB6\x38\xF5\xBC\x24\xF7\x5B\x73\x34\xD5\x8B" + "\xBB\x15\xE3\x6F\x9A\x9B\x1E\x32\xB9\x6F\x5F\xE3" + "\xC9\x9F\xF6\xD9\x33\x03\xCD\x0D\x8E\xD4\x3F\x67" + "\x11\x65\x0A\x90\x67\x83\xC1\xCC\x70\xB1\xA9\x46" + "\x4B\x5E\x0B\x84\xDC\x02\xBA\x50\x1D\x4A\x5B\xC7" + "\xB4\x5E\xDF\x35\x01\x45\x3D\x64\x5C\x2E\xCD\xA6" + "\x20\xFB\x35\x74\xC0\x7C\x2D\x24\x66\xAB\x38\x12" + "\x38\xCE\x52\xCB\x38\x9B\x95\xDE\x0C\x2A\x8C\x9D" + "\xF7\x81\x48\x9E\xD6\x10\xF1\x83\x71\x44\x53\x2F" + "\xCE\xF3\xEC\xB3\x29\x67\xF1\x41\xFC\xD6\xB6\x49" + "\xE3\x13\x74\x4D\xB2\x3E\xEA\x73\x2B\x03\x68\xAC" + "\x2F\x57\x8C\x58\xEC\x34\xE9\xEF\x18\x36\xDE\xAD" + "\xE9\x48\x1D\xF7\x9E\xB7\xA1\x60\x2E\x78\xF5\x62" + "\x68\xDD\xB8\x5B\x33\x6B\x66\xAD\xA1\xD5\xFB\x46" + "\x5E\x8F\xF8\x9D\x37\xE5\xC2\xD8\x76\xDC\x2B\x6A" + "\x99\x1E\xDF\x91\xB1\x0A\x81\x2A\x9D\xEB\xE7\xE4" + "\xD1\x21\xD4\xDA\x0E\x55\x8A\x14\xB2\xB6\x15\x7D" + "\x48\x52\x6A\xB0\xA2\x92\x4D\x50", + .entprlen = 320, + .addtla = "\xC2\x89\x7C\x07\x46\x74\x02\x2C\xEA\xAD\xFD\x74" + "\x0C\x40\xEF\xA2\x95\x64\x6B\xC4\x2D\xED\xF4\x16" + "\x26\x25\x06\xB3\x36\x6B\xD8\x9A\x5F\xF4\x25\xC1" + "\xC3\x69\x3F\x7A\x19\xB7\x02\xA6\xCC\x3B\xA2\x4E" + "\x05\xA1\x1C\x7B\x2D\xAD\x44\xE7\x4A\x40\x71\x85" + "\xEF\x1C\xE4\xEC\x54\xCA\xB0\xAF\x8F\xF5\x43\xB1" + "\xE0\x99\x71\x71\xD4\x3E\x56\x97\xAA\xF5\xD0\x1A" + "\x58\x2D\x65\x0F\xA4\xB4\xB6\x07\x1B\x1F\x13\x8B" + "\x29\xD6\xE5\x23\xD3\x4D\x43\xD6\xBC\x74\xA8\x92" + "\xBD\xE9\x9B\x01\x47\x8C\xA5\x02\xA8\x0D\xC3\x3A" + "\xED\x83\xFD\xD2\xCB\xFF\x25\x89\x2C\x2F\x5B\x70" + "\x3F\x9E\x24\x50\xF8\x78\x28\x1B\x67\x52\x92\xA2" + "\x87\x81\x07\x40\xA9\x40\xBA\x84\x47\x25\xC1\xF7" + "\x9E\x3B\x4E\xE4\x8F\x10\xE5\x50\x8B\x22\x83\x4F" + "\xCD\x4E\x42\x63\x92\x0A\x5F\xAF\x7A\x9B\x0E\x1A" + "\xE3\xB4\x99\x11\x7F\xE6\x93\xC3\xED\xF1\x9F\x3A", + .addtlb = "\x1E\x75\xB6\x70\x60\xFD\xE6\xD1\xC7\xA5\x74\xCF" + "\xA7\x50\x17\xAE\xDD\xC4\x6E\xC4\xE0\x15\xF0\x3B" + "\xF7\x1C\x46\x45\xEE\x60\x66\x48\x1D\x2C\x36\xCC" + "\x95\x3E\xB7\xEB\x1B\xFF\x8C\xC0\x78\x6D\x56\x3A" + "\xC7\x24\x18\x9E\x7C\xA1\x60\x54\x41\x4B\xAF\x18" + "\xE8\x02\xD1\x54\x65\xEC\x3D\xFD\x8B\xDF\xD2\xF5" + "\x62\xEA\x66\x41\x6A\x32\x87\xA6\x34\x2F\x48\xBF" + "\xB5\xCC\x35\x5A\x2A\xC1\xAB\x68\x34\x1A\xD6\x82" + "\x40\xF7\xF2\x00\x14\x8B\x69\x0F\xE4\xCD\x6B\xB1" + "\xFC\x8B\x16\xEC\xB4\xE3\x33\xBF\x84\x12\x4B\x58" + "\xED\x51\x88\xF5\xEF\xB6\xC3\xCE\x9B\x63\xCC\x80" + "\x1F\x3C\x8A\x67\xEE\xCD\xD2\x01\x25\x22\xAC\xB3" + "\xB6\x9B\x1F\xF8\xE8\x71\xE6\x0D\x78\x11\x3C\x9E" + "\xF2\x57\xDC\xB6\xCF\x90\xD3\xA8\x3E\xCD\x88\xD4" + "\xDC\x1C\x31\x6B\x1F\xC3\x6A\x29\xF0\x7B\x4C\xCC" + "\x6D\x92\x5E\x6F\x0C\x0B\x4D\xA7\x10\x66\x84\x1F", + .addtllen = 192, + + .expected = "\xAA\x76\x91\xAE\x99\xCD\x8D\x83\x49\x9D\xC5\x51" + "\xA5\x95\xC6\x9D\xAD\x4B\x40\x2B\x5F\x8C\x30\x5D" + "\x1E\x89\x58\xD1\x8A\x86\xF9\x61\x2C\x45\x41\x8E" + "\xC5\xC6\x0E\x33\x7C\xFE\x91\x71\xC9\x53\x76\xD6" + "\xC2\x8D\x05\x09\xB8\x2A\x2B\x9B\x36\x1D\x31\xD7" + "\x50\x45\xB1\x08\x58\xC4\x99\x25\xEA\x2F\x18\xDB" + "\x34\x8A\x02\xD8\x38\xDD\x7B\x9E\x0E\xEF\x9C\x45" + "\xC7\x4F\x7E\x36\x3A\x90\x8B\x41\x51\x4A\x1B\xE9" + "\x8A\x61\xE9\xB5\x4E\xA5\xE2\xBD\x16\x59\x61\x0F" + "\x9C\x5A\x63\xA7\x87\x79\x5C\x0A\x16\xDF\x6D\x88" + "\x11\x25\x56\x8B\x5D\xA6\xF8\x4F\xB9\x01\x19\xAE" + "\x57\x3B\xC4\x06\xBB\xE7\xCB\xAF\xB3\x8D\xE2\x40" + "\xED\x42\x29\xB3\x0D\x64\x20\xF2\x66\x58\xB1\xDD" + "\x59\xB1\x39\x7C\xD9\xB2\x34\x08\x53\x9B\x3A\xB7" + "\x18\x35\xD0\x90\x7F\xB5\x30\xF2\x27\xA0\x90\x63" + "\x6F\xF2\x72\x49\xBF\xD0\xAE\x4A\xF4\xCA\xB3\x1A" + "\xAE\x7F\x93\xF3\xB9\x84\x99\x09\x50\xB9\xA0\x43" + "\x4F\x83\x33\x92\xA5\xC7\x25\x44\x6A\x74\xF4\xFA" + "\xBA\x60\x43\x13\x97\x53\x99\x98\xA3\x05\x02\xC1" + "\x03\xDF\x53\x76\x9E\x74\xE7\xA0\xB5\xD7\xA7\x87" + "\x1E\x00\x1D\x29\x47\x8F\x65\x4E\x0F\x76\xCA\xA9" + "\x2A\xC5\x05\x4F\xA6\xFE\x96\xC6\x81\xC0\x55\xFC" + "\x92\x89\xA6\x81\xF0\x37\xF1\x41\xA6\x88\x0B\x01" + "\xE0\xA5\x78\x4C\xF4\x61\xA7\x91\xD8\x4B\xE9\x2C" + "\xF0\x68\xEE\x46\x41\xD2\x74\xE5\x5F\x6F\x1F\xE6" + "\xBE\x5C\xB1\x3C\x60\x1A\xAA\xB9\x88\x3C\xB9\x1C" + "\xCD\x67\x78\x1F\x45\x18\xE7\x8B\xBD\xE4\x24\xDA" + "\xA8\x26\xD1\x03\xF1\xC7\x6B\x28\x62\xAB\x5C\xAB" + "\x98\xCA\xFB\xCB\x0B\x2D\x01\xD9\xC1\xA6\xFA\x91" + "\x71\x3D\x9B\x3B\x60\xEB\xD7\xA2\x61\xC1\x92\x60" + "\xB1\x02\x44\x0C\x97\x70\x77\x83\xF9\x35\xEA\x24" + "\x85\xF8\x0A\x32\xA2\xC7\x05\x40\x90\x83\x4F\x87" + "\x57\x66\xB5\xDE\xEE\xFF\x8B\x01\xBC\x96\xB0\xC5" + "\x29\xB6\xC1\xF0\x11\x31\x51\x11\xB0\xC2\x0F\x08" + "\xCF\x09\x69\x74\xE1\x0D\x6C\x0A\x10\xD0\x73\xF0" + "\x8E\xDC\x5F\xB1\xBD\x47\x8A\xA7\x90\xB3\x08\x86" + "\xD2\xE4\x58\xE5\x68\x33\x67\x3B\x37\xF1\x28\x28" + "\x59\x91\xB5\x5F\x8D\x84\x54\xCE\x18\x76\xE3\x5C" + "\x55\x37\x8E\x10\x34\x9B\x6E\x1F\x73\x88\x31\xBF" + "\x0D\x5C\xED\x7A\xBC\xF2\xCE\x7A\x2E\x2E\xE7\x04" + "\xE7\xF2\x8F\x33\xCC\x06\x77\x96\xBB\xA8\x65\x03" + "\x26\x79\xC0\xF0\x52\x3B\xD4\xF2\x5D\x00\xE4\x80" + "\x7F\x78\xC0\x45\x29\x55\xCA\x63", + .expectedlen = 512, + } +}; + /* Test vector obtained during NIST ACVP testing */ static const struct drbg_testvec drbg_nopr_hmac_sha512_tv_template[] = { { From 8237a5f626a2fdfbc8325c4ab672b4e04f564619 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:00 -0700 Subject: [PATCH 134/655] crypto: testmgr - Update test for drbg_nopr_hmac_sha512 Synchronize the drbg_nopr_hmac_sha512 test vector with the first test vector from the latest ACVP json files, so that both of the DRBG test vectors are pulled from a consistent source. Note that the new test vector has a nonempty personalization string. That should be helpful as well: Some FIPS labs require this, due to their interpretation of SP800-90A 11.3.2 which says that a "representative" value of the personalization string must be tested. It also now does an explicit reseed, which makes it clearer that the requirement to test "Reseed" is met, without having to interpret the additional input processing as covering that. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/testmgr.c | 13 ++- crypto/testmgr.h | 249 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 215 insertions(+), 47 deletions(-) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 5a984b3b9a9b..ad4c2e66b812 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3504,10 +3504,21 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr, crypto_rng_set_entropy(drng, test->entropy, test->entropylen); ret = crypto_rng_reset(drng, test->pers, test->perslen); if (ret) { - printk(KERN_ERR "alg: drbg: Failed to reset rng\n"); + printk(KERN_ERR "alg: drbg: Failed to instantiate rng\n"); goto outbuf; } + if (test->ent_reseed_len) { + crypto_rng_set_entropy(drng, test->ent_reseed, + test->ent_reseed_len); + ret = crypto_rng_reset(drng, test->addtl_reseed, + test->addtl_reseed_len); + if (ret) { + printk(KERN_ERR "alg: drbg: Failed to reseed rng\n"); + goto outbuf; + } + } + if (pr) crypto_rng_set_entropy(drng, test->entpra, test->entprlen); ret = crypto_rng_generate(drng, test->addtla, test->addtllen, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 77935a457313..fc70ca86d61f 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -120,16 +120,27 @@ struct aead_testvec { }; struct drbg_testvec { + /* Instantiate */ const unsigned char *entropy; size_t entropylen; + const unsigned char *pers; + size_t perslen; + + /* Reseed (optional) */ + const unsigned char *ent_reseed; + size_t ent_reseed_len; + const unsigned char *addtl_reseed; + size_t addtl_reseed_len; + + /* Generate (twice) */ const unsigned char *entpra; const unsigned char *entprb; size_t entprlen; const unsigned char *addtla; const unsigned char *addtlb; size_t addtllen; - const unsigned char *pers; - size_t perslen; + + /* Expected output from last call to Generate */ const unsigned char *expected; size_t expectedlen; }; @@ -23901,52 +23912,198 @@ static const struct drbg_testvec drbg_pr_hmac_sha512_tv_template[] = { } }; -/* Test vector obtained during NIST ACVP testing */ static const struct drbg_testvec drbg_nopr_hmac_sha512_tv_template[] = { + /* + * Borrowed from the first applicable test vector from ACVP: + * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/prompt.json#L4596 + * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/expectedResults.json#L986 + */ { - .entropy = (unsigned char *) - "\xDF\xB0\xF2\x18\xF0\x78\x07\x01\x29\xA4\x29\x26" - "\x2F\x8A\x34\xCB\x37\xEF\xEE\x41\xE6\x96\xF7\xFF" - "\x61\x47\xD3\xED\x41\x97\xEF\x64\x0C\x48\x56\x5A" - "\xE6\x40\x6E\x4A\x3B\x9E\x7F\xAC\x08\xEC\x25\xAE" - "\x0B\x51\x0E\x2C\x44\x2E\xBD\xDB\x57\xD0\x4A\x6D" - "\x80\x3E\x37\x0F", - .entropylen = 64, - .expected = (unsigned char *) - "\x48\xc6\xa8\xdb\x09\xae\xde\x5d\x8c\x77\xf3\x52" - "\x92\x71\xa7\xb9\x6d\x53\x6d\xa3\x73\xe3\x55\xb8" - "\x39\xd6\x44\x2b\xee\xcb\xe1\x32\x15\x30\xbe\x4e" - "\x9b\x1e\x06\xd1\x6b\xbf\xd5\x3e\xea\x7c\xf5\xaa" - "\x4b\x05\xb5\xd3\xa7\xb2\xc4\xfe\xe7\x1b\xda\x11" - "\x43\x98\x03\x70\x90\xbf\x6e\x43\x9b\xe4\x14\xef" - "\x71\xa3\x2a\xef\x9f\x0d\xb9\xe3\x52\xf2\x89\xc9" - "\x66\x9a\x60\x60\x99\x60\x62\x4c\xd6\x45\x52\x54" - "\xe6\x32\xb2\x1b\xd4\x48\xb5\xa6\xf9\xba\xd3\xff" - "\x29\xc5\x21\xe0\x91\x31\xe0\x38\x8c\x93\x0f\x3c" - "\x30\x7b\x53\xa3\xc0\x7f\x2d\xc1\x39\xec\x69\x0e" - "\xf2\x4a\x3c\x65\xcc\xed\x07\x2a\xf2\x33\x83\xdb" - "\x10\x74\x96\x40\xa7\xc5\x1b\xde\x81\xca\x0b\x8f" - "\x1e\x0a\x1a\x7a\xbf\x3c\x4a\xb8\x8c\xaf\x7b\x80" - "\xb7\xdc\x5d\x0f\xef\x1b\x97\x6e\x3d\x17\x23\x5a" - "\x31\xb9\x19\xcf\x5a\xc5\x00\x2a\xb6\xf3\x99\x34" - "\x65\xee\xe9\x1c\x55\xa0\x3b\x07\x60\xc9\xc4\xe4" - "\xf7\x57\x5c\x34\x9f\xc6\x31\x30\x3f\x23\xb2\x89" - "\xc0\xe7\x50\xf3\xde\x59\xd1\x0e\xb3\x0f\x78\xcc" - "\x7e\x54\x5e\x61\xf6\x86\x3d\xb3\x11\x94\x36\x3e" - "\x61\x5c\x48\x99\xf6\x7b\x02\x9a\xdc\x6a\x28\xe6" - "\xd1\xa7\xd1\xa3", - .expectedlen = 256, - .addtla = (unsigned char *) - "\x6B\x0F\x4A\x48\x0B\x12\x85\xE4\x72\x23\x7F\x7F" - "\x94\x7C\x24\x69\x14\x9F\xDC\x72\xA6\x33\xAD\x3C" - "\x8C\x72\xC1\x88\x49\x59\x82\xC5", - .addtlb = (unsigned char *) - "\xC4\xAF\x36\x3D\xB8\x5D\x9D\xFA\x92\xF5\xC3\x3C" - "\x2D\x1E\x22\x2A\xBD\x8B\x05\x6F\xA3\xFC\xBF\x16" - "\xED\xAA\x75\x8D\x73\x9A\xF6\xEC", - .addtllen = 32, - .pers = NULL, - .perslen = 0, + /* .entropy = ACVP entropyInput || nonce */ + .entropy = "\x47\x28\x33\x05\x82\xE8\xA7\x58\x05\xBD\x07\x9E" + "\xDB\x59\x87\x08\x3B\x82\x40\x70\xA1\xB7\x33\x4F" + "\x0F\x53\xBE\xF6\x98\x75\xFA\x21\x00\x04\xBC\x58" + "\x9B\xB1\xB3\xBC\x2A\xF6\xA4\x2A\xE1\xB3\x65\x24" + "\xA8\xEE\x56\x70\x5E\x28\x06\x04\x80\xCE\xB7\x36" + "\xA4\xD1\x4E\xAA\xE7\xE8\x51\x40\x7D\x30\xF7\x91" + "\xF2\x9E\x98\xA7\xBB\xB3\x1D\xC6\x8A\x62\xC7\xE7" + "\x1F\xE1\x0A\x52\x45\x39\x88\x92\x43\xA6\x5B\xC3" + "\x9D\x60\xDE\xFE\x79\xEF\x87\x6F\xD5\x76\x51\x69" + "\x7B\x4C\x3D\x08\x60\xFA\xDC\x00\x94\xEC\x0A\xC5" + "\xE7\xCB\x30\x05\x9F\xCC\x07\x44\x07\x14\xF4\xF9" + "\xBC\x7D\xC0\x66\x63\x5B\xD3\x2A\xA7\xF2\x1D\x75" + "\x3F\x28\x5F\x4A\xEB\x63\xD7\x92\x5A\x9A\x7C\x3A" + "\x56\xEA\xCB\xA9\xA0\xF9\x5B\x99\xC2\x7D\x31\xBF" + "\x44\xC7\x64\x6B\x7E\x64\x60\x64\x05\x86\xF0\x6B" + "\x76\xA7\x3E\x63\xAD\xB6\x76\xED\x3D\x05\x2E\xC7" + "\xC7\x52\x8F\x07\x56\x23\xFC\x2F\x93\xD5\xF2\x29" + "\xC6\x84\x48\xD1\x88\xB9\x3F\x84\xB2\x93\xFC\x2F" + "\x00\xB1\xBC\xBE\xAC\xC4\x94\x36\xF1\x2B\xF0\xC7" + "\x36\xE8\x1D\x45\x0A\xA2\xFE\x72\xD7\x3E\x15\x6A" + "\x74\x23\xB2\xD1\x3C\x20\xF2\xB7\x19\xC5\xF0\x74" + "\x69\x06\xD1\x92\x47\xC9\x68\xDC\xEE\xBC\xF4\x3A" + "\x8B\x7C\xA4\xA4\x4A\x15\xF4\xF0\x26\x26\xC5\x7D" + "\x57\xDC\x00\x59\x07\xDF\x84\x2A\x23\xA9\xC1\xAF" + "\x47\x49\x88\xCC\x2F\x3B\x90\x39\xA0\x09\xAE\x3C" + "\x79\xF9\x97\x9D\xEF\x13\x1D\x2B\xB6\x18\xDB\xCF" + "\x95\x98\x17\x7F\xF6\x95\x44\x3A\x40\x90\x63\x16" + "\x70\x38\x22\xC5\xD8\xE4\x57\xA0\x8E\x51\x6B\xED" + "\x03\x18\xC6\x74\xFA\xCA\xF2\xD5\xB2\x5A\x0C\x02" + "\x48\x9F\x70\x0B\x1C\x0A\xD1\xD6\x4F\x3F\x70\x3C" + "\x1A\x62\x29\x63\xD0\x92\x76\x30\x7C\xB9\x54\xEC" + "\xF6\x92\xA3\x11\x66\xB2\x56\xE0\x75\x3D\x27\x01", + .entropylen = 384, + .pers = "\x03\x75\x33\x7B\x6B\xE5\x14\xAF\x0E\x43\x33\xCC\xD3" + "\xF4\xF0\x8B\x8A\xCC\xFE\x95\xC1\x20\xB9\x56\x3D\x2C" + "\x34\xC7\xA1\x4C\xBC\xDC\x0A\x8D\xBE\x68\x28\x89\x2A" + "\x92\x10\x05\x4E\xF9\xE2\x51\xF7\x4F\xF4\x48\x76\xC9" + "\xCE\xA8\x6D\xC1\xDE\x5C\x05\x95\x77\x24\xB4\x5D\x3D" + "\x16\x1D\xCB\x43\xE5\xD3\x01\x96\xCC\x3E\x2E\xE1\x97" + "\xB3\x42\xC2\xAB\xEC\x56\xA9\xF9\xF2\x28\x59\x01\x4E" + "\xFC\x8A\xC0\x5E\x4E\x33\x30\x91\x96\x93\xBA\xFA\xE1" + "\x9F\x20\xC3\xC1\xD1\xC6\xC3\x2C\x59\x8F\x56\xD5\x73" + "\xE8\x8D\xCF\xAC\xB1\x85\x3E\xC7\x73\x21\x59\x8D\x0F" + "\xF4\xA4\xC4\x0C\xD2\x18\x81\x5F\x3E\x37\xC9\x9F\xD9" + "\xDE\x3F\x15\x6F\xAC\x1A\xEC\x5E\x28\xD5\x56\xA2\x65" + "\xD2\x7C\x41\xDE\x57\x8C\x60\xAB\xA5\x03\x42\xC8\x3C" + "\x70\xC2\xD1\x11\x62\x25\x4E\x17\x58\xBB\x08\x51\x79" + "\xE6\xED\xBA\x9A\xA7\x07\xD5\x0E\x89\x43\x31\x4F\x99" + "\xEE\xED\xF1\x36\xFA\x1E\xC0\x25\x01\xDA\x19\xC2\x7D" + "\x5D\x78\x74\x5C\xC0\x72\x2E\xF1\x7B\x4E\x9C\xDB\xFE" + "\x60\x89\x62\x71\x9C\xEA\xD3\xDF\x82\xC7\x8B\xB4\x7B" + "\x7B\x7F\x6A\x62\x3C\x57\x76\xA5\x67\x5F\x70\xFB\xE0" + "\x1B\x23\x79\x71\xB5\x7C\xEA\x76\x99", + .perslen = 256, + + .ent_reseed = "\xE0\x5B\x69\xC5\xF9\xD4\x5A\x1F\xC1\x71\x0C" + "\x37\x6F\xFE\x31\xE0\xEF\x3E\x9B\xD5\x46\x43" + "\xA2\x15\xFA\x86\x75\x1C\x95\x9F\xE6\xD6\x41" + "\x50\x36\x0F\x67\x68\x4A\x72\x32\x85\xB0\xCB" + "\xA4\x0D\x1F\xA2\x43\xCA\x30\xF1\x42\xF8\xC4" + "\x17\x6A\xD1\x2D\x43\x46\x8C\xA5\x72\x3C\xB1" + "\x44\x8E\xA1\x75\xAA\x20\x30\xDD\xCD\x0B\x5A" + "\x0D\xE6\x28\xCA\xBC\xA9\x3B\x11\x23\x88\x85" + "\xDF\xD8\x84\x11\x89\x7A\x4F\x00\x90\x0B\xD8" + "\x8A\x35\xE9\x5F\xEC\x05\x42\x15\xCA\x7E\xA3" + "\xEF\xEF\xE3\xB7\xBE\x96\x8C\x36\x7D\x15\x3C" + "\x7A\x78\x00\x61\xAF\x62\x45\xA7\x4B\xAE\x4A" + "\xFD\xC9\xE0\x89\x53\x36\x71\x8F\x38\xC4\x00" + "\x57\xD9\xE6\xC1\xEC\xBF\xF7\x4B\x3F\x55\xD6" + "\x54\x15\x72\xB2\x23\x76\xD1\x4E\x8E\x7E\xFB" + "\xC8\xD6\xA4\xA4\x7E\x8E\xD8\x76\xD3\xEB\x90" + "\x90\xEB\xB3\x84\x26\x34\x93\x36\xCA\xA9\x12" + "\xD3\x6D\x84\x07\xE1\x0E\xE7\x63\x24\x54\x90" + "\x42\x8C\x6B\xE7\x21\x53\x2D\x16\xE9\x68\xA9" + "\xC2\x9A\x7A\x93\x31\x5E\x35\x72\xE2\x0F\x3D" + "\x55\x41\x8C\xC5\xD1\xBB\xEE\x5F\x3C\x95\x52" + "\x2A\x65\x47\xB6\x84\x6A\x05\x19\xD9\xE7\x68" + "\x15\xFA\x49\xD9\x9D\xFD\x47\x9F\xB9\xA6\xBB" + "\xA8\xD4\x22\x6C\x8B\x59\x47\xEF\xD1\xD0\xBF" + "\xBC\xE4\x53\x31\x2F\xA5\xD4\x2C\x89\xCA\xE5" + "\x29\x64\xF8\x51\x2A\x02\xDE\x31\x0D\x54\x0E" + "\x0E\xB8\x78\xE6\x2A\x3E\x31\xA2\xA4\xCD\x91" + "\x79\xF2\x9B\x04\xA0\xDB\x78\xAC\x0D\xB5\xCA" + "\x60\x4C\x08\x96\xCA\x8A\xE9\x93\x9F\x62\x38" + "\xAE", + .ent_reseed_len = 320, + .addtl_reseed = "\xD5\x46\x71\x38\x46\xE0\xC1\x27\x2C\xF1\x07" + "\xDD\x29\x73\xD7\xF4\x5A\x3A\xE0\x99\x98\x0A" + "\xEB\xA5\x9E\x2E\x49\x21\x7B\x18\xC0\xD8\x3D" + "\xEE\x49\xF9\x52\x7C\x55\x5E\x5E\x06\xC2\x7E" + "\x34\x3A\xA5\xB7\x78\x21\xC1\xB8\x8B\x4E\x07" + "\x1F\x3F\xC4\xB4\x9B\x3F\x20\x2D\xEE\x70\x3B" + "\x18\xCF\x2B\x50\x15\x1B\xF3\x6C\xE7\x9F\x2A" + "\x2B\x69\x53\xCA\x88\x41\xA9\x07\x31\x14\x55" + "\xBD\x75\x49\x68\x98\x48\xCA\x46\xA5\xEC\xAA" + "\x9D\x8E\x6F\x40\xBA\xCA\xC8\xE9\x9F\xA4\xC5" + "\x94\x89\x2C\x4D\xE4\x0A\x66\xD3\xDB\x1A\xD9" + "\xA7\x3F\x6B\x0A\xE0\xE4\xDC\x0B\x8B\x64\xBF" + "\xB4\x95\xA1\xAE\x92\xA8\x7C\xE2\x4B\xED\xFD" + "\xFD\xE0\x54\x48\x7C\x25\xD6\xD1\x0A\xAB\x5E" + "\x33\x2F\x1D\xD3\x62\x47\xAB\x35\x8C\xA1\xC2" + "\x75\xDD\x75\xCA\x09\xE1\x38\xDE\x87\x79\x0C" + "\xD7\x5D\x3E\x6D\x28\x8F\x12\x98\x2C\x26\x34" + "\x91\x0B\x6B\xB7\x73", + .addtl_reseed_len = 192, + + .addtla = "\xC8\xE1\x03\x59\xEA\x9F\xD3\x1F\xCC\xCB\x5A\x3E" + "\x23\xDB\x47\x75\x1B\x3A\x6C\x0B\xED\xE6\xC0\xB6" + "\x4B\x82\x53\x5B\x6D\xEE\x2B\x97\x0F\x59\x07\xA4" + "\xFE\xE2\x26\x4F\xFF\xF7\x46\xAF\x62\xC4\x42\xE8" + "\x06\xFA\x1F\xAA\x66\xF3\xA4\xCF\x85\x02\x3C\x11" + "\xEF\xD2\x16\x13\x7A\xBD\x03\x66\xC3\x4D\x6F\x3A" + "\xE5\xD3\xFF\x92\xB6\x45\xB8\x88\x94\x42\x2E\x84" + "\x02\xA5\x54\x12\xBF\xCB\xF1\x6E\x1C\x0C\x23\xFE" + "\x8A\xFD\xF5\x1A\x4C\xD6\x2A\x34\x7F\x21\x50\xBB" + "\x06\x64\x9A\x77\x70\x59\x1D\x12\xD1\xA0\x10\x70" + "\xD7\x4F\x3C\xEE\x82\xEF\x5B\x35\x8F\x05\xF6\x51" + "\xBC\x28\xE1\xB1\x54\xFF\x25\x12\x16\x2C\x62\xFC" + "\xB9\x74\x5E\x78\x41\xB2\x04\x80\x4E\xB1\x43\x2E" + "\x88\x7F\x34\xA4\x33\x66\xE8\x68\x60\x54\xEB\xCE" + "\xD1\x5F\xC4\xD6\x21\x5E\x22\x1A\x7E\xC5\x6D\xB7" + "\x93\x8F\x9C\x77\x6E\x56\xA5\xA8\xF7\xB2\x10\x19", + .addtlb = "\xB8\x1E\x9E\xE2\xB3\xE4\x04\x43\x51\x7B\x96\x32" + "\xAC\x95\xF2\x1E\x5E\x7A\xBF\x68\xE3\x7A\xCE\xE5" + "\x2B\x3B\xB0\x34\x7F\xE1\xB5\x37\x3C\x5B\xD2\x6B" + "\x17\xF6\x18\xAF\x7C\x01\xA5\x84\xFE\x07\x0B\x46" + "\xCC\x96\x61\xAB\xCD\x81\x95\x8A\x8A\xB6\xD8\xCC" + "\x94\x80\x45\xF6\xFF\x95\x3A\xB8\xDC\xBF\xB4\xBF" + "\x26\x8C\xE9\x79\x05\x58\x9C\x03\x08\x45\xB5\xC4" + "\xD8\xB4\xCD\x76\x13\xAE\x2B\xCC\xB5\x3E\x3C\x65" + "\x7A\xAA\xDC\x9B\x0B\x13\x8B\x82\x5A\x39\x60\x9A" + "\xF7\xA8\x38\xB5\x83\x8E\x0B\xD1\xE6\xBF\xA1\xDC" + "\x30\x45\xCC\x67\x41\x0F\xF9\x86\x27\xE0\x22\x3E" + "\x0D\x1F\x92\x13\x16\x9B\x84\x79\x91\xFE\xBC\xDF" + "\x15\x6C\xDC\xAE\xC5\x64\x46\x9C\xE8\xEA\xBB\x9D" + "\x27\xA2\x1E\xDF\xB2\xF2\x98\xB4\x88\x4E\x22\x5F" + "\x3C\xD0\x35\x2C\x5C\x89\xC7\xEC\xE3\xF3\x09\x60" + "\xEF\xAC\x78\xBF\x94\xAA\x8C\x30\x7F\xCF\xE4\x4B", + .addtllen = 192, + + .expected = "\x93\xFF\x4F\x4A\xA7\xE0\xFC\x3B\xCF\xCE\x57\xCD" + "\xFD\xE9\x94\x6D\x0D\x45\x7E\xA3\x98\xBB\xE6\x54" + "\x36\xF9\x92\xE6\xBB\xC5\x93\x16\x69\x35\x01\xF0" + "\x5A\xE2\x43\xFC\x73\x7C\xA3\x5C\x5B\x49\x72\x69" + "\x6A\xC4\xB6\xD4\xB2\x48\x27\x72\xCA\xE3\xF3\xB8" + "\xD6\x95\x9F\x39\xC8\xD7\x72\xAF\xC2\x7C\x75\xE5" + "\xA4\xF7\x52\x4F\xDF\x80\x75\xCA\x4B\xFA\x75\x9A" + "\x7A\x8D\x48\x94\x30\x1C\x82\x5E\xD6\x3F\xF1\x78" + "\x84\xAA\x8D\x8B\x4F\x6A\x20\x12\xA2\x65\xC5\x02" + "\x32\xA1\xE4\x6B\x86\x2F\xCF\x92\xCD\x01\x55\xF7" + "\xB8\xAB\xC3\x2C\x42\xC3\xFD\x9B\x59\x2D\x47\x8E" + "\xB6\x8D\xE7\x04\x2E\x67\xD9\x07\x14\xA3\xF2\x74" + "\x79\x9C\xAB\xC6\xD6\x52\x3E\x91\x81\xA4\x3C\x9A" + "\x3E\x10\x1E\xD0\x28\xBC\x1C\x50\xF0\xB6\xEC\x01" + "\xE5\x40\x16\x08\xB5\x58\xE0\xC4\xC2\x9A\xBB\x13" + "\xAB\x10\x4B\x07\x24\x09\xEB\xF9\x5E\xAA\x3E\x3A" + "\x25\x34\x5B\x97\x92\xF9\x46\x8A\x8E\x5A\x06\x9C" + "\x2B\x1C\x8E\x47\x19\xC3\x3B\x14\x8A\xC1\xEB\xF7" + "\xB0\xA2\x05\xE0\x70\x12\x88\x21\xFF\xC0\x35\x6D" + "\xE9\x08\x7E\x11\x6E\xD7\x16\x48\x24\x43\xAF\x33" + "\xA3\x48\x44\x91\xC5\x32\x1D\x87\xF6\x9B\x10\x1C" + "\xA4\x7A\x74\x23\xB3\xFC\xB9\x87\x08\xE6\x9A\xEF" + "\xD5\x93\x82\x17\xD4\x78\xDA\x46\x34\xC2\x61\x8C" + "\xB7\x53\x89\xC4\x8A\xD8\xA0\x2E\xCE\xCA\x24\x16" + "\xF0\x18\x7F\xC3\x12\x3F\xD0\xB1\xEF\x37\x99\xA8" + "\x04\x1F\x76\x50\x81\x08\xCD\x4D\x43\xEF\x64\xB6" + "\x03\x57\xB7\x5F\xDD\xF6\xBA\x34\xE2\x88\xE7\x1F" + "\x62\xA5\xA4\x05\xEB\x1A\xFE\x0B\xFE\x74\x7D\x64" + "\x29\x83\xE8\x0B\x97\x7D\x94\x5B\xF9\x3C\x8E\xC8" + "\x6B\xCD\xAD\x63\x32\x6E\x00\xBF\x8E\x57\xF2\x32" + "\x88\x53\x17\x40\xE3\xF8\xF8\xD9\xFD\xCD\x76\x84" + "\xC6\xFD\xB1\x10\x40\xED\x75\xDD\xBD\x78\x8B\x0A" + "\x61\x1E\xCC\xC4\x4F\x95\xF1\x2F\x8F\x5A\xF0\x12" + "\x00\xCE\x75\xB8\xE9\xAB\x63\xC0\x7A\xF6\x9A\x47" + "\xD2\x3C\xB0\xAD\xAF\x03\xDF\x25\xDD\x0C\x0F\xB6" + "\x29\x09\x0F\x28\x5E\xA8\x67\xBB\xC9\x78\xBE\x12" + "\xD8\xD6\xD0\x98\x82\x29\xA3\x82\xFB\x8E\x1C\x79" + "\x28\x52\x22\x73\x3C\x6F\xB5\x33\xFF\x40\x26\x4C" + "\x30\xE4\xE0\x39\x59\x72\x65\x79\x9F\xB7\x89\x87" + "\x64\xAC\x45\x11\x0D\xDD\xC0\x44\x5E\x0D\xDF\xDB" + "\x91\x42\x5F\x52\x7F\xBB\x66\xEE\x32\x90\x8F\x6F" + "\xF8\xB9\xFE\xEA\x42\xFB\x60\x2B\xE3\xD9\xB2\xD1" + "\x74\x37\x14\xC6\xDA\x68\xE6\x09", + .expectedlen = 512, } }; From 89cfd38c788e9d8a2d05d1487c4513043e6d46a2 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:01 -0700 Subject: [PATCH 135/655] crypto: drbg - Remove support for HMAC-SHA256 and HMAC-SHA384 Remove support for the HMAC-SHA256 and HMAC-SHA384 variants of HMAC_DRBG, leaving only the HMAC-SHA512 variant of HMAC_DRBG. HMAC-SHA512 is already the default. The default did used to be HMAC-SHA256, but several years ago it was upgraded to HMAC-SHA512 "to support compliance with SP800-90B and SP800-90C". Given that the point of crypto/drbg.c is compliance with those standards, and there's also no technical reason to prefer HMAC-SHA384 in this situation even if acceptable, there's really no point in offering anything else. Note: now that only HMAC-SHA512 remains, a lot of unnecessary abstractions can be removed. A later commit will do that. This commit just straightforwardly removes the HMAC-SHA256 and HMAC-SHA384 code. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 22 +--- crypto/testmgr.c | 27 ----- crypto/testmgr.h | 280 ----------------------------------------------- 3 files changed, 2 insertions(+), 327 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 6301eb2e304c..81bccacd3595 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1,9 +1,7 @@ /* * DRBG: Deterministic Random Bits Generator - * Based on NIST Recommended DRBG from NIST SP800-90A with the following - * properties: - * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores - * * with and without prediction resistance + * Implementation of the HMAC SHA-512 DRBG from NIST SP800-90A, + * both with and without prediction resistance * * Copyright Stephan Mueller , 2014 * @@ -215,18 +213,6 @@ enum drbg_prefixes { */ static const struct drbg_core drbg_cores[] = { { - .flags = DRBG_HMAC | DRBG_STRENGTH256, - .statelen = 48, /* block length of cipher */ - .blocklen_bytes = 48, - .cra_name = "hmac_sha384", - .backend_cra_name = "hmac(sha384)", - }, { - .flags = DRBG_HMAC | DRBG_STRENGTH256, - .statelen = 32, /* block length of cipher */ - .blocklen_bytes = 32, - .cra_name = "hmac_sha256", - .backend_cra_name = "hmac(sha256)", - }, { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 64, /* block length of cipher */ .blocklen_bytes = 64, @@ -276,10 +262,6 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg); MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha384"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha384"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha256"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha256"); /* update function of HMAC DRBG as defined in 10.1.2.2 */ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, diff --git a/crypto/testmgr.c b/crypto/testmgr.c index ad4c2e66b812..4199b7d3e9fb 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4649,21 +4649,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "digest_null", .test = alg_test_null, - }, { - .alg = "drbg_nopr_hmac_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_nopr_hmac_sha256_tv_template) - } - }, { - /* - * There is no need to specifically test the DRBG with every - * backend cipher -- covered by drbg_nopr_hmac_sha512 test - */ - .alg = "drbg_nopr_hmac_sha384", - .test = alg_test_null, - .fips_allowed = 1 }, { .alg = "drbg_nopr_hmac_sha512", .test = alg_test_drbg, @@ -4671,18 +4656,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) } - }, { - .alg = "drbg_pr_hmac_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_hmac_sha256_tv_template) - } - }, { - /* covered by drbg_pr_hmac_sha256 test */ - .alg = "drbg_pr_hmac_sha384", - .test = alg_test_null, - .fips_allowed = 1 }, { .alg = "drbg_pr_hmac_sha512", .test = alg_test_drbg, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index fc70ca86d61f..c47203f73fd1 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -23433,286 +23433,6 @@ static const struct aead_testvec aegis128_tv_template[] = { }, }; -static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\x99\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" - "\x7e\x5c\x0e\xae\x0d\x3e\x30\x95\x59\xe9\xfe\x96" - "\xb0\x67\x6d\x49\xd5\x91\xea\x4d\x07\xd2\x0d\x46" - "\xd0\x64\x75\x7d\x30\x23\xca\xc2\x37\x61\x27\xab", - .entropylen = 48, - .entpra = (unsigned char *) - "\xc6\x0f\x29\x99\x10\x0f\x73\x8c\x10\xf7\x47\x92" - "\x67\x6a\x3f\xc4\xa2\x62\xd1\x37\x21\x79\x80\x46" - "\xe2\x9a\x29\x51\x81\x56\x9f\x54", - .entprb = (unsigned char *) - "\xc1\x1d\x45\x24\xc9\x07\x1b\xd3\x09\x60\x15\xfc" - "\xf7\xbc\x24\xa6\x07\xf2\x2f\xa0\x65\xc9\x37\x65" - "\x8a\x2a\x77\xa8\x69\x90\x89\xf4", - .entprlen = 32, - .expected = (unsigned char *) - "\xab\xc0\x15\x85\x60\x94\x80\x3a\x93\x8d\xff\xd2" - "\x0d\xa9\x48\x43\x87\x0e\xf9\x35\xb8\x2c\xfe\xc1" - "\x77\x06\xb8\xf5\x51\xb8\x38\x50\x44\x23\x5d\xd4" - "\x4b\x59\x9f\x94\xb3\x9b\xe7\x8d\xd4\x76\xe0\xcf" - "\x11\x30\x9c\x99\x5a\x73\x34\xe0\xa7\x8b\x37\xbc" - "\x95\x86\x23\x50\x86\xfa\x3b\x63\x7b\xa9\x1c\xf8" - "\xfb\x65\xef\xa2\x2a\x58\x9c\x13\x75\x31\xaa\x7b" - "\x2d\x4e\x26\x07\xaa\xc2\x72\x92\xb0\x1c\x69\x8e" - "\x6e\x01\xae\x67\x9e\xb8\x7c\x01\xa8\x9c\x74\x22" - "\xd4\x37\x2d\x6d\x75\x4a\xba\xbb\x4b\xf8\x96\xfc" - "\xb1\xcd\x09\xd6\x92\xd0\x28\x3f", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xb9\x1f\xe9\xef\xdd\x9b\x7d\x20\xb6\xec\xe0\x2f" - "\xdb\x76\x24\xce\x41\xc8\x3a\x4a\x12\x7f\x3e\x2f" - "\xae\x05\x99\xea\xb5\x06\x71\x0d\x0c\x4c\xb4\x05" - "\x26\xc6\xbd\xf5\x7f\x2a\x3d\xf2\xb5\x49\x7b\xda", - .entropylen = 48, - .entpra = (unsigned char *) - "\xef\x67\x50\x9c\xa7\x7d\xdf\xb7\x2d\x81\x01\xa4" - "\x62\x81\x6a\x69\x5b\xb3\x37\x45\xa7\x34\x8e\x26" - "\x46\xd9\x26\xa2\x19\xd4\x94\x43", - .entprb = (unsigned char *) - "\x97\x75\x53\x53\xba\xb4\xa6\xb2\x91\x60\x71\x79" - "\xd1\x6b\x4a\x24\x9a\x34\x66\xcc\x33\xab\x07\x98" - "\x51\x78\x72\xb2\x79\xfd\x2c\xff", - .entprlen = 32, - .expected = (unsigned char *) - "\x9c\xdc\x63\x8a\x19\x23\x22\x66\x0c\xc5\xb9\xd7" - "\xfb\x2a\xb0\x31\xe3\x8a\x36\xa8\x5a\xa8\x14\xda" - "\x1e\xa9\xcc\xfe\xb8\x26\x44\x83\x9f\xf6\xff\xaa" - "\xc8\x98\xb8\x30\x35\x3b\x3d\x36\xd2\x49\xd4\x40" - "\x62\x0a\x65\x10\x76\x55\xef\xc0\x95\x9c\xa7\xda" - "\x3f\xcf\xb7\x7b\xc6\xe1\x28\x52\xfc\x0c\xe2\x37" - "\x0d\x83\xa7\x51\x4b\x31\x47\x3c\xe1\x3c\xae\x70" - "\x01\xc8\xa3\xd3\xc2\xac\x77\x9c\xd1\x68\x77\x9b" - "\x58\x27\x3b\xa5\x0f\xc2\x7a\x8b\x04\x65\x62\xd5" - "\xe8\xd6\xfe\x2a\xaf\xd3\xd3\xfe\xbd\x18\xfb\xcd" - "\xcd\x66\xb5\x01\x69\x66\xa0\x3c", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x17\xc1\x56\xcb\xcc\x50\xd6\x03\x7d\x45\x76\xa3" - "\x75\x76\xc1\x4a\x66\x1b\x2e\xdf\xb0\x2e\x7d\x56" - "\x6d\x99\x3b\xc6\x58\xda\x03\xf6", - .addtlb = (unsigned char *) - "\x7c\x7b\x4a\x4b\x32\x5e\x6f\x67\x34\xf5\x21\x4c" - "\xf9\x96\xf9\xbf\x1c\x8c\x81\xd3\x9b\x60\x6a\x44" - "\xc6\x03\xa2\xfb\x13\x20\x19\xb7", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89" - "\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf" - "\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20" - "\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67", - .entropylen = 48, - .entpra = (unsigned char *) - "\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79" - "\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57" - "\x20\x28\xad\xf2\x60\xd7\xcd\x45", - .entprb = (unsigned char *) - "\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71" - "\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66" - "\x1f\xfa\x74\xd3\xac\xa6\x74\x60", - .entprlen = 32, - .expected = (unsigned char *) - "\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99" - "\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3" - "\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75" - "\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61" - "\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88" - "\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e" - "\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c" - "\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce" - "\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc" - "\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc" - "\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f" - "\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce" - "\xcd\x56\x80\xbc\xb8\x15\xc8\xaa", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xc7\xcc\xbc\x67\x7e\x21\x66\x1e\x27\x2b\x63\xdd" - "\x3a\x78\xdc\xdf\x66\x6d\x3f\x24\xae\xcf\x37\x01" - "\xa9\x0d\x89\x8a\xa7\xdc\x81\x58\xae\xb2\x10\x15" - "\x7e\x18\x44\x6d\x13\xea\xdf\x37\x85\xfe\x81\xfb", - .entropylen = 48, - .entpra = (unsigned char *) - "\x7b\xa1\x91\x5b\x3c\x04\xc4\x1b\x1d\x19\x2f\x1a" - "\x18\x81\x60\x3c\x6c\x62\x91\xb7\xe9\xf5\xcb\x96" - "\xbb\x81\x6a\xcc\xb5\xae\x55\xb6", - .entprb = (unsigned char *) - "\x99\x2c\xc7\x78\x7e\x3b\x88\x12\xef\xbe\xd3\xd2" - "\x7d\x2a\xa5\x86\xda\x8d\x58\x73\x4a\x0a\xb2\x2e" - "\xbb\x4c\x7e\xe3\x9a\xb6\x81\xc1", - .entprlen = 32, - .expected = (unsigned char *) - "\x95\x6f\x95\xfc\x3b\xb7\xfe\x3e\xd0\x4e\x1a\x14" - "\x6c\x34\x7f\x7b\x1d\x0d\x63\x5e\x48\x9c\x69\xe6" - "\x46\x07\xd2\x87\xf3\x86\x52\x3d\x98\x27\x5e\xd7" - "\x54\xe7\x75\x50\x4f\xfb\x4d\xfd\xac\x2f\x4b\x77" - "\xcf\x9e\x8e\xcc\x16\xa2\x24\xcd\x53\xde\x3e\xc5" - "\x55\x5d\xd5\x26\x3f\x89\xdf\xca\x8b\x4e\x1e\xb6" - "\x88\x78\x63\x5c\xa2\x63\x98\x4e\x6f\x25\x59\xb1" - "\x5f\x2b\x23\xb0\x4b\xa5\x18\x5d\xc2\x15\x74\x40" - "\x59\x4c\xb4\x1e\xcf\x9a\x36\xfd\x43\xe2\x03\xb8" - "\x59\x91\x30\x89\x2a\xc8\x5a\x43\x23\x7c\x73\x72" - "\xda\x3f\xad\x2b\xba\x00\x6b\xd1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x18\xe8\x17\xff\xef\x39\xc7\x41\x5c\x73\x03\x03" - "\xf6\x3d\xe8\x5f\xc8\xab\xe4\xab\x0f\xad\xe8\xd6" - "\x86\x88\x55\x28\xc1\x69\xdd\x76", - .addtlb = (unsigned char *) - "\xac\x07\xfc\xbe\x87\x0e\xd3\xea\x1f\x7e\xb8\xe7" - "\x9d\xec\xe8\xe7\xbc\xf3\x18\x25\x77\x35\x4a\xaa" - "\x00\x99\x2a\xdd\x0a\x00\x50\x82", - .addtllen = 32, - .pers = (unsigned char *) - "\xbc\x55\xab\x3c\xf6\x52\xb0\x11\x3d\x7b\x90\xb8" - "\x24\xc9\x26\x4e\x5a\x1e\x77\x0d\x3d\x58\x4a\xda" - "\xd1\x81\xe9\xf8\xeb\x30\x8f\x6f", - .perslen = 32, - }, -}; - -static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { - { - .entropy = (unsigned char *) - "\xca\x85\x19\x11\x34\x93\x84\xbf\xfe\x89\xde\x1c" - "\xbd\xc4\x6e\x68\x31\xe4\x4d\x34\xa4\xfb\x93\x5e" - "\xe2\x85\xdd\x14\xb7\x1a\x74\x88\x65\x9b\xa9\x6c" - "\x60\x1d\xc6\x9f\xc9\x02\x94\x08\x05\xec\x0c\xa8", - .entropylen = 48, - .expected = (unsigned char *) - "\xe5\x28\xe9\xab\xf2\xde\xce\x54\xd4\x7c\x7e\x75" - "\xe5\xfe\x30\x21\x49\xf8\x17\xea\x9f\xb4\xbe\xe6" - "\xf4\x19\x96\x97\xd0\x4d\x5b\x89\xd5\x4f\xbb\x97" - "\x8a\x15\xb5\xc4\x43\xc9\xec\x21\x03\x6d\x24\x60" - "\xb6\xf7\x3e\xba\xd0\xdc\x2a\xba\x6e\x62\x4a\xbf" - "\x07\x74\x5b\xc1\x07\x69\x4b\xb7\x54\x7b\xb0\x99" - "\x5f\x70\xde\x25\xd6\xb2\x9e\x2d\x30\x11\xbb\x19" - "\xd2\x76\x76\xc0\x71\x62\xc8\xb5\xcc\xde\x06\x68" - "\x96\x1d\xf8\x68\x03\x48\x2c\xb3\x7e\xd6\xd5\xc0" - "\xbb\x8d\x50\xcf\x1f\x50\xd4\x76\xaa\x04\x58\xbd" - "\xab\xa8\x06\xf4\x8b\xe9\xdc\xb8", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\xf9\x7a\x3c\xfd\x91\xfa\xa0\x46\xb9\xe6\x1b\x94" - "\x93\xd4\x36\xc4\x93\x1f\x60\x4b\x22\xf1\x08\x15" - "\x21\xb3\x41\x91\x51\xe8\xff\x06\x11\xf3\xa7\xd4" - "\x35\x95\x35\x7d\x58\x12\x0b\xd1\xe2\xdd\x8a\xed", - .entropylen = 48, - .expected = (unsigned char *) - "\xc6\x87\x1c\xff\x08\x24\xfe\x55\xea\x76\x89\xa5" - "\x22\x29\x88\x67\x30\x45\x0e\x5d\x36\x2d\xa5\xbf" - "\x59\x0d\xcf\x9a\xcd\x67\xfe\xd4\xcb\x32\x10\x7d" - "\xf5\xd0\x39\x69\xa6\x6b\x1f\x64\x94\xfd\xf5\xd6" - "\x3d\x5b\x4d\x0d\x34\xea\x73\x99\xa0\x7d\x01\x16" - "\x12\x6d\x0d\x51\x8c\x7c\x55\xba\x46\xe1\x2f\x62" - "\xef\xc8\xfe\x28\xa5\x1c\x9d\x42\x8e\x6d\x37\x1d" - "\x73\x97\xab\x31\x9f\xc7\x3d\xed\x47\x22\xe5\xb4" - "\xf3\x00\x04\x03\x2a\x61\x28\xdf\x5e\x74\x97\xec" - "\xf8\x2c\xa7\xb0\xa5\x0e\x86\x7e\xf6\x72\x8a\x4f" - "\x50\x9a\x8c\x85\x90\x87\x03\x9c", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x51\x72\x89\xaf\xe4\x44\xa0\xfe\x5e\xd1\xa4\x1d" - "\xbb\xb5\xeb\x17\x15\x00\x79\xbd\xd3\x1e\x29\xcf" - "\x2f\xf3\x00\x34\xd8\x26\x8e\x3b", - .addtlb = (unsigned char *) - "\x88\x02\x8d\x29\xef\x80\xb4\xe6\xf0\xfe\x12\xf9" - "\x1d\x74\x49\xfe\x75\x06\x26\x82\xe8\x9c\x57\x14" - "\x40\xc0\xc9\xb5\x2c\x42\xa6\xe0", - .addtllen = 32, - .pers = NULL, - .perslen = 0, - }, { - .entropy = (unsigned char *) - "\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf" - "\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54" - "\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf" - "\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e", - .entropylen = 48, - .expected = (unsigned char *) - "\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81" - "\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37" - "\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10" - "\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61" - "\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28" - "\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f" - "\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07" - "\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66" - "\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2" - "\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29" - "\x10\x37\x41\x03\x0c\xcc\x3a\x56", - .expectedlen = 128, - .addtla = NULL, - .addtlb = NULL, - .addtllen = 0, - .pers = (unsigned char *) - "\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37" - "\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58" - "\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9", - .perslen = 32, - }, { - .entropy = (unsigned char *) - "\xc2\xa5\x66\xa9\xa1\x81\x7b\x15\xc5\xc3\xb7\x78" - "\x17\x7a\xc8\x7c\x24\xe7\x97\xbe\x0a\x84\x5f\x11" - "\xc2\xfe\x39\x9d\xd3\x77\x32\xf2\xcb\x18\x94\xeb" - "\x2b\x97\xb3\xc5\x6e\x62\x83\x29\x51\x6f\x86\xec", - .entropylen = 48, - .expected = (unsigned char *) - "\xb3\xa3\x69\x8d\x77\x76\x99\xa0\xdd\x9f\xa3\xf0" - "\xa9\xfa\x57\x83\x2d\x3c\xef\xac\x5d\xf2\x44\x37" - "\xc6\xd7\x3a\x0f\xe4\x10\x40\xf1\x72\x90\x38\xae" - "\xf1\xe9\x26\x35\x2e\xa5\x9d\xe1\x20\xbf\xb7\xb0" - "\x73\x18\x3a\x34\x10\x6e\xfe\xd6\x27\x8f\xf8\xad" - "\x84\x4b\xa0\x44\x81\x15\xdf\xdd\xf3\x31\x9a\x82" - "\xde\x6b\xb1\x1d\x80\xbd\x87\x1a\x9a\xcd\x35\xc7" - "\x36\x45\xe1\x27\x0f\xb9\xfe\x4f\xa8\x8e\xc0\xe4" - "\x65\x40\x9e\xa0\xcb\xa8\x09\xfe\x2f\x45\xe0\x49" - "\x43\xa2\xe3\x96\xbb\xb7\xdd\x2f\x4e\x07\x95\x30" - "\x35\x24\xcc\x9c\xc5\xea\x54\xa1", - .expectedlen = 128, - .addtla = (unsigned char *) - "\x41\x3d\xd8\x3f\xe5\x68\x35\xab\xd4\x78\xcb\x96" - "\x93\xd6\x76\x35\x90\x1c\x40\x23\x9a\x26\x64\x62" - "\xd3\x13\x3b\x83\xe4\x9c\x82\x0b", - .addtlb = (unsigned char *) - "\xd5\xc4\xa7\x1f\x9d\x6d\x95\xa1\xbe\xdf\x0b\xd2" - "\x24\x7c\x27\x7d\x1f\x84\xa4\xe5\x7a\x4a\x88\x25" - "\xb8\x2a\x2d\x09\x7d\xe6\x3e\xf1", - .addtllen = 32, - .pers = (unsigned char *) - "\x13\xce\x4d\x8d\xd2\xdb\x97\x96\xf9\x41\x56\xc8" - "\xe8\xf0\x76\x9b\x0a\xa1\xc8\x2c\x13\x23\xb6\x15" - "\x36\x60\x3b\xca\x37\xc9\xee\x29", - .perslen = 32, - }, -}; - static const struct drbg_testvec drbg_pr_hmac_sha512_tv_template[] = { /* * Borrowed from the first applicable test vector from ACVP: From b9e081978ea4d21f006d40d6517421142f9fa479 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:02 -0700 Subject: [PATCH 136/655] crypto: drbg - Simplify algorithm registration Now that "drbg_pr_hmac_sha512" and "drbg_nopr_hmac_sha512" are the only crypto_rng algorithms left in crypto/drbg.c, simplify the algorithm registration logic to register these more directly without relying on the drbg_cores[] array (which will be removed). Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 100 ++++++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 65 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 81bccacd3595..4a778d0d1fc4 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1145,86 +1145,56 @@ static inline int __init drbg_healthcheck_sanity(void) return rc; } -static struct rng_alg drbg_algs[22]; - -/* - * Fill the array drbg_algs used to register the different DRBGs - * with the kernel crypto API. To fill the array, the information - * from drbg_cores[] is used. - */ -static inline void __init drbg_fill_array(struct rng_alg *alg, - const struct drbg_core *core, int pr) -{ - int pos = 0; - static int priority = 200; - - memcpy(alg->base.cra_name, "stdrng", 6); - if (pr) { - memcpy(alg->base.cra_driver_name, "drbg_pr_", 8); - pos = 8; - } else { - memcpy(alg->base.cra_driver_name, "drbg_nopr_", 10); - pos = 10; - } - memcpy(alg->base.cra_driver_name + pos, core->cra_name, - strlen(core->cra_name)); - - alg->base.cra_priority = priority; - priority++; - /* - * If FIPS mode enabled, the selected DRBG shall have the - * highest cra_priority over other stdrng instances to ensure - * it is selected. - */ - if (fips_enabled) - alg->base.cra_priority += 2000; - - alg->base.cra_ctxsize = sizeof(struct drbg_state); - alg->base.cra_module = THIS_MODULE; - alg->base.cra_init = drbg_kcapi_init; - alg->base.cra_exit = drbg_kcapi_cleanup; - alg->generate = drbg_kcapi_random; - alg->seed = drbg_kcapi_seed; - alg->set_ent = drbg_kcapi_set_entropy; - alg->seedsize = 0; -} +static struct rng_alg drbg_algs[] = { + { + .base.cra_name = "stdrng", + .base.cra_driver_name = "drbg_pr_hmac_sha512", + .base.cra_priority = 200, + .base.cra_ctxsize = sizeof(struct drbg_state), + .base.cra_module = THIS_MODULE, + .base.cra_init = drbg_kcapi_init, + .set_ent = drbg_kcapi_set_entropy, + .seed = drbg_kcapi_seed, + .generate = drbg_kcapi_random, + .base.cra_exit = drbg_kcapi_cleanup, + }, + { + .base.cra_name = "stdrng", + .base.cra_driver_name = "drbg_nopr_hmac_sha512", + .base.cra_priority = 201, + .base.cra_ctxsize = sizeof(struct drbg_state), + .base.cra_module = THIS_MODULE, + .base.cra_init = drbg_kcapi_init, + .set_ent = drbg_kcapi_set_entropy, + .seed = drbg_kcapi_seed, + .generate = drbg_kcapi_random, + .base.cra_exit = drbg_kcapi_cleanup, + }, +}; static int __init drbg_init(void) { - unsigned int i = 0; /* pointer to drbg_algs */ - unsigned int j = 0; /* pointer to drbg_cores */ int ret; ret = drbg_healthcheck_sanity(); if (ret) return ret; - if (ARRAY_SIZE(drbg_cores) * 2 > ARRAY_SIZE(drbg_algs)) { - pr_info("DRBG: Cannot register all DRBG types" - "(slots needed: %zu, slots available: %zu)\n", - ARRAY_SIZE(drbg_cores) * 2, ARRAY_SIZE(drbg_algs)); - return -EFAULT; + /* + * In FIPS mode, boost the algorithm priorities to ensure that when + * users request "stdrng", they really get an algorithm from here. + */ + if (fips_enabled) { + for (size_t i = 0; i < ARRAY_SIZE(drbg_algs); i++) + drbg_algs[i].base.cra_priority += 2000; } - /* - * each DRBG definition can be used with PR and without PR, thus - * we instantiate each DRBG in drbg_cores[] twice. - * - * As the order of placing them into the drbg_algs array matters - * (the later DRBGs receive a higher cra_priority) we register the - * prediction resistance DRBGs first as the should not be too - * interesting. - */ - for (j = 0; ARRAY_SIZE(drbg_cores) > j; j++, i++) - drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 1); - for (j = 0; ARRAY_SIZE(drbg_cores) > j; j++, i++) - drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 0); - return crypto_register_rngs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2)); + return crypto_register_rngs(drbg_algs, ARRAY_SIZE(drbg_algs)); } static void __exit drbg_exit(void) { - crypto_unregister_rngs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2)); + crypto_unregister_rngs(drbg_algs, ARRAY_SIZE(drbg_algs)); } module_init(drbg_init); From aaa891b7c71a493d8746d877cf4c02ecf261ecc4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:03 -0700 Subject: [PATCH 137/655] crypto: drbg - De-virtualize drbg_state_ops Now that there's only one set of state operations, use direct calls to those operations. No change in behavior. In particular, drbg_alloc_state() doesn't change behavior, because the only remaining drbg_core uses HMAC_DRBG. drbg_uninstantiate() doesn't change behavior, because a NULL d_ops implied NULL priv_data which makes a drbg_fini_hash_kernel() a no-op. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 50 ++++++-------------------------------------------- 1 file changed, 6 insertions(+), 44 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 4a778d0d1fc4..04c798d7a8b6 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -111,17 +111,6 @@ struct drbg_core { char backend_cra_name[CRYPTO_MAX_ALG_NAME]; }; -struct drbg_state_ops { - int (*update)(struct drbg_state *drbg, struct list_head *seed, - int reseed); - int (*generate)(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct list_head *addtl); - int (*crypto_init)(struct drbg_state *drbg); - int (*crypto_fini)(struct drbg_state *drbg); - -}; - enum drbg_seed_state { DRBG_SEED_STATE_UNSEEDED, DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ @@ -143,7 +132,6 @@ struct drbg_state { unsigned long last_seed_time; bool pr; /* Prediction resistance enabled? */ struct crypto_rng *jent; - const struct drbg_state_ops *d_ops; const struct drbg_core *core; struct drbg_string test_data; }; @@ -250,7 +238,7 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags) } /****************************************************************** - * HMAC DRBG callback functions + * HMAC DRBG functions ******************************************************************/ static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, @@ -360,21 +348,10 @@ static int drbg_hmac_generate(struct drbg_state *drbg, return len; } -static const struct drbg_state_ops drbg_hmac_ops = { - .update = drbg_hmac_update, - .generate = drbg_hmac_generate, - .crypto_init = drbg_init_hash_kernel, - .crypto_fini = drbg_fini_hash_kernel, -}; - -/****************************************************************** - * Functions common for DRBG implementations - ******************************************************************/ - static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, int reseed, enum drbg_seed_state new_seed_state) { - int ret = drbg->d_ops->update(drbg, seed, reseed); + int ret = drbg_hmac_update(drbg, seed, reseed); if (ret) return ret; @@ -578,7 +555,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) drbg->Cbuf = NULL; drbg->C = NULL; drbg->reseed_ctr = 0; - drbg->d_ops = NULL; drbg->core = NULL; } @@ -590,16 +566,7 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) { int ret = -ENOMEM; - switch (drbg->core->flags & DRBG_TYPE_MASK) { - case DRBG_HMAC: - drbg->d_ops = &drbg_hmac_ops; - break; - default: - ret = -EOPNOTSUPP; - goto err; - } - - ret = drbg->d_ops->crypto_init(drbg); + ret = drbg_init_hash_kernel(drbg); if (ret < 0) goto err; @@ -619,16 +586,12 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) return 0; fini: - drbg->d_ops->crypto_fini(drbg); + drbg_fini_hash_kernel(drbg); err: drbg_dealloc_state(drbg); return ret; } -/************************************************************************* - * DRBG interface functions - *************************************************************************/ - /* * DRBG generate function as required by SP800-90A - this function * generates random numbers @@ -714,7 +677,7 @@ static int drbg_generate(struct drbg_state *drbg, if (addtl && 0 < addtl->len) list_add_tail(&addtl->list, &addtllist); /* 9.3.1 step 8 and 10 */ - len = drbg->d_ops->generate(drbg, buf, buflen, &addtllist); + len = drbg_hmac_generate(drbg, buf, buflen, &addtllist); /* 10.1.2.5 step 7 */ drbg->reseed_ctr++; @@ -879,8 +842,7 @@ static int drbg_uninstantiate(struct drbg_state *drbg) crypto_free_rng(drbg->jent); drbg->jent = NULL; - if (drbg->d_ops) - drbg->d_ops->crypto_fini(drbg); + drbg_fini_hash_kernel(drbg); drbg_dealloc_state(drbg); /* no scrubbing of test_data -- this shall survive an uninstantiate */ return 0; From 7e9a68e83b0f0663d630a1d1cd7e6443c80186ae Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:04 -0700 Subject: [PATCH 138/655] crypto: drbg - Move fixed values into constants Since only one drbg_core remains, the state length, block length, and security strength are now fixed values. Moreover, the maximum request length, maximum additional data length, and maximum number of requests were all already fixed values. Simplify the code by just using #defines for all these fixed values. In drbg_seed_from_random(), take advantage of the constant to define the array size. Remove assertions that are no longer useful. In the case of drbg_blocklen() and drbg_statelen(), replace these with a single value DRBG_STATE_LEN, as for HMAC_DRBG they are the same thing. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 183 +++++++++++++++++--------------------------------- 1 file changed, 61 insertions(+), 122 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 04c798d7a8b6..34a7cbdda1f1 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -100,12 +101,8 @@ #include struct drbg_state; -typedef uint32_t drbg_flag_t; struct drbg_core { - drbg_flag_t flags; /* flags for the cipher */ - __u8 statelen; /* maximum state length */ - __u8 blocklen_bytes; /* block size of output in bytes */ char cra_name[CRYPTO_MAX_ALG_NAME]; /* mapping to kernel crypto API */ /* kernel crypto API backend cipher name */ char backend_cra_name[CRYPTO_MAX_ALG_NAME]; @@ -117,6 +114,32 @@ enum drbg_seed_state { DRBG_SEED_STATE_FULL, }; +/* State length in bytes */ +#define DRBG_STATE_LEN SHA512_DIGEST_SIZE + +/* Security strength in bytes */ +#define DRBG_SEC_STRENGTH (SHA512_DIGEST_SIZE / 2) + +/* + * Maximum number of requests before reseeding is forced. + * SP800-90A allows this to be up to 2**48. We use a lower value. + */ +#define DRBG_MAX_REQUESTS (1 << 20) + +/* + * Maximum number of random bytes that can be requested at once. + * SP800-90A allows up to 2**19 bits, which is 2**16 bytes. + */ +#define DRBG_MAX_REQUEST_BYTES (1 << 16) + +/* + * Maximum length of additional info and personalization strings, in bytes. + * SP800-90A allows up to 2**35 bits, i.e. 2**32 bytes. We use 2**32 - 2 bytes + * so that the value never quite completely fills the range of a size_t, + * allowing the health check to verify that larger values are rejected. + */ +#define DRBG_MAX_ADDTL (U32_MAX - 1) + struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ unsigned char *V; /* internal state -- 10.1.2.1 1a */ @@ -136,53 +159,6 @@ struct drbg_state { struct drbg_string test_data; }; -static inline __u8 drbg_statelen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return drbg->core->statelen; - return 0; -} - -static inline __u8 drbg_blocklen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return drbg->core->blocklen_bytes; - return 0; -} - -static inline size_t drbg_max_request_bytes(struct drbg_state *drbg) -{ - /* SP800-90A requires the limit 2**19 bits, but we return bytes */ - return (1 << 16); -} - -/* - * SP800-90A allows implementations to support additional info / personalization - * strings of up to 2**35 bits. Implementations can have a smaller maximum. We - * use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a - * size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. - */ -static inline size_t drbg_max_addtl(struct drbg_state *drbg) -{ - return U32_MAX - 1; -} - -static inline size_t drbg_max_requests(struct drbg_state *drbg) -{ - /* SP800-90A requires 2**48 maximum requests before reseeding */ - return (1<<20); -} - -/* DRBG type flags */ -#define DRBG_HMAC ((drbg_flag_t)1<<1) -#define DRBG_TYPE_MASK DRBG_HMAC -/* DRBG strength flags */ -#define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) -#define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) -#define DRBG_STRENGTH256 ((drbg_flag_t)1<<5) -#define DRBG_STRENGTH_MASK (DRBG_STRENGTH128 | DRBG_STRENGTH192 | \ - DRBG_STRENGTH256) - enum drbg_prefixes { DRBG_PREFIX0 = 0x00, DRBG_PREFIX1, @@ -201,9 +177,6 @@ enum drbg_prefixes { */ static const struct drbg_core drbg_cores[] = { { - .flags = DRBG_HMAC | DRBG_STRENGTH256, - .statelen = 64, /* block length of cipher */ - .blocklen_bytes = 64, .cra_name = "hmac_sha512", .backend_cra_name = "hmac(sha512)", }, @@ -211,32 +184,6 @@ static const struct drbg_core drbg_cores[] = { static int drbg_uninstantiate(struct drbg_state *drbg); -/****************************************************************** - * Generic helper functions - ******************************************************************/ - -/* - * Return strength of DRBG according to SP800-90A section 8.4 - * - * @flags DRBG flags reference - * - * Return: normalized strength in *bytes* value or 32 as default - * to counter programming errors - */ -static inline unsigned short drbg_sec_strength(drbg_flag_t flags) -{ - switch (flags & DRBG_STRENGTH_MASK) { - case DRBG_STRENGTH128: - return 16; - case DRBG_STRENGTH192: - return 24; - case DRBG_STRENGTH256: - return 32; - default: - return 32; - } -} - /****************************************************************** * HMAC DRBG functions ******************************************************************/ @@ -263,11 +210,11 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, if (!reseed) { /* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ - memset(drbg->V, 1, drbg_statelen(drbg)); + memset(drbg->V, 1, DRBG_STATE_LEN); drbg_kcapi_hmacsetkey(drbg, drbg->C); } - drbg_string_fill(&seed1, drbg->V, drbg_statelen(drbg)); + drbg_string_fill(&seed1, drbg->V, DRBG_STATE_LEN); list_add_tail(&seed1.list, &seedlist); /* buffer of seed2 will be filled in for loop below with one byte */ drbg_string_fill(&seed2, NULL, 1); @@ -276,7 +223,7 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, if (seed) list_splice_tail(seed, &seedlist); - drbg_string_fill(&vdata, drbg->V, drbg_statelen(drbg)); + drbg_string_fill(&vdata, drbg->V, DRBG_STATE_LEN); list_add_tail(&vdata.list, &vdatalist); for (i = 2; 0 < i; i--) { /* first round uses 0x0, second 0x1 */ @@ -321,7 +268,7 @@ static int drbg_hmac_generate(struct drbg_state *drbg, return ret; } - drbg_string_fill(&data, drbg->V, drbg_statelen(drbg)); + drbg_string_fill(&data, drbg->V, DRBG_STATE_LEN); list_add_tail(&data.list, &datalist); while (len < buflen) { unsigned int outlen = 0; @@ -329,8 +276,8 @@ static int drbg_hmac_generate(struct drbg_state *drbg, ret = drbg_kcapi_hash(drbg, drbg->V, &datalist); if (ret) return ret; - outlen = (drbg_blocklen(drbg) < (buflen - len)) ? - drbg_blocklen(drbg) : (buflen - len); + outlen = (DRBG_STATE_LEN < (buflen - len)) ? + DRBG_STATE_LEN : (buflen - len); /* 10.1.2.5 step 4.2 */ memcpy(buf + len, drbg->V, outlen); @@ -377,7 +324,7 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, * Seed source has become fully initialized, frequent * reseeds no longer required. */ - drbg->reseed_threshold = drbg_max_requests(drbg); + drbg->reseed_threshold = DRBG_MAX_REQUESTS; break; } @@ -389,21 +336,17 @@ static int drbg_seed_from_random(struct drbg_state *drbg) { struct drbg_string data; LIST_HEAD(seedlist); - unsigned int entropylen = drbg_sec_strength(drbg->core->flags); - unsigned char entropy[32]; + unsigned char entropy[DRBG_SEC_STRENGTH]; int ret; - BUG_ON(!entropylen); - BUG_ON(entropylen > sizeof(entropy)); - - drbg_string_fill(&data, entropy, entropylen); + drbg_string_fill(&data, entropy, DRBG_SEC_STRENGTH); list_add_tail(&data.list, &seedlist); - get_random_bytes(entropy, entropylen); + get_random_bytes(entropy, DRBG_SEC_STRENGTH); ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); - memzero_explicit(entropy, entropylen); + memzero_explicit(entropy, DRBG_SEC_STRENGTH); return ret; } @@ -444,13 +387,13 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, { int ret; unsigned char entropy[((32 + 16) * 2)]; - unsigned int entropylen = drbg_sec_strength(drbg->core->flags); + unsigned int entropylen; struct drbg_string data1; LIST_HEAD(seedlist); enum drbg_seed_state new_seed_state = DRBG_SEED_STATE_FULL; /* 9.1 / 9.2 / 9.3.1 step 3 */ - if (pers && pers->len > (drbg_max_addtl(drbg))) { + if (pers && pers->len > DRBG_MAX_ADDTL) { pr_devel("DRBG: personalization string too long %zu\n", pers->len); return -EINVAL; @@ -469,9 +412,10 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, * of the strength. The consideration of a nonce is only * applicable during initial seeding. */ - BUG_ON(!entropylen); if (!reseed) - entropylen = ((entropylen + 1) / 2) * 3; + entropylen = ((DRBG_SEC_STRENGTH + 1) / 2) * 3; + else + entropylen = DRBG_SEC_STRENGTH; BUG_ON((entropylen * 2) > sizeof(entropy)); /* Get seed from in-kernel /dev/urandom */ @@ -531,14 +475,14 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, } if (!reseed) { - memset(drbg->V, 0, drbg_statelen(drbg)); - memset(drbg->C, 0, drbg_statelen(drbg)); + memset(drbg->V, 0, DRBG_STATE_LEN); + memset(drbg->C, 0, DRBG_STATE_LEN); } ret = __drbg_seed(drbg, &seedlist, reseed, new_seed_state); out: - memzero_explicit(entropy, entropylen * 2); + memzero_explicit(entropy, sizeof(entropy)); return ret; } @@ -570,13 +514,13 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) if (ret < 0) goto err; - drbg->Vbuf = kmalloc(drbg_statelen(drbg) + ret, GFP_KERNEL); + drbg->Vbuf = kmalloc(DRBG_STATE_LEN + ret, GFP_KERNEL); if (!drbg->Vbuf) { ret = -ENOMEM; goto fini; } drbg->V = PTR_ALIGN(drbg->Vbuf, ret + 1); - drbg->Cbuf = kmalloc(drbg_statelen(drbg) + ret, GFP_KERNEL); + drbg->Cbuf = kmalloc(DRBG_STATE_LEN + ret, GFP_KERNEL); if (!drbg->Cbuf) { ret = -ENOMEM; goto fini; @@ -630,20 +574,19 @@ static int drbg_generate(struct drbg_state *drbg, } /* 9.3.1 step 2 */ - len = -EINVAL; - if (buflen > (drbg_max_request_bytes(drbg))) { + if (buflen > DRBG_MAX_REQUEST_BYTES) { pr_devel("DRBG: requested random numbers too large %u\n", buflen); - goto err; + return -EINVAL; } /* 9.3.1 step 3 is implicit with the chosen DRBG */ /* 9.3.1 step 4 */ - if (addtl && addtl->len > (drbg_max_addtl(drbg))) { + if (addtl && addtl->len > DRBG_MAX_ADDTL) { pr_devel("DRBG: additional information string too long %zu\n", addtl->len); - goto err; + return -EINVAL; } /* 9.3.1 step 5 is implicit with the chosen DRBG */ @@ -723,8 +666,8 @@ static int drbg_generate_long(struct drbg_state *drbg, do { int err = 0; unsigned int chunk = 0; - slice = ((buflen - len) / drbg_max_request_bytes(drbg)); - chunk = slice ? drbg_max_request_bytes(drbg) : (buflen - len); + slice = (buflen - len) / DRBG_MAX_REQUEST_BYTES; + chunk = slice ? DRBG_MAX_REQUEST_BYTES : (buflen - len); mutex_lock(&drbg->drbg_mutex); err = drbg_generate(drbg, buf + len, chunk, addtl); mutex_unlock(&drbg->drbg_mutex); @@ -785,18 +728,17 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, /* * 9.1 step 2 is implicit as caller can select prediction resistance - * and the flag is copied into drbg->flags -- * all DRBG types support prediction resistance */ - /* 9.1 step 4 is implicit in drbg_sec_strength */ + /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ if (!drbg->core) { drbg->core = &drbg_cores[coreref]; drbg->pr = pr; drbg->seeded = DRBG_SEED_STATE_UNSEEDED; drbg->last_seed_time = 0; - drbg->reseed_threshold = drbg_max_requests(drbg); + drbg->reseed_threshold = DRBG_MAX_REQUESTS; ret = drbg_alloc_state(drbg); if (ret) @@ -884,7 +826,7 @@ static int drbg_init_hash_kernel(struct drbg_state *drbg) drbg->core->backend_cra_name); return PTR_ERR(tfm); } - BUG_ON(drbg_blocklen(drbg) != crypto_shash_digestsize(tfm)); + BUG_ON(DRBG_STATE_LEN != crypto_shash_digestsize(tfm)); sdesc = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm), GFP_KERNEL); if (!sdesc) { @@ -914,7 +856,7 @@ static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, { struct sdesc *sdesc = drbg->priv_data; - crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg)); + crypto_shash_setkey(sdesc->shash.tfm, key, DRBG_STATE_LEN); } static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, @@ -1060,7 +1002,6 @@ static inline int __init drbg_healthcheck_sanity(void) bool pr = false; int coreref = 0; struct drbg_string addtl; - size_t max_addtllen, max_request_bytes; /* only perform test in FIPS mode */ if (!fips_enabled) @@ -1074,7 +1015,7 @@ static inline int __init drbg_healthcheck_sanity(void) guard(mutex_init)(&drbg->drbg_mutex); drbg->core = &drbg_cores[coreref]; - drbg->reseed_threshold = drbg_max_requests(drbg); + drbg->reseed_threshold = DRBG_MAX_REQUESTS; /* * if the following tests fail, it is likely that there is a buffer @@ -1084,14 +1025,12 @@ static inline int __init drbg_healthcheck_sanity(void) * grave bug. */ - max_addtllen = drbg_max_addtl(drbg); - max_request_bytes = drbg_max_request_bytes(drbg); - drbg_string_fill(&addtl, buf, max_addtllen + 1); + drbg_string_fill(&addtl, buf, DRBG_MAX_ADDTL + 1); /* overflow addtllen with additional info string */ ret = drbg_generate(drbg, buf, OUTBUFLEN, &addtl); BUG_ON(ret == 0); /* overflow max_bits */ - ret = drbg_generate(drbg, buf, max_request_bytes + 1, NULL); + ret = drbg_generate(drbg, buf, DRBG_MAX_REQUEST_BYTES + 1, NULL); BUG_ON(ret == 0); /* overflow max addtllen with personalization string */ From fcc62e0991ff0ceb7f53a93f4b12982b7d91d233 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:05 -0700 Subject: [PATCH 139/655] crypto: drbg - Embed V and C into struct drbg_state Now that the sizes of V and C are known at compile time, embed them into struct drbg_state rather than using separate allocations. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 34a7cbdda1f1..e62bde7aab43 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -142,10 +142,8 @@ enum drbg_seed_state { struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ - unsigned char *V; /* internal state -- 10.1.2.1 1a */ - unsigned char *Vbuf; - unsigned char *C; /* current key -- 10.1.2.1 1b */ - unsigned char *Cbuf; + u8 V[DRBG_STATE_LEN]; /* internal state -- 10.1.2.1 1a */ + u8 C[DRBG_STATE_LEN]; /* current key -- 10.1.2.1 1b */ /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr; size_t reseed_threshold; @@ -492,12 +490,8 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) { if (!drbg) return; - kfree_sensitive(drbg->Vbuf); - drbg->Vbuf = NULL; - drbg->V = NULL; - kfree_sensitive(drbg->Cbuf); - drbg->Cbuf = NULL; - drbg->C = NULL; + memzero_explicit(drbg->V, sizeof(drbg->V)); + memzero_explicit(drbg->C, sizeof(drbg->C)); drbg->reseed_ctr = 0; drbg->core = NULL; } @@ -513,24 +507,8 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) ret = drbg_init_hash_kernel(drbg); if (ret < 0) goto err; - - drbg->Vbuf = kmalloc(DRBG_STATE_LEN + ret, GFP_KERNEL); - if (!drbg->Vbuf) { - ret = -ENOMEM; - goto fini; - } - drbg->V = PTR_ALIGN(drbg->Vbuf, ret + 1); - drbg->Cbuf = kmalloc(DRBG_STATE_LEN + ret, GFP_KERNEL); - if (!drbg->Cbuf) { - ret = -ENOMEM; - goto fini; - } - drbg->C = PTR_ALIGN(drbg->Cbuf, ret + 1); - return 0; -fini: - drbg_fini_hash_kernel(drbg); err: drbg_dealloc_state(drbg); return ret; From 245c8d0d177f129d105f84331272494e2cd31f2a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:06 -0700 Subject: [PATCH 140/655] crypto: drbg - Use HMAC-SHA512 library API Since the HMAC algorithm is now fixed at HMAC-SHA512, just use the HMAC-SHA512 library API. This is simpler and more efficient. Remove error-handling code that is no longer needed. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/Kconfig | 3 +- crypto/drbg.c | 213 ++++++++++--------------------------------------- 2 files changed, 41 insertions(+), 175 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 1abb3d356458..608b2c739193 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1115,10 +1115,9 @@ menu "Random number generation" config CRYPTO_DRBG tristate "NIST SP800-90A DRBG (Deterministic Random Bit Generator)" - select CRYPTO_HMAC select CRYPTO_JITTERENTROPY + select CRYPTO_LIB_SHA512 select CRYPTO_RNG - select CRYPTO_SHA512 help DRBG (Deterministic Random Bit Generator) (NIST SP800-90A) diff --git a/crypto/drbg.c b/crypto/drbg.c index e62bde7aab43..4f326385cf36 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -4,6 +4,7 @@ * both with and without prediction resistance * * Copyright Stephan Mueller , 2014 + * Copyright 2026 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -90,7 +91,6 @@ #include #include -#include #include #include #include @@ -143,12 +143,11 @@ enum drbg_seed_state { struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ u8 V[DRBG_STATE_LEN]; /* internal state -- 10.1.2.1 1a */ + struct hmac_sha512_key key; /* current key -- 10.1.2.1 1b */ u8 C[DRBG_STATE_LEN]; /* current key -- 10.1.2.1 1b */ /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr; size_t reseed_threshold; - void *priv_data; /* Cipher handle */ - enum drbg_seed_state seeded; /* DRBG fully seeded? */ unsigned long last_seed_time; bool pr; /* Prediction resistance enabled? */ @@ -186,94 +185,67 @@ static int drbg_uninstantiate(struct drbg_state *drbg); * HMAC DRBG functions ******************************************************************/ -static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, - const struct list_head *in); -static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, - const unsigned char *key); -static int drbg_init_hash_kernel(struct drbg_state *drbg); -static int drbg_fini_hash_kernel(struct drbg_state *drbg); - MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); /* update function of HMAC DRBG as defined in 10.1.2.2 */ -static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) +static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, + int reseed) { - int ret = -EFAULT; int i = 0; - struct drbg_string seed1, seed2, vdata; - LIST_HEAD(seedlist); - LIST_HEAD(vdatalist); + struct hmac_sha512_ctx hmac_ctx; if (!reseed) { /* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ memset(drbg->V, 1, DRBG_STATE_LEN); - drbg_kcapi_hmacsetkey(drbg, drbg->C); + hmac_sha512_preparekey(&drbg->key, drbg->C, DRBG_STATE_LEN); } - drbg_string_fill(&seed1, drbg->V, DRBG_STATE_LEN); - list_add_tail(&seed1.list, &seedlist); - /* buffer of seed2 will be filled in for loop below with one byte */ - drbg_string_fill(&seed2, NULL, 1); - list_add_tail(&seed2.list, &seedlist); - /* input data of seed is allowed to be NULL at this point */ - if (seed) - list_splice_tail(seed, &seedlist); - - drbg_string_fill(&vdata, drbg->V, DRBG_STATE_LEN); - list_add_tail(&vdata.list, &vdatalist); for (i = 2; 0 < i; i--) { /* first round uses 0x0, second 0x1 */ unsigned char prefix = DRBG_PREFIX0; if (1 == i) prefix = DRBG_PREFIX1; /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ - seed2.buf = &prefix; - ret = drbg_kcapi_hash(drbg, drbg->C, &seedlist); - if (ret) - return ret; - drbg_kcapi_hmacsetkey(drbg, drbg->C); + hmac_sha512_init(&hmac_ctx, &drbg->key); + hmac_sha512_update(&hmac_ctx, drbg->V, DRBG_STATE_LEN); + hmac_sha512_update(&hmac_ctx, &prefix, 1); + if (seed) { + struct drbg_string *input; + + list_for_each_entry(input, seed, list) + hmac_sha512_update(&hmac_ctx, input->buf, + input->len); + } + hmac_sha512_final(&hmac_ctx, drbg->C); + hmac_sha512_preparekey(&drbg->key, drbg->C, DRBG_STATE_LEN); /* 10.1.2.2 step 2 and 5 -- HMAC for V */ - ret = drbg_kcapi_hash(drbg, drbg->V, &vdatalist); - if (ret) - return ret; + hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); /* 10.1.2.2 step 3 */ if (!seed) - return ret; + break; } - - return 0; } /* generate function of HMAC DRBG as defined in 10.1.2.5 */ -static int drbg_hmac_generate(struct drbg_state *drbg, - unsigned char *buf, - unsigned int buflen, - struct list_head *addtl) +static void drbg_hmac_generate(struct drbg_state *drbg, + unsigned char *buf, + unsigned int buflen, + struct list_head *addtl) { int len = 0; - int ret = 0; - struct drbg_string data; - LIST_HEAD(datalist); /* 10.1.2.5 step 2 */ - if (addtl && !list_empty(addtl)) { - ret = drbg_hmac_update(drbg, addtl, 1); - if (ret) - return ret; - } + if (addtl && !list_empty(addtl)) + drbg_hmac_update(drbg, addtl, 1); - drbg_string_fill(&data, drbg->V, DRBG_STATE_LEN); - list_add_tail(&data.list, &datalist); while (len < buflen) { unsigned int outlen = 0; + /* 10.1.2.5 step 4.1 */ - ret = drbg_kcapi_hash(drbg, drbg->V, &datalist); - if (ret) - return ret; + hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); outlen = (DRBG_STATE_LEN < (buflen - len)) ? DRBG_STATE_LEN : (buflen - len); @@ -284,22 +256,15 @@ static int drbg_hmac_generate(struct drbg_state *drbg, /* 10.1.2.5 step 6 */ if (addtl && !list_empty(addtl)) - ret = drbg_hmac_update(drbg, addtl, 1); + drbg_hmac_update(drbg, addtl, 1); else - ret = drbg_hmac_update(drbg, NULL, 1); - if (ret) - return ret; - - return len; + drbg_hmac_update(drbg, NULL, 1); } -static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, - int reseed, enum drbg_seed_state new_seed_state) +static inline void __drbg_seed(struct drbg_state *drbg, struct list_head *seed, + int reseed, enum drbg_seed_state new_seed_state) { - int ret = drbg_hmac_update(drbg, seed, reseed); - - if (ret) - return ret; + drbg_hmac_update(drbg, seed, reseed); drbg->seeded = new_seed_state; drbg->last_seed_time = jiffies; @@ -325,27 +290,23 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, drbg->reseed_threshold = DRBG_MAX_REQUESTS; break; } - - return ret; } -static int drbg_seed_from_random(struct drbg_state *drbg) +static void drbg_seed_from_random(struct drbg_state *drbg) __must_hold(&drbg->drbg_mutex) { struct drbg_string data; LIST_HEAD(seedlist); unsigned char entropy[DRBG_SEC_STRENGTH]; - int ret; drbg_string_fill(&data, entropy, DRBG_SEC_STRENGTH); list_add_tail(&data.list, &seedlist); get_random_bytes(entropy, DRBG_SEC_STRENGTH); - ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); + __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); memzero_explicit(entropy, DRBG_SEC_STRENGTH); - return ret; } static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg) @@ -477,8 +438,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, memset(drbg->C, 0, DRBG_STATE_LEN); } - ret = __drbg_seed(drbg, &seedlist, reseed, new_seed_state); - + __drbg_seed(drbg, &seedlist, reseed, new_seed_state); + ret = 0; out: memzero_explicit(entropy, sizeof(entropy)); @@ -490,30 +451,13 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) { if (!drbg) return; + memzero_explicit(&drbg->key, sizeof(drbg->key)); memzero_explicit(drbg->V, sizeof(drbg->V)); memzero_explicit(drbg->C, sizeof(drbg->C)); drbg->reseed_ctr = 0; drbg->core = NULL; } -/* - * Allocate all sub-structures for a DRBG state. - * The DRBG state structure must already be allocated. - */ -static inline int drbg_alloc_state(struct drbg_state *drbg) -{ - int ret = -ENOMEM; - - ret = drbg_init_hash_kernel(drbg); - if (ret < 0) - goto err; - return 0; - -err: - drbg_dealloc_state(drbg); - return ret; -} - /* * DRBG generate function as required by SP800-90A - this function * generates random numbers @@ -590,20 +534,16 @@ static int drbg_generate(struct drbg_state *drbg, } else if (rng_is_initialized() && (drbg->seeded == DRBG_SEED_STATE_PARTIAL || drbg_nopr_reseed_interval_elapsed(drbg))) { - len = drbg_seed_from_random(drbg); - if (len) - goto err; + drbg_seed_from_random(drbg); } if (addtl && 0 < addtl->len) list_add_tail(&addtl->list, &addtllist); /* 9.3.1 step 8 and 10 */ - len = drbg_hmac_generate(drbg, buf, buflen, &addtllist); + drbg_hmac_generate(drbg, buf, buflen, &addtllist); /* 10.1.2.5 step 7 */ drbg->reseed_ctr++; - if (0 >= len) - goto err; /* * Section 11.3.3 requires to re-perform self tests after some @@ -718,10 +658,6 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, drbg->last_seed_time = 0; drbg->reseed_threshold = DRBG_MAX_REQUESTS; - ret = drbg_alloc_state(drbg); - if (ret) - goto unlock; - ret = drbg_prepare_hrng(drbg); if (ret) goto free_everything; @@ -737,10 +673,6 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, mutex_unlock(&drbg->drbg_mutex); return ret; -unlock: - mutex_unlock(&drbg->drbg_mutex); - return ret; - free_everything: mutex_unlock(&drbg->drbg_mutex); drbg_uninstantiate(drbg); @@ -762,7 +694,6 @@ static int drbg_uninstantiate(struct drbg_state *drbg) crypto_free_rng(drbg->jent); drbg->jent = NULL; - drbg_fini_hash_kernel(drbg); drbg_dealloc_state(drbg); /* no scrubbing of test_data -- this shall survive an uninstantiate */ return 0; @@ -785,70 +716,6 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, mutex_unlock(&drbg->drbg_mutex); } -/*************************************************************** - * Kernel crypto API cipher invocations requested by DRBG - ***************************************************************/ - -struct sdesc { - struct shash_desc shash; -}; - -static int drbg_init_hash_kernel(struct drbg_state *drbg) -{ - struct sdesc *sdesc; - struct crypto_shash *tfm; - - tfm = crypto_alloc_shash(drbg->core->backend_cra_name, 0, 0); - if (IS_ERR(tfm)) { - pr_info("DRBG: could not allocate digest TFM handle: %s\n", - drbg->core->backend_cra_name); - return PTR_ERR(tfm); - } - BUG_ON(DRBG_STATE_LEN != crypto_shash_digestsize(tfm)); - sdesc = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm), - GFP_KERNEL); - if (!sdesc) { - crypto_free_shash(tfm); - return -ENOMEM; - } - - sdesc->shash.tfm = tfm; - drbg->priv_data = sdesc; - - return 0; -} - -static int drbg_fini_hash_kernel(struct drbg_state *drbg) -{ - struct sdesc *sdesc = drbg->priv_data; - if (sdesc) { - crypto_free_shash(sdesc->shash.tfm); - kfree_sensitive(sdesc); - } - drbg->priv_data = NULL; - return 0; -} - -static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, - const unsigned char *key) -{ - struct sdesc *sdesc = drbg->priv_data; - - crypto_shash_setkey(sdesc->shash.tfm, key, DRBG_STATE_LEN); -} - -static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, - const struct list_head *in) -{ - struct sdesc *sdesc = drbg->priv_data; - struct drbg_string *input = NULL; - - crypto_shash_init(&sdesc->shash); - list_for_each_entry(input, in, list) - crypto_shash_update(&sdesc->shash, input->buf, input->len); - return crypto_shash_final(&sdesc->shash, outval); -} - /*************************************************************** * Kernel crypto API interface to register DRBG ***************************************************************/ From e8806e2e97dc769e03c1fc50ed32622dad476dfb Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:07 -0700 Subject: [PATCH 141/655] crypto: drbg - Remove drbg_core Now that none of the information in struct drbg_core is used, remove it. The null-ity of the pointer drbg_state::core was used to keep track of whether the DRBG has been instantiated. Replace it with a boolean. No functional change. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 99 +++++++-------------------------------------------- 1 file changed, 13 insertions(+), 86 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 4f326385cf36..161070b10f85 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -100,14 +100,6 @@ #include #include -struct drbg_state; - -struct drbg_core { - char cra_name[CRYPTO_MAX_ALG_NAME]; /* mapping to kernel crypto API */ - /* kernel crypto API backend cipher name */ - char backend_cra_name[CRYPTO_MAX_ALG_NAME]; -}; - enum drbg_seed_state { DRBG_SEED_STATE_UNSEEDED, DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ @@ -150,9 +142,9 @@ struct drbg_state { size_t reseed_threshold; enum drbg_seed_state seeded; /* DRBG fully seeded? */ unsigned long last_seed_time; + bool instantiated; bool pr; /* Prediction resistance enabled? */ struct crypto_rng *jent; - const struct drbg_core *core; struct drbg_string test_data; }; @@ -161,24 +153,6 @@ enum drbg_prefixes { DRBG_PREFIX1, }; -/*************************************************************** - * Backend cipher definitions available to DRBG - ***************************************************************/ - -/* - * The order of the DRBG definitions here matter: every DRBG is registered - * as stdrng. Each DRBG receives an increasing cra_priority values the later - * they are defined in this array (see drbg_fill_array). - * - * Thus, the favored DRBGs are the latest entries in this array. - */ -static const struct drbg_core drbg_cores[] = { - { - .cra_name = "hmac_sha512", - .backend_cra_name = "hmac(sha512)", - }, -}; - static int drbg_uninstantiate(struct drbg_state *drbg); /****************************************************************** @@ -455,7 +429,7 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) memzero_explicit(drbg->V, sizeof(drbg->V)); memzero_explicit(drbg->C, sizeof(drbg->C)); drbg->reseed_ctr = 0; - drbg->core = NULL; + drbg->instantiated = false; } /* @@ -482,8 +456,8 @@ static int drbg_generate(struct drbg_state *drbg, int len = 0; LIST_HEAD(addtllist); - if (!drbg->core) { - pr_devel("DRBG: not yet seeded\n"); + if (!drbg->instantiated) { + pr_devel("DRBG: not yet instantiated\n"); return -EINVAL; } if (0 == buflen || !buf) { @@ -625,7 +599,6 @@ static int drbg_prepare_hrng(struct drbg_state *drbg) * the entropy is pulled by the DRBG internally unconditionally * as defined in SP800-90A. The additional input is mixed into * the state in addition to the pulled entropy. - * @coreref reference to core * @pr prediction resistance enabled * * return @@ -633,13 +606,13 @@ static int drbg_prepare_hrng(struct drbg_state *drbg) * error value otherwise */ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, - int coreref, bool pr) + bool pr) { int ret; bool reseed = true; - pr_devel("DRBG: Initializing DRBG core %d with prediction resistance " - "%s\n", coreref, str_enabled_disabled(pr)); + pr_devel("DRBG: Initializing DRBG with prediction resistance %s\n", + str_enabled_disabled(pr)); mutex_lock(&drbg->drbg_mutex); /* 9.1 step 1 is implicit with the selected DRBG type */ @@ -651,8 +624,8 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ - if (!drbg->core) { - drbg->core = &drbg_cores[coreref]; + if (!drbg->instantiated) { + drbg->instantiated = true; drbg->pr = pr; drbg->seeded = DRBG_SEED_STATE_UNSEEDED; drbg->last_seed_time = 0; @@ -720,46 +693,6 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, * Kernel crypto API interface to register DRBG ***************************************************************/ -/* - * Look up the DRBG flags by given kernel crypto API cra_name - * The code uses the drbg_cores definition to do this - * - * @cra_name kernel crypto API cra_name - * @coreref reference to integer which is filled with the pointer to - * the applicable core - * @pr reference for setting prediction resistance - * - * return: flags - */ -static inline void drbg_convert_tfm_core(const char *cra_driver_name, - int *coreref, bool *pr) -{ - int i = 0; - size_t start = 0; - int len = 0; - - *pr = true; - /* disassemble the names */ - if (!memcmp(cra_driver_name, "drbg_nopr_", 10)) { - start = 10; - *pr = false; - } else if (!memcmp(cra_driver_name, "drbg_pr_", 8)) { - start = 8; - } else { - return; - } - - /* remove the first part */ - len = strlen(cra_driver_name) - start; - for (i = 0; ARRAY_SIZE(drbg_cores) > i; i++) { - if (!memcmp(cra_driver_name + start, drbg_cores[i].cra_name, - len)) { - *coreref = i; - return; - } - } -} - static int drbg_kcapi_init(struct crypto_tfm *tfm) { struct drbg_state *drbg = crypto_tfm_ctx(tfm); @@ -808,19 +741,17 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, { struct drbg_state *drbg = crypto_rng_ctx(tfm); struct crypto_tfm *tfm_base = crypto_rng_tfm(tfm); - bool pr = false; + bool pr = memcmp(crypto_tfm_alg_driver_name(tfm_base), + "drbg_nopr_", 10) != 0; struct drbg_string string; struct drbg_string *seed_string = NULL; - int coreref = 0; - drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm_base), &coreref, - &pr); if (0 < slen) { drbg_string_fill(&string, seed, slen); seed_string = &string; } - return drbg_instantiate(drbg, seed_string, coreref, pr); + return drbg_instantiate(drbg, seed_string, pr); } /*************************************************************** @@ -844,22 +775,18 @@ static inline int __init drbg_healthcheck_sanity(void) struct drbg_state *drbg = NULL; int ret; int rc = -EFAULT; - bool pr = false; - int coreref = 0; struct drbg_string addtl; /* only perform test in FIPS mode */ if (!fips_enabled) return 0; - drbg_convert_tfm_core("drbg_nopr_hmac_sha512", &coreref, &pr); - drbg = kzalloc_obj(struct drbg_state); if (!drbg) return -ENOMEM; guard(mutex_init)(&drbg->drbg_mutex); - drbg->core = &drbg_cores[coreref]; + drbg->instantiated = true; drbg->reseed_threshold = DRBG_MAX_REQUESTS; /* From 7f0ef29864ebf2ab5fea04523cc0bd8f1c7d1ccd Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:08 -0700 Subject: [PATCH 142/655] crypto: drbg - Install separate seed functions for pr and nopr Set rng_alg::seed to different functions for the prediction-resistant and non-prediction-resistant algorithms, so that the function does not need to parse the algorithm name to figure out which algorithm it is. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 161070b10f85..c29f4ca93d1b 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -733,16 +733,11 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, return drbg_generate_long(drbg, dst, dlen, addtl); } -/* - * Seed the DRBG invoked by the kernel crypto API - */ +/* Seed (i.e. instantiate) or re-seed the DRBG. */ static int drbg_kcapi_seed(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen) + const u8 *seed, unsigned int slen, bool pr) { struct drbg_state *drbg = crypto_rng_ctx(tfm); - struct crypto_tfm *tfm_base = crypto_rng_tfm(tfm); - bool pr = memcmp(crypto_tfm_alg_driver_name(tfm_base), - "drbg_nopr_", 10) != 0; struct drbg_string string; struct drbg_string *seed_string = NULL; @@ -754,6 +749,18 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, return drbg_instantiate(drbg, seed_string, pr); } +static int drbg_kcapi_seed_pr(struct crypto_rng *tfm, + const u8 *seed, unsigned int slen) +{ + return drbg_kcapi_seed(tfm, seed, slen, /* pr= */ true); +} + +static int drbg_kcapi_seed_nopr(struct crypto_rng *tfm, + const u8 *seed, unsigned int slen) +{ + return drbg_kcapi_seed(tfm, seed, slen, /* pr= */ false); +} + /*************************************************************** * Kernel module: code to load the module ***************************************************************/ @@ -827,7 +834,7 @@ static struct rng_alg drbg_algs[] = { .base.cra_module = THIS_MODULE, .base.cra_init = drbg_kcapi_init, .set_ent = drbg_kcapi_set_entropy, - .seed = drbg_kcapi_seed, + .seed = drbg_kcapi_seed_pr, .generate = drbg_kcapi_random, .base.cra_exit = drbg_kcapi_cleanup, }, @@ -839,7 +846,7 @@ static struct rng_alg drbg_algs[] = { .base.cra_module = THIS_MODULE, .base.cra_init = drbg_kcapi_init, .set_ent = drbg_kcapi_set_entropy, - .seed = drbg_kcapi_seed, + .seed = drbg_kcapi_seed_nopr, .generate = drbg_kcapi_random, .base.cra_exit = drbg_kcapi_cleanup, }, From 54957e44db1fc3524da15e34c6c86f77bbd664da Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:09 -0700 Subject: [PATCH 143/655] crypto: drbg - Move module aliases to end of file Move the MODULE_ALIAS_CRYPTO lines in the middle of the file to the end so that they are in the usual place and next to the other one. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index c29f4ca93d1b..439581d7bb83 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -159,9 +159,6 @@ static int drbg_uninstantiate(struct drbg_state *drbg); * HMAC DRBG functions ******************************************************************/ -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); - /* update function of HMAC DRBG as defined in 10.1.2.2 */ static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, int reseed) @@ -883,3 +880,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Stephan Mueller "); MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG)"); MODULE_ALIAS_CRYPTO("stdrng"); +MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); +MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); From 2245b1bfecc861e000f115f017e08eeed4808191 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:10 -0700 Subject: [PATCH 144/655] crypto: drbg - Consolidate "instantiate" logic and remove drbg_state::C Currently some of the steps of "Instantiate the DRBG" occur in a convoluted way in different places in the call stack: drbg_instantiate() => drbg_seed(reseed=0) sets the raw HMAC key drbg_state::C to its correct initial value, and it sets the state value drbg_state::V to an *incorrect* initial value. => drbg_hmac_update(reseed=0) overwrites drbg_state::V with the correct initial value, then prepares the hmac_sha512_key drbg_state::key from the initial raw HMAC key drbg_state::C. Later, each time the HMAC key is updated, drbg_hmac_update() also uses drbg_state::C to temporarily store the new raw key. Simplify all of this by: - Making drbg_instantiate() set the correct initial values of drbg_state::V and drbg_state::key. - Converting drbg_hmac_update() to generate the raw key in a temporary on-stack array instead of drbg_state::C. - Removing drbg_state::C. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 439581d7bb83..7e3ab2f811b6 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -136,7 +136,6 @@ struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ u8 V[DRBG_STATE_LEN]; /* internal state -- 10.1.2.1 1a */ struct hmac_sha512_key key; /* current key -- 10.1.2.1 1b */ - u8 C[DRBG_STATE_LEN]; /* current key -- 10.1.2.1 1b */ /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr; size_t reseed_threshold; @@ -160,17 +159,11 @@ static int drbg_uninstantiate(struct drbg_state *drbg); ******************************************************************/ /* update function of HMAC DRBG as defined in 10.1.2.2 */ -static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) +static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed) { int i = 0; struct hmac_sha512_ctx hmac_ctx; - - if (!reseed) { - /* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ - memset(drbg->V, 1, DRBG_STATE_LEN); - hmac_sha512_preparekey(&drbg->key, drbg->C, DRBG_STATE_LEN); - } + u8 new_key[DRBG_STATE_LEN]; for (i = 2; 0 < i; i--) { /* first round uses 0x0, second 0x1 */ @@ -188,8 +181,8 @@ static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, hmac_sha512_update(&hmac_ctx, input->buf, input->len); } - hmac_sha512_final(&hmac_ctx, drbg->C); - hmac_sha512_preparekey(&drbg->key, drbg->C, DRBG_STATE_LEN); + hmac_sha512_final(&hmac_ctx, new_key); + hmac_sha512_preparekey(&drbg->key, new_key, DRBG_STATE_LEN); /* 10.1.2.2 step 2 and 5 -- HMAC for V */ hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); @@ -198,6 +191,7 @@ static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, if (!seed) break; } + memzero_explicit(new_key, sizeof(new_key)); } /* generate function of HMAC DRBG as defined in 10.1.2.5 */ @@ -210,7 +204,7 @@ static void drbg_hmac_generate(struct drbg_state *drbg, /* 10.1.2.5 step 2 */ if (addtl && !list_empty(addtl)) - drbg_hmac_update(drbg, addtl, 1); + drbg_hmac_update(drbg, addtl); while (len < buflen) { unsigned int outlen = 0; @@ -227,15 +221,15 @@ static void drbg_hmac_generate(struct drbg_state *drbg, /* 10.1.2.5 step 6 */ if (addtl && !list_empty(addtl)) - drbg_hmac_update(drbg, addtl, 1); + drbg_hmac_update(drbg, addtl); else - drbg_hmac_update(drbg, NULL, 1); + drbg_hmac_update(drbg, NULL); } static inline void __drbg_seed(struct drbg_state *drbg, struct list_head *seed, - int reseed, enum drbg_seed_state new_seed_state) + enum drbg_seed_state new_seed_state) { - drbg_hmac_update(drbg, seed, reseed); + drbg_hmac_update(drbg, seed); drbg->seeded = new_seed_state; drbg->last_seed_time = jiffies; @@ -275,7 +269,7 @@ static void drbg_seed_from_random(struct drbg_state *drbg) get_random_bytes(entropy, DRBG_SEC_STRENGTH); - __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); + __drbg_seed(drbg, &seedlist, DRBG_SEED_STATE_FULL); memzero_explicit(entropy, DRBG_SEC_STRENGTH); } @@ -404,12 +398,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, pr_devel("DRBG: using personalization string\n"); } - if (!reseed) { - memset(drbg->V, 0, DRBG_STATE_LEN); - memset(drbg->C, 0, DRBG_STATE_LEN); - } - __drbg_seed(drbg, &seedlist, reseed, new_seed_state); + __drbg_seed(drbg, &seedlist, new_seed_state); ret = 0; out: memzero_explicit(entropy, sizeof(entropy)); @@ -424,7 +414,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) return; memzero_explicit(&drbg->key, sizeof(drbg->key)); memzero_explicit(drbg->V, sizeof(drbg->V)); - memzero_explicit(drbg->C, sizeof(drbg->C)); drbg->reseed_ctr = 0; drbg->instantiated = false; } @@ -605,6 +594,7 @@ static int drbg_prepare_hrng(struct drbg_state *drbg) static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, bool pr) { + static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */ int ret; bool reseed = true; @@ -627,6 +617,8 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, drbg->seeded = DRBG_SEED_STATE_UNSEEDED; drbg->last_seed_time = 0; drbg->reseed_threshold = DRBG_MAX_REQUESTS; + memset(drbg->V, 1, DRBG_STATE_LEN); + hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); ret = drbg_prepare_hrng(drbg); if (ret) From 6585b5b4fddd47c174310a57930369e52335a034 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:11 -0700 Subject: [PATCH 145/655] crypto: drbg - Eliminate use of 'drbg_string' and lists Use straightforward (buffer, len) parameters instead of struct drbg_string or lists of strings. This simplifies the code considerably. For now struct drbg_string is still used in crypto_drbg_ctr_df(), so move its definition to crypto/df_sp80090a.h. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/df_sp80090a.c | 1 - crypto/drbg.c | 179 +++++++++++----------------- drivers/crypto/xilinx/xilinx-trng.c | 1 - include/crypto/df_sp80090a.h | 25 ++++ include/crypto/internal/drbg.h | 39 ------ 5 files changed, 94 insertions(+), 151 deletions(-) delete mode 100644 include/crypto/internal/drbg.h diff --git a/crypto/df_sp80090a.c b/crypto/df_sp80090a.c index f4bb7be016e8..90e1973ee40c 100644 --- a/crypto/df_sp80090a.c +++ b/crypto/df_sp80090a.c @@ -13,7 +13,6 @@ #include #include #include -#include static void drbg_kcapi_sym(struct aes_enckey *aeskey, unsigned char *outval, const struct drbg_string *in, u8 blocklen_bytes) diff --git a/crypto/drbg.c b/crypto/drbg.c index 7e3ab2f811b6..b0cd8da51b26 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -89,7 +89,6 @@ * Just mix both scenarios above. */ -#include #include #include #include @@ -144,7 +143,8 @@ struct drbg_state { bool instantiated; bool pr; /* Prediction resistance enabled? */ struct crypto_rng *jent; - struct drbg_string test_data; + const u8 *test_entropy; + size_t test_entropylen; }; enum drbg_prefixes { @@ -159,7 +159,9 @@ static int drbg_uninstantiate(struct drbg_state *drbg); ******************************************************************/ /* update function of HMAC DRBG as defined in 10.1.2.2 */ -static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed) +static void drbg_hmac_update(struct drbg_state *drbg, + const u8 *data1, size_t data1_len, + const u8 *data2, size_t data2_len) { int i = 0; struct hmac_sha512_ctx hmac_ctx; @@ -174,13 +176,8 @@ static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed) hmac_sha512_init(&hmac_ctx, &drbg->key); hmac_sha512_update(&hmac_ctx, drbg->V, DRBG_STATE_LEN); hmac_sha512_update(&hmac_ctx, &prefix, 1); - if (seed) { - struct drbg_string *input; - - list_for_each_entry(input, seed, list) - hmac_sha512_update(&hmac_ctx, input->buf, - input->len); - } + hmac_sha512_update(&hmac_ctx, data1, data1_len); + hmac_sha512_update(&hmac_ctx, data2, data2_len); hmac_sha512_final(&hmac_ctx, new_key); hmac_sha512_preparekey(&drbg->key, new_key, DRBG_STATE_LEN); @@ -188,7 +185,7 @@ static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed) hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); /* 10.1.2.2 step 3 */ - if (!seed) + if (data1_len == 0 && data2_len == 0) break; } memzero_explicit(new_key, sizeof(new_key)); @@ -198,13 +195,13 @@ static void drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed) static void drbg_hmac_generate(struct drbg_state *drbg, unsigned char *buf, unsigned int buflen, - struct list_head *addtl) + const u8 *addtl, size_t addtl_len) { int len = 0; /* 10.1.2.5 step 2 */ - if (addtl && !list_empty(addtl)) - drbg_hmac_update(drbg, addtl); + if (addtl_len) + drbg_hmac_update(drbg, addtl, addtl_len, NULL, 0); while (len < buflen) { unsigned int outlen = 0; @@ -220,16 +217,15 @@ static void drbg_hmac_generate(struct drbg_state *drbg, } /* 10.1.2.5 step 6 */ - if (addtl && !list_empty(addtl)) - drbg_hmac_update(drbg, addtl); - else - drbg_hmac_update(drbg, NULL); + drbg_hmac_update(drbg, addtl, addtl_len, NULL, 0); } -static inline void __drbg_seed(struct drbg_state *drbg, struct list_head *seed, +static inline void __drbg_seed(struct drbg_state *drbg, + const u8 *seed1, size_t seed1_len, + const u8 *seed2, size_t seed2_len, enum drbg_seed_state new_seed_state) { - drbg_hmac_update(drbg, seed); + drbg_hmac_update(drbg, seed1, seed1_len, seed2, seed2_len); drbg->seeded = new_seed_state; drbg->last_seed_time = jiffies; @@ -260,16 +256,12 @@ static inline void __drbg_seed(struct drbg_state *drbg, struct list_head *seed, static void drbg_seed_from_random(struct drbg_state *drbg) __must_hold(&drbg->drbg_mutex) { - struct drbg_string data; - LIST_HEAD(seedlist); - unsigned char entropy[DRBG_SEC_STRENGTH]; - - drbg_string_fill(&data, entropy, DRBG_SEC_STRENGTH); - list_add_tail(&data.list, &seedlist); + u8 entropy[DRBG_SEC_STRENGTH]; get_random_bytes(entropy, DRBG_SEC_STRENGTH); - __drbg_seed(drbg, &seedlist, DRBG_SEED_STATE_FULL); + __drbg_seed(drbg, entropy, DRBG_SEC_STRENGTH, NULL, 0, + DRBG_SEED_STATE_FULL); memzero_explicit(entropy, DRBG_SEC_STRENGTH); } @@ -279,7 +271,7 @@ static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg) unsigned long next_reseed; /* Don't ever reseed from get_random_bytes() in test mode. */ - if (list_empty(&drbg->test_data.list)) + if (drbg->test_entropylen) return false; /* @@ -299,33 +291,33 @@ static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg) * * @drbg: DRBG state struct * @pers: personalization / additional information buffer - * @reseed: 0 for initial seed process, 1 for reseeding + * @pers_len: length of @pers in bytes + * @reseed: false for initial seeding (instantiation), true for reseeding * * return: * 0 on success * error value otherwise */ -static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, +static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, bool reseed) __must_hold(&drbg->drbg_mutex) { int ret; - unsigned char entropy[((32 + 16) * 2)]; - unsigned int entropylen; - struct drbg_string data1; - LIST_HEAD(seedlist); + u8 entropy_buf[(32 + 16) * 2]; + size_t entropylen; + const u8 *entropy; enum drbg_seed_state new_seed_state = DRBG_SEED_STATE_FULL; /* 9.1 / 9.2 / 9.3.1 step 3 */ - if (pers && pers->len > DRBG_MAX_ADDTL) { + if (pers_len > DRBG_MAX_ADDTL) { pr_devel("DRBG: personalization string too long %zu\n", - pers->len); + pers_len); return -EINVAL; } - if (list_empty(&drbg->test_data.list)) { - drbg_string_fill(&data1, drbg->test_data.buf, - drbg->test_data.len); + if (drbg->test_entropylen) { + entropy = drbg->test_entropy; + entropylen = drbg->test_entropylen; pr_devel("DRBG: using test entropy\n"); } else { /* @@ -336,21 +328,21 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, * of the strength. The consideration of a nonce is only * applicable during initial seeding. */ + entropy = entropy_buf; if (!reseed) entropylen = ((DRBG_SEC_STRENGTH + 1) / 2) * 3; else entropylen = DRBG_SEC_STRENGTH; - BUG_ON((entropylen * 2) > sizeof(entropy)); + BUG_ON(entropylen * 2 > sizeof(entropy_buf)); /* Get seed from in-kernel /dev/urandom */ if (!rng_is_initialized()) new_seed_state = DRBG_SEED_STATE_PARTIAL; - get_random_bytes(entropy, entropylen); + get_random_bytes(entropy_buf, entropylen); if (!drbg->jent) { - drbg_string_fill(&data1, entropy, entropylen); - pr_devel("DRBG: (re)seeding with %u bytes of entropy\n", + pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n", entropylen); } else { /* @@ -358,7 +350,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, * fatal only in FIPS mode. */ ret = crypto_rng_get_bytes(drbg->jent, - entropy + entropylen, + &entropy_buf[entropylen], entropylen); if (fips_enabled && ret) { pr_devel("DRBG: jent failed with %d\n", ret); @@ -381,28 +373,19 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, goto out; } - drbg_string_fill(&data1, entropy, entropylen * 2); - pr_devel("DRBG: (re)seeding with %u bytes of entropy\n", - entropylen * 2); + entropylen *= 2; + pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n", + entropylen); } } - list_add_tail(&data1.list, &seedlist); - /* - * concatenation of entropy with personalization str / addtl input) - * the variable pers is directly handed in by the caller, so check its - * contents whether it is appropriate - */ - if (pers && pers->buf && 0 < pers->len) { - list_add_tail(&pers->list, &seedlist); + if (pers_len) pr_devel("DRBG: using personalization string\n"); - } - - __drbg_seed(drbg, &seedlist, new_seed_state); + __drbg_seed(drbg, entropy, entropylen, pers, pers_len, new_seed_state); ret = 0; out: - memzero_explicit(entropy, sizeof(entropy)); + memzero_explicit(entropy_buf, sizeof(entropy_buf)); return ret; } @@ -427,20 +410,17 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) * be pre-allocated by caller * @buflen Length of output buffer - this value defines the number of random * bytes pulled from DRBG - * @addtl Additional input that is mixed into state, may be NULL -- note - * the entropy is pulled by the DRBG internally unconditionally - * as defined in SP800-90A. The additional input is mixed into - * the state in addition to the pulled entropy. + * @addtl Optional additional input that is mixed into state + * @addtl_len Length of @addtl in bytes, may be 0 * * return: 0 when all bytes are generated; < 0 in case of an error */ static int drbg_generate(struct drbg_state *drbg, unsigned char *buf, unsigned int buflen, - struct drbg_string *addtl) + const u8 *addtl, size_t addtl_len) __must_hold(&drbg->drbg_mutex) { int len = 0; - LIST_HEAD(addtllist); if (!drbg->instantiated) { pr_devel("DRBG: not yet instantiated\n"); @@ -450,7 +430,7 @@ static int drbg_generate(struct drbg_state *drbg, pr_devel("DRBG: no output buffer provided\n"); return -EINVAL; } - if (addtl && NULL == addtl->buf && 0 < addtl->len) { + if (addtl == NULL && addtl_len != 0) { pr_devel("DRBG: wrong format of additional information\n"); return -EINVAL; } @@ -465,9 +445,9 @@ static int drbg_generate(struct drbg_state *drbg, /* 9.3.1 step 3 is implicit with the chosen DRBG */ /* 9.3.1 step 4 */ - if (addtl && addtl->len > DRBG_MAX_ADDTL) { + if (addtl_len > DRBG_MAX_ADDTL) { pr_devel("DRBG: additional information string too long %zu\n", - addtl->len); + addtl_len); return -EINVAL; } /* 9.3.1 step 5 is implicit with the chosen DRBG */ @@ -486,21 +466,20 @@ static int drbg_generate(struct drbg_state *drbg, (drbg->seeded == DRBG_SEED_STATE_FULL ? "seeded" : "unseeded")); /* 9.3.1 steps 7.1 through 7.3 */ - len = drbg_seed(drbg, addtl, true); + len = drbg_seed(drbg, addtl, addtl_len, true); if (len) goto err; /* 9.3.1 step 7.4 */ addtl = NULL; + addtl_len = 0; } else if (rng_is_initialized() && (drbg->seeded == DRBG_SEED_STATE_PARTIAL || drbg_nopr_reseed_interval_elapsed(drbg))) { drbg_seed_from_random(drbg); } - if (addtl && 0 < addtl->len) - list_add_tail(&addtl->list, &addtllist); /* 9.3.1 step 8 and 10 */ - drbg_hmac_generate(drbg, buf, buflen, &addtllist); + drbg_hmac_generate(drbg, buf, buflen, addtl, addtl_len); /* 10.1.2.5 step 7 */ drbg->reseed_ctr++; @@ -537,7 +516,7 @@ err: */ static int drbg_generate_long(struct drbg_state *drbg, unsigned char *buf, unsigned int buflen, - struct drbg_string *addtl) + const u8 *addtl, size_t addtl_len) { unsigned int len = 0; unsigned int slice = 0; @@ -547,7 +526,7 @@ static int drbg_generate_long(struct drbg_state *drbg, slice = (buflen - len) / DRBG_MAX_REQUEST_BYTES; chunk = slice ? DRBG_MAX_REQUEST_BYTES : (buflen - len); mutex_lock(&drbg->drbg_mutex); - err = drbg_generate(drbg, buf + len, chunk, addtl); + err = drbg_generate(drbg, buf + len, chunk, addtl, addtl_len); mutex_unlock(&drbg->drbg_mutex); if (0 > err) return err; @@ -559,7 +538,7 @@ static int drbg_generate_long(struct drbg_state *drbg, static int drbg_prepare_hrng(struct drbg_state *drbg) { /* We do not need an HRNG in test mode. */ - if (list_empty(&drbg->test_data.list)) + if (drbg->test_entropylen != 0) return 0; drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); @@ -581,18 +560,16 @@ static int drbg_prepare_hrng(struct drbg_state *drbg) * checks required by SP800-90A * * @drbg memory of state -- if NULL, new memory is allocated - * @pers Personalization string that is mixed into state, may be NULL -- note - * the entropy is pulled by the DRBG internally unconditionally - * as defined in SP800-90A. The additional input is mixed into - * the state in addition to the pulled entropy. + * @pers Optional personalization string that is mixed into state + * @pers_len Length of personalization string in bytes, may be 0 * @pr prediction resistance enabled * * return * 0 on success * error value otherwise */ -static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, - bool pr) +static int drbg_instantiate(struct drbg_state *drbg, + const u8 *pers, size_t pers_len, bool pr) { static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */ int ret; @@ -627,7 +604,7 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, reseed = false; } - ret = drbg_seed(drbg, pers, reseed); + ret = drbg_seed(drbg, pers, pers_len, reseed); if (ret && !reseed) goto free_everything; @@ -674,7 +651,8 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, struct drbg_state *drbg = crypto_rng_ctx(tfm); mutex_lock(&drbg->drbg_mutex); - drbg_string_fill(&drbg->test_data, data, len); + drbg->test_entropy = data; + drbg->test_entropylen = len; mutex_unlock(&drbg->drbg_mutex); } @@ -710,16 +688,8 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, u8 *dst, unsigned int dlen) { struct drbg_state *drbg = crypto_rng_ctx(tfm); - struct drbg_string *addtl = NULL; - struct drbg_string string; - if (slen) { - /* linked list variable is now local to allow modification */ - drbg_string_fill(&string, src, slen); - addtl = &string; - } - - return drbg_generate_long(drbg, dst, dlen, addtl); + return drbg_generate_long(drbg, dst, dlen, src, slen); } /* Seed (i.e. instantiate) or re-seed the DRBG. */ @@ -727,15 +697,8 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen, bool pr) { struct drbg_state *drbg = crypto_rng_ctx(tfm); - struct drbg_string string; - struct drbg_string *seed_string = NULL; - if (0 < slen) { - drbg_string_fill(&string, seed, slen); - seed_string = &string; - } - - return drbg_instantiate(drbg, seed_string, pr); + return drbg_instantiate(drbg, seed, slen, pr); } static int drbg_kcapi_seed_pr(struct crypto_rng *tfm, @@ -767,11 +730,9 @@ static int drbg_kcapi_seed_nopr(struct crypto_rng *tfm, static inline int __init drbg_healthcheck_sanity(void) { #define OUTBUFLEN 16 - unsigned char buf[OUTBUFLEN]; + u8 buf[OUTBUFLEN]; struct drbg_state *drbg = NULL; int ret; - int rc = -EFAULT; - struct drbg_string addtl; /* only perform test in FIPS mode */ if (!fips_enabled) @@ -793,25 +754,23 @@ static inline int __init drbg_healthcheck_sanity(void) * grave bug. */ - drbg_string_fill(&addtl, buf, DRBG_MAX_ADDTL + 1); /* overflow addtllen with additional info string */ - ret = drbg_generate(drbg, buf, OUTBUFLEN, &addtl); + ret = drbg_generate(drbg, buf, OUTBUFLEN, buf, DRBG_MAX_ADDTL + 1); BUG_ON(ret == 0); /* overflow max_bits */ - ret = drbg_generate(drbg, buf, DRBG_MAX_REQUEST_BYTES + 1, NULL); + ret = drbg_generate(drbg, buf, DRBG_MAX_REQUEST_BYTES + 1, NULL, 0); BUG_ON(ret == 0); /* overflow max addtllen with personalization string */ - ret = drbg_seed(drbg, &addtl, false); - BUG_ON(0 == ret); + ret = drbg_seed(drbg, buf, DRBG_MAX_ADDTL + 1, false); + BUG_ON(ret == 0); /* all tests passed */ - rc = 0; pr_devel("DRBG: Sanity tests for failure code paths successfully " "completed\n"); kfree(drbg); - return rc; + return 0; } static struct rng_alg drbg_algs[] = { diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c index 5276ac2d82bb..43a4832f07e7 100644 --- a/drivers/crypto/xilinx/xilinx-trng.c +++ b/drivers/crypto/xilinx/xilinx-trng.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/include/crypto/df_sp80090a.h b/include/crypto/df_sp80090a.h index cb5d6fe15d40..e594fb718eb8 100644 --- a/include/crypto/df_sp80090a.h +++ b/include/crypto/df_sp80090a.h @@ -9,6 +9,31 @@ #include #include +#include + +/* + * Concatenation Helper and string operation helper + * + * SP800-90A requires the concatenation of different data. To avoid copying + * buffers around or allocate additional memory, the following data structure + * is used to point to the original memory with its size. In addition, it + * is used to build a linked list. The linked list defines the concatenation + * of individual buffers. The order of memory block referenced in that + * linked list determines the order of concatenation. + */ +struct drbg_string { + const unsigned char *buf; + size_t len; + struct list_head list; +}; + +static inline void drbg_string_fill(struct drbg_string *string, + const unsigned char *buf, size_t len) +{ + string->buf = buf; + string->len = len; + INIT_LIST_HEAD(&string->list); +} static inline int crypto_drbg_ctr_df_datalen(u8 statelen, u8 blocklen) { diff --git a/include/crypto/internal/drbg.h b/include/crypto/internal/drbg.h deleted file mode 100644 index 5d4174cc6a53..000000000000 --- a/include/crypto/internal/drbg.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* - * NIST SP800-90A DRBG derivation function - * - * Copyright (C) 2014, Stephan Mueller - */ - -#ifndef _INTERNAL_DRBG_H -#define _INTERNAL_DRBG_H - -#include -#include - -/* - * Concatenation Helper and string operation helper - * - * SP800-90A requires the concatenation of different data. To avoid copying - * buffers around or allocate additional memory, the following data structure - * is used to point to the original memory with its size. In addition, it - * is used to build a linked list. The linked list defines the concatenation - * of individual buffers. The order of memory block referenced in that - * linked list determines the order of concatenation. - */ -struct drbg_string { - const unsigned char *buf; - size_t len; - struct list_head list; -}; - -static inline void drbg_string_fill(struct drbg_string *string, - const unsigned char *buf, size_t len) -{ - string->buf = buf; - string->len = len; - INIT_LIST_HEAD(&string->list); -} - -#endif //_INTERNAL_DRBG_H From 7ba94ec2d896590d2200ac7999f6a7fae970e72b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:12 -0700 Subject: [PATCH 146/655] crypto: drbg - Simplify drbg_generate_long() and fold into caller Simplify drbg_generate_long() to use a more straightforward loop, and then fold it into its only caller. No functional change. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 48 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index b0cd8da51b26..9ff1a0e1b129 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -506,35 +506,6 @@ err: return len; } -/* - * Wrapper around drbg_generate which can pull arbitrary long strings - * from the DRBG without hitting the maximum request limitation. - * - * Parameters: see drbg_generate - * Return codes: see drbg_generate -- if one drbg_generate request fails, - * the entire drbg_generate_long request fails - */ -static int drbg_generate_long(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - const u8 *addtl, size_t addtl_len) -{ - unsigned int len = 0; - unsigned int slice = 0; - do { - int err = 0; - unsigned int chunk = 0; - slice = (buflen - len) / DRBG_MAX_REQUEST_BYTES; - chunk = slice ? DRBG_MAX_REQUEST_BYTES : (buflen - len); - mutex_lock(&drbg->drbg_mutex); - err = drbg_generate(drbg, buf + len, chunk, addtl, addtl_len); - mutex_unlock(&drbg->drbg_mutex); - if (0 > err) - return err; - len += chunk; - } while (slice > 0 && (len < buflen)); - return 0; -} - static int drbg_prepare_hrng(struct drbg_state *drbg) { /* We do not need an HRNG in test mode. */ @@ -676,7 +647,6 @@ static void drbg_kcapi_cleanup(struct crypto_tfm *tfm) /* * Generate random numbers invoked by the kernel crypto API: - * The API of the kernel crypto API is extended as follows: * * src is additional input supplied to the RNG. * slen is the length of src. @@ -689,7 +659,23 @@ static int drbg_kcapi_random(struct crypto_rng *tfm, { struct drbg_state *drbg = crypto_rng_ctx(tfm); - return drbg_generate_long(drbg, dst, dlen, src, slen); + /* + * Break the request into multiple requests if needed, to avoid + * exceeding the maximum request length of the core algorithm. + */ + do { + unsigned int n = min(dlen, DRBG_MAX_REQUEST_BYTES); + int err; + + mutex_lock(&drbg->drbg_mutex); + err = drbg_generate(drbg, dst, n, src, slen); + mutex_unlock(&drbg->drbg_mutex); + if (err < 0) + return err; + dst += n; + dlen -= n; + } while (dlen); + return 0; } /* Seed (i.e. instantiate) or re-seed the DRBG. */ From fb2d8b7003467b4c893afd6f4be579d08f8360ce Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:13 -0700 Subject: [PATCH 147/655] crypto: drbg - Put rng_alg methods in logical order Put the DRBG implementation of the rng_alg methods in the order in which they're called (cra_init => set_ent => seed => generate => cra_exit) so that it's easier to understand the flow. Also rename drbg_kcapi_random to drbg_kcapi_generate, and drbg_kcapi_cleanup to drbg_kcapi_exit, so they match the method names. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 108 +++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 9ff1a0e1b129..ef9c3e9fdf6e 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -609,26 +609,8 @@ static int drbg_uninstantiate(struct drbg_state *drbg) return 0; } -/* - * Helper function for setting the test data in the DRBG - * - * @drbg DRBG state handle - * @data test data - * @len test data length - */ -static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, - const u8 *data, unsigned int len) -{ - struct drbg_state *drbg = crypto_rng_ctx(tfm); - - mutex_lock(&drbg->drbg_mutex); - drbg->test_entropy = data; - drbg->test_entropylen = len; - mutex_unlock(&drbg->drbg_mutex); -} - /*************************************************************** - * Kernel crypto API interface to register DRBG + * Kernel crypto API interface to DRBG ***************************************************************/ static int drbg_kcapi_init(struct crypto_tfm *tfm) @@ -640,42 +622,16 @@ static int drbg_kcapi_init(struct crypto_tfm *tfm) return 0; } -static void drbg_kcapi_cleanup(struct crypto_tfm *tfm) -{ - drbg_uninstantiate(crypto_tfm_ctx(tfm)); -} - -/* - * Generate random numbers invoked by the kernel crypto API: - * - * src is additional input supplied to the RNG. - * slen is the length of src. - * dst is the output buffer where random data is to be stored. - * dlen is the length of dst. - */ -static int drbg_kcapi_random(struct crypto_rng *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int dlen) +/* Set test entropy in the DRBG. */ +static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, + const u8 *data, unsigned int len) { struct drbg_state *drbg = crypto_rng_ctx(tfm); - /* - * Break the request into multiple requests if needed, to avoid - * exceeding the maximum request length of the core algorithm. - */ - do { - unsigned int n = min(dlen, DRBG_MAX_REQUEST_BYTES); - int err; - - mutex_lock(&drbg->drbg_mutex); - err = drbg_generate(drbg, dst, n, src, slen); - mutex_unlock(&drbg->drbg_mutex); - if (err < 0) - return err; - dst += n; - dlen -= n; - } while (dlen); - return 0; + mutex_lock(&drbg->drbg_mutex); + drbg->test_entropy = data; + drbg->test_entropylen = len; + mutex_unlock(&drbg->drbg_mutex); } /* Seed (i.e. instantiate) or re-seed the DRBG. */ @@ -699,9 +655,43 @@ static int drbg_kcapi_seed_nopr(struct crypto_rng *tfm, return drbg_kcapi_seed(tfm, seed, slen, /* pr= */ false); } -/*************************************************************** - * Kernel module: code to load the module - ***************************************************************/ +/* + * Generate random numbers invoked by the kernel crypto API: + * + * src is additional input supplied to the RNG. + * slen is the length of src. + * dst is the output buffer where random data is to be stored. + * dlen is the length of dst. + */ +static int drbg_kcapi_generate(struct crypto_rng *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int dlen) +{ + struct drbg_state *drbg = crypto_rng_ctx(tfm); + + /* + * Break the request into multiple requests if needed, to avoid + * exceeding the maximum request length of the core algorithm. + */ + do { + unsigned int n = min(dlen, DRBG_MAX_REQUEST_BYTES); + int err; + + mutex_lock(&drbg->drbg_mutex); + err = drbg_generate(drbg, dst, n, src, slen); + mutex_unlock(&drbg->drbg_mutex); + if (err < 0) + return err; + dst += n; + dlen -= n; + } while (dlen); + return 0; +} + +static void drbg_kcapi_exit(struct crypto_tfm *tfm) +{ + drbg_uninstantiate(crypto_tfm_ctx(tfm)); +} /* * Tests as defined in 11.3.2 in addition to the cipher tests: testing @@ -769,8 +759,8 @@ static struct rng_alg drbg_algs[] = { .base.cra_init = drbg_kcapi_init, .set_ent = drbg_kcapi_set_entropy, .seed = drbg_kcapi_seed_pr, - .generate = drbg_kcapi_random, - .base.cra_exit = drbg_kcapi_cleanup, + .generate = drbg_kcapi_generate, + .base.cra_exit = drbg_kcapi_exit, }, { .base.cra_name = "stdrng", @@ -781,8 +771,8 @@ static struct rng_alg drbg_algs[] = { .base.cra_init = drbg_kcapi_init, .set_ent = drbg_kcapi_set_entropy, .seed = drbg_kcapi_seed_nopr, - .generate = drbg_kcapi_random, - .base.cra_exit = drbg_kcapi_cleanup, + .generate = drbg_kcapi_generate, + .base.cra_exit = drbg_kcapi_exit, }, }; From 810ba022870bfdf7b7ac0e04db98b2891e80f59e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:14 -0700 Subject: [PATCH 148/655] crypto: drbg - Fold drbg_instantiate() into drbg_kcapi_seed() Fold drbg_instantiate() into its only caller. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 111 ++++++++++++++++++++------------------------------ 1 file changed, 45 insertions(+), 66 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index ef9c3e9fdf6e..763c14e3786c 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -525,70 +525,6 @@ static int drbg_prepare_hrng(struct drbg_state *drbg) return 0; } -/* - * DRBG instantiation function as required by SP800-90A - this function - * sets up the DRBG handle, performs the initial seeding and all sanity - * checks required by SP800-90A - * - * @drbg memory of state -- if NULL, new memory is allocated - * @pers Optional personalization string that is mixed into state - * @pers_len Length of personalization string in bytes, may be 0 - * @pr prediction resistance enabled - * - * return - * 0 on success - * error value otherwise - */ -static int drbg_instantiate(struct drbg_state *drbg, - const u8 *pers, size_t pers_len, bool pr) -{ - static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */ - int ret; - bool reseed = true; - - pr_devel("DRBG: Initializing DRBG with prediction resistance %s\n", - str_enabled_disabled(pr)); - mutex_lock(&drbg->drbg_mutex); - - /* 9.1 step 1 is implicit with the selected DRBG type */ - - /* - * 9.1 step 2 is implicit as caller can select prediction resistance - * all DRBG types support prediction resistance - */ - - /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ - - if (!drbg->instantiated) { - drbg->instantiated = true; - drbg->pr = pr; - drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - drbg->last_seed_time = 0; - drbg->reseed_threshold = DRBG_MAX_REQUESTS; - memset(drbg->V, 1, DRBG_STATE_LEN); - hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); - - ret = drbg_prepare_hrng(drbg); - if (ret) - goto free_everything; - - reseed = false; - } - - ret = drbg_seed(drbg, pers, pers_len, reseed); - - if (ret && !reseed) - goto free_everything; - - mutex_unlock(&drbg->drbg_mutex); - return ret; - -free_everything: - mutex_unlock(&drbg->drbg_mutex); - drbg_uninstantiate(drbg); - return ret; -} - /* * DRBG uninstantiate function as required by SP800-90A - this function * frees all buffers and the DRBG handle @@ -636,11 +572,54 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, /* Seed (i.e. instantiate) or re-seed the DRBG. */ static int drbg_kcapi_seed(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen, bool pr) + const u8 *pers, size_t pers_len, bool pr) { + static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */ struct drbg_state *drbg = crypto_rng_ctx(tfm); + int ret; + bool reseed = true; - return drbg_instantiate(drbg, seed, slen, pr); + pr_devel("DRBG: Initializing DRBG with prediction resistance %s\n", + str_enabled_disabled(pr)); + mutex_lock(&drbg->drbg_mutex); + + /* 9.1 step 1 is implicit with the selected DRBG type */ + + /* + * 9.1 step 2 is implicit as caller can select prediction resistance + * all DRBG types support prediction resistance + */ + + /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ + + if (!drbg->instantiated) { + drbg->instantiated = true; + drbg->pr = pr; + drbg->seeded = DRBG_SEED_STATE_UNSEEDED; + drbg->last_seed_time = 0; + drbg->reseed_threshold = DRBG_MAX_REQUESTS; + memset(drbg->V, 1, DRBG_STATE_LEN); + hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); + + ret = drbg_prepare_hrng(drbg); + if (ret) + goto free_everything; + + reseed = false; + } + + ret = drbg_seed(drbg, pers, pers_len, reseed); + + if (ret && !reseed) + goto free_everything; + + mutex_unlock(&drbg->drbg_mutex); + return ret; + +free_everything: + mutex_unlock(&drbg->drbg_mutex); + drbg_uninstantiate(drbg); + return ret; } static int drbg_kcapi_seed_pr(struct crypto_rng *tfm, From ad8883374f34809f04d6839b9e7efe0afa5e92cd Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:15 -0700 Subject: [PATCH 149/655] crypto: drbg - Separate "reseed" case in drbg_kcapi_seed() Clearly separate the code for the "reseed" and "instantiate" cases, since what they need to do is quite different. Note that the mutex guard makes the mutex start being held during the call to drbg_uninstantiate(), which is fine. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 763c14e3786c..a9d586107ebe 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -577,11 +577,13 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */ struct drbg_state *drbg = crypto_rng_ctx(tfm); int ret; - bool reseed = true; pr_devel("DRBG: Initializing DRBG with prediction resistance %s\n", str_enabled_disabled(pr)); - mutex_lock(&drbg->drbg_mutex); + guard(mutex)(&drbg->drbg_mutex); + + if (drbg->instantiated) + return drbg_seed(drbg, pers, pers_len, /* reseed= */ true); /* 9.1 step 1 is implicit with the selected DRBG type */ @@ -592,32 +594,24 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ - if (!drbg->instantiated) { - drbg->instantiated = true; - drbg->pr = pr; - drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - drbg->last_seed_time = 0; - drbg->reseed_threshold = DRBG_MAX_REQUESTS; - memset(drbg->V, 1, DRBG_STATE_LEN); - hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); + drbg->instantiated = true; + drbg->pr = pr; + drbg->seeded = DRBG_SEED_STATE_UNSEEDED; + drbg->last_seed_time = 0; + drbg->reseed_threshold = DRBG_MAX_REQUESTS; + memset(drbg->V, 1, DRBG_STATE_LEN); + hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); - ret = drbg_prepare_hrng(drbg); - if (ret) - goto free_everything; - - reseed = false; - } - - ret = drbg_seed(drbg, pers, pers_len, reseed); - - if (ret && !reseed) + ret = drbg_prepare_hrng(drbg); + if (ret) + goto free_everything; + ret = drbg_seed(drbg, pers, pers_len, /* reseed= */ false); + if (ret) goto free_everything; - mutex_unlock(&drbg->drbg_mutex); return ret; free_everything: - mutex_unlock(&drbg->drbg_mutex); drbg_uninstantiate(drbg); return ret; } From 2b30c567603b6e12f153dc7f584d3be87a96be35 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:16 -0700 Subject: [PATCH 150/655] crypto: drbg - Fold drbg_prepare_hrng() into drbg_kcapi_seed() Fold drbg_prepare_hrng() into its only caller. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index a9d586107ebe..45d97f3ba4ef 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -506,25 +506,6 @@ err: return len; } -static int drbg_prepare_hrng(struct drbg_state *drbg) -{ - /* We do not need an HRNG in test mode. */ - if (drbg->test_entropylen != 0) - return 0; - - drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); - if (IS_ERR(drbg->jent)) { - const int err = PTR_ERR(drbg->jent); - - drbg->jent = NULL; - if (fips_enabled) - return err; - pr_info("DRBG: Continuing without Jitter RNG\n"); - } - - return 0; -} - /* * DRBG uninstantiate function as required by SP800-90A - this function * frees all buffers and the DRBG handle @@ -602,9 +583,18 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, memset(drbg->V, 1, DRBG_STATE_LEN); hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); - ret = drbg_prepare_hrng(drbg); - if (ret) - goto free_everything; + /* Allocate jitterentropy_rng if not in test mode. */ + if (drbg->test_entropylen == 0) { + drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); + if (IS_ERR(drbg->jent)) { + ret = PTR_ERR(drbg->jent); + drbg->jent = NULL; + if (fips_enabled) + goto free_everything; + pr_info("DRBG: Continuing without Jitter RNG\n"); + } + } + ret = drbg_seed(drbg, pers, pers_len, /* reseed= */ false); if (ret) goto free_everything; From b87c8286bfe63c176b9af59b5ca1c98005312bd8 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:17 -0700 Subject: [PATCH 151/655] crypto: drbg - Simplify "uninstantiate" logic drbg_kcapi_seed() calls drbg_uninstantiate() only to free drbg->jent and set drbg->instantiated = false. However, the latter is necessary only because drbg_kcapi_seed() sets drbg->instantiated = true too early. Fix that, then just inline the freeing of drbg->jent. Then, simplify the actual "uninstantiate" in drbg_kcapi_exit(). Just free drbg->jent (note that this is a no-op on error and null pointers), then memzero_explicit() the entire drbg_state. Note that in reality the memzero_explicit() is redundant, since the crypto_rng API zeroizes the memory anyway. But the way SP800-90A is worded, it's easy to imagine that someone assessing conformance with it would be looking for code in drbg.c that says it does an "Uninstantiate" and does the zeroization. So it's probably worth keeping it somewhat explicit, even though that means double zeroization in practice. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 57 ++++++++++++--------------------------------------- 1 file changed, 13 insertions(+), 44 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 45d97f3ba4ef..b2af481aef01 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -152,8 +152,6 @@ enum drbg_prefixes { DRBG_PREFIX1, }; -static int drbg_uninstantiate(struct drbg_state *drbg); - /****************************************************************** * HMAC DRBG functions ******************************************************************/ @@ -390,17 +388,6 @@ out: return ret; } -/* Free all substructures in a DRBG state without the DRBG state structure */ -static inline void drbg_dealloc_state(struct drbg_state *drbg) -{ - if (!drbg) - return; - memzero_explicit(&drbg->key, sizeof(drbg->key)); - memzero_explicit(drbg->V, sizeof(drbg->V)); - drbg->reseed_ctr = 0; - drbg->instantiated = false; -} - /* * DRBG generate function as required by SP800-90A - this function * generates random numbers @@ -506,26 +493,6 @@ err: return len; } -/* - * DRBG uninstantiate function as required by SP800-90A - this function - * frees all buffers and the DRBG handle - * - * @drbg DRBG state handle - * - * return - * 0 on success - */ -static int drbg_uninstantiate(struct drbg_state *drbg) -{ - if (!IS_ERR_OR_NULL(drbg->jent)) - crypto_free_rng(drbg->jent); - drbg->jent = NULL; - - drbg_dealloc_state(drbg); - /* no scrubbing of test_data -- this shall survive an uninstantiate */ - return 0; -} - /*************************************************************** * Kernel crypto API interface to DRBG ***************************************************************/ @@ -575,7 +542,6 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ - drbg->instantiated = true; drbg->pr = pr; drbg->seeded = DRBG_SEED_STATE_UNSEEDED; drbg->last_seed_time = 0; @@ -590,20 +556,19 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, ret = PTR_ERR(drbg->jent); drbg->jent = NULL; if (fips_enabled) - goto free_everything; + return ret; pr_info("DRBG: Continuing without Jitter RNG\n"); } } ret = drbg_seed(drbg, pers, pers_len, /* reseed= */ false); - if (ret) - goto free_everything; - - return ret; - -free_everything: - drbg_uninstantiate(drbg); - return ret; + if (ret) { + crypto_free_rng(drbg->jent); + drbg->jent = NULL; + return ret; + } + drbg->instantiated = true; + return 0; } static int drbg_kcapi_seed_pr(struct crypto_rng *tfm, @@ -651,9 +616,13 @@ static int drbg_kcapi_generate(struct crypto_rng *tfm, return 0; } +/* Uninstantiate the DRBG. */ static void drbg_kcapi_exit(struct crypto_tfm *tfm) { - drbg_uninstantiate(crypto_tfm_ctx(tfm)); + struct drbg_state *drbg = crypto_tfm_ctx(tfm); + + crypto_free_rng(drbg->jent); + memzero_explicit(drbg, sizeof(*drbg)); } /* From ca659874af31c6c6e1c5992475b88be8cb65d484 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:18 -0700 Subject: [PATCH 152/655] crypto: drbg - Include get_random_bytes() output in additional input Woodage & Shumow (2018) (https://eprint.iacr.org/2018/349.pdf) showed that contrary to the claims made by NIST in SP800-90A, HMAC_DRBG doesn't satisfy the formal definition of forward secrecy (i.e. "backtracking resistance") when it's called with an empty additional input string. The actual attack seems pretty benign, as it doesn't actually give the attacker any previous RNG output, but rather just allows them to test whether their guess of the previous block of RNG output is correct. Regardless, it's an annoying design flaw, and it's yet another example of why NIST's DRBGs aren't all that great. Meanwhile, the kernel's HMAC_DRBG code also tries to reseed itself automatically after random.c has reseeded itself. But the implementation is buggy, as it just checks whether 300 seconds have elapsed, rather than looking at the actual generation counter. Let's just follow the example of BoringSSL and use the conservative approach of always including 32 bytes of "regular" random data in the additional input string. This fixes both issues described above. This does reduce performance. But this should be tolerable, since: - Due to earlier changes, the kernel code that was previously using drbg.c regardless of FIPS mode is now using it only in FIPS mode. - The additional input string is processed only once per request. So if a lot of bytes are generated at once, the cost is amortized. - The NIST DRBGs are notoriously slow anyway. Note that this fix should have no impact (either positive or negative) on FIPS 140 certifiability. From FIPS's point of view the code added by this commit simply doesn't matter: it adds zero entropy to something that doesn't need to contain entropy. Fixes: 541af946fe13 ("crypto: drbg - SP800-90A Deterministic Random Bit Generator") Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index b2af481aef01..cda79d601f4f 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -193,13 +193,32 @@ static void drbg_hmac_update(struct drbg_state *drbg, static void drbg_hmac_generate(struct drbg_state *drbg, unsigned char *buf, unsigned int buflen, - const u8 *addtl, size_t addtl_len) + const u8 *addtl1, size_t addtl1_len) { int len = 0; + u8 addtl2[32]; + size_t addtl2_len = 0; + + /* + * Append some bytes from get_random_bytes() to the additional input + * string, except when in test mode (as it would break the tests). + * Using a nonempty additional input string works around the forward + * secrecy bug in HMAC_DRBG described by Woodage & Shumow (2018) + * (https://eprint.iacr.org/2018/349.pdf). Filling the string with + * get_random_bytes() rather than a fixed value is safer still, and in + * particular makes random.c reseeds be immediately reflected. + * + * Note that there's no need to pull bytes from jitterentropy here too, + * since FIPS doesn't require any entropy in the additional input. + */ + if (drbg->test_entropylen == 0) { + get_random_bytes(addtl2, sizeof(addtl2)); + addtl2_len = sizeof(addtl2); + } /* 10.1.2.5 step 2 */ - if (addtl_len) - drbg_hmac_update(drbg, addtl, addtl_len, NULL, 0); + if (addtl1_len || addtl2_len) + drbg_hmac_update(drbg, addtl1, addtl1_len, addtl2, addtl2_len); while (len < buflen) { unsigned int outlen = 0; @@ -215,7 +234,9 @@ static void drbg_hmac_generate(struct drbg_state *drbg, } /* 10.1.2.5 step 6 */ - drbg_hmac_update(drbg, addtl, addtl_len, NULL, 0); + drbg_hmac_update(drbg, addtl1, addtl1_len, addtl2, addtl2_len); + + memzero_explicit(addtl2, sizeof(addtl2)); } static inline void __drbg_seed(struct drbg_state *drbg, From 005b19f18ea9fc51fc35fbcb27759ae83c7c89f8 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:19 -0700 Subject: [PATCH 153/655] crypto: drbg - Change DRBG_MAX_REQUESTS to 4096 Currently a formal reseed happens only after each 1048576 requests. That's quite a high number. Let's follow the example of BoringSSL and use a more conservative value of 4096. Note that in practice this makes little difference, now that we're including 32 bytes from get_random_bytes() in the additional input on every request anyway, which is a de facto reseed. But for the same reason, we might as well decrease the actual reseed interval to something more reasonable. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index cda79d601f4f..7fd076ddc105 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -115,7 +115,7 @@ enum drbg_seed_state { * Maximum number of requests before reseeding is forced. * SP800-90A allows this to be up to 2**48. We use a lower value. */ -#define DRBG_MAX_REQUESTS (1 << 20) +#define DRBG_MAX_REQUESTS 4096 /* * Maximum number of random bytes that can be requested at once. From a918c3680d2ea1d3c2df589397c0ffd4dac2ceaa Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:20 -0700 Subject: [PATCH 154/655] crypto: drbg - Remove redundant reseeding based on random.c state We're now incorporating 32 bytes from get_random_bytes() in the additional input string on every request. The additional input string is processed with a call to drbg_hmac_update(), which is exactly how the seed is processed. Thus, in reality this is as good as a reseed. From the perspective of FIPS 140-3, it isn't as good as a reseed. But it doesn't actually matter, because from FIPS's point of view get_random_bytes() provides zero entropy anyway. Thus, neither the reseed with more get_random_bytes() every 300s, nor the logic that reseeds more frequently before rng_is_initialized(), is actually needed anymore. Remove it to simplify the code significantly. (Technically the use of get_random_bytes() in drbg_seed() itself could be removed too. But it's safer to keep it there for now.) Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 107 +++++--------------------------------------------- 1 file changed, 9 insertions(+), 98 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 7fd076ddc105..bab766026177 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -93,18 +93,11 @@ #include #include #include -#include #include #include #include #include -enum drbg_seed_state { - DRBG_SEED_STATE_UNSEEDED, - DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ - DRBG_SEED_STATE_FULL, -}; - /* State length in bytes */ #define DRBG_STATE_LEN SHA512_DIGEST_SIZE @@ -137,9 +130,6 @@ struct drbg_state { struct hmac_sha512_key key; /* current key -- 10.1.2.1 1b */ /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr; - size_t reseed_threshold; - enum drbg_seed_state seeded; /* DRBG fully seeded? */ - unsigned long last_seed_time; bool instantiated; bool pr; /* Prediction resistance enabled? */ struct crypto_rng *jent; @@ -239,72 +229,6 @@ static void drbg_hmac_generate(struct drbg_state *drbg, memzero_explicit(addtl2, sizeof(addtl2)); } -static inline void __drbg_seed(struct drbg_state *drbg, - const u8 *seed1, size_t seed1_len, - const u8 *seed2, size_t seed2_len, - enum drbg_seed_state new_seed_state) -{ - drbg_hmac_update(drbg, seed1, seed1_len, seed2, seed2_len); - - drbg->seeded = new_seed_state; - drbg->last_seed_time = jiffies; - drbg->reseed_ctr = 1; - - switch (drbg->seeded) { - case DRBG_SEED_STATE_UNSEEDED: - /* Impossible, but handle it to silence compiler warnings. */ - fallthrough; - case DRBG_SEED_STATE_PARTIAL: - /* - * Require frequent reseeds until the seed source is - * fully initialized. - */ - drbg->reseed_threshold = 50; - break; - - case DRBG_SEED_STATE_FULL: - /* - * Seed source has become fully initialized, frequent - * reseeds no longer required. - */ - drbg->reseed_threshold = DRBG_MAX_REQUESTS; - break; - } -} - -static void drbg_seed_from_random(struct drbg_state *drbg) - __must_hold(&drbg->drbg_mutex) -{ - u8 entropy[DRBG_SEC_STRENGTH]; - - get_random_bytes(entropy, DRBG_SEC_STRENGTH); - - __drbg_seed(drbg, entropy, DRBG_SEC_STRENGTH, NULL, 0, - DRBG_SEED_STATE_FULL); - - memzero_explicit(entropy, DRBG_SEC_STRENGTH); -} - -static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg) -{ - unsigned long next_reseed; - - /* Don't ever reseed from get_random_bytes() in test mode. */ - if (drbg->test_entropylen) - return false; - - /* - * Obtain fresh entropy for the nopr DRBGs after 300s have - * elapsed in order to still achieve sort of partial - * prediction resistance over the time domain at least. Note - * that the period of 300s has been chosen to match the - * CRNG_RESEED_INTERVAL of the get_random_bytes()' chacha - * rngs. - */ - next_reseed = drbg->last_seed_time + 300 * HZ; - return time_after(jiffies, next_reseed); -} - /* * Seeding or reseeding of the DRBG * @@ -325,7 +249,6 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, u8 entropy_buf[(32 + 16) * 2]; size_t entropylen; const u8 *entropy; - enum drbg_seed_state new_seed_state = DRBG_SEED_STATE_FULL; /* 9.1 / 9.2 / 9.3.1 step 3 */ if (pers_len > DRBG_MAX_ADDTL) { @@ -355,9 +278,6 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, BUG_ON(entropylen * 2 > sizeof(entropy_buf)); /* Get seed from in-kernel /dev/urandom */ - if (!rng_is_initialized()) - new_seed_state = DRBG_SEED_STATE_PARTIAL; - get_random_bytes(entropy_buf, entropylen); if (!drbg->jent) { @@ -401,7 +321,8 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, if (pers_len) pr_devel("DRBG: using personalization string\n"); - __drbg_seed(drbg, entropy, entropylen, pers, pers_len, new_seed_state); + drbg_hmac_update(drbg, entropy, entropylen, pers, pers_len); + drbg->reseed_ctr = 1; ret = 0; out: memzero_explicit(entropy_buf, sizeof(entropy_buf)); @@ -463,16 +384,14 @@ static int drbg_generate(struct drbg_state *drbg, /* * 9.3.1 step 6 and 9 supplemented by 9.3.2 step c is implemented * here. The spec is a bit convoluted here, we make it simpler. + * + * We no longer try to detect when random.c has reseeded itself and call + * drbg_seed() then too, since drbg_hmac_generate() adds bytes from + * random.c to the additional input, which is a de facto reseed anyway. */ - if (drbg->reseed_threshold < drbg->reseed_ctr) - drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - - if (drbg->pr || drbg->seeded == DRBG_SEED_STATE_UNSEEDED) { - pr_devel("DRBG: reseeding before generation (prediction " - "resistance: %s, state %s)\n", - str_true_false(drbg->pr), - (drbg->seeded == DRBG_SEED_STATE_FULL ? - "seeded" : "unseeded")); + if (drbg->pr || drbg->reseed_ctr > DRBG_MAX_REQUESTS) { + pr_devel("DRBG: reseeding before generation (prediction resistance: %s)\n", + str_true_false(drbg->pr)); /* 9.3.1 steps 7.1 through 7.3 */ len = drbg_seed(drbg, addtl, addtl_len, true); if (len) @@ -480,10 +399,6 @@ static int drbg_generate(struct drbg_state *drbg, /* 9.3.1 step 7.4 */ addtl = NULL; addtl_len = 0; - } else if (rng_is_initialized() && - (drbg->seeded == DRBG_SEED_STATE_PARTIAL || - drbg_nopr_reseed_interval_elapsed(drbg))) { - drbg_seed_from_random(drbg); } /* 9.3.1 step 8 and 10 */ @@ -564,9 +479,6 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ drbg->pr = pr; - drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - drbg->last_seed_time = 0; - drbg->reseed_threshold = DRBG_MAX_REQUESTS; memset(drbg->V, 1, DRBG_STATE_LEN); hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); @@ -673,7 +585,6 @@ static inline int __init drbg_healthcheck_sanity(void) guard(mutex_init)(&drbg->drbg_mutex); drbg->instantiated = true; - drbg->reseed_threshold = DRBG_MAX_REQUESTS; /* * if the following tests fail, it is likely that there is a buffer From 7cca456c3e6a0fefc752e9e93634aa63545d6a68 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:21 -0700 Subject: [PATCH 155/655] crypto: drbg - Clean up generation code A few miscellaneous cleanups to make the code a bit more readable: - Replace (buf, buflen) with (out, outlen) - Update (out, outlen) as we go along - Use size_t for lengths - Use min() - Adjust some comments and log messages - Rename a variable named 'len' to 'err', since it isn't a length Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 53 ++++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index bab766026177..b54c807930af 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -180,12 +180,9 @@ static void drbg_hmac_update(struct drbg_state *drbg, } /* generate function of HMAC DRBG as defined in 10.1.2.5 */ -static void drbg_hmac_generate(struct drbg_state *drbg, - unsigned char *buf, - unsigned int buflen, +static void drbg_hmac_generate(struct drbg_state *drbg, u8 *out, size_t outlen, const u8 *addtl1, size_t addtl1_len) { - int len = 0; u8 addtl2[32]; size_t addtl2_len = 0; @@ -210,17 +207,16 @@ static void drbg_hmac_generate(struct drbg_state *drbg, if (addtl1_len || addtl2_len) drbg_hmac_update(drbg, addtl1, addtl1_len, addtl2, addtl2_len); - while (len < buflen) { - unsigned int outlen = 0; + while (outlen) { + size_t n = min(DRBG_STATE_LEN, outlen); /* 10.1.2.5 step 4.1 */ hmac_sha512(&drbg->key, drbg->V, DRBG_STATE_LEN, drbg->V); - outlen = (DRBG_STATE_LEN < (buflen - len)) ? - DRBG_STATE_LEN : (buflen - len); /* 10.1.2.5 step 4.2 */ - memcpy(buf + len, drbg->V, outlen); - len += outlen; + memcpy(out, drbg->V, n); + out += n; + outlen -= n; } /* 10.1.2.5 step 6 */ @@ -331,31 +327,27 @@ out: } /* - * DRBG generate function as required by SP800-90A - this function - * generates random numbers + * Generate random bytes from an SP800-90A DRBG. * * @drbg DRBG state handle - * @buf Buffer where to store the random numbers -- the buffer must already - * be pre-allocated by caller - * @buflen Length of output buffer - this value defines the number of random - * bytes pulled from DRBG + * @out Buffer where to store the random bytes + * @outlen Number of random bytes to generate * @addtl Optional additional input that is mixed into state * @addtl_len Length of @addtl in bytes, may be 0 * * return: 0 when all bytes are generated; < 0 in case of an error */ -static int drbg_generate(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, +static int drbg_generate(struct drbg_state *drbg, u8 *out, size_t outlen, const u8 *addtl, size_t addtl_len) __must_hold(&drbg->drbg_mutex) { - int len = 0; + int err; if (!drbg->instantiated) { pr_devel("DRBG: not yet instantiated\n"); return -EINVAL; } - if (0 == buflen || !buf) { + if (out == NULL || outlen == 0) { pr_devel("DRBG: no output buffer provided\n"); return -EINVAL; } @@ -365,9 +357,8 @@ static int drbg_generate(struct drbg_state *drbg, } /* 9.3.1 step 2 */ - if (buflen > DRBG_MAX_REQUEST_BYTES) { - pr_devel("DRBG: requested random numbers too large %u\n", - buflen); + if (outlen > DRBG_MAX_REQUEST_BYTES) { + pr_devel("DRBG: request length is too long %zu\n", outlen); return -EINVAL; } @@ -393,16 +384,16 @@ static int drbg_generate(struct drbg_state *drbg, pr_devel("DRBG: reseeding before generation (prediction resistance: %s)\n", str_true_false(drbg->pr)); /* 9.3.1 steps 7.1 through 7.3 */ - len = drbg_seed(drbg, addtl, addtl_len, true); - if (len) - goto err; + err = drbg_seed(drbg, addtl, addtl_len, true); + if (err) + return err; /* 9.3.1 step 7.4 */ addtl = NULL; addtl_len = 0; } /* 9.3.1 step 8 and 10 */ - drbg_hmac_generate(drbg, buf, buflen, addtl, addtl_len); + drbg_hmac_generate(drbg, out, outlen, addtl, addtl_len); /* 10.1.2.5 step 7 */ drbg->reseed_ctr++; @@ -420,13 +411,7 @@ static int drbg_generate(struct drbg_state *drbg, * correct operation of the DRBG. */ - /* - * All operations were successful, return 0 as mandated by - * the kernel crypto API interface. - */ - len = 0; -err: - return len; + return 0; } /*************************************************************** From 58d0b2b90796d603b01afb8eeaeb14c58131ad57 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Apr 2026 23:34:22 -0700 Subject: [PATCH 156/655] crypto: drbg - Clean up loop in drbg_hmac_update() This loop is a bit hard to read, with the loop counter that's used in the HMAC being separate from the actual loop counter, which counts backwards for some reason. Just replace it with a regular loop. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index b54c807930af..ad7b9577479e 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -137,11 +137,6 @@ struct drbg_state { size_t test_entropylen; }; -enum drbg_prefixes { - DRBG_PREFIX0 = 0x00, - DRBG_PREFIX1, -}; - /****************************************************************** * HMAC DRBG functions ******************************************************************/ @@ -151,19 +146,14 @@ static void drbg_hmac_update(struct drbg_state *drbg, const u8 *data1, size_t data1_len, const u8 *data2, size_t data2_len) { - int i = 0; struct hmac_sha512_ctx hmac_ctx; u8 new_key[DRBG_STATE_LEN]; - for (i = 2; 0 < i; i--) { - /* first round uses 0x0, second 0x1 */ - unsigned char prefix = DRBG_PREFIX0; - if (1 == i) - prefix = DRBG_PREFIX1; + for (u8 i = 0; i < 2; i++) { /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ hmac_sha512_init(&hmac_ctx, &drbg->key); hmac_sha512_update(&hmac_ctx, drbg->V, DRBG_STATE_LEN); - hmac_sha512_update(&hmac_ctx, &prefix, 1); + hmac_sha512_update(&hmac_ctx, &i, 1); hmac_sha512_update(&hmac_ctx, data1, data1_len); hmac_sha512_update(&hmac_ctx, data2, data2_len); hmac_sha512_final(&hmac_ctx, new_key); From cba5aebae1094a52eb951a66e1edd0a670d6aacb Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 20 Apr 2026 11:41:20 +0200 Subject: [PATCH 157/655] crypto: crypto_null - Drop unused cipher_null crypto_alg The cipher_null crypto_alg cipher is never used in a meaningful way, given that it is always wrapped in ecb(), which has its own dedicated implementation. IOW, the cipher_null crypto_alg should never be used to implement the ecb(cipher_null) skcipher, and using it for other things is bogus. However, it is accessible from user space, and due to the nature of the AF_ALG interface, it may be wrapped in arbitrary ways, exposing issues in template code that wasn't written with block ciphers with a block size of '1' in mind. So drop this code. Signed-off-by: Ard Biesheuvel Reviewed-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/crypto_null.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index 34588f39fdfc..fea151df1648 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -50,15 +50,6 @@ static int null_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { return 0; } -static int null_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ return 0; } - -static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - memcpy(dst, src, NULL_BLOCK_SIZE); -} - static int null_skcipher_crypt(struct skcipher_request *req) { if (req->src != req->dst) @@ -97,35 +88,16 @@ static struct skcipher_alg skcipher_null = { .decrypt = null_skcipher_crypt, }; -static struct crypto_alg cipher_null = { - .cra_name = "cipher_null", - .cra_driver_name = "cipher_null-generic", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_ctxsize = 0, - .cra_module = THIS_MODULE, - .cra_u = { .cipher = { - .cia_min_keysize = NULL_KEY_SIZE, - .cia_max_keysize = NULL_KEY_SIZE, - .cia_setkey = null_setkey, - .cia_encrypt = null_crypt, - .cia_decrypt = null_crypt } } -}; - MODULE_ALIAS_CRYPTO("digest_null"); -MODULE_ALIAS_CRYPTO("cipher_null"); +MODULE_ALIAS_CRYPTO("ecb(cipher_null)"); static int __init crypto_null_mod_init(void) { int ret = 0; - ret = crypto_register_alg(&cipher_null); - if (ret < 0) - goto out; - ret = crypto_register_shash(&digest_null); if (ret < 0) - goto out_unregister_algs; + goto out; ret = crypto_register_skcipher(&skcipher_null); if (ret < 0) @@ -135,15 +107,12 @@ static int __init crypto_null_mod_init(void) out_unregister_shash: crypto_unregister_shash(&digest_null); -out_unregister_algs: - crypto_unregister_alg(&cipher_null); out: return ret; } static void __exit crypto_null_mod_fini(void) { - crypto_unregister_alg(&cipher_null); crypto_unregister_shash(&digest_null); crypto_unregister_skcipher(&skcipher_null); } From 7e04a638dee0313db8b8ecd38be5d36ead22cbf5 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 20 Apr 2026 17:34:45 +0100 Subject: [PATCH 158/655] dt-bindings: rng: mtk-rng: fix style problems in example Use 4 spaces for each level indentation, remove unused label, and add missing empty line between header include and body. Signed-off-by: Daniel Golle Acked-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/rng/mtk-rng.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/rng/mtk-rng.yaml b/Documentation/devicetree/bindings/rng/mtk-rng.yaml index 7e8dc62e5d3a..8f2f4c32a0cf 100644 --- a/Documentation/devicetree/bindings/rng/mtk-rng.yaml +++ b/Documentation/devicetree/bindings/rng/mtk-rng.yaml @@ -47,9 +47,10 @@ additionalProperties: false examples: - | #include - rng: rng@1020f000 { - compatible = "mediatek,mt7623-rng"; - reg = <0x1020f000 0x1000>; - clocks = <&infracfg CLK_INFRA_TRNG>; - clock-names = "rng"; + + rng@1020f000 { + compatible = "mediatek,mt7623-rng"; + reg = <0x1020f000 0x1000>; + clocks = <&infracfg CLK_INFRA_TRNG>; + clock-names = "rng"; }; From 20f43e30b3f56cc757b2576364d07a4ddb324ab4 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 20 Apr 2026 17:35:09 +0100 Subject: [PATCH 159/655] dt-bindings: rng: mtk-rng: add SMC-based TRNG variants Add compatible strings for MediaTek SoCs where the hardware random number generator is accessed via a vendor-defined Secure Monitor Call (SMC) rather than direct MMIO register access: - mediatek,mt7981-rng - mediatek,mt7987-rng - mediatek,mt7988-rng These variants require no reg, clocks, or clock-names properties since the RNG hardware is managed by ARM Trusted Firmware-A. Relax the $nodename pattern to also allow 'rng' in addition to the existing 'rng@...' pattern. Add a second example showing the minimal SMC variant binding. Signed-off-by: Daniel Golle Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- .../devicetree/bindings/rng/mtk-rng.yaml | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/rng/mtk-rng.yaml b/Documentation/devicetree/bindings/rng/mtk-rng.yaml index 8f2f4c32a0cf..38e67861b88f 100644 --- a/Documentation/devicetree/bindings/rng/mtk-rng.yaml +++ b/Documentation/devicetree/bindings/rng/mtk-rng.yaml @@ -11,12 +11,13 @@ maintainers: properties: $nodename: - pattern: "^rng@[0-9a-f]+$" + pattern: "^rng(@[0-9a-f]+)?$" compatible: oneOf: - enum: - mediatek,mt7623-rng + - mediatek,mt7981-rng - items: - enum: - mediatek,mt7622-rng @@ -25,6 +26,11 @@ properties: - mediatek,mt8365-rng - mediatek,mt8516-rng - const: mediatek,mt7623-rng + - items: + - enum: + - mediatek,mt7987-rng + - mediatek,mt7988-rng + - const: mediatek,mt7981-rng reg: maxItems: 1 @@ -38,9 +44,23 @@ properties: required: - compatible - - reg - - clocks - - clock-names + +allOf: + - if: + properties: + compatible: + contains: + const: mediatek,mt7981-rng + then: + properties: + reg: false + clocks: false + clock-names: false + else: + required: + - reg + - clocks + - clock-names additionalProperties: false @@ -54,3 +74,7 @@ examples: clocks = <&infracfg CLK_INFRA_TRNG>; clock-names = "rng"; }; + - | + rng { + compatible = "mediatek,mt7981-rng"; + }; From 066d65adf83db97361fe73745715336c503d1aa9 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 20 Apr 2026 17:35:24 +0100 Subject: [PATCH 160/655] hwrng: mtk - add support for hw access via SMCC Newer versions of ARM TrustedFirmware-A on MediaTek's ARMv8 SoCs no longer allow accessing the TRNG from outside of the trusted firmware. Instead, a vendor-defined custom Secure Monitor Call can be used to acquire random bytes. Add support for newer SoCs (MT7981, MT7987, MT7988). As TF-A for the MT7986 may either follow the old or the new convention, the best bet is to test if firmware blocks direct access to the hwrng and if so, expect the SMCC interface to be usable. Signed-off-by: Daniel Golle Signed-off-by: Herbert Xu --- drivers/char/hw_random/mtk-rng.c | 125 ++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 20 deletions(-) diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c index 5808d09d12c4..1f9793010e6c 100644 --- a/drivers/char/hw_random/mtk-rng.c +++ b/drivers/char/hw_random/mtk-rng.c @@ -3,9 +3,11 @@ * Driver for Mediatek Hardware Random Number Generator * * Copyright (C) 2017 Sean Wang + * Copyright (C) 2026 Daniel Golle */ #define MTK_RNG_DEV KBUILD_MODNAME +#include #include #include #include @@ -17,6 +19,7 @@ #include #include #include +#include /* Runtime PM autosuspend timeout: */ #define RNG_AUTOSUSPEND_TIMEOUT 100 @@ -30,6 +33,11 @@ #define RNG_DATA 0x08 +/* Driver feature flags */ +#define MTK_RNG_SMC BIT(0) + +#define MTK_SIP_KERNEL_GET_RND MTK_SIP_SMC_CMD(0x550) + #define to_mtk_rng(p) container_of(p, struct mtk_rng, rng) struct mtk_rng { @@ -37,6 +45,7 @@ struct mtk_rng { struct clk *clk; struct hwrng rng; struct device *dev; + unsigned long flags; }; static int mtk_rng_init(struct hwrng *rng) @@ -103,6 +112,56 @@ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) return retval || !wait ? retval : -EIO; } +static int mtk_rng_read_smc(struct hwrng *rng, void *buf, size_t max, + bool wait) +{ + struct arm_smccc_res res; + int retval = 0; + + while (max >= sizeof(u32)) { + arm_smccc_smc(MTK_SIP_KERNEL_GET_RND, 0, 0, 0, 0, 0, 0, 0, + &res); + if (res.a0) + break; + + *(u32 *)buf = res.a1; + retval += sizeof(u32); + buf += sizeof(u32); + max -= sizeof(u32); + } + + return retval || !wait ? retval : -EIO; +} + +static bool mtk_rng_hw_accessible(struct mtk_rng *priv) +{ + u32 val; + int err; + + err = clk_prepare_enable(priv->clk); + if (err) + return false; + + val = readl(priv->base + RNG_CTRL); + val |= RNG_EN; + writel(val, priv->base + RNG_CTRL); + + val = readl(priv->base + RNG_CTRL); + + if (val & RNG_EN) { + /* HW is accessible, clean up: disable RNG and clock */ + writel(val & ~RNG_EN, priv->base + RNG_CTRL); + clk_disable_unprepare(priv->clk); + return true; + } + + /* + * If TF-A blocks direct access, the register reads back as 0. + * Leave the clock enabled as TF-A needs it. + */ + return false; +} + static int mtk_rng_probe(struct platform_device *pdev) { int ret; @@ -114,23 +173,42 @@ static int mtk_rng_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->rng.name = pdev->name; -#ifndef CONFIG_PM - priv->rng.init = mtk_rng_init; - priv->rng.cleanup = mtk_rng_cleanup; -#endif - priv->rng.read = mtk_rng_read; priv->rng.quality = 900; + priv->flags = (unsigned long)device_get_match_data(&pdev->dev); - priv->clk = devm_clk_get(&pdev->dev, "rng"); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "no clock for device: %d\n", ret); - return ret; + if (!(priv->flags & MTK_RNG_SMC)) { + priv->clk = devm_clk_get(&pdev->dev, "rng"); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + dev_err(&pdev->dev, "no clock for device: %d\n", ret); + return ret; + } + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) && + of_device_is_compatible(pdev->dev.of_node, + "mediatek,mt7986-rng") && + !mtk_rng_hw_accessible(priv)) { + priv->flags |= MTK_RNG_SMC; + dev_info(&pdev->dev, + "HW RNG not MMIO accessible, using SMC\n"); + } } - priv->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); + if (priv->flags & MTK_RNG_SMC) { + if (!IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) + return -ENODEV; + priv->rng.read = mtk_rng_read_smc; + } else { +#ifndef CONFIG_PM + priv->rng.init = mtk_rng_init; + priv->rng.cleanup = mtk_rng_cleanup; +#endif + priv->rng.read = mtk_rng_read; + } ret = devm_hwrng_register(&pdev->dev, &priv->rng); if (ret) { @@ -139,12 +217,15 @@ static int mtk_rng_probe(struct platform_device *pdev) return ret; } - dev_set_drvdata(&pdev->dev, priv); - pm_runtime_set_autosuspend_delay(&pdev->dev, RNG_AUTOSUSPEND_TIMEOUT); - pm_runtime_use_autosuspend(&pdev->dev); - ret = devm_pm_runtime_enable(&pdev->dev); - if (ret) - return ret; + if (!(priv->flags & MTK_RNG_SMC)) { + dev_set_drvdata(&pdev->dev, priv); + pm_runtime_set_autosuspend_delay(&pdev->dev, + RNG_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + } dev_info(&pdev->dev, "registered RNG driver\n"); @@ -181,8 +262,11 @@ static const struct dev_pm_ops mtk_rng_pm_ops = { #endif /* CONFIG_PM */ static const struct of_device_id mtk_rng_match[] = { - { .compatible = "mediatek,mt7986-rng" }, { .compatible = "mediatek,mt7623-rng" }, + { .compatible = "mediatek,mt7981-rng", .data = (void *)MTK_RNG_SMC }, + { .compatible = "mediatek,mt7986-rng" }, + { .compatible = "mediatek,mt7987-rng", .data = (void *)MTK_RNG_SMC }, + { .compatible = "mediatek,mt7988-rng", .data = (void *)MTK_RNG_SMC }, {}, }; MODULE_DEVICE_TABLE(of, mtk_rng_match); @@ -200,4 +284,5 @@ module_platform_driver(mtk_rng_driver); MODULE_DESCRIPTION("Mediatek Random Number Generator Driver"); MODULE_AUTHOR("Sean Wang "); +MODULE_AUTHOR("Daniel Golle "); MODULE_LICENSE("GPL"); From ef6127bb4f4b51ca91eab58348861c8adcd8db25 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 23 Apr 2026 08:55:42 +0200 Subject: [PATCH 161/655] crypto: sun8i-ss - avoid hash and rng references While the sun4i-ss and sun8i-ce drivers started selecting CRYPTO_RNG, the sun8i-ss variant does not, and causes a link failure: aarch64-linux-ld: drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.o: in function `sun8i_ss_unregister_algs': sun8i-ss-core.c:(.text.sun8i_ss_unregister_algs+0x94): undefined reference to `crypto_unregister_rng' aarch64-linux-ld: drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.o: in function `sun8i_ss_probe': sun8i-ss-core.c:(.text.sun8i_ss_probe+0x40c): undefined reference to `crypto_register_rng' Looking more closely, I see that all of the allwinner crypto drivers have the same logic where the rng and hash parts of the driver are optional, but then the generic code is still selected, which is a bit inconsistent, aside from the missing CRYPTO_RNG select on sun8i-ss. Change the approach so only the bits that are actually used are built, using ifdef checks around the optional portions that match the optional references to the sub-drivers. Ideally the drivers would get reworked in a way that keeps all the bits related to the skcipher/ahash/rng codecs in the respective sub-drivers, rather than having a common driver that knows about all of these. Fixes: cdadc1435937 ("crypto: cryptomgr - Select algorithm types only when CRYPTO_SELFTESTS") Signed-off-by: Arnd Bergmann Signed-off-by: Herbert Xu --- drivers/crypto/allwinner/Kconfig | 2 -- drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 8 ++++++++ drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 12 ++++++++++++ drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c | 12 ++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig index 7270e5fbc573..b8e75210a0e3 100644 --- a/drivers/crypto/allwinner/Kconfig +++ b/drivers/crypto/allwinner/Kconfig @@ -14,7 +14,6 @@ config CRYPTO_DEV_SUN4I_SS select CRYPTO_SHA1 select CRYPTO_AES select CRYPTO_LIB_DES - select CRYPTO_RNG select CRYPTO_SKCIPHER help Some Allwinner SoC have a crypto accelerator named @@ -50,7 +49,6 @@ config CRYPTO_DEV_SUN8I_CE select CRYPTO_CBC select CRYPTO_AES select CRYPTO_DES - select CRYPTO_RNG depends on CRYPTO_DEV_ALLWINNER depends on PM help diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c index 58a76e2ba64e..813c4bc6312a 100644 --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c @@ -247,12 +247,14 @@ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v) ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb, ss_algs[i].stat_bytes); break; +#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG case CRYPTO_ALG_TYPE_RNG: seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n", ss_algs[i].alg.rng.base.cra_driver_name, ss_algs[i].alg.rng.base.cra_name, ss_algs[i].stat_req, ss_algs[i].stat_bytes); break; +#endif case CRYPTO_ALG_TYPE_AHASH: seq_printf(seq, "%s %s reqs=%lu\n", ss_algs[i].alg.hash.halg.base.cra_driver_name, @@ -471,6 +473,7 @@ static int sun4i_ss_probe(struct platform_device *pdev) goto error_alg; } break; +#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG case CRYPTO_ALG_TYPE_RNG: err = crypto_register_rng(&ss_algs[i].alg.rng); if (err) { @@ -478,6 +481,7 @@ static int sun4i_ss_probe(struct platform_device *pdev) ss_algs[i].alg.rng.base.cra_name); } break; +#endif } } @@ -497,9 +501,11 @@ error_alg: case CRYPTO_ALG_TYPE_AHASH: crypto_unregister_ahash(&ss_algs[i].alg.hash); break; +#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG case CRYPTO_ALG_TYPE_RNG: crypto_unregister_rng(&ss_algs[i].alg.rng); break; +#endif } } error_pm: @@ -520,9 +526,11 @@ static void sun4i_ss_remove(struct platform_device *pdev) case CRYPTO_ALG_TYPE_AHASH: crypto_unregister_ahash(&ss_algs[i].alg.hash); break; +#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG case CRYPTO_ALG_TYPE_RNG: crypto_unregister_rng(&ss_algs[i].alg.rng); break; +#endif } } diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index c16bb6ce6ee3..f3b58ed6aed0 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -676,6 +676,7 @@ static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v) seq_printf(seq, "\tFallback due to SG numbers: %lu\n", ce_algs[i].stat_fb_maxsg); break; +#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_HASH case CRYPTO_ALG_TYPE_AHASH: seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", ce_algs[i].alg.hash.base.halg.base.cra_driver_name, @@ -692,12 +693,15 @@ static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v) seq_printf(seq, "\tFallback due to SG numbers: %lu\n", ce_algs[i].stat_fb_maxsg); break; +#endif +#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG case CRYPTO_ALG_TYPE_RNG: seq_printf(seq, "%s %s reqs=%lu bytes=%lu\n", ce_algs[i].alg.rng.base.cra_driver_name, ce_algs[i].alg.rng.base.cra_name, ce_algs[i].stat_req, ce_algs[i].stat_bytes); break; +#endif } } #if defined(CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG) && \ @@ -905,6 +909,7 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce) return err; } break; +#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_HASH case CRYPTO_ALG_TYPE_AHASH: id = ce_algs[i].ce_algo_id; ce_method = ce->variant->alg_hash[id]; @@ -925,6 +930,8 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce) return err; } break; +#endif +#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG case CRYPTO_ALG_TYPE_RNG: if (ce->variant->prng == CE_ID_NOTSUPP) { dev_info(ce->dev, @@ -942,6 +949,7 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce) ce_algs[i].ce = NULL; } break; +#endif default: ce_algs[i].ce = NULL; dev_err(ce->dev, "ERROR: tried to register an unknown algo\n"); @@ -963,16 +971,20 @@ static void sun8i_ce_unregister_algs(struct sun8i_ce_dev *ce) ce_algs[i].alg.skcipher.base.base.cra_name); crypto_engine_unregister_skcipher(&ce_algs[i].alg.skcipher); break; +#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_HASH case CRYPTO_ALG_TYPE_AHASH: dev_info(ce->dev, "Unregister %d %s\n", i, ce_algs[i].alg.hash.base.halg.base.cra_name); crypto_engine_unregister_ahash(&ce_algs[i].alg.hash); break; +#endif +#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG case CRYPTO_ALG_TYPE_RNG: dev_info(ce->dev, "Unregister %d %s\n", i, ce_algs[i].alg.rng.base.cra_name); crypto_unregister_rng(&ce_algs[i].alg.rng); break; +#endif } } } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c index f45685707e0d..59c9bc45ec0f 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c @@ -501,12 +501,15 @@ static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v) seq_printf(seq, "\tFallback due to SG numbers: %lu\n", ss_algs[i].stat_fb_sgnum); break; +#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG case CRYPTO_ALG_TYPE_RNG: seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n", ss_algs[i].alg.rng.base.cra_driver_name, ss_algs[i].alg.rng.base.cra_name, ss_algs[i].stat_req, ss_algs[i].stat_bytes); break; +#endif +#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_HASH case CRYPTO_ALG_TYPE_AHASH: seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", ss_algs[i].alg.hash.base.halg.base.cra_driver_name, @@ -523,6 +526,7 @@ static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v) seq_printf(seq, "\tFallback due to SG numbers: %lu\n", ss_algs[i].stat_fb_sgnum); break; +#endif } } return 0; @@ -707,6 +711,7 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss) return err; } break; +#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG case CRYPTO_ALG_TYPE_RNG: err = crypto_register_rng(&ss_algs[i].alg.rng); if (err) { @@ -715,6 +720,8 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss) ss_algs[i].ss = NULL; } break; +#endif +#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_HASH case CRYPTO_ALG_TYPE_AHASH: id = ss_algs[i].ss_algo_id; ss_method = ss->variant->alg_hash[id]; @@ -735,6 +742,7 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss) return err; } break; +#endif default: ss_algs[i].ss = NULL; dev_err(ss->dev, "ERROR: tried to register an unknown algo\n"); @@ -756,16 +764,20 @@ static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss) ss_algs[i].alg.skcipher.base.base.cra_name); crypto_engine_unregister_skcipher(&ss_algs[i].alg.skcipher); break; +#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG case CRYPTO_ALG_TYPE_RNG: dev_info(ss->dev, "Unregister %d %s\n", i, ss_algs[i].alg.rng.base.cra_name); crypto_unregister_rng(&ss_algs[i].alg.rng); break; +#endif +#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_HASH case CRYPTO_ALG_TYPE_AHASH: dev_info(ss->dev, "Unregister %d %s\n", i, ss_algs[i].alg.hash.base.halg.base.cra_name); crypto_engine_unregister_ahash(&ss_algs[i].alg.hash); break; +#endif } } } From 25056329384010a8672552b134f609601dc4f80e Mon Sep 17 00:00:00 2001 From: Ruoyu Wang Date: Thu, 23 Apr 2026 19:19:56 +0800 Subject: [PATCH 162/655] crypto: ixp4xx - fix buffer chain unwind on allocation failure chainup_buffers() builds a linked list of buffer descriptors for a scatterlist. If dma_pool_alloc() fails while constructing the list, the current code sets buf to NULL and later dereferences it unconditionally at the end of the function: buf->next = NULL; buf->phys_next = 0; This can lead to a null-pointer dereference on allocation failure. If the failure happens after part of the descriptor chain has already been allocated and DMA-mapped, the partially constructed chain also needs to be released. Fix this by terminating the partially constructed chain on allocation failure and letting the callers unwind it via their existing cleanup paths. Also fix ablk_perform() to preserve the hook pointers before checking for failure, so partially built chains can be freed correctly. Signed-off-by: Ruoyu Wang Acked-by: Linus Walleij Signed-off-by: Herbert Xu --- drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c b/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c index fcc0cf4df637..5b90cf0fb0e4 100644 --- a/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c +++ b/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c @@ -884,8 +884,9 @@ static struct buffer_desc *chainup_buffers(struct device *dev, ptr = sg_virt(sg); next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys); if (!next_buf) { - buf = NULL; - break; + buf->next = NULL; + buf->phys_next = 0; + return NULL; } sg_dma_address(sg) = dma_map_single(dev, ptr, len, dir); buf->next = next_buf; @@ -983,7 +984,7 @@ static int ablk_perform(struct skcipher_request *req, int encrypt) unsigned int nbytes = req->cryptlen; enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; struct ablk_ctx *req_ctx = skcipher_request_ctx(req); - struct buffer_desc src_hook; + struct buffer_desc *buf, src_hook; struct device *dev = &pdev->dev; unsigned int offset; gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? @@ -1025,22 +1026,24 @@ static int ablk_perform(struct skcipher_request *req, int encrypt) /* This was never tested by Intel * for more than one dst buffer, I think. */ req_ctx->dst = NULL; - if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook, - flags, DMA_FROM_DEVICE)) - goto free_buf_dest; - src_direction = DMA_TO_DEVICE; + buf = chainup_buffers(dev, req->dst, nbytes, &dst_hook, + flags, DMA_FROM_DEVICE); req_ctx->dst = dst_hook.next; crypt->dst_buf = dst_hook.phys_next; + if (!buf) + goto free_buf_dest; + src_direction = DMA_TO_DEVICE; } else { req_ctx->dst = NULL; } req_ctx->src = NULL; - if (!chainup_buffers(dev, req->src, nbytes, &src_hook, flags, - src_direction)) - goto free_buf_src; - + buf = chainup_buffers(dev, req->src, nbytes, &src_hook, flags, + src_direction); req_ctx->src = src_hook.next; crypt->src_buf = src_hook.phys_next; + if (!buf) + goto free_buf_src; + crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK; qmgr_put_entry(send_qid, crypt_virt2phys(crypt)); BUG_ON(qmgr_stat_overflow(send_qid)); From 76d2e560c76dabbf9f31f4311069e68610d1ac18 Mon Sep 17 00:00:00 2001 From: Jeff Barnes Date: Thu, 23 Apr 2026 11:21:41 -0400 Subject: [PATCH 163/655] crypto: testmgr - disallow RSA PKCS#1 SHA-1 sig algs in FIPS mode When booted with fips=1, RSA signature generation using SHA-1 must not be available. However, pkcs1pad(rsa,sha1) can currently be instantiated because it is not present in alg_test_descs; alg_test() falls through the no_test path and succeeds, after which the algorithm appears in /proc/crypto as fips-capable. Add explicit alg_test_descs entries for pkcs1pad(rsa,sha1) and pkcs1(rsa,sha1) without marking them fips_allowed, so they are treated as not FIPS-allowed when fips=1 is enabled. Include both names to cover kernels where RSA sign/verify is provided via the pkcs1(...) signature template, while pkcs1pad(...) remains for the traditional wrapper naming and/or RSAES operations. Signed-off-by: Jeff Barnes Signed-off-by: Herbert Xu --- crypto/testmgr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 4199b7d3e9fb..9059bea7a5b0 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -5198,6 +5198,9 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .sig = __VECS(pkcs1_rsa_none_tv_template) } + }, { + .alg = "pkcs1(rsa,sha1)", + .test = alg_test_null, }, { .alg = "pkcs1(rsa,sha224)", .test = alg_test_null, @@ -5233,6 +5236,9 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "pkcs1pad(rsa)", .test = alg_test_null, .fips_allowed = 1, + }, { + .alg = "pkcs1pad(rsa,sha1)", + .test = alg_test_null, }, { .alg = "rfc3686(ctr(aes))", .generic_driver = "rfc3686(ctr(aes-lib))", From bd11fb14dee63ec5662ec70ec48eb86304d17c4d Mon Sep 17 00:00:00 2001 From: Harshal Dev Date: Fri, 24 Apr 2026 14:05:07 +0530 Subject: [PATCH 164/655] dt-bindings: crypto: qcom,prng: Document Glymur TRNG Document glymur compatible for the True Random Number Generator. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Harshal Dev Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom,prng.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml index 41402599e9ab..498d6914135e 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml @@ -17,6 +17,7 @@ properties: - qcom,prng-ee # 8996 and later using EE - items: - enum: + - qcom,glymur-trng - qcom,ipq5332-trng - qcom,ipq5424-trng - qcom,ipq9574-trng From 6ef4cd5b0c2b13bbf8689d50abbe51c052f31a03 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Fri, 24 Apr 2026 19:32:47 -0700 Subject: [PATCH 165/655] crypto: cesa - allocate engines with main struct Use a flexible array member to combine and simplify allocation. Move struct mv_cesa_dev down as flexible array members require full definitions. Signed-off-by: Rosen Penev Signed-off-by: Herbert Xu --- drivers/crypto/marvell/cesa/cesa.c | 11 +++----- drivers/crypto/marvell/cesa/cesa.h | 42 +++++++++++++++--------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c index 8afa3a87e38d..687ed730174d 100644 --- a/drivers/crypto/marvell/cesa/cesa.c +++ b/drivers/crypto/marvell/cesa/cesa.c @@ -416,7 +416,7 @@ static int mv_cesa_probe(struct platform_device *pdev) const struct mbus_dram_target_info *dram; struct device *dev = &pdev->dev; struct mv_cesa_dev *cesa; - struct mv_cesa_engine *engines; + struct mv_cesa_engine *engine; int irq, ret, i, cpu; u32 sram_size; @@ -431,7 +431,8 @@ static int mv_cesa_probe(struct platform_device *pdev) return -ENOTSUPP; } - cesa = devm_kzalloc(dev, sizeof(*cesa), GFP_KERNEL); + cesa = devm_kzalloc(dev, struct_size(cesa, engines, caps->nengines), + GFP_KERNEL); if (!cesa) return -ENOMEM; @@ -445,10 +446,6 @@ static int mv_cesa_probe(struct platform_device *pdev) sram_size = CESA_SA_MIN_SRAM_SIZE; cesa->sram_size = sram_size; - cesa->engines = devm_kcalloc(dev, caps->nengines, sizeof(*engines), - GFP_KERNEL); - if (!cesa->engines) - return -ENOMEM; spin_lock_init(&cesa->lock); @@ -465,7 +462,7 @@ static int mv_cesa_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cesa); for (i = 0; i < caps->nengines; i++) { - struct mv_cesa_engine *engine = &cesa->engines[i]; + engine = &cesa->engines[i]; char res_name[16]; engine->id = i; diff --git a/drivers/crypto/marvell/cesa/cesa.h b/drivers/crypto/marvell/cesa/cesa.h index 50ca1039fdaa..18f9f28040a6 100644 --- a/drivers/crypto/marvell/cesa/cesa.h +++ b/drivers/crypto/marvell/cesa/cesa.h @@ -402,27 +402,6 @@ struct mv_cesa_dev_dma { struct dma_pool *padding_pool; }; -/** - * struct mv_cesa_dev - CESA device - * @caps: device capabilities - * @regs: device registers - * @sram_size: usable SRAM size - * @lock: device lock - * @engines: array of engines - * @dma: dma pools - * - * Structure storing CESA device information. - */ -struct mv_cesa_dev { - const struct mv_cesa_caps *caps; - void __iomem *regs; - struct device *dev; - unsigned int sram_size; - spinlock_t lock; - struct mv_cesa_engine *engines; - struct mv_cesa_dev_dma *dma; -}; - /** * struct mv_cesa_engine - CESA engine * @id: engine id @@ -471,6 +450,27 @@ struct mv_cesa_engine { int irq; }; +/** + * struct mv_cesa_dev - CESA device + * @caps: device capabilities + * @regs: device registers + * @sram_size: usable SRAM size + * @lock: device lock + * @dma: dma pools + * @engines: array of engines + * + * Structure storing CESA device information. + */ +struct mv_cesa_dev { + const struct mv_cesa_caps *caps; + void __iomem *regs; + struct device *dev; + unsigned int sram_size; + spinlock_t lock; + struct mv_cesa_dev_dma *dma; + struct mv_cesa_engine engines[]; +}; + /** * struct mv_cesa_req_ops - CESA request operations * @process: process a request chunk result (should return 0 if the From 319400fc5ee15db5793aa45f854968141326effc Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 26 Apr 2026 21:29:47 +0000 Subject: [PATCH 166/655] crypto: atmel-sha204a - fix blocking and non-blocking rng logic The blocking and non-blocking paths were failing to provide valid entropy due to improper buffer management. Reading the buffer starting from byte 1, only fetch the 32 bytes of random data from the return message. Tested on an Atmel SHA204A device. Before (here for blocking), tests showed repeatedly reading reduced bytes. $ head -c 32 /dev/hwrng | hexdump -C 00000000 02 28 85 b3 47 40 f2 ee 00 00 00 00 00 00 00 00 |.(..G@..........| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 After, the result will be similar to the following: $ head -c 32 /dev/hwrng | hexdump -C 00000000 5a fc 3f 13 14 68 fe 06 68 0a bd 04 83 6e 09 69 |Z.?..h..h....n.i| 00000010 75 ff cf 87 10 84 3b c9 c1 df ae eb 45 53 4c c3 |u.....;.....ESL.| 00000020 Fixes: da001fb651b0 ("crypto: atmel-i2c - add support for SHA204A random number generator") Suggested-by: Ard Biesheuvel Signed-off-by: Lothar Rubusch Tested-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha204a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index dbb39ed0cea1..5699bb532325 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -48,8 +48,8 @@ static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data, if (rng->priv) { work_data = (struct atmel_i2c_work_data *)rng->priv; - max = min(sizeof(work_data->cmd.data), max); - memcpy(data, &work_data->cmd.data, max); + max = min(RANDOM_RSP_SIZE - CMD_OVERHEAD_SIZE, max); + memcpy(data, &work_data->cmd.data[RSP_DATA_IDX], max); rng->priv = 0; } else { work_data = kmalloc_obj(*work_data, GFP_ATOMIC); @@ -87,8 +87,8 @@ static int atmel_sha204a_rng_read(struct hwrng *rng, void *data, size_t max, if (ret) return ret; - max = min(sizeof(cmd.data), max); - memcpy(data, cmd.data, max); + max = min(RANDOM_RSP_SIZE - CMD_OVERHEAD_SIZE, max); + memcpy(data, &cmd.data[RSP_DATA_IDX], max); return max; } From 3f57657b6ea23f933371f2c2846322f441773cee Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 Apr 2026 18:39:37 +0200 Subject: [PATCH 167/655] crypto: caam - use print_hex_dump_devel to guard key hex dumps Use print_hex_dump_devel() for dumping sensitive key material in *_setkey() and gen_split_key() to avoid leaking secrets at runtime when CONFIG_DYNAMIC_DEBUG is enabled. Fixes: 6e005503199b ("crypto: caam - print debug messages at debug level") Cc: stable@vger.kernel.org Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 12 ++++++------ drivers/crypto/caam/caamalg_qi.c | 12 ++++++------ drivers/crypto/caam/caamhash.c | 4 ++-- drivers/crypto/caam/key_gen.c | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 32a6e6e15ee2..ddbd60cf3b3c 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -603,7 +603,7 @@ static int aead_setkey(struct crypto_aead *aead, dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n", keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); /* @@ -639,7 +639,7 @@ static int aead_setkey(struct crypto_aead *aead, dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); - print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ctx->adata.keylen_pad + keys.enckeylen, 1); @@ -680,7 +680,7 @@ static int gcm_setkey(struct crypto_aead *aead, if (err) return err; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -701,7 +701,7 @@ static int rfc4106_setkey(struct crypto_aead *aead, if (err) return err; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -727,7 +727,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, if (err) return err; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -754,7 +754,7 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, u32 *desc; const bool is_rfc3686 = alg->caam.rfc3686; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); /* Here keylen is actual key length */ diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index 65f6adb6c673..aa779caacfe5 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -212,7 +212,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n", keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); /* @@ -248,7 +248,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); - print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ctx->adata.keylen_pad + keys.enckeylen, 1); @@ -371,7 +371,7 @@ static int gcm_setkey(struct crypto_aead *aead, if (ret) return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -475,7 +475,7 @@ static int rfc4106_setkey(struct crypto_aead *aead, if (ret) return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -581,7 +581,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, if (ret) return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -631,7 +631,7 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, const bool is_rfc3686 = alg->caam.rfc3686; int ret = 0; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ctx->cdata.keylen = keylen; diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index ddb2a35aec2d..3cd71810380f 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -505,7 +505,7 @@ static int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key, DMA_TO_DEVICE); ctx->adata.keylen = keylen; - print_hex_dump_debug("axcbc ctx.key@" __stringify(__LINE__)" : ", + print_hex_dump_devel("axcbc ctx.key@" __stringify(__LINE__)" : ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, keylen, 1); return axcbc_set_sh_desc(ahash); @@ -525,7 +525,7 @@ static int acmac_setkey(struct crypto_ahash *ahash, const u8 *key, ctx->adata.key_virt = key; ctx->adata.keylen = keylen; - print_hex_dump_debug("acmac ctx.key@" __stringify(__LINE__)" : ", + print_hex_dump_devel("acmac ctx.key@" __stringify(__LINE__)" : ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); return acmac_set_sh_desc(ahash); diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index 88cc4fe2a585..de2fcc387477 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -58,7 +58,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, dev_dbg(jrdev, "split keylen %d split keylen padded %d\n", adata->keylen, adata->keylen_pad); - print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); if (local_max > max_keylen) @@ -113,7 +113,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, wait_for_completion(&result.completion); ret = result.err; - print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_out, adata->keylen_pad, 1); } From 8005dc808bcce7d6cc2ae015a3cde1683bee602d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 Apr 2026 18:39:39 +0200 Subject: [PATCH 168/655] crypto: caam - use print_hex_dump_devel to guard key hex dumps Use print_hex_dump_devel() for dumping sensitive key material in *_setkey() to avoid leaking secrets at runtime when CONFIG_DYNAMIC_DEBUG is enabled. Fixes: 8d818c105501 ("crypto: caam/qi2 - add DPAA2-CAAM driver") Fixes: 226853ac3ebe ("crypto: caam/qi2 - add skcipher algorithms") Cc: stable@vger.kernel.org Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg_qi2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index bf10c3dda745..6b47bcc16a50 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -301,7 +301,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, dev_dbg(dev, "keylen %d enckeylen %d authkeylen %d\n", keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ctx->adata.keylen = keys.authkeylen; @@ -315,7 +315,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); - print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ctx->adata.keylen_pad + keys.enckeylen, 1); @@ -732,7 +732,7 @@ static int gcm_setkey(struct crypto_aead *aead, ret = aes_check_keylen(keylen); if (ret) return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -828,7 +828,7 @@ static int rfc4106_setkey(struct crypto_aead *aead, if (ret) return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -927,7 +927,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, if (ret) return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -955,7 +955,7 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, u32 *desc; const bool is_rfc3686 = alg->caam.rfc3686; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ctx->cdata.keylen = keylen; From c207524b73f890d20da26fda0458fcfd73ccfdc2 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 Apr 2026 19:20:18 +0200 Subject: [PATCH 169/655] crypto: omap - add omap_aes_unregister_algs helper Add a new helper omap_aes_unregister_algs() and replace two for loops in omap_aes_probe() and omap_aes_remove(), which also ensure ->registered is reset to 0. Replace two additional for loops with crypto_engine_unregister_aeads() while at it and reset ->registered to 0 explicitly. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 43 ++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 3eadaf7a64fa..f31555c0d715 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -1089,6 +1089,20 @@ static struct attribute *omap_aes_attrs[] = { }; ATTRIBUTE_GROUPS(omap_aes); +static void omap_aes_unregister_algs(const struct omap_aes_pdata *pdata) +{ + struct omap_aes_algs_info *alg_info; + int i; + + for (i = pdata->algs_info_size - 1; i >= 0; i--) { + alg_info = &pdata->algs_info[i]; + + crypto_engine_unregister_skciphers(alg_info->algs_list, + alg_info->registered); + alg_info->registered = 0; + } +} + static int omap_aes_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1215,15 +1229,11 @@ static int omap_aes_probe(struct platform_device *pdev) return 0; err_aead_algs: - for (i = dd->pdata->aead_algs_info->registered - 1; i >= 0; i--) { - aalg = &dd->pdata->aead_algs_info->algs_list[i]; - crypto_engine_unregister_aead(aalg); - } + crypto_engine_unregister_aeads(dd->pdata->aead_algs_info->algs_list, + dd->pdata->aead_algs_info->registered); + dd->pdata->aead_algs_info->registered = 0; err_algs: - for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) - for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) - crypto_engine_unregister_skcipher( - &dd->pdata->algs_info[i].algs_list[j]); + omap_aes_unregister_algs(dd->pdata); err_engine: if (dd->engine) @@ -1244,25 +1254,16 @@ err_data: static void omap_aes_remove(struct platform_device *pdev) { struct omap_aes_dev *dd = platform_get_drvdata(pdev); - struct aead_engine_alg *aalg; - int i, j; spin_lock_bh(&list_lock); list_del(&dd->list); spin_unlock_bh(&list_lock); - for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) - for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) { - crypto_engine_unregister_skcipher( - &dd->pdata->algs_info[i].algs_list[j]); - dd->pdata->algs_info[i].registered--; - } + omap_aes_unregister_algs(dd->pdata); - for (i = dd->pdata->aead_algs_info->registered - 1; i >= 0; i--) { - aalg = &dd->pdata->aead_algs_info->algs_list[i]; - crypto_engine_unregister_aead(aalg); - dd->pdata->aead_algs_info->registered--; - } + crypto_engine_unregister_aeads(dd->pdata->aead_algs_info->algs_list, + dd->pdata->aead_algs_info->registered); + dd->pdata->aead_algs_info->registered = 0; crypto_engine_exit(dd->engine); From 9ab1392b1163daab674484d6ddacf16f0ad4c040 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 Apr 2026 19:20:19 +0200 Subject: [PATCH 170/655] crypto: omap - add omap_des_unregister_algs helper Add a new helper omap_des_unregister_algs() and replace two for loops in omap_des_probe() and omap_des_remove(), which also ensure ->registered is reset to 0. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/omap-des.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 149ebd77710b..16d5c617d5ee 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -938,6 +938,20 @@ static int omap_des_get_pdev(struct omap_des_dev *dd, return 0; } +static void omap_des_unregister_algs(const struct omap_des_pdata *pdata) +{ + struct omap_des_algs_info *alg_info; + int i; + + for (i = pdata->algs_info_size - 1; i >= 0; i--) { + alg_info = &pdata->algs_info[i]; + + crypto_engine_unregister_skciphers(alg_info->algs_list, + alg_info->registered); + alg_info->registered = 0; + } +} + static int omap_des_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1043,11 +1057,7 @@ static int omap_des_probe(struct platform_device *pdev) return 0; err_algs: - for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) - for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) - crypto_engine_unregister_skcipher( - &dd->pdata->algs_info[i].algs_list[j]); - + omap_des_unregister_algs(dd->pdata); err_engine: if (dd->engine) crypto_engine_exit(dd->engine); @@ -1067,16 +1077,12 @@ err_data: static void omap_des_remove(struct platform_device *pdev) { struct omap_des_dev *dd = platform_get_drvdata(pdev); - int i, j; spin_lock_bh(&list_lock); list_del(&dd->list); spin_unlock_bh(&list_lock); - for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) - for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) - crypto_engine_unregister_skcipher( - &dd->pdata->algs_info[i].algs_list[j]); + omap_des_unregister_algs(dd->pdata); cancel_work_sync(&dd->done_task); omap_des_dma_cleanup(dd); From c3494e6fbb35579a131de11369b658a59b1323e5 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 Apr 2026 19:20:20 +0200 Subject: [PATCH 171/655] crypto: omap - add omap_sham_unregister_algs helper Add a new helper omap_sham_unregister_algs() and replace two for loops in omap_sham_probe() and omap_sham_remove(), which also ensure ->registered is reset to 0. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index b8c416c5ee70..be1ac640ee59 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -2042,6 +2042,20 @@ static struct attribute *omap_sham_attrs[] = { }; ATTRIBUTE_GROUPS(omap_sham); +static void omap_sham_unregister_algs(const struct omap_sham_pdata *pdata) +{ + struct omap_sham_algs_info *alg_info; + int i; + + for (i = pdata->algs_info_size - 1; i >= 0; i--) { + alg_info = &pdata->algs_info[i]; + + crypto_engine_unregister_ahashes(alg_info->algs_list, + alg_info->registered); + alg_info->registered = 0; + } +} + static int omap_sham_probe(struct platform_device *pdev) { struct omap_sham_dev *dd; @@ -2158,10 +2172,7 @@ static int omap_sham_probe(struct platform_device *pdev) return 0; err_algs: - for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) - for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) - crypto_engine_unregister_ahash( - &dd->pdata->algs_info[i].algs_list[j]); + omap_sham_unregister_algs(dd->pdata); err_engine_start: crypto_engine_exit(dd->engine); err_engine: @@ -2182,19 +2193,13 @@ data_err: static void omap_sham_remove(struct platform_device *pdev) { struct omap_sham_dev *dd; - int i, j; dd = platform_get_drvdata(pdev); spin_lock_bh(&sham.lock); list_del(&dd->list); spin_unlock_bh(&sham.lock); - for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) - for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) { - crypto_engine_unregister_ahash( - &dd->pdata->algs_info[i].algs_list[j]); - dd->pdata->algs_info[i].registered--; - } + omap_sham_unregister_algs(dd->pdata); cancel_work_sync(&dd->done_task); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); From bee54677bc516e28ced4276792958f0f1a264871 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 27 Apr 2026 23:35:06 +0200 Subject: [PATCH 172/655] crypto: starfive - use list_first_entry_or_null to simplify cryp_find_dev Use list_first_entry_or_null() to simplify starfive_cryp_find_dev() and remove the now-unused local variable 'struct starfive_cryp_dev *tmp'. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/starfive/jh7110-cryp.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c index 42114e9364f0..e19cd7945968 100644 --- a/drivers/crypto/starfive/jh7110-cryp.c +++ b/drivers/crypto/starfive/jh7110-cryp.c @@ -36,19 +36,14 @@ static struct starfive_dev_list dev_list = { struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx) { - struct starfive_cryp_dev *cryp = NULL, *tmp; + struct starfive_cryp_dev *cryp; spin_lock_bh(&dev_list.lock); - if (!ctx->cryp) { - list_for_each_entry(tmp, &dev_list.dev_list, list) { - cryp = tmp; - break; - } - ctx->cryp = cryp; - } else { - cryp = ctx->cryp; - } - + if (!ctx->cryp) + ctx->cryp = list_first_entry_or_null(&dev_list.dev_list, + struct starfive_cryp_dev, + list); + cryp = ctx->cryp; spin_unlock_bh(&dev_list.lock); return cryp; From ea5e57cc97185329dcc5ebdcaae7e1500bf0ad0b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 28 Apr 2026 12:14:32 +0200 Subject: [PATCH 173/655] crypto: atmel-sha204a - drop hwrng quality reduction for ATSHA204A Commit 8006aff15516 ("crypto: atmel-sha204a - Set hwrng quality to lowest possible") reduced the hwrng quality to 1 based on a review by Bill Cox [1]. However, despite its title, the review only tested the ATSHA204, not the ATSHA204A. In the same thread, Atmel engineer Landon Cox wrote "this behavior has been eliminated entirely"[2] in the ATSHA204A and "this problem does not affect the ATECC108 or the ATECC108A (or the ATSHA204A)"[3]. According to the official ATSHA204A datasheet [4], the device contains a high-quality hardware RNG that combines its output with an internal seed value stored in EEPROM or SRAM to generate random numbers. The device also implements all security functions using SHA-256, and the driver uses the chip's Random command in seed-update mode. Keep 'quality = 1' for ATSHA204, but drop the explicit hwrng quality reduction for ATSHA204A and fall back to the hwrng core default. [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html [2] https://www.metzdowd.com/pipermail/cryptography/2014-December/023852.html [3] https://www.metzdowd.com/pipermail/cryptography/2014-December/023886.html [4] https://ww1.microchip.com/downloads/en/DeviceDoc/ATSHA204A-Data-Sheet-40002025A.pdf Fixes: 8006aff15516 ("crypto: atmel-sha204a - Set hwrng quality to lowest possible") Cc: stable@vger.kernel.org Signed-off-by: Thorsten Blum Reviewed-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha204a.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index 5699bb532325..ed7d69bf6890 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -19,6 +19,12 @@ #include #include "atmel-i2c.h" +/* + * According to review by Bill Cox [1], the ATSHA204 has very low entropy. + * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html + */ +static const unsigned short atsha204_quality = 1; + static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data, void *areq, int status) { @@ -158,6 +164,7 @@ static const struct attribute_group atmel_sha204a_groups = { static int atmel_sha204a_probe(struct i2c_client *client) { struct atmel_i2c_client_priv *i2c_priv; + const unsigned short *quality; int ret; ret = atmel_i2c_probe(client); @@ -171,11 +178,9 @@ static int atmel_sha204a_probe(struct i2c_client *client) i2c_priv->hwrng.name = dev_name(&client->dev); i2c_priv->hwrng.read = atmel_sha204a_rng_read; - /* - * According to review by Bill Cox [1], this HWRNG has very low entropy. - * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html - */ - i2c_priv->hwrng.quality = 1; + quality = i2c_get_match_data(client); + if (quality) + i2c_priv->hwrng.quality = *quality; ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng); if (ret) @@ -203,14 +208,14 @@ static void atmel_sha204a_remove(struct i2c_client *client) } static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = { - { .compatible = "atmel,atsha204", }, + { .compatible = "atmel,atsha204", .data = &atsha204_quality }, { .compatible = "atmel,atsha204a", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); static const struct i2c_device_id atmel_sha204a_id[] = { - { "atsha204" }, + { "atsha204", (kernel_ulong_t)&atsha204_quality }, { "atsha204a" }, { /* sentinel */ } }; From a67afb1884ba815079bd43d5c998e155e03b08b6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 29 Apr 2026 18:15:44 -0700 Subject: [PATCH 174/655] crypto: af_alg - Document the deprecation of AF_ALG AF_ALG is almost completely unnecessary, and it exposes a massive attack surface that hasn't been standing up to modern vulnerability discovery tools. The latest one even has its own website, providing a small Python script that reliably roots most Linux distros: https://copy.fail/ This isn't sustainable, especially as LLMs have accelerated the rate the vulnerabilities are coming in. The effort that is being put into this thing is vastly disproportional to the few programs that actually use it, and those programs would be better served by userspace code anyway. These issues have been noted in many mailing list discussions already. But until now they haven't been reflected in the documentation or kconfig menu itself, and the vulnerabilities are still coming in. Let's go ahead and document the deprecation. This isn't intended to change anything overnight. After all, most Linux distros won't be able to disable the kconfig options quite yet, mainly because of iwd. But this should create a bit more impetus for these userspace programs to be fixed, and the documentation update should also help prevent more users from appearing. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- Documentation/crypto/userspace-if.rst | 74 +++++++++++++++++++++------ crypto/Kconfig | 69 ++++++++++++++++++------- 2 files changed, 109 insertions(+), 34 deletions(-) diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst index a3b13ff83cb3..2c4e9a1ac3e5 100644 --- a/Documentation/crypto/userspace-if.rst +++ b/Documentation/crypto/userspace-if.rst @@ -4,26 +4,68 @@ User Space Interface Introduction ------------ -The concepts of the kernel crypto API visible to kernel space is fully -applicable to the user space interface as well. Therefore, the kernel -crypto API high level discussion for the in-kernel use cases applies -here as well. +AF_ALG provides unprivileged userspace programs access to arbitrary hash, +symmetric cipher, AEAD, and RNG algorithms that are implemented in kernel-mode +code. -The major difference, however, is that user space can only act as a -consumer and never as a provider of a transformation or cipher -algorithm. +AF_ALG is insecure and is deprecated. Originally added to the kernel in 2010, +most kernel developers now consider it to be a mistake. -The following covers the user space interface exported by the kernel -crypto API. A working example of this description is libkcapi that can -be obtained from [1]. That library can be used by user space -applications that require cryptographic services from the kernel. +AF_ALG continues to be supported only for backwards compatibility. On systems +where no programs using AF_ALG remain, the support for it should be disabled by +disabling ``CONFIG_CRYPTO_USER_API_*``. -Some details of the in-kernel kernel crypto API aspects do not apply to -user space, however. This includes the difference between synchronous -and asynchronous invocations. The user space API call is fully -synchronous. +Deprecation +----------- -[1] https://www.chronox.de/libkcapi/index.html +AF_ALG was originally intended to provide userspace programs access to crypto +accelerators that they wouldn't otherwise have access to. + +However, that capability turned out to not be useful on very many systems. More +significantly, the actual implementation exposes a vastly greater amount of +functionality than that. It actually provides access to all software algorithms. + +This includes arbitrary compositions of different algorithms created via a +complex template system, as well as algorithms that only make sense as internal +implementation details of other algorithms. It also includes full zero-copy +support, which is difficult for the kernel to implement securely. + +Ultimately, these algorithms are just math computations. They use the same +instructions that userspace programs already have access to, just accessed in a +much more convoluted and less efficient way. + +Indeed, userspace code is nearly always what is being used anyway. These same +algorithms are widely implemented in userspace crypto libraries. + +Meanwhile, AF_ALG hasn't been withstanding modern vulnerability discovery tools +such as syzbot and large language models. It receives a steady stream of CVEs. +Some of the examples include: + +- CVE-2026-31677 +- CVE-2026-31431 (https://copy.fail) +- CVE-2025-38079 +- CVE-2025-37808 +- CVE-2024-26824 +- CVE-2022-48781 +- CVE-2019-8912 +- CVE-2018-14619 +- CVE-2017-18075 +- CVE-2017-17806 +- CVE-2017-17805 +- CVE-2016-10147 +- CVE-2015-8970 +- CVE-2015-3331 +- CVE-2014-9644 +- CVE-2013-7421 +- CVE-2011-4081 + +It is recommended that, whenever possible, userspace programs be migrated to +userspace crypto code (which again, is what is normally used anyway) and +``CONFIG_CRYPTO_USER_API_*`` be disabled. On systems that use SELinux, SELinux +can also be used to restrict the use of AF_ALG to trusted programs. + +The remainder of this documentation provides the historical documentation for +the deprecated AF_ALG interface. User Space API General Remarks ------------------------------ diff --git a/crypto/Kconfig b/crypto/Kconfig index 608b2c739193..00b7ce4227ae 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1252,44 +1252,68 @@ config CRYPTO_DF80090A select CRYPTO_CTR endmenu -menu "Userspace interface" +menu "Userspace interface (deprecated)" config CRYPTO_USER_API tristate config CRYPTO_USER_API_HASH - tristate "Hash algorithms" + tristate "Hash algorithms (deprecated)" depends on NET select CRYPTO_HASH select CRYPTO_USER_API help - Enable the userspace interface for hash algorithms. + Enable the AF_ALG userspace interface for hash algorithms. This + provides unprivileged userspace programs access to arbitrary hash + algorithms implemented in the kernel's privileged execution context. - See Documentation/crypto/userspace-if.rst and - https://www.chronox.de/libkcapi/html/index.html + This interface is deprecated and is supported only for backwards + compatibility. It regularly has vulnerabilities, and the capabilities + it provides are redundant with userspace crypto libraries. + + Enable this only if needed for support for a program that hasn't yet + been converted to userspace crypto, for example iwd. + + See also Documentation/crypto/userspace-if.rst config CRYPTO_USER_API_SKCIPHER - tristate "Symmetric key cipher algorithms" + tristate "Symmetric key cipher algorithms (deprecated)" depends on NET select CRYPTO_SKCIPHER select CRYPTO_USER_API help - Enable the userspace interface for symmetric key cipher algorithms. + Enable the AF_ALG userspace interface for symmetric key algorithms. + This provides unprivileged userspace programs access to arbitrary + symmetric key algorithms implemented in the kernel's privileged + execution context. - See Documentation/crypto/userspace-if.rst and - https://www.chronox.de/libkcapi/html/index.html + This interface is deprecated and is supported only for backwards + compatibility. It regularly has vulnerabilities, and the capabilities + it provides are redundant with userspace crypto libraries. + + Enable this only if needed for support for a program that hasn't yet + been converted to userspace crypto, for example iwd, or cryptsetup + with certain algorithms. + + See also Documentation/crypto/userspace-if.rst config CRYPTO_USER_API_RNG - tristate "RNG (random number generator) algorithms" + tristate "Random number generation algorithms (deprecated)" depends on NET select CRYPTO_RNG select CRYPTO_USER_API help - Enable the userspace interface for RNG (random number generator) - algorithms. + Enable the AF_ALG userspace interface for random number generation + (RNG) algorithms. This provides unprivileged userspace programs + access to arbitrary RNG algorithms implemented in the kernel's + privileged execution context. - See Documentation/crypto/userspace-if.rst and - https://www.chronox.de/libkcapi/html/index.html + This interface is deprecated and is supported only for backwards + compatibility. It regularly has vulnerabilities, and the capabilities + it provides are redundant with userspace crypto libraries as well as + the normal kernel RNG (e.g., /dev/urandom and getrandom(2)). + + See also Documentation/crypto/userspace-if.rst config CRYPTO_USER_API_RNG_CAVP bool "Enable CAVP testing of DRBG" @@ -1304,16 +1328,25 @@ config CRYPTO_USER_API_RNG_CAVP no unless you know what this is. config CRYPTO_USER_API_AEAD - tristate "AEAD cipher algorithms" + tristate "AEAD cipher algorithms (deprecated)" depends on NET select CRYPTO_AEAD select CRYPTO_SKCIPHER select CRYPTO_USER_API help - Enable the userspace interface for AEAD cipher algorithms. + Enable the AF_ALG userspace interface for authenticated encryption + with associated data (AEAD) algorithms. This provides unprivileged + userspace programs access to arbitrary AEAD algorithms implemented in + the kernel's privileged execution context. - See Documentation/crypto/userspace-if.rst and - https://www.chronox.de/libkcapi/html/index.html + This interface is deprecated and is supported only for backwards + compatibility. It regularly has vulnerabilities, and the capabilities + it provides are redundant with userspace crypto libraries. + + Enable this only if needed for support for a program that hasn't yet + been converted to userspace crypto, for example iwd. + + See also Documentation/crypto/userspace-if.rst config CRYPTO_USER_API_ENABLE_OBSOLETE bool "Obsolete cryptographic algorithms" From c04337343ef6e1d5ee5b49ac386e468c2d063e07 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 2 May 2026 12:53:42 +0800 Subject: [PATCH 175/655] crypto: authencesn - Use memcpy_from/to_sglist Convert scatterwalk_map_and_copy to memcpy_to/from_sglist as they are more readable and less error-prone. Signed-off-by: Herbert Xu --- crypto/authencesn.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 522df41365d8..ca063576f670 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -94,11 +94,11 @@ static int crypto_authenc_esn_genicv_tail(struct aead_request *req, u32 tmp[2]; /* Move high-order bits of sequence number back. */ - scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); - scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); - scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); + memcpy_from_sglist(tmp, dst, 4, 4); + memcpy_from_sglist(tmp + 1, dst, assoclen + cryptlen, 4); + memcpy_to_sglist(dst, 0, tmp, 8); - scatterwalk_map_and_copy(hash, dst, assoclen + cryptlen, authsize, 1); + memcpy_to_sglist(dst, assoclen + cryptlen, hash, authsize); return 0; } @@ -129,9 +129,9 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, return 0; /* Move high-order bits of sequence number to the end. */ - scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); - scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); - scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); + memcpy_from_sglist(tmp, dst, 0, 8); + memcpy_to_sglist(dst, 4, tmp, 4); + memcpy_to_sglist(dst, assoclen + cryptlen, tmp + 1, 4); sg_init_table(areq_ctx->dst, 2); dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); @@ -217,9 +217,9 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, if (src == dst) { /* Move high-order bits of sequence number back. */ - scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); - scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); - scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); + memcpy_from_sglist(tmp, dst, 4, 4); + memcpy_from_sglist(tmp + 1, dst, assoclen + cryptlen, 4); + memcpy_to_sglist(dst, 0, tmp, 8); } else memcpy_sglist(dst, src, assoclen); @@ -274,18 +274,17 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req) goto tail; cryptlen -= authsize; - scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen, - authsize, 0); + memcpy_from_sglist(ihash, req->src, assoclen + cryptlen, authsize); /* Move high-order bits of sequence number to the end. */ - scatterwalk_map_and_copy(tmp, src, 0, 8, 0); + memcpy_from_sglist(tmp, src, 0, 8); if (src == dst) { - scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); - scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); + memcpy_to_sglist(dst, 4, tmp, 4); + memcpy_to_sglist(dst, assoclen + cryptlen, tmp + 1, 4); dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); } else { - scatterwalk_map_and_copy(tmp, dst, 0, 4, 1); - scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen - 4, 4, 1); + memcpy_to_sglist(dst, 0, tmp, 4); + memcpy_to_sglist(dst, assoclen + cryptlen - 4, tmp + 1, 4); src = scatterwalk_ffwd(areq_ctx->src, src, 8); dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); From 2d7b2cfc59998baf5e8622a24dc28f69a5212e06 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sat, 2 May 2026 21:09:04 +0200 Subject: [PATCH 176/655] crypto: ecrdsa - fix unknown OID check in ecrdsa_param_curve The ->curve_oid check in ecrdsa_param_curve() rejects the valid enum value 0 (OID_id_dsa_with_sha1), but look_up_OID() returns OID__NR on lookup failure. Compare ->curve_oid with OID__NR instead to ensure that only unknown OIDs return -EINVAL. Fixes: 0d7a78643f69 ("crypto: ecrdsa - add EC-RDSA (GOST 34.10) algorithm") Signed-off-by: Thorsten Blum Reviewed-by: Lukas Wunner Reviewed-by: Vitaly Chikunov Signed-off-by: Herbert Xu --- crypto/ecrdsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/ecrdsa.c b/crypto/ecrdsa.c index 2c0602f0cd40..0cd7eb367604 100644 --- a/crypto/ecrdsa.c +++ b/crypto/ecrdsa.c @@ -145,7 +145,7 @@ int ecrdsa_param_curve(void *context, size_t hdrlen, unsigned char tag, struct ecrdsa_ctx *ctx = context; ctx->curve_oid = look_up_OID(value, vlen); - if (!ctx->curve_oid) + if (ctx->curve_oid == OID__NR) return -EINVAL; ctx->curve = get_curve_by_oid(ctx->curve_oid); return 0; From f7dd32c5179d7755de18e21d5674b08f9e5cb180 Mon Sep 17 00:00:00 2001 From: Weiming Shi Date: Thu, 30 Apr 2026 10:36:34 -0700 Subject: [PATCH 177/655] crypto: asymmetric_keys - fix OOB read in pefile_digest_pe_contents pefile_digest_pe_contents() computes the trailing-data hash length as pelen - (hashed_bytes + certs_size). A crafted PE can make the addition exceed pelen, causing the unsigned subtraction to underflow to ~4 GiB. This is passed to crypto_shash_update() which reads out of bounds and panics on unmapped vmalloc guard pages. BUG: unable to handle page fault for address: ffffc900038d8000 Oops: Oops: 0000 [#1] SMP KASAN NOPTI RIP: 0010:sha256_blocks_generic (lib/crypto/sha256.c:152) Call Trace: __sha256_update (lib/crypto/sha256.c:208) crypto_sha256_update (crypto/sha256.c:142) verify_pefile_signature (crypto/asymmetric_keys/verify_pefile.c:436) kexec_kernel_verify_pe_sig (kernel/kexec_file.c:151) __do_sys_kexec_file_load (kernel/kexec_file.c:406) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) Kernel panic - not syncing: Fatal exception Validate that the addition does not overflow and the result does not exceed pelen before the subtraction. Return -ELIBBAD on failure. Fixes: af316fc442ef ("pefile: Digest the PE binary and compare to the PKCS#7 data") Reported-by: Xiang Mei Signed-off-by: Weiming Shi Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/verify_pefile.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 1f3b227ba7f2..cec99db14129 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c @@ -305,6 +305,8 @@ static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen, if (pelen > hashed_bytes) { tmp = hashed_bytes + ctx->certs_size; + if (tmp <= hashed_bytes || pelen < tmp) + return -ELIBBAD; ret = crypto_shash_update(desc, pebuf + hashed_bytes, pelen - tmp); From 54725e3049e1684bc77e0cf892ab1d194c515121 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Wed, 6 May 2026 23:35:12 +0500 Subject: [PATCH 178/655] spi: amlogic-spisg: drop misleading NULL check on exdesc aml_spisg_setup_transfer() takes a non-NULL exdesc pointer; the function dereferences exdesc unconditionally later in the body to populate the SPI scatter-gather descriptors (tx_ccsg / rx_ccsg). The sole caller, aml_spisg_transfer_one_message(), always passes a valid pointer derived from kcalloc(). The "if (exdesc)" guard around the memset() at the start of the function is therefore dead and misleading -- it suggests callers may pass NULL when in fact they may not. smatch flags the inconsistency: drivers/spi/spi-amlogic-spisg.c:314 aml_spisg_setup_transfer() error: we previously assumed 'exdesc' could be null (see line 261) Drop the check; the unconditional memset matches the unconditional dereferences elsewhere in the function and removes the inconsistency that smatch reports. No functional change. Signed-off-by: Stepan Ionichev Reviewed-by: Xianwei Zhao Link: https://patch.msgid.link/20260506183513.482-1-sozdayvek@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-amlogic-spisg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c index f9de2d2c9213..601fb73b3595 100644 --- a/drivers/spi/spi-amlogic-spisg.c +++ b/drivers/spi/spi-amlogic-spisg.c @@ -258,8 +258,7 @@ static int aml_spisg_setup_transfer(struct spisg_device *spisg, int ret; memset(desc, 0, sizeof(*desc)); - if (exdesc) - memset(exdesc, 0, sizeof(*exdesc)); + memset(exdesc, 0, sizeof(*exdesc)); aml_spisg_set_speed(spisg, xfer->speed_hz); xfer->effective_speed_hz = spisg->effective_speed_hz; From 79bbc356d537969332ddd0bf3b990438224e013b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 22 Feb 2026 18:24:16 -0500 Subject: [PATCH 179/655] watchdog: pic32-wdt: allow driver to be compiled on all architectures with COMPILE_TEST This driver currently only supports builds against a PIC32 target, or with COMPILE_TEST on MIPS. Now that commit 5aa5879eeebb ("watchdog: pic32-wdt: update include to use pic32.h from platform_data") is merged, it's possible to compile this driver on other architectures. To avoid future breakage of this driver in the future, let's update the Kconfig so that it can be built with COMPILE_TEST enabled on all architectures. Signed-off-by: Brian Masney Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260222-watchdog-pic32-v1-1-a2538aa528d1@redhat.com Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 3397c82ded9c..ae8c90fa194a 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1998,7 +1998,7 @@ config MT7621_WDT config PIC32_WDT tristate "Microchip PIC32 hardware watchdog" select WATCHDOG_CORE - depends on MACH_PIC32 || (MIPS && COMPILE_TEST) + depends on MACH_PIC32 || COMPILE_TEST help Watchdog driver for the built in watchdog hardware in a PIC32. From 96bbd6217953d371617bf2131f0805ed7885a5d9 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 22 Feb 2026 18:24:17 -0500 Subject: [PATCH 180/655] watchdog: pic32-dmt: allow driver to be compiled on all architectures with COMPILE_TEST This driver currently only supports builds against a PIC32 target, or with COMPILE_TEST on MIPS. Now that commit 0f8a61ca78d6 ("watchdog: pic32-dmt: update include to use pic32.h from platform_data") is merged, it's possible to compile this driver on other architectures. To avoid future breakage of this driver in the future, let's update the Kconfig so that it can be built with COMPILE_TEST enabled on all architectures. Signed-off-by: Brian Masney Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260222-watchdog-pic32-v1-2-a2538aa528d1@redhat.com Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index ae8c90fa194a..d58a0bd0bdeb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -2011,7 +2011,7 @@ config PIC32_WDT config PIC32_DMT tristate "Microchip PIC32 Deadman Timer" select WATCHDOG_CORE - depends on MACH_PIC32 || (MIPS && COMPILE_TEST) + depends on MACH_PIC32 || COMPILE_TEST help Watchdog driver for PIC32 instruction fetch counting timer. This specific timer is typically be used in mission critical and safety From 4e9590d8d52ac3193d723f55bd0fbc6a18e10549 Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Fri, 6 Feb 2026 17:42:54 -0600 Subject: [PATCH 181/655] dt-bindings: watchdog: ti,rti-wdt: Add ti,am62l-rti-wdt compatible Add a new compatible ti,am62l-rti-wdt for AM62L SoC [0]. [0] https://www.ti.com/product/AM62L Signed-off-by: Judith Mendez Acked-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260206234255.380530-2-jm@ti.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml b/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml index 62ddc284a524..2966e5bfb6c0 100644 --- a/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml @@ -23,6 +23,7 @@ allOf: properties: compatible: enum: + - ti,am62l-rti-wdt - ti,j7-rti-wdt reg: From aed1abf31ea3f13b8ac8aa0f6c1078a9bc7b9564 Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Fri, 6 Feb 2026 17:42:55 -0600 Subject: [PATCH 182/655] watchdog: rti_wdt: Add reaction control This configures the reaction between NMI and reset for WWD. On K3 SoCs other than AM62L SoC [0], watchdog reset output is routed to the ESM module which can subsequently route the signal to safety master or SoC reset. On AM62L, the watchdog reset output is routed to the SoC HW reset block. So, add a new compatible for AM62L to add SoC data and configure reaction to reset instead of NMI. [0] https://www.ti.com/product/AM62L Signed-off-by: Judith Mendez Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20260206234255.380530-3-jm@ti.com Signed-off-by: Guenter Roeck --- drivers/watchdog/rti_wdt.c | 39 ++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index be7d7db47591..c3c7715140ea 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -35,7 +35,8 @@ #define RTIWWDRXCTRL 0xa4 #define RTIWWDSIZECTRL 0xa8 -#define RTIWWDRX_NMI 0xa +#define RTIWWDRXN_RST 0x5 +#define RTIWWDRXN_NMI 0xa #define RTIWWDSIZE_50P 0x50 #define RTIWWDSIZE_25P 0x500 @@ -63,22 +64,29 @@ static int heartbeat; +struct rti_wdt_data { + bool nmi; +}; + /* * struct to hold data for each WDT device * @base - base io address of WD device * @freq - source clock frequency of WDT * @wdd - hold watchdog device as is in WDT core + * @nmi - Set if this WDT instance supports generating NMI */ struct rti_wdt_device { void __iomem *base; unsigned long freq; struct watchdog_device wdd; + bool nmi; }; static int rti_wdt_start(struct watchdog_device *wdd) { u32 timer_margin; struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd); + u8 reaction; int ret; ret = pm_runtime_resume_and_get(wdd->parent); @@ -101,8 +109,13 @@ static int rti_wdt_start(struct watchdog_device *wdd) */ wdd->min_hw_heartbeat_ms = 520 * wdd->timeout + MAX_HW_ERROR; - /* Generate NMI when wdt expires */ - writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL); + /* When WDT expires, generate NMI or reset if NMI not supported */ + if (wdt->nmi) + reaction = RTIWWDRXN_NMI; + else + reaction = RTIWWDRXN_RST; + + writel_relaxed(reaction, wdt->base + RTIWWDRXCTRL); /* Open window size 50%; this is the largest window size available */ writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL); @@ -210,6 +223,7 @@ static int rti_wdt_probe(struct platform_device *pdev) { int ret = 0; struct device *dev = &pdev->dev; + const struct rti_wdt_data *data; struct watchdog_device *wdd; struct rti_wdt_device *wdt; struct clk *clk; @@ -254,6 +268,14 @@ static int rti_wdt_probe(struct platform_device *pdev) wdd->timeout = DEFAULT_HEARTBEAT; wdd->parent = dev; + data = device_get_match_data(dev); + if (!data) { + ret = -ENODEV; + goto err_iomap; + } + + wdt->nmi = data->nmi; + watchdog_set_drvdata(wdd, wdt); watchdog_set_nowayout(wdd, 1); watchdog_set_restart_priority(wdd, 128); @@ -361,8 +383,17 @@ static void rti_wdt_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } +static const struct rti_wdt_data rti_wdt_j7_data = { + .nmi = true, +}; + +static const struct rti_wdt_data rti_wdt_am62l_data = { + .nmi = false, +}; + static const struct of_device_id rti_wdt_of_match[] = { - { .compatible = "ti,j7-rti-wdt", }, + { .compatible = "ti,j7-rti-wdt", .data = &rti_wdt_j7_data }, + { .compatible = "ti,am62l-rti-wdt", .data = &rti_wdt_am62l_data }, {}, }; MODULE_DEVICE_TABLE(of, rti_wdt_of_match); From 1f5b29add64e7c1500530079bbbe359cad28cb63 Mon Sep 17 00:00:00 2001 From: Ranjani Vaidyanathan Date: Fri, 6 Feb 2026 08:23:32 +0800 Subject: [PATCH 183/655] watchdog: imx7ulp_wdt: Keep WDOG running until A55 enters WFI on i.MX94 On i.MX94, watchdog sources clock from bus clock that will be always on during the lifecycle of Linux. There is a Low Power Clock Gating(LPCG) between the bus clock and watchdog, but the LPCG is not exported for software to control, it is hardware automatically controlled. When Cortex-A55 executes WFI during suspend flow, the LPCG will automatically gate off the clock to stop watchdog and resume clock when Cortex-A55 is woke up. So watchdog could always be alive to protect Linux, except Cortex-A platform WFI is executed in Linux suspend flow. Introduce a new hardware feature flag to indicate CPU low-power-mode auto clock gating support, and use it to avoid stopping the watchdog during suspend when LPCG can safely keep it running. Add i.MX94-specific watchdog hardware data and DT compatible entry to enable this behavior. Signed-off-by: Ranjani Vaidyanathan [peng.fan@nxp.com: rewrite commit log for clarity] Signed-off-by: Peng Fan Reviewed-by: Guenter Roeck Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20260206-imx94-wdog-v2-1-4dd725faec1f@nxp.com Signed-off-by: Guenter Roeck --- drivers/watchdog/imx7ulp_wdt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c index 03479110453c..855dc9d5083a 100644 --- a/drivers/watchdog/imx7ulp_wdt.c +++ b/drivers/watchdog/imx7ulp_wdt.c @@ -56,6 +56,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" struct imx_wdt_hw_feature { bool prescaler_enable; bool post_rcs_wait; + bool cpu_lpm_auto_cg; u32 wdog_clock_rate; }; @@ -360,7 +361,7 @@ static int __maybe_unused imx7ulp_wdt_suspend_noirq(struct device *dev) { struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev); - if (watchdog_active(&imx7ulp_wdt->wdd)) + if (watchdog_active(&imx7ulp_wdt->wdd) && !imx7ulp_wdt->hw->cpu_lpm_auto_cg) imx7ulp_wdt_stop(&imx7ulp_wdt->wdd); clk_disable_unprepare(imx7ulp_wdt->clk); @@ -408,10 +409,17 @@ static const struct imx_wdt_hw_feature imx93_wdt_hw = { .wdog_clock_rate = 125, }; +static const struct imx_wdt_hw_feature imx94_wdt_hw = { + .prescaler_enable = true, + .wdog_clock_rate = 125, + .cpu_lpm_auto_cg = true, +}; + static const struct of_device_id imx7ulp_wdt_dt_ids[] = { { .compatible = "fsl,imx7ulp-wdt", .data = &imx7ulp_wdt_hw, }, { .compatible = "fsl,imx8ulp-wdt", .data = &imx8ulp_wdt_hw, }, { .compatible = "fsl,imx93-wdt", .data = &imx93_wdt_hw, }, + { .compatible = "fsl,imx94-wdt", .data = &imx94_wdt_hw, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx7ulp_wdt_dt_ids); From 10820327b9386c77aaa8c5c3c3690a7443baf9b9 Mon Sep 17 00:00:00 2001 From: Balakrishnan Sambath Date: Mon, 2 Mar 2026 17:03:10 +0530 Subject: [PATCH 184/655] watchdog: at91sam9_wdt.h: Document WDDIS bit position per SoC family AT91_WDT_WDDIS (bit 15) applies to SAMA5/AT91SAM9261 and AT91_SAM9X60_WDDIS (bit 12) to SAM9X60/SAMA7G5/SAM9X75. Update comments to reflect this and add SAMA7G5 and SAM9X75 datasheet references to the file header. Signed-off-by: Balakrishnan Sambath Reviewed-by: Alexandre Belloni Link: https://lore.kernel.org/r/20260302113310.133989-3-balakrishnan.s@microchip.com Signed-off-by: Guenter Roeck --- drivers/watchdog/at91sam9_wdt.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/at91sam9_wdt.h b/drivers/watchdog/at91sam9_wdt.h index 298d545df1a1..2020694f8f6f 100644 --- a/drivers/watchdog/at91sam9_wdt.h +++ b/drivers/watchdog/at91sam9_wdt.h @@ -9,6 +9,8 @@ * Watchdog Timer (WDT) - System peripherals regsters. * Based on AT91SAM9261 datasheet revision D. * Based on SAM9X60 datasheet. + * Based on SAMA7G5 datasheet. + * Based on SAM9X75 datasheet. * */ @@ -27,10 +29,10 @@ #define AT91_SAM9X60_PERIODRST BIT(4) /* Period Reset */ #define AT91_SAM9X60_RPTHRST BIT(5) /* Minimum Restart Period */ #define AT91_WDT_WDFIEN BIT(12) /* Fault Interrupt Enable */ -#define AT91_SAM9X60_WDDIS BIT(12) /* Watchdog Disable */ +#define AT91_SAM9X60_WDDIS BIT(12) /* Watchdog Disable (SAM9X60, SAMA7G5, SAM9X75) */ #define AT91_WDT_WDRSTEN BIT(13) /* Reset Processor */ #define AT91_WDT_WDRPROC BIT(14) /* Timer Restart */ -#define AT91_WDT_WDDIS BIT(15) /* Watchdog Disable */ +#define AT91_WDT_WDDIS BIT(15) /* Watchdog Disable (SAMA5, AT91SAM9261) */ #define AT91_WDT_WDD (0xfffUL << 16) /* Delta Value */ #define AT91_WDT_SET_WDD(x) (((x) << 16) & AT91_WDT_WDD) #define AT91_WDT_WDDBGHLT BIT(28) /* Debug Halt */ From fec053e452a5e859cf6e8aa2c9d44d78fed60034 Mon Sep 17 00:00:00 2001 From: CL Wang Date: Thu, 15 Jan 2026 16:14:42 +0800 Subject: [PATCH 185/655] dt-bindings: watchdog: Add support for Andes ATCWDT200 Add the devicetree binding documentation for the Andes ATCWDT200 watchdog timer. ATCWDT200 is the IP name, which is embedded in AndesCore-based platforms or SoCs such as AE350 and Qilai. Signed-off-by: CL Wang Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20260115081444.2452357-2-cl634@andestech.com Signed-off-by: Guenter Roeck --- .../watchdog/andestech,ae350-wdt.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml diff --git a/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml b/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml new file mode 100644 index 000000000000..f1107c552788 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/andestech,ae350-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Andes ATCWDT200 Watchdog Timer + +maintainers: + - CL Wang + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + oneOf: + - items: + - enum: + - andestech,qilai-wdt + - const: andestech,ae350-wdt + - const: andestech,ae350-wdt + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + andestech,clock-source: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: | + Select the clock source for the watchdog timer. + 0 - External clock + 1 - P clock + +required: + - compatible + - reg + - clocks + - andestech,clock-source + +unevaluatedProperties: false + +examples: + - | + watchdog@f0500000 { + compatible = "andestech,ae350-wdt"; + reg = <0xf0500000 0x20>; + clocks = <&clk_wdt>; + andestech,clock-source = <0>; + }; From e4e0848ad046da9304e0656a71f74ddfbb316e98 Mon Sep 17 00:00:00 2001 From: CL Wang Date: Thu, 15 Jan 2026 16:14:43 +0800 Subject: [PATCH 186/655] watchdog: atcwdt200: Add driver for Andes ATCWDT200 Add support for the Andes ATCWDT200 watchdog timer. The driver implements programmable reset and interrupt timers, and includes automatic detection of the supported IntTime bit-width. Integrated with the Linux watchdog framework, it supports basic operations including start, stop, ping, timeout configuration, and system reset via the restart handler. Signed-off-by: CL Wang Link: https://lore.kernel.org/r/20260115081444.2452357-3-cl634@andestech.com Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 9 + drivers/watchdog/Makefile | 1 + drivers/watchdog/atcwdt200_wdt.c | 580 +++++++++++++++++++++++++++++++ 3 files changed, 590 insertions(+) create mode 100644 drivers/watchdog/atcwdt200_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d58a0bd0bdeb..eb8eb307e04d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -2119,6 +2119,15 @@ config WATCHDOG_RTAS # RISC-V Architecture +config ATCWDT200_WATCHDOG + tristate "Andes ATCWDT200 Watchdog support" + depends on ARCH_ANDES || COMPILE_TEST + help + Driver for the Andes ATCWDT200 watchdog timer. It provides access to + programmable reset and interrupt counters with clock-source dependent + timing. The driver automatically detects the supported IntTime bit-width + and is fully integrated with the Linux Watchdog Framework. + config STARFIVE_WATCHDOG tristate "StarFive Watchdog support" depends on ARCH_STARFIVE || COMPILE_TEST diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index ff1dc6fd5867..a4341b251bdf 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -198,6 +198,7 @@ obj-$(CONFIG_PSERIES_WDT) += pseries-wdt.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # RISC-V Architecture +obj-$(CONFIG_ATCWDT200_WATCHDOG) += atcwdt200_wdt.o obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o # S390 Architecture diff --git a/drivers/watchdog/atcwdt200_wdt.c b/drivers/watchdog/atcwdt200_wdt.c new file mode 100644 index 000000000000..8e3b18aea368 --- /dev/null +++ b/drivers/watchdog/atcwdt200_wdt.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Andes ATCWDT200 watchdog timer driver. + * + * Copyright (C) 2025 Andes Technology Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define REG_CTRL 0x10 +#define REG_RESTART 0x14 +#define REG_WRITE_EN 0x18 +#define REG_STATUS 0x1C + +/* Control Register */ +#define CTRL_RST_TIME_MSK GENMASK(10, 8) +#define CTRL_RST_TIME_SET(x) FIELD_PREP(CTRL_RST_TIME_MSK, x) +#define CTRL_INT_TIME_MSK GENMASK(7, 4) +#define CTRL_INT_TIME_SET(x) FIELD_PREP(CTRL_INT_TIME_MSK, x) +#define CTRL_INT_TIME_GET(x) FIELD_GET(CTRL_INT_TIME_MSK, x) +#define CTRL_RST_EN BIT(3) +#define CTRL_CLK_SEL BIT(1) +#define CTRL_CLK_SEL_PCLK 1 +#define CTRL_CLK_SEL_SET(x) FIELD_PREP(CTRL_CLK_SEL, x) +#define CTRL_WDT_EN BIT(0) + +/* Restart Register */ +#define RESTART_MAGIC 0xCAFE + +/* Write Enable Register */ +#define WRITE_EN_MAGIC 0x5AA5 + +/* Status Register */ +#define STATUS_INT_EXPIRED BIT(1) + +/* The default timeout value in seconds */ +#define ATCWDT_TIMEOUT 4 + +/* Define the array size for each timer type */ +#define TMR_SZ_RST 8 +#define TMR_SZ_INT_16 8 +#define TMR_SZ_INT_32 16 + +#define DRV_NAME "atcwdt200" +/** + * enum timer_type - Supported timer types for ATCWDT200 watchdog driver + * @TMR_RST: Reset timer (non-interrupt). + * @TMR_INT_16: 16-bit interrupt timer supported by hardware. + * @TMR_INT_32: 32-bit interrupt timer supported by hardware. + * @TMR_UNKNOWN: Timer type cannot be determined. + */ +enum timer_type { + TMR_RST, + TMR_INT_16, + TMR_INT_32, + TMR_UNKNOWN +}; + +static unsigned int timeout = ATCWDT_TIMEOUT; +static bool nowayout = WATCHDOG_NOWAYOUT; + +/** + * struct atcwdt_drv - ATCWDT200 watchdog driver private data + * @wdt_dev: Watchdog device used by the watchdog framework. + * @regmap: Register map for accessing hardware registers. + * @clk: Hardware clock used by the watchdog timer. + * @lock: Spinlock protecting register accesses and driver state. + * @clk_freq: Input clock frequency of the ATCWDT200. + * @clk_src: Selected clock source for the watchdog timer. + * @int_timer_type: Detected interrupt timer type (16-bit, 32-bit, or unknown). + */ +struct atcwdt_drv { + struct watchdog_device wdt_dev; + struct regmap *regmap; + struct clk *clk; + spinlock_t lock; + unsigned int clk_freq; + unsigned char clk_src; + unsigned char int_timer_type; +}; + +static const struct watchdog_info atcwdt_info = { + .identity = DRV_NAME, + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +/** + * atcwdt_get_index - Get the interval value for the specified timer type + * @index: The index of the interval in the array + * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or + * TMR_INT_32. + * + * This function retrieves the interval value based on the timer type and + * ensures the index stays within the valid range for the given timer type. + * For TMR_RST: + * - The maximum array size is 8 (index range: 0-7). + * For TMR_INT_16: + * - The maximum array size is 8 (index range: 0-7). + * For TMR_INT_32: + * - The maximum array size is 16 (index range: 0-15). + * + * If the index exceeds the maximum array size, the function will return + * the last element of the respective array. + */ +static inline unsigned char atcwdt_get_index(unsigned char index, + enum timer_type timer_type) +{ + static const unsigned char rst_timer_interval[TMR_SZ_RST] = { + 7, 8, 9, 10, 11, 12, 13, 14}; + static const unsigned char int_timer_interval[TMR_SZ_INT_32] = { + 6, 8, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31}; + unsigned char array_index; + + if (timer_type == TMR_RST) { + array_index = min(index, TMR_SZ_RST - 1); + return rst_timer_interval[array_index]; + } + + if (timer_type == TMR_INT_32) + array_index = min(index, TMR_SZ_INT_32 - 1); + else + array_index = min(index, TMR_SZ_INT_16 - 1); + + return int_timer_interval[array_index]; +} + +/** + * atcwdt_get_clock_period - Calculate the closest clock period based on a + * given tick count + * @tick: The target tick count to match + * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or + * TMR_INT_32. + * @index: Pointer to store the index of the selected parameter + * + * This function calculates the closest clock period to the given tick count + * by iterating through the timer parameters and selecting the one that + * minimizes the difference between the target tick count and the calculated + * clock period. The function determines the index of the closest parameter + * and returns the difference between the target tick count and the selected + * clock period. + * + * Return: The difference between the target tick count and the selected + * clock period. + */ +static long long atcwdt_get_clock_period(long long tick, + enum timer_type timer_type, + unsigned char *index) +{ + long long result; + unsigned char size; + char i; + + if (timer_type == TMR_RST) + size = TMR_SZ_RST; + else if (timer_type == TMR_INT_32) + size = TMR_SZ_INT_32; + else + size = TMR_SZ_INT_16; + + *index = size - 1; + for (i = 0; i < size; i++) { + result = tick - (1LL << atcwdt_get_index(i, timer_type)); + + if (result <= 1) { + *index = i; + break; + } + } + + return result; +} + +/** + * atcwdt_get_timeout_params - Calculate optimal parameters for Watchdog Timer + * @drv_data: Pointer to the Watchdog driver data structure + * @timeout: Desired timeout value (in seconds) + * @int_timer_params: Pointer to store the calculated interrupt timer + * parameter index + * @rst_timer_params: Pointer to store the calculated reset timer parameter + * index + * + * This function calculates the optimal parameter combination for the + * interrupt timer and reset timer of the Watchdog Timer to achieve a + * timeout value closest to, but not less than the specified timeout. + * + * Algorithm: + * 1. The parameters for both the interrupt timer and reset timer are + * predefined as a series of options represented as powers of 2. + * 2. The function first determines the interrupt timer's parameter index + * that provides a time closest to and not exceeding the desired timeout. + * 3. Based on the selected interrupt timer, it calculates the required + * reset timer parameter to ensure the total timeout matches the target. + * + * Return: The calculated parameter indices are stored in the provided + * pointers. + */ +static void atcwdt_get_timeout_params(struct atcwdt_drv *drv_data, + unsigned int timeout, + unsigned char *int_timer_params, + unsigned char *rst_timer_params) +{ + long long rest_time_ms; + long long result; + long long tick; + unsigned char rst_index; + unsigned char int_index; + unsigned char above; + unsigned char below; + + tick = (long long)timeout * drv_data->clk_freq; + result = atcwdt_get_clock_period(tick, + drv_data->int_timer_type, + &above); + if (result == 0 || above == 0) { + *int_timer_params = above; + *rst_timer_params = 0; + return; + } + below = above - 1; + + int_index = atcwdt_get_index(below, drv_data->int_timer_type); + rest_time_ms = timeout * 1000LL + - div64_s64(1000LL << int_index, drv_data->clk_freq); + + result = atcwdt_get_clock_period(rest_time_ms * drv_data->clk_freq, + TMR_RST, + &rst_index); + + if (result > 1) { + *int_timer_params = above; + *rst_timer_params = 0; + } else { + *int_timer_params = below; + *rst_timer_params = rst_index; + } +} + +/** + * atcwdt_get_int_timer_type - Get the supported interrupt timer type. + * @drv_data: Pointer to the watchdog driver data structure. + * + * This function tests the writable bits in the IntTime field of the control + * register to determine the interrupt timer type supported by the hardware. + * + * Note: This function must only be called when the ATCWDT200 watchdog is + * disabled. If the watchdog is enabled, this function returns TMR_UNKNOWN. + * + * Returns: The interrupt timer type supported by the hardware. + */ +static int atcwdt_get_int_timer_type(struct atcwdt_drv *drv_data) +{ + struct device *dev = drv_data->wdt_dev.parent; + unsigned int val; + int ret = 0; + + spin_lock(&drv_data->lock); + regmap_read(drv_data->regmap, REG_CTRL, &val); + if (val & CTRL_WDT_EN) { + spin_unlock(&drv_data->lock); + return TMR_UNKNOWN; + } + + /* + * Configures the IntTime field with the maximum mask value + * (CTRL_INT_TIME_MSK), reads its value from the control register + * to identify the maximum writable bits. + */ + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_write(drv_data->regmap, REG_CTRL, CTRL_INT_TIME_MSK); + regmap_read(drv_data->regmap, REG_CTRL, &val); + spin_unlock(&drv_data->lock); + + val = CTRL_INT_TIME_GET(val); + switch (val) { + case 7: + drv_data->int_timer_type = TMR_INT_16; + break; + case 15: + drv_data->int_timer_type = TMR_INT_32; + break; + default: + drv_data->int_timer_type = TMR_UNKNOWN; + ret = dev_err_probe(dev, -ENODEV, + "Failed to detect interrupt timer type\n"); + } + + return ret; +} + +static int atcwdt_ping(struct watchdog_device *wdt_dev) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_write(drv_data->regmap, REG_RESTART, RESTART_MAGIC); + regmap_update_bits(drv_data->regmap, REG_STATUS, STATUS_INT_EXPIRED, + STATUS_INT_EXPIRED); + spin_unlock(&drv_data->lock); + + return 0; +} + +static int atcwdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int timeout) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + unsigned int value; + unsigned char rst_val; + unsigned char int_val; + + wdt_dev->timeout = timeout; + atcwdt_get_timeout_params(drv_data, timeout, &int_val, &rst_val); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + + value = CTRL_RST_TIME_SET(rst_val) | + CTRL_INT_TIME_SET(int_val) | + CTRL_CLK_SEL_SET(drv_data->clk_src); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_TIME_MSK | + CTRL_INT_TIME_MSK | + CTRL_CLK_SEL, + value); + + spin_unlock(&drv_data->lock); + atcwdt_ping(wdt_dev); + + return 0; +} + +static int atcwdt_start(struct watchdog_device *wdt_dev) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + atcwdt_set_timeout(wdt_dev, wdt_dev->timeout); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_EN | CTRL_WDT_EN, + CTRL_RST_EN | CTRL_WDT_EN); + + spin_unlock(&drv_data->lock); + + return 0; +} + +static int atcwdt_stop(struct watchdog_device *wdt_dev) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_EN | CTRL_WDT_EN, + 0); + spin_unlock(&drv_data->lock); + + return 0; +} + +static int atcwdt_restart(struct watchdog_device *wdt_dev, + unsigned long action, void *data) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + atcwdt_set_timeout(wdt_dev, 0); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_EN | CTRL_WDT_EN, + CTRL_RST_EN | CTRL_WDT_EN); + spin_unlock(&drv_data->lock); + + return 0; +} + +static const struct watchdog_ops atcwdt_ops = { + .owner = THIS_MODULE, + .start = atcwdt_start, + .stop = atcwdt_stop, + .ping = atcwdt_ping, + .set_timeout = atcwdt_set_timeout, + .restart = atcwdt_restart, +}; + +static int atcwdt_init_resource(struct platform_device *pdev, + struct atcwdt_drv *drv_data) +{ + struct device *dev = &pdev->dev; + void __iomem *base; + const struct regmap_config cfg = { + .name = "atcwdt", + .reg_bits = 32, + .val_bits = 32, + .cache_type = REGCACHE_NONE, + .reg_stride = 4, + .max_register = REG_STATUS, + }; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), + "Failed to ioremap I/O resource\n"); + + drv_data->regmap = devm_regmap_init_mmio(dev, base, &cfg); + if (IS_ERR(drv_data->regmap)) + return dev_err_probe(dev, PTR_ERR(drv_data->regmap), + "Failed to create regmap\n"); + + return 0; +} + +static int atcwdt_enable_clk(struct atcwdt_drv *drv_data) +{ + struct device *dev = drv_data->wdt_dev.parent; + unsigned int val; + int clk_src; + + drv_data->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(drv_data->clk)) + return dev_err_probe(dev, PTR_ERR(drv_data->clk), + "Failed to get watchdog clock\n"); + + drv_data->clk_freq = clk_get_rate(drv_data->clk); + if (!drv_data->clk_freq) + return dev_err_probe(dev, -EINVAL, + "Failed to get clock rate\n"); + + clk_src = device_property_read_u32(dev, "andestech,clock-source", &val); + drv_data->clk_src = (!clk_src && val != 0) ? CTRL_CLK_SEL_PCLK : 0; + + return 0; +} + +static int atcwdt_init_wdt_device(struct device *dev, + struct atcwdt_drv *drv_data) +{ + struct watchdog_device *wdd = &drv_data->wdt_dev; + + wdd->parent = dev; + wdd->info = &atcwdt_info; + wdd->ops = &atcwdt_ops; + wdd->timeout = ATCWDT_TIMEOUT; + wdd->min_timeout = 1; + + watchdog_set_nowayout(wdd, nowayout); + watchdog_set_drvdata(wdd, drv_data); + + return 0; +} + +static void atcwdt_calc_max_timeout(struct atcwdt_drv *drv_data) +{ + unsigned char rst_idx = atcwdt_get_index(0xFF, TMR_RST); + unsigned char int_idx = atcwdt_get_index(0xFF, + drv_data->int_timer_type); + + drv_data->wdt_dev.max_timeout = + ((1U << rst_idx) + (1U << int_idx)) / drv_data->clk_freq; +} + +static int atcwdt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct atcwdt_drv *drv_data; + int ret; + + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + platform_set_drvdata(pdev, drv_data); + spin_lock_init(&drv_data->lock); + + ret = atcwdt_init_wdt_device(dev, drv_data); + if (ret) + return ret; + + ret = atcwdt_init_resource(pdev, drv_data); + if (ret) + return ret; + + ret = atcwdt_enable_clk(drv_data); + if (ret) + return ret; + + ret = atcwdt_get_int_timer_type(drv_data); + if (ret) + return ret; + + atcwdt_calc_max_timeout(drv_data); + + ret = devm_watchdog_register_device(dev, &drv_data->wdt_dev); + + return ret; +} + +static int atcwdt_suspend(struct device *dev) +{ + struct atcwdt_drv *drv_data = dev_get_drvdata(dev); + + if (watchdog_active(&drv_data->wdt_dev)) { + atcwdt_stop(&drv_data->wdt_dev); + clk_disable_unprepare(drv_data->clk); + } + + return 0; +} + +static int atcwdt_resume(struct device *dev) +{ + struct atcwdt_drv *drv_data = dev_get_drvdata(dev); + int ret = 0; + + if (watchdog_active(&drv_data->wdt_dev)) { + ret = clk_prepare_enable(drv_data->clk); + if (ret) + return ret; + atcwdt_start(&drv_data->wdt_dev); + atcwdt_ping(&drv_data->wdt_dev); + } + + return ret; +} + +static const struct of_device_id atcwdt_match[] = { + { .compatible = "andestech,ae350-wdt" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, atcwdt_match); + +static DEFINE_SIMPLE_DEV_PM_OPS(atcwdt_pm_ops, atcwdt_suspend, atcwdt_resume); + +static struct platform_driver atcwdt_driver = { + .probe = atcwdt_probe, + .driver = { + .name = DRV_NAME, + .of_match_table = atcwdt_match, + .pm = pm_sleep_ptr(&atcwdt_pm_ops), + }, +}; + +module_platform_driver(atcwdt_driver); + +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=" + __MODULE_STRING(ATCWDT_TIMEOUT) ")"); + +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("CL Wang "); +MODULE_DESCRIPTION("Andes ATCWDT200 Watchdog timer driver"); From b5998b4bc54888528a087db1c2744c69748bd822 Mon Sep 17 00:00:00 2001 From: CL Wang Date: Thu, 15 Jan 2026 16:14:44 +0800 Subject: [PATCH 187/655] MAINTAINERS: Add entry for Andes ATCWDT200 Add a MAINTAINERS entry for the Andes ATCWDT200 watchdog driver and its associated Device Tree bindings. Signed-off-by: CL Wang Link: https://lore.kernel.org/r/20260115081444.2452357-4-cl634@andestech.com Signed-off-by: Guenter Roeck --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f35e1769fa72..358eb89484e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1874,6 +1874,12 @@ S: Supported F: Documentation/devicetree/bindings/spi/andestech,ae350-spi.yaml F: drivers/spi/spi-atcspi200.c +ANDES ATCWDT200 WATCHDOG DRIVER +M: CL Wang +S: Supported +F: Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml +F: drivers/watchdog/atcwdt200_wdt.c + ANDROID DRIVERS M: Greg Kroah-Hartman M: Arve Hjønnevåg From 7b25feb19ce8073193fff6a05a43b5a5c2854b4b Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Tue, 28 Apr 2026 08:49:44 -0400 Subject: [PATCH 188/655] watchdog: lenovo_se10_wdt: Add support for SE10 Gen 2 platform The Lenovo SE10 Gen 2 platform uses a watchdog chip from the same family. Watchdog functionality is the same, so update the driver with the new chip ID. Add the Gen 2 MTM's to enable support on the platform. Tested on SE10 G2. Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20260428124954.1193450-1-mpearson-lenovo@squebb.ca Signed-off-by: Guenter Roeck --- drivers/watchdog/lenovo_se10_wdt.c | 66 +++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/lenovo_se10_wdt.c b/drivers/watchdog/lenovo_se10_wdt.c index cd0500e5080b..99ff01af4124 100644 --- a/drivers/watchdog/lenovo_se10_wdt.c +++ b/drivers/watchdog/lenovo_se10_wdt.c @@ -178,7 +178,7 @@ static int se10_wdt_probe(struct platform_device *pdev) return -EBUSY; chip_id = get_chipID(); - if (chip_id != 0x5632) { + if (chip_id != 0x5632 && chip_id != 0x5652) { release_region(CFG_PORT, CFG_SIZE); return -ENODEV; } @@ -280,6 +280,70 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { }, .callback = se10_create_platform_device, }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13LJ"), + }, + .callback = se10_create_platform_device, + }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13LK"), + }, + .callback = se10_create_platform_device, + }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13S1"), + }, + .callback = se10_create_platform_device, + }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13S2"), + }, + .callback = se10_create_platform_device, + }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13S3"), + }, + .callback = se10_create_platform_device, + }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13S4"), + }, + .callback = se10_create_platform_device, + }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13S5"), + }, + .callback = se10_create_platform_device, + }, + { + .ident = "LENOVO-SE10-G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "13S6"), + }, + .callback = se10_create_platform_device, + }, {} }; MODULE_DEVICE_TABLE(dmi, se10_dmi_table); From 8ff498b2501205964af23ed3949042acfabce5aa Mon Sep 17 00:00:00 2001 From: Deepti Jaggi Date: Mon, 4 May 2026 16:16:43 +0800 Subject: [PATCH 189/655] dt-bindings: watchdog: qcom-wdt: Add compatible for Nord watchdog Document Krait Processor Sub-system (KPSS) Watchdog timer on Nord SoC. Signed-off-by: Deepti Jaggi Signed-off-by: Shawn Guo Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260504081643.826038-1-shengchao.guo@oss.qualcomm.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 1d5d01c2547a..47dea1a29ea8 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -28,6 +28,7 @@ properties: - qcom,apss-wdt-msm8226 - qcom,apss-wdt-msm8974 - qcom,apss-wdt-msm8994 + - qcom,apss-wdt-nord - qcom,apss-wdt-qcm2290 - qcom,apss-wdt-qcs404 - qcom,apss-wdt-qcs615 From d15a35c059ec88642794729225050eedaeec9ff0 Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Tue, 5 May 2026 11:26:12 +0200 Subject: [PATCH 190/655] watchdog: Change suffix .txt to .rst in references Fix link to documentation, which has already been converted to reST. Also remove apostrophes which are no longer needed. Signed-off-by: Philipp Hahn Link: https://lore.kernel.org/r/bb1aa3129d5e52bc4c8e1ec3340b88f80f726fef.1777972790.git.phahn-oss@avm.de Signed-off-by: Guenter Roeck --- Documentation/watchdog/convert_drivers_to_kernel_api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/watchdog/convert_drivers_to_kernel_api.rst b/Documentation/watchdog/convert_drivers_to_kernel_api.rst index e83609a5d007..9eddb962f8e4 100644 --- a/Documentation/watchdog/convert_drivers_to_kernel_api.rst +++ b/Documentation/watchdog/convert_drivers_to_kernel_api.rst @@ -114,7 +114,7 @@ Add the watchdog operations --------------------------- All possible callbacks are defined in 'struct watchdog_ops'. You can find it -explained in 'watchdog-kernel-api.txt' in this directory. start() and +explained in watchdog-kernel-api.rst in this directory. start() and owner must be set, the rest are optional. You will easily find corresponding functions in the old driver. Note that you will now get a pointer to the watchdog_device as a parameter to these functions, so you probably have to @@ -153,7 +153,7 @@ Add the watchdog device Now we need to create a 'struct watchdog_device' and populate it with the necessary information for the framework. The struct is also explained in detail -in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory +in watchdog-kernel-api.rst in this directory. We pass it the mandatory watchdog_info struct and the newly created watchdog_ops. Often, old drivers have their own record-keeping for things like bootstatus and timeout using static variables. Those have to be converted to use the members in From e40714929f638c3b68547260bace7f533fe9f987 Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Tue, 5 May 2026 11:26:13 +0200 Subject: [PATCH 191/655] watchdog: Move `struct` before name Write `struct ` before the structure name as Sphinx otherwise uses the following word after it. See https://docs.kernel.org/watchdog/watchdog-api.html#environmental-monitoring Signed-off-by: Philipp Hahn Link: https://lore.kernel.org/r/e66ec58f3b8252b3676cc9fe68818af95123210c.1777972790.git.phahn-oss@avm.de Signed-off-by: Guenter Roeck --- .../convert_drivers_to_kernel_api.rst | 24 +++++++++---------- Documentation/watchdog/watchdog-api.rst | 2 +- .../watchdog/watchdog-kernel-api.rst | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Documentation/watchdog/convert_drivers_to_kernel_api.rst b/Documentation/watchdog/convert_drivers_to_kernel_api.rst index 9eddb962f8e4..004fe6ef76e9 100644 --- a/Documentation/watchdog/convert_drivers_to_kernel_api.rst +++ b/Documentation/watchdog/convert_drivers_to_kernel_api.rst @@ -11,12 +11,12 @@ This document shall guide you for this task. The necessary steps are described as well as things to look out for. -Remove the file_operations struct +Remove the struct file_operations --------------------------------- Old drivers define their own file_operations for actions like open(), write(), etc... These are now handled by the framework and just call the driver when -needed. So, in general, the 'file_operations' struct and assorted functions can +needed. So, in general, the struct file_operations and assorted functions can go. Only very few driver-specific details have to be moved to other functions. Here is a overview of the functions and probably needed actions: @@ -36,7 +36,7 @@ Here is a overview of the functions and probably needed actions: from the driver: WDIOC_GETSUPPORT: - Returns the mandatory watchdog_info struct from the driver + Returns the mandatory struct watchdog_info from the driver WDIOC_GETSTATUS: Needs the status-callback defined, otherwise returns 0 @@ -88,8 +88,8 @@ refactoring. The rest can go. Remove the miscdevice --------------------- -Since the file_operations are gone now, you can also remove the 'struct -miscdevice'. The framework will create it on watchdog_dev_register() called by +Since the file_operations are gone now, you can also remove the struct +miscdevice. The framework will create it on watchdog_dev_register() called by watchdog_register_device():: -static struct miscdevice s3c2410wdt_miscdev = { @@ -113,10 +113,10 @@ them. Includes can be removed, too. For example:: Add the watchdog operations --------------------------- -All possible callbacks are defined in 'struct watchdog_ops'. You can find it +All possible callbacks are defined in struct watchdog_ops. You can find it explained in watchdog-kernel-api.rst in this directory. start() and owner must be set, the rest are optional. You will easily find corresponding -functions in the old driver. Note that you will now get a pointer to the +functions in the old driver. Note that you will now get a pointer to the struct watchdog_device as a parameter to these functions, so you probably have to change the function header. Other changes are most likely not needed, because here simply happens the direct hardware access. If you have device-specific @@ -151,12 +151,12 @@ A typical function-header change looks like:: Add the watchdog device ----------------------- -Now we need to create a 'struct watchdog_device' and populate it with the -necessary information for the framework. The struct is also explained in detail +Now we need to create a struct watchdog_device and populate it with the +necessary information for the framework. The structure is also explained in detail in watchdog-kernel-api.rst in this directory. We pass it the mandatory -watchdog_info struct and the newly created watchdog_ops. Often, old drivers +struct watchdog_info and the newly created struct watchdog_ops. Often, old drivers have their own record-keeping for things like bootstatus and timeout using -static variables. Those have to be converted to use the members in +static variables. Those have to be converted to use the members in struct watchdog_device. Note that the timeout values are unsigned int. Some drivers use signed int, so this has to be converted, too. @@ -174,7 +174,7 @@ Handle the 'nowayout' feature A few drivers use nowayout statically, i.e. there is no module parameter for it and only CONFIG_WATCHDOG_NOWAYOUT determines if the feature is going to be used. This needs to be converted by initializing the status variable of the -watchdog_device like this:: +struct watchdog_device like this:: .status = WATCHDOG_NOWAYOUT_INIT_STATUS, diff --git a/Documentation/watchdog/watchdog-api.rst b/Documentation/watchdog/watchdog-api.rst index 984f7362d5fb..f732cd6e37ae 100644 --- a/Documentation/watchdog/watchdog-api.rst +++ b/Documentation/watchdog/watchdog-api.rst @@ -158,7 +158,7 @@ available to ask what the device can do:: struct watchdog_info ident; ioctl(fd, WDIOC_GETSUPPORT, &ident); -the fields returned in the ident struct are: +the fields returned in the struct watchdog_info are: ================ ============================================= identity a string identifying the watchdog driver diff --git a/Documentation/watchdog/watchdog-kernel-api.rst b/Documentation/watchdog/watchdog-kernel-api.rst index 5649c54cf6fb..e2c1386c9550 100644 --- a/Documentation/watchdog/watchdog-kernel-api.rst +++ b/Documentation/watchdog/watchdog-kernel-api.rst @@ -257,7 +257,7 @@ bit-operations. The status bits that are defined are: To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog timer device) you can either: - * set it statically in your watchdog_device struct with + * set it statically in your struct watchdog_device with .status = WATCHDOG_NOWAYOUT_INIT_STATUS, From e46082426b09a019862714a6518e792ef16cc72a Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Tue, 5 May 2026 11:26:14 +0200 Subject: [PATCH 192/655] watchdog: Replace intermixed tab/space indent Consistently indent all lines with tabs instead of having one line using blanks. Signed-off-by: Philipp Hahn Link: https://lore.kernel.org/r/e1ccbfb0efb9a9f508d1afe10263af1578a1aa46.1777972790.git.phahn-oss@avm.de Signed-off-by: Guenter Roeck --- Documentation/watchdog/watchdog-api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/watchdog/watchdog-api.rst b/Documentation/watchdog/watchdog-api.rst index f732cd6e37ae..9acf7fe1fb58 100644 --- a/Documentation/watchdog/watchdog-api.rst +++ b/Documentation/watchdog/watchdog-api.rst @@ -161,7 +161,7 @@ available to ask what the device can do:: the fields returned in the struct watchdog_info are: ================ ============================================= - identity a string identifying the watchdog driver + identity a string identifying the watchdog driver firmware_version the firmware version of the card if available options a flags describing what the device supports ================ ============================================= From dfc93986a5cbb376fa6c4d35ce092c947fa77943 Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Tue, 5 May 2026 11:26:15 +0200 Subject: [PATCH 193/655] watchdog: Separate kind of documentation Currently there are several (sub-)documents for "Generic kernel infrastructure API" and several "driver specific" documents. Put each one into its own sub-section. Signed-off-by: Philipp Hahn Link: https://lore.kernel.org/r/7d1b722205bab83603832e66750f7b5f1f73eaa5.1777972790.git.phahn-oss@avm.de Signed-off-by: Guenter Roeck --- Documentation/watchdog/index.rst | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Documentation/watchdog/index.rst b/Documentation/watchdog/index.rst index 1cea24681e6b..293ed05ba6b8 100644 --- a/Documentation/watchdog/index.rst +++ b/Documentation/watchdog/index.rst @@ -4,15 +4,25 @@ Watchdog Support ================ +Kernel infrastructure +===================== + .. toctree:: :maxdepth: 1 - hpwdt - mlx-wdt - pcwd-watchdog watchdog-api watchdog-kernel-api - watchdog-parameters watchdog-pm - wdt convert_drivers_to_kernel_api + +Driver specific +=============== + +.. toctree:: + :maxdepth: 1 + + watchdog-parameters + hpwdt + wdt + mlx-wdt + pcwd-watchdog From 44c94a7e11a52e915731458a636537bc4d13cb95 Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Tue, 5 May 2026 11:26:16 +0200 Subject: [PATCH 194/655] watchdog: Prefix WDT with ICS for clarity `wdt.rst` is only about the Watchdog from "Industrial Computer Source" (ICS). Change the title and rename the file to better express this. Add missing SPDX license identifier `GPL-2.0-or-later` same as code to silence `checkpatch`. Fix wrong link to sample driver in drivers/watchdog/smsc37b787_wdt.c. Signed-off-by: Philipp Hahn Link: https://lore.kernel.org/r/5a71979d8e8ab8e0a30de33f6aa2540b3b5dc1ee.1777972790.git.phahn-oss@avm.de Signed-off-by: Guenter Roeck --- Documentation/watchdog/{wdt.rst => ics-wdt.rst} | 8 +++++--- Documentation/watchdog/index.rst | 2 +- drivers/watchdog/Kconfig | 10 ++++++---- drivers/watchdog/smsc37b787_wdt.c | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) rename Documentation/watchdog/{wdt.rst => ics-wdt.rst} (91%) diff --git a/Documentation/watchdog/wdt.rst b/Documentation/watchdog/ics-wdt.rst similarity index 91% rename from Documentation/watchdog/wdt.rst rename to Documentation/watchdog/ics-wdt.rst index d97b0361535b..b0dc29e56358 100644 --- a/Documentation/watchdog/wdt.rst +++ b/Documentation/watchdog/ics-wdt.rst @@ -1,6 +1,8 @@ -============================================================ -WDT Watchdog Timer Interfaces For The Linux Operating System -============================================================ +.. SPDX-License-Identifier: GPL-2.0-or-later + +========================================== +Industrial Computer Source Watchdog Driver +========================================== Last Reviewed: 10/05/2007 diff --git a/Documentation/watchdog/index.rst b/Documentation/watchdog/index.rst index 293ed05ba6b8..dbc702b31a43 100644 --- a/Documentation/watchdog/index.rst +++ b/Documentation/watchdog/index.rst @@ -23,6 +23,6 @@ Driver specific watchdog-parameters hpwdt - wdt + ics-wdt mlx-wdt pcwd-watchdog diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index eb8eb307e04d..4c204951bc95 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -2266,10 +2266,11 @@ config MIXCOMWD Most people will say N. config WDT - tristate "WDT Watchdog timer" + tristate "ICS WDT500P/501P Watchdog timer" depends on ISA help - If you have a WDT500P or WDT501P watchdog board, say Y here, + If you have an Industrial Computer Source (ICS) WDT500P or WDT501P + watchdog board, say Y here, otherwise N. It is not possible to probe for this board, which means that you have to inform the kernel about the IO port and IRQ that is needed (you can do this via the io and irq parameters) @@ -2300,10 +2301,11 @@ config PCIPCWATCHDOG Most people will say N. config WDTPCI - tristate "PCI-WDT500/501 Watchdog timer" + tristate "ICS PCI-WDT500/501 Watchdog timer" depends on PCI && HAS_IOPORT help - If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N. + If you have an Industrial Computer Source (ICS) PCI-WDT500/501 watchdog + board, say Y here, otherwise N. If you have a PCI-WDT501 watchdog board then you can enable the temperature sensor by setting the type parameter to 501. diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c index 3011e1af00f9..9f2c2ab4e2f1 100644 --- a/drivers/watchdog/smsc37b787_wdt.c +++ b/drivers/watchdog/smsc37b787_wdt.c @@ -36,7 +36,7 @@ * mknod /dev/watchdog c 10 130 * * For an example userspace keep-alive daemon, see: - * Documentation/watchdog/wdt.rst + * samples/watchdog/watchdog-simple.c */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt From 5e5b01ae7a70859fc6ab8a62ac922c232de70970 Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Fri, 1 May 2026 23:35:49 +0530 Subject: [PATCH 195/655] dt-bindings: watchdog: qcom-wdt: Document Shikra watchdog Add devicetree binding for watchdog present on Qualcomm's Shikra SoC Signed-off-by: Komal Bajaj Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260501-shikra-wdog-binding-v1-1-fd8c14bc2d20@oss.qualcomm.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 47dea1a29ea8..b3f8f063f282 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -42,6 +42,7 @@ properties: - qcom,apss-wdt-sdm845 - qcom,apss-wdt-sdx55 - qcom,apss-wdt-sdx65 + - qcom,apss-wdt-shikra - qcom,apss-wdt-sm6115 - qcom,apss-wdt-sm6350 - qcom,apss-wdt-sm8150 From 3394e894880a60338a2981dd688fd25e88d79667 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Mon, 4 May 2026 14:01:42 -0400 Subject: [PATCH 196/655] watchdog: lenovo_se10_wdt: Fix use-after-free and resource leak risk Review by sashiko.dev highlighted potential use after free and resource leak instances. Set se10_pdev to null to prevent use after free Remove DMI call back and instead directly call se10_create_platform_device. Handle error cases appropriately Link: https://sashiko.dev/#/patchset/20260428124954.1193450-1-mpearson-lenovo%40squebb.ca Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20260504180159.999189-1-mpearson-lenovo@squebb.ca Signed-off-by: Guenter Roeck --- drivers/watchdog/lenovo_se10_wdt.c | 32 ++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/watchdog/lenovo_se10_wdt.c b/drivers/watchdog/lenovo_se10_wdt.c index 99ff01af4124..503e220263f9 100644 --- a/drivers/watchdog/lenovo_se10_wdt.c +++ b/drivers/watchdog/lenovo_se10_wdt.c @@ -224,7 +224,7 @@ static struct platform_driver se10_wdt_driver = { .probe = se10_wdt_probe, }; -static int se10_create_platform_device(const struct dmi_system_id *id) +static int se10_create_platform_device(void) { int err; @@ -233,9 +233,10 @@ static int se10_create_platform_device(const struct dmi_system_id *id) return -ENOMEM; err = platform_device_add(se10_pdev); - if (err) + if (err) { platform_device_put(se10_pdev); - + se10_pdev = NULL; + } return err; } @@ -246,7 +247,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "12NH"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10", @@ -254,7 +254,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "12NJ"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10", @@ -262,7 +261,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "12NK"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10", @@ -270,7 +268,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "12NL"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10", @@ -278,7 +275,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "12NM"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -286,7 +282,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13LJ"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -294,7 +289,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13LK"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -302,7 +296,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13S1"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -310,7 +303,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13S2"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -318,7 +310,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13S3"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -326,7 +317,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13S4"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -334,7 +324,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13S5"), }, - .callback = se10_create_platform_device, }, { .ident = "LENOVO-SE10-G2", @@ -342,7 +331,6 @@ static const struct dmi_system_id se10_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "13S6"), }, - .callback = se10_create_platform_device, }, {} }; @@ -350,10 +338,20 @@ MODULE_DEVICE_TABLE(dmi, se10_dmi_table); static int __init se10_wdt_init(void) { + int err; + if (!dmi_check_system(se10_dmi_table)) return -ENODEV; - return platform_driver_register(&se10_wdt_driver); + err = platform_driver_register(&se10_wdt_driver); + if (err) + return err; + + err = se10_create_platform_device(); + if (err) + platform_driver_unregister(&se10_wdt_driver); + + return err; } static void __exit se10_wdt_exit(void) From 550c3bcdda0e9e3b3258b2fa9da040a96db058fb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 5 May 2026 09:23:43 -0700 Subject: [PATCH 197/655] watchdog: Remove AMD Elan SC520 processor watchdog driver AMD Elan support was removed from the upstream kernel with commit 8b793a92d862 ("x86/cpu: Remove M486/M486SX/ELAN support"). Its watchdog driver can no longer be enabled except for test builds. Remove it. Signed-off-by: Guenter Roeck --- .../watchdog/watchdog-parameters.rst | 9 - drivers/watchdog/Kconfig | 13 - drivers/watchdog/Makefile | 1 - drivers/watchdog/sc520_wdt.c | 430 ------------------ 4 files changed, 453 deletions(-) delete mode 100644 drivers/watchdog/sc520_wdt.c diff --git a/Documentation/watchdog/watchdog-parameters.rst b/Documentation/watchdog/watchdog-parameters.rst index 173adee71901..8482cc976ce0 100644 --- a/Documentation/watchdog/watchdog-parameters.rst +++ b/Documentation/watchdog/watchdog-parameters.rst @@ -522,15 +522,6 @@ sc1200wdt: ------------------------------------------------- -sc520_wdt: - timeout: - Watchdog timeout in seconds. (1 <= timeout <= 3600, default=30) - nowayout: - Watchdog cannot be stopped once started - (default=kernel config parameter) - -------------------------------------------------- - sch311x_wdt: force_id: Override the detected device ID diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 4c204951bc95..d1d2cdbd1995 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1270,19 +1270,6 @@ config GEODE_WDT You can compile this driver directly into the kernel, or use it as a module. The module will be called geodewdt. -config SC520_WDT - tristate "AMD Elan SC520 processor Watchdog" - depends on MELAN || COMPILE_TEST - help - This is the driver for the hardware watchdog built in to the - AMD "Elan" SC520 microcomputer commonly used in embedded systems. - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called sc520_wdt. - config SBC_FITPC2_WATCHDOG tristate "Compulab SBC-FITPC2 watchdog" depends on (X86 || COMPILE_TEST) && HAS_IOPORT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index a4341b251bdf..bc1d52220f22 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -117,7 +117,6 @@ obj-$(CONFIG_EXAR_WDT) += exar_wdt.o obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o obj-$(CONFIG_GEODE_WDT) += geodewdt.o -obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_IB700_WDT) += ib700wdt.o diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c deleted file mode 100644 index 005f62e4a4fb..000000000000 --- a/drivers/watchdog/sc520_wdt.c +++ /dev/null @@ -1,430 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * AMD Elan SC520 processor Watchdog Timer driver - * - * Based on acquirewdt.c by Alan Cox, - * and sbc60xxwdt.c by Jakob Oestergaard - * - * The authors do NOT admit liability nor provide warranty for - * any of this software. This material is provided "AS-IS" in - * the hope that it may be useful for others. - * - * (c) Copyright 2001 Scott Jennings - * 9/27 - 2001 [Initial release] - * - * Additional fixes Alan Cox - * - Fixed formatting - * - Removed debug printks - * - Fixed SMP built kernel deadlock - * - Switched to private locks not lock_kernel - * - Used ioremap/writew/readw - * - Added NOWAYOUT support - * 4/12 - 2002 Changes by Rob Radez - * - Change comments - * - Eliminate fop_llseek - * - Change CONFIG_WATCHDOG_NOWAYOUT semantics - * - Add KERN_* tags to printks - * - fix possible wdt_is_open race - * - Report proper capabilities in watchdog_info - * - Add WDIOC_{GETSTATUS, GETBOOTSTATUS, SETTIMEOUT, - * GETTIMEOUT, SETOPTIONS} ioctls - * 09/8 - 2003 Changes by Wim Van Sebroeck - * - cleanup of trailing spaces - * - added extra printk's for startup problems - * - use module_param - * - made timeout (the emulated heartbeat) a module_param - * - made the keepalive ping an internal subroutine - * 3/27 - 2004 Changes by Sean Young - * - set MMCR_BASE to 0xfffef000 - * - CBAR does not need to be read - * - removed debugging printks - * - * This WDT driver is different from most other Linux WDT - * drivers in that the driver will ping the watchdog by itself, - * because this particular WDT has a very short timeout (1.6 - * seconds) and it would be insane to count on any userspace - * daemon always getting scheduled within that time frame. - * - * This driver uses memory mapped IO, and spinlock. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7) - * - * 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s - * 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s - * - * We will program the SC520 watchdog for a timeout of 2.01s. - * If we reset the watchdog every ~250ms we should be safe. - */ - -#define WDT_INTERVAL (HZ/4+1) - -/* - * We must not require too good response from the userspace daemon. - * Here we require the userspace daemon to send us a heartbeat - * char to /dev/watchdog every 30 seconds. - */ - -#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ -/* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ -static int timeout = WATCHDOG_TIMEOUT; -module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, - "Watchdog timeout in seconds. (1 <= timeout <= 3600, default=" - __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); - -static bool nowayout = WATCHDOG_NOWAYOUT; -module_param(nowayout, bool, 0); -MODULE_PARM_DESC(nowayout, - "Watchdog cannot be stopped once started (default=" - __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); - -/* - * AMD Elan SC520 - Watchdog Timer Registers - */ -#define MMCR_BASE 0xfffef000 /* The default base address */ -#define OFFS_WDTMRCTL 0xCB0 /* Watchdog Timer Control Register */ - -/* WDT Control Register bit definitions */ -#define WDT_EXP_SEL_01 0x0001 /* [01] Time-out = 496 us (with 33 Mhz clk). */ -#define WDT_EXP_SEL_02 0x0002 /* [02] Time-out = 508 ms (with 33 Mhz clk). */ -#define WDT_EXP_SEL_03 0x0004 /* [03] Time-out = 1.02 s (with 33 Mhz clk). */ -#define WDT_EXP_SEL_04 0x0008 /* [04] Time-out = 2.03 s (with 33 Mhz clk). */ -#define WDT_EXP_SEL_05 0x0010 /* [05] Time-out = 4.07 s (with 33 Mhz clk). */ -#define WDT_EXP_SEL_06 0x0020 /* [06] Time-out = 8.13 s (with 33 Mhz clk). */ -#define WDT_EXP_SEL_07 0x0040 /* [07] Time-out = 16.27s (with 33 Mhz clk). */ -#define WDT_EXP_SEL_08 0x0080 /* [08] Time-out = 32.54s (with 33 Mhz clk). */ -#define WDT_IRQ_FLG 0x1000 /* [12] Interrupt Request Flag */ -#define WDT_WRST_ENB 0x4000 /* [14] Watchdog Timer Reset Enable */ -#define WDT_ENB 0x8000 /* [15] Watchdog Timer Enable */ - -static __u16 __iomem *wdtmrctl; - -static void wdt_timer_ping(struct timer_list *); -static DEFINE_TIMER(timer, wdt_timer_ping); -static unsigned long next_heartbeat; -static unsigned long wdt_is_open; -static char wdt_expect_close; -static DEFINE_SPINLOCK(wdt_spinlock); - -/* - * Whack the dog - */ - -static void wdt_timer_ping(struct timer_list *unused) -{ - /* If we got a heartbeat pulse within the WDT_US_INTERVAL - * we agree to ping the WDT - */ - if (time_before(jiffies, next_heartbeat)) { - /* Ping the WDT */ - spin_lock(&wdt_spinlock); - writew(0xAAAA, wdtmrctl); - writew(0x5555, wdtmrctl); - spin_unlock(&wdt_spinlock); - - /* Re-set the timer interval */ - mod_timer(&timer, jiffies + WDT_INTERVAL); - } else - pr_warn("Heartbeat lost! Will not ping the watchdog\n"); -} - -/* - * Utility routines - */ - -static void wdt_config(int writeval) -{ - unsigned long flags; - - /* buy some time (ping) */ - spin_lock_irqsave(&wdt_spinlock, flags); - readw(wdtmrctl); /* ensure write synchronization */ - writew(0xAAAA, wdtmrctl); - writew(0x5555, wdtmrctl); - /* unlock WDT = make WDT configuration register writable one time */ - writew(0x3333, wdtmrctl); - writew(0xCCCC, wdtmrctl); - /* write WDT configuration register */ - writew(writeval, wdtmrctl); - spin_unlock_irqrestore(&wdt_spinlock, flags); -} - -static int wdt_startup(void) -{ - next_heartbeat = jiffies + (timeout * HZ); - - /* Start the timer */ - mod_timer(&timer, jiffies + WDT_INTERVAL); - - /* Start the watchdog */ - wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04); - - pr_info("Watchdog timer is now enabled\n"); - return 0; -} - -static int wdt_turnoff(void) -{ - /* Stop the timer */ - timer_delete_sync(&timer); - - /* Stop the watchdog */ - wdt_config(0); - - pr_info("Watchdog timer is now disabled...\n"); - return 0; -} - -static int wdt_keepalive(void) -{ - /* user land ping */ - next_heartbeat = jiffies + (timeout * HZ); - return 0; -} - -static int wdt_set_heartbeat(int t) -{ - if ((t < 1) || (t > 3600)) /* arbitrary upper limit */ - return -EINVAL; - - timeout = t; - return 0; -} - -/* - * /dev/watchdog handling - */ - -static ssize_t fop_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - /* See if we got the magic character 'V' and reload the timer */ - if (count) { - if (!nowayout) { - size_t ofs; - - /* note: just in case someone wrote the magic character - * five months ago... */ - wdt_expect_close = 0; - - /* now scan */ - for (ofs = 0; ofs != count; ofs++) { - char c; - if (get_user(c, buf + ofs)) - return -EFAULT; - if (c == 'V') - wdt_expect_close = 42; - } - } - - /* Well, anyhow someone wrote to us, we should - return that favour */ - wdt_keepalive(); - } - return count; -} - -static int fop_open(struct inode *inode, struct file *file) -{ - /* Just in case we're already talking to someone... */ - if (test_and_set_bit(0, &wdt_is_open)) - return -EBUSY; - if (nowayout) - __module_get(THIS_MODULE); - - /* Good, fire up the show */ - wdt_startup(); - return stream_open(inode, file); -} - -static int fop_close(struct inode *inode, struct file *file) -{ - if (wdt_expect_close == 42) - wdt_turnoff(); - else { - pr_crit("Unexpected close, not stopping watchdog!\n"); - wdt_keepalive(); - } - clear_bit(0, &wdt_is_open); - wdt_expect_close = 0; - return 0; -} - -static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int __user *p = argp; - static const struct watchdog_info ident = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT - | WDIOF_MAGICCLOSE, - .firmware_version = 1, - .identity = "SC520", - }; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_SETOPTIONS: - { - int new_options, retval = -EINVAL; - - if (get_user(new_options, p)) - return -EFAULT; - - if (new_options & WDIOS_DISABLECARD) { - wdt_turnoff(); - retval = 0; - } - - if (new_options & WDIOS_ENABLECARD) { - wdt_startup(); - retval = 0; - } - - return retval; - } - case WDIOC_KEEPALIVE: - wdt_keepalive(); - return 0; - case WDIOC_SETTIMEOUT: - { - int new_timeout; - - if (get_user(new_timeout, p)) - return -EFAULT; - - if (wdt_set_heartbeat(new_timeout)) - return -EINVAL; - - wdt_keepalive(); - } - fallthrough; - case WDIOC_GETTIMEOUT: - return put_user(timeout, p); - default: - return -ENOTTY; - } -} - -static const struct file_operations wdt_fops = { - .owner = THIS_MODULE, - .write = fop_write, - .open = fop_open, - .release = fop_close, - .unlocked_ioctl = fop_ioctl, - .compat_ioctl = compat_ptr_ioctl, -}; - -static struct miscdevice wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &wdt_fops, -}; - -/* - * Notifier for system down - */ - -static int wdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - wdt_turnoff(); - return NOTIFY_DONE; -} - -/* - * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block wdt_notifier = { - .notifier_call = wdt_notify_sys, -}; - -static void __exit sc520_wdt_unload(void) -{ - if (!nowayout) - wdt_turnoff(); - - /* Deregister */ - misc_deregister(&wdt_miscdev); - unregister_reboot_notifier(&wdt_notifier); - iounmap(wdtmrctl); -} - -static int __init sc520_wdt_init(void) -{ - int rc = -EBUSY; - - /* Check that the timeout value is within it's range ; - if not reset to the default */ - if (wdt_set_heartbeat(timeout)) { - wdt_set_heartbeat(WATCHDOG_TIMEOUT); - pr_info("timeout value must be 1 <= timeout <= 3600, using %d\n", - WATCHDOG_TIMEOUT); - } - - wdtmrctl = ioremap(MMCR_BASE + OFFS_WDTMRCTL, 2); - if (!wdtmrctl) { - pr_err("Unable to remap memory\n"); - rc = -ENOMEM; - goto err_out_region2; - } - - rc = register_reboot_notifier(&wdt_notifier); - if (rc) { - pr_err("cannot register reboot notifier (err=%d)\n", rc); - goto err_out_ioremap; - } - - rc = misc_register(&wdt_miscdev); - if (rc) { - pr_err("cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, rc); - goto err_out_notifier; - } - - pr_info("WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n", - timeout, nowayout); - - return 0; - -err_out_notifier: - unregister_reboot_notifier(&wdt_notifier); -err_out_ioremap: - iounmap(wdtmrctl); -err_out_region2: - return rc; -} - -module_init(sc520_wdt_init); -module_exit(sc520_wdt_unload); - -MODULE_AUTHOR("Scott and Bill Jennings"); -MODULE_DESCRIPTION( - "Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor"); -MODULE_LICENSE("GPL"); From 63e07a8ecb1ea9ac5cdcb267244716d38c942b30 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 6 May 2026 10:16:00 +0200 Subject: [PATCH 198/655] watchdog: convert the Kconfig dependency on OF_GPIO to OF OF_GPIO is selected automatically on all OF systems. Any symbols it controls also provide stubs so there's really no reason to select it explicitly. We could simply remove the dependency but in order to avoid a new symbol popping up for everyone in make config - just convert it to requiring CONFIG_OF. Reviewed-by: Guenter Roeck Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20260506081600.4921-1-bartosz.golaszewski@oss.qualcomm.com [groeck: Resolved conflict; updated dependencies to require OF _or_ ACPI] Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d1d2cdbd1995..a8fc1d7a5031 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -250,7 +250,7 @@ config DA9062_WATCHDOG config GPIO_WATCHDOG tristate "Watchdog device controlled through GPIO-line" - depends on (ACPI && GPIOLIB) || OF_GPIO + depends on GPIOLIB && (ACPI || OF) select WATCHDOG_CORE help If you say yes here you get support for watchdog device From 29d71b732bdc43f0c13a4e7258c007bf841a2d29 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 6 May 2026 11:24:20 +0200 Subject: [PATCH 199/655] dt-bindings: watchdog: Add watchdog compatible for RK3528 The RK3528 uses the same watchdog block as all previous Rockchip SoCs. So add a compatible for it to the soc-list. Signed-off-by: Jonas Karlman Signed-off-by: Heiko Stuebner Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20260506092420.3320031-1-heiko@sntech.de Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml index 141c72909b15..9d25f5e497e2 100644 --- a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml @@ -29,6 +29,7 @@ properties: - rockchip,rk3368-wdt - rockchip,rk3399-wdt - rockchip,rk3506-wdt + - rockchip,rk3528-wdt - rockchip,rk3562-wdt - rockchip,rk3568-wdt - rockchip,rk3576-wdt From fafd036b80a7c85aa86763e70a1a608aa398a144 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 7 May 2026 12:24:08 +0200 Subject: [PATCH 200/655] watchdog: rzn1: remove now obsolete interrupt support Previously, it was overlooked that the watchdog could reset the system directly. So, a workaround using the interrupt which called emergency_restart() was implemented. We now configure the controller when booting properly to allow watchdog resets directly. Thus, remove the interrupt workaround. Signed-off-by: Wolfram Sang Reviewed-by: Herve Codina Link: https://lore.kernel.org/r/20260507102410.43384-4-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- drivers/watchdog/rzn1_wdt.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/watchdog/rzn1_wdt.c b/drivers/watchdog/rzn1_wdt.c index 48d5afef62a5..4fdc5363ba98 100644 --- a/drivers/watchdog/rzn1_wdt.c +++ b/drivers/watchdog/rzn1_wdt.c @@ -79,14 +79,6 @@ static int rzn1_wdt_start(struct watchdog_device *w) return 0; } -static irqreturn_t rzn1_wdt_irq(int irq, void *_wdt) -{ - pr_crit("RZN1 Watchdog. Initiating system reboot\n"); - emergency_restart(); - - return IRQ_HANDLED; -} - static struct watchdog_info rzn1_wdt_info = { .identity = "RZ/N1 Watchdog", .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, @@ -101,12 +93,10 @@ static const struct watchdog_ops rzn1_wdt_ops = { static int rzn1_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; struct rzn1_watchdog *wdt; unsigned long clk_rate; struct clk *clk; int ret; - int irq; wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); if (!wdt) @@ -116,15 +106,6 @@ static int rzn1_wdt_probe(struct platform_device *pdev) if (IS_ERR(wdt->base)) return PTR_ERR(wdt->base); - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_irq(dev, irq, rzn1_wdt_irq, 0, - np->name, wdt); - if (ret) - return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); - clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "failed to get the clock\n"); From 4af89d7d8552a1f0437521acf89fa51601bce973 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:50 +0200 Subject: [PATCH 201/655] spi: pic32: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-2-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-pic32.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index 70427e529945..972128271e4b 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -752,7 +752,7 @@ static int pic32_spi_probe(struct platform_device *pdev) struct pic32_spi *pic32s; int ret; - host = spi_alloc_host(&pdev->dev, sizeof(*pic32s)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*pic32s)); if (!host) return -ENOMEM; @@ -761,7 +761,7 @@ static int pic32_spi_probe(struct platform_device *pdev) ret = pic32_spi_hw_probe(pdev, pic32s); if (ret) - goto err_host; + return ret; host->dev.of_node = pdev->dev.of_node; host->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH; @@ -833,8 +833,7 @@ static int pic32_spi_probe(struct platform_device *pdev) err_bailout: pic32_spi_dma_unprep(pic32s); -err_host: - spi_controller_put(host); + return ret; } @@ -842,14 +841,10 @@ static void pic32_spi_remove(struct platform_device *pdev) { struct pic32_spi *pic32s = platform_get_drvdata(pdev); - spi_controller_get(pic32s->host); - spi_unregister_controller(pic32s->host); pic32_spi_disable(pic32s); pic32_spi_dma_unprep(pic32s); - - spi_controller_put(pic32s->host); } static const struct of_device_id pic32_spi_of_match[] = { From dda3a77e1a32b329d3c543a1ac236106acf64ec5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:51 +0200 Subject: [PATCH 202/655] spi: pic32-sqi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-3-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-pic32-sqi.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index 41662992dbe5..5d3921e29461 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -572,7 +572,7 @@ static int pic32_sqi_probe(struct platform_device *pdev) struct pic32_sqi *sqi; int ret; - host = spi_alloc_host(&pdev->dev, sizeof(*sqi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*sqi)); if (!host) return -ENOMEM; @@ -580,31 +580,25 @@ static int pic32_sqi_probe(struct platform_device *pdev) sqi->host = host; sqi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(sqi->regs)) { - ret = PTR_ERR(sqi->regs); - goto err_free_host; - } + if (IS_ERR(sqi->regs)) + return PTR_ERR(sqi->regs); /* irq */ sqi->irq = platform_get_irq(pdev, 0); - if (sqi->irq < 0) { - ret = sqi->irq; - goto err_free_host; - } + if (sqi->irq < 0) + return sqi->irq; /* clocks */ sqi->sys_clk = devm_clk_get_enabled(&pdev->dev, "reg_ck"); if (IS_ERR(sqi->sys_clk)) { - ret = PTR_ERR(sqi->sys_clk); dev_err(&pdev->dev, "no sys_clk ?\n"); - goto err_free_host; + return PTR_ERR(sqi->sys_clk); } sqi->base_clk = devm_clk_get_enabled(&pdev->dev, "spi_ck"); if (IS_ERR(sqi->base_clk)) { - ret = PTR_ERR(sqi->base_clk); dev_err(&pdev->dev, "no base clk ?\n"); - goto err_free_host; + return PTR_ERR(sqi->base_clk); } init_completion(&sqi->xfer_done); @@ -616,7 +610,7 @@ static int pic32_sqi_probe(struct platform_device *pdev) ret = ring_desc_ring_alloc(sqi); if (ret) { dev_err(&pdev->dev, "ring alloc failed\n"); - goto err_free_host; + return ret; } /* install irq handlers */ @@ -656,8 +650,6 @@ static int pic32_sqi_probe(struct platform_device *pdev) err_free_ring: ring_desc_ring_free(sqi); -err_free_host: - spi_controller_put(host); return ret; } @@ -665,15 +657,11 @@ static void pic32_sqi_remove(struct platform_device *pdev) { struct pic32_sqi *sqi = platform_get_drvdata(pdev); - spi_controller_get(sqi->host); - spi_unregister_controller(sqi->host); /* release resources */ free_irq(sqi->irq, sqi); ring_desc_ring_free(sqi); - - spi_controller_put(sqi->host); } static const struct of_device_id pic32_sqi_of_ids[] = { From 02efc5557c8e4202b1c5d260ec532986e9769897 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:52 +0200 Subject: [PATCH 203/655] spi: pl022: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20260505072909.618363-4-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 9c0211f94fd0..95652df5fd09 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1868,7 +1868,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) } /* Allocate host with space for data */ - host = spi_alloc_host(dev, sizeof(struct pl022)); + host = devm_spi_alloc_host(dev, sizeof(struct pl022)); if (host == NULL) { dev_err(&adev->dev, "probe - cannot alloc SPI host\n"); return -ENOMEM; @@ -1907,7 +1907,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) status = amba_request_regions(adev, NULL); if (status) - goto err_no_ioregion; + return status; pl022->phybase = adev->res.start; pl022->virtbase = devm_ioremap(dev, adev->res.start, @@ -1984,8 +1984,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) err_no_clk: err_no_ioremap: amba_release_regions(adev); - err_no_ioregion: - spi_controller_put(host); + return status; } @@ -1997,8 +1996,6 @@ pl022_remove(struct amba_device *adev) if (!pl022) return; - spi_controller_get(pl022->host); - spi_unregister_controller(pl022->host); /* @@ -2012,8 +2009,6 @@ pl022_remove(struct amba_device *adev) pl022_dma_remove(pl022); amba_release_regions(adev); - - spi_controller_put(pl022->host); } #ifdef CONFIG_PM_SLEEP From 86e8160240af1143e0a9f185e45ac300fe0d93a6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:53 +0200 Subject: [PATCH 204/655] spi: qup: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-5-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 45d9b4cb75e4..4df01ef2e662 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1071,11 +1071,9 @@ static int spi_qup_probe(struct platform_device *pdev) if (ret && ret != -ENODEV) return dev_err_probe(dev, ret, "invalid OPP table\n"); - host = spi_alloc_host(dev, sizeof(struct spi_qup)); - if (!host) { - dev_err(dev, "cannot allocate host\n"); + host = devm_spi_alloc_host(dev, sizeof(struct spi_qup)); + if (!host) return -ENOMEM; - } /* use num-cs unless not present or out of range */ if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) || @@ -1108,7 +1106,7 @@ static int spi_qup_probe(struct platform_device *pdev) ret = spi_qup_init_dma(host, res->start); if (ret == -EPROBE_DEFER) - goto error; + return ret; else if (!ret) host->can_dma = spi_qup_can_dma; @@ -1206,8 +1204,7 @@ error_clk: clk_disable_unprepare(iclk); error_dma: spi_qup_release_dma(host); -error: - spi_controller_put(host); + return ret; } @@ -1320,8 +1317,6 @@ static void spi_qup_remove(struct platform_device *pdev) struct spi_qup *controller = spi_controller_get_devdata(host); int ret; - spi_controller_get(host); - spi_unregister_controller(host); ret = pm_runtime_get_sync(&pdev->dev); @@ -1343,8 +1338,6 @@ static void spi_qup_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); - - spi_controller_put(host); } static const struct of_device_id spi_qup_dt_match[] = { From 368d0e6c6f82a090b3fb080929f4478217e597e8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:54 +0200 Subject: [PATCH 205/655] spi: rspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-6-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index a8180dece716..951e9a8af547 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1171,14 +1171,10 @@ static void rspi_remove(struct platform_device *pdev) { struct rspi_data *rspi = platform_get_drvdata(pdev); - spi_controller_get(rspi->ctlr); - spi_unregister_controller(rspi->ctlr); rspi_release_dma(rspi->ctlr); pm_runtime_disable(&pdev->dev); - - spi_controller_put(rspi->ctlr); } static const struct spi_ops rspi_ops = { @@ -1294,7 +1290,7 @@ static int rspi_probe(struct platform_device *pdev) const struct spi_ops *ops; unsigned long clksrc; - ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rspi_data)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(struct rspi_data)); if (ctlr == NULL) return -ENOMEM; @@ -1302,7 +1298,7 @@ static int rspi_probe(struct platform_device *pdev) if (ops) { ret = rspi_parse_dt(&pdev->dev, ctlr); if (ret) - goto error1; + return ret; } else { ops = (struct spi_ops *)pdev->id_entry->driver_data; ctlr->num_chipselect = 2; /* default */ @@ -1314,16 +1310,13 @@ static int rspi_probe(struct platform_device *pdev) rspi->ctlr = ctlr; rspi->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(rspi->addr)) { - ret = PTR_ERR(rspi->addr); - goto error1; - } + if (IS_ERR(rspi->addr)) + return PTR_ERR(rspi->addr); rspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(rspi->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); - ret = PTR_ERR(rspi->clk); - goto error1; + return PTR_ERR(rspi->clk); } rspi->pdev = pdev; @@ -1396,8 +1389,6 @@ error3: rspi_release_dma(ctlr); error2: pm_runtime_disable(&pdev->dev); -error1: - spi_controller_put(ctlr); return ret; } From 042414e4da73e67d0e1e77ac1292e6aa15a54928 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:55 +0200 Subject: [PATCH 206/655] spi: sh-hspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-7-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 1e3ca718ca73..f840467cfdb2 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -224,15 +224,14 @@ static int hspi_probe(struct platform_device *pdev) return -EINVAL; } - ctlr = spi_alloc_host(&pdev->dev, sizeof(*hspi)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*hspi)); if (!ctlr) return -ENOMEM; clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "couldn't get clock\n"); - ret = -EINVAL; - goto error0; + return PTR_ERR(clk); } hspi = spi_controller_get_devdata(ctlr); @@ -269,8 +268,6 @@ static int hspi_probe(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); error1: clk_put(clk); - error0: - spi_controller_put(ctlr); return ret; } @@ -279,15 +276,11 @@ static void hspi_remove(struct platform_device *pdev) { struct hspi_priv *hspi = platform_get_drvdata(pdev); - spi_controller_get(hspi->ctlr); - spi_unregister_controller(hspi->ctlr); pm_runtime_disable(&pdev->dev); clk_put(hspi->clk); - - spi_controller_put(hspi->ctlr); } static const struct of_device_id hspi_of_match[] = { From 354b0a4ad4eb50a947b1b7b143c01a01a37489e7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:56 +0200 Subject: [PATCH 207/655] spi: sh-msiof: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-8-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index f114b6313f4f..070e16bc764f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1215,9 +1215,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) info->dtdl = 200; if (info->mode == MSIOF_SPI_TARGET) - ctlr = spi_alloc_target(dev, sizeof(struct sh_msiof_spi_priv)); + ctlr = devm_spi_alloc_target(dev, sizeof(struct sh_msiof_spi_priv)); else - ctlr = spi_alloc_host(dev, sizeof(struct sh_msiof_spi_priv)); + ctlr = devm_spi_alloc_host(dev, sizeof(struct sh_msiof_spi_priv)); if (ctlr == NULL) return -ENOMEM; @@ -1234,26 +1234,21 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p->clk = devm_clk_get(dev, NULL); if (IS_ERR(p->clk)) { dev_err(dev, "cannot get clock\n"); - ret = PTR_ERR(p->clk); - goto err1; + return PTR_ERR(p->clk); } i = platform_get_irq(pdev, 0); - if (i < 0) { - ret = i; - goto err1; - } + if (i < 0) + return i; p->mapbase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(p->mapbase)) { - ret = PTR_ERR(p->mapbase); - goto err1; - } + if (IS_ERR(p->mapbase)) + return PTR_ERR(p->mapbase); ret = devm_request_irq(dev, i, sh_msiof_spi_irq, 0, dev_name(dev), p); if (ret) { dev_err(dev, "unable to request irq\n"); - goto err1; + return ret; } p->pdev = pdev; @@ -1300,8 +1295,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) err2: sh_msiof_release_dma(p); pm_runtime_disable(dev); - err1: - spi_controller_put(ctlr); + return ret; } @@ -1309,14 +1303,10 @@ static void sh_msiof_spi_remove(struct platform_device *pdev) { struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); - spi_controller_get(p->ctlr); - spi_unregister_controller(p->ctlr); sh_msiof_release_dma(p); pm_runtime_disable(&pdev->dev); - - spi_controller_put(p->ctlr); } static const struct platform_device_id spi_driver_ids[] = { From fd260013577d0a6f3b6a8b07d059c34fb710efac Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:57 +0200 Subject: [PATCH 208/655] spi: sifive: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-9-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sifive.c | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 74a3e32fd2b5..cee4d92e46f4 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -296,7 +296,7 @@ static int sifive_spi_probe(struct platform_device *pdev) u32 cs_bits, max_bits_per_word; struct spi_controller *host; - host = spi_alloc_host(&pdev->dev, sizeof(struct sifive_spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct sifive_spi)); if (!host) { dev_err(&pdev->dev, "out of memory\n"); return -ENOMEM; @@ -307,24 +307,19 @@ static int sifive_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); spi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(spi->regs)) { - ret = PTR_ERR(spi->regs); - goto put_host; - } + if (IS_ERR(spi->regs)) + return PTR_ERR(spi->regs); /* Spin up the bus clock before hitting registers */ spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(spi->clk)) { dev_err(&pdev->dev, "Unable to find bus clock\n"); - ret = PTR_ERR(spi->clk); - goto put_host; + return PTR_ERR(spi->clk); } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto put_host; - } + if (irq < 0) + return irq; /* Optional parameters */ ret = @@ -339,8 +334,7 @@ static int sifive_spi_probe(struct platform_device *pdev) if (!ret && max_bits_per_word < 8) { dev_err(&pdev->dev, "Only 8bit SPI words supported by the driver\n"); - ret = -EINVAL; - goto put_host; + return -EINVAL; } /* probe the number of CS lines */ @@ -350,15 +344,13 @@ static int sifive_spi_probe(struct platform_device *pdev) sifive_spi_write(spi, SIFIVE_SPI_REG_CSDEF, spi->cs_inactive); if (!cs_bits) { dev_err(&pdev->dev, "Could not auto probe CS lines\n"); - ret = -EINVAL; - goto put_host; + return -EINVAL; } num_cs = ilog2(cs_bits) + 1; if (num_cs > SIFIVE_SPI_MAX_CS) { dev_err(&pdev->dev, "Invalid number of spi targets\n"); - ret = -EINVAL; - goto put_host; + return -EINVAL; } /* Define our host */ @@ -386,7 +378,7 @@ static int sifive_spi_probe(struct platform_device *pdev) dev_name(&pdev->dev), spi); if (ret) { dev_err(&pdev->dev, "Unable to bind to interrupt\n"); - goto put_host; + return ret; } dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n", @@ -395,15 +387,10 @@ static int sifive_spi_probe(struct platform_device *pdev) ret = spi_register_controller(host); if (ret < 0) { dev_err(&pdev->dev, "spi_register_host failed\n"); - goto put_host; + return ret; } return 0; - -put_host: - spi_controller_put(host); - - return ret; } static void sifive_spi_remove(struct platform_device *pdev) @@ -411,14 +398,10 @@ static void sifive_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct sifive_spi *spi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); /* Disable all the interrupts just in case */ sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0); - - spi_controller_put(host); } static int sifive_spi_suspend(struct device *dev) From cd1cd2ff56bf106a71d3170d6b74d08386d99428 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:58 +0200 Subject: [PATCH 209/655] spi: slave-mt27xx: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-10-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-slave-mt27xx.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index 7aedeaa5889d..e60ab4c18bed 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -388,11 +388,9 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) int irq, ret; const struct of_device_id *of_id; - ctlr = spi_alloc_target(&pdev->dev, sizeof(*mdata)); - if (!ctlr) { - dev_err(&pdev->dev, "failed to alloc spi target\n"); + ctlr = devm_spi_alloc_target(&pdev->dev, sizeof(*mdata)); + if (!ctlr) return -ENOMEM; - } ctlr->auto_runtime_pm = true; ctlr->mode_bits = SPI_CPOL | SPI_CPHA; @@ -406,8 +404,7 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) of_id = of_match_node(mtk_spi_slave_of_match, pdev->dev.of_node); if (!of_id) { dev_err(&pdev->dev, "failed to probe of_node\n"); - ret = -EINVAL; - goto err_put_ctlr; + return -EINVAL; } mdata = spi_controller_get_devdata(ctlr); mdata->dev_comp = of_id->data; @@ -420,35 +417,31 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) init_completion(&mdata->xfer_done); mdata->dev = &pdev->dev; mdata->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(mdata->base)) { - ret = PTR_ERR(mdata->base); - goto err_put_ctlr; - } + if (IS_ERR(mdata->base)) + return PTR_ERR(mdata->base); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err_put_ctlr; - } + if (irq < 0) + return irq; ret = devm_request_irq(&pdev->dev, irq, mtk_spi_slave_interrupt, IRQF_TRIGGER_NONE, dev_name(&pdev->dev), ctlr); if (ret) { dev_err(&pdev->dev, "failed to register irq (%d)\n", ret); - goto err_put_ctlr; + return ret; } mdata->spi_clk = devm_clk_get(&pdev->dev, "spi"); if (IS_ERR(mdata->spi_clk)) { ret = PTR_ERR(mdata->spi_clk); dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret); - goto err_put_ctlr; + return ret; } ret = clk_prepare_enable(mdata->spi_clk); if (ret < 0) { dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret); - goto err_put_ctlr; + return ret; } pm_runtime_enable(&pdev->dev); @@ -465,8 +458,6 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) err_disable_runtime_pm: pm_runtime_disable(&pdev->dev); -err_put_ctlr: - spi_controller_put(ctlr); return ret; } @@ -475,13 +466,9 @@ static void mtk_spi_slave_remove(struct platform_device *pdev) { struct spi_controller *ctlr = platform_get_drvdata(pdev); - spi_controller_get(ctlr); - spi_unregister_controller(ctlr); pm_runtime_disable(&pdev->dev); - - spi_controller_put(ctlr); } #ifdef CONFIG_PM_SLEEP From d68627cc76cd895d07363c795a198d1edd687107 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:28:59 +0200 Subject: [PATCH 210/655] spi: sprd: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-11-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sprd.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index fd3fd0ce122c..d27b51698dbd 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -923,16 +923,14 @@ static int sprd_spi_probe(struct platform_device *pdev) int ret; pdev->id = of_alias_get_id(pdev->dev.of_node, "spi"); - sctlr = spi_alloc_host(&pdev->dev, sizeof(*ss)); + sctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*ss)); if (!sctlr) return -ENOMEM; ss = spi_controller_get_devdata(sctlr); ss->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(ss->base)) { - ret = PTR_ERR(ss->base); - goto free_controller; - } + if (IS_ERR(ss->base)) + return PTR_ERR(ss->base); ss->phy_base = res->start; ss->dev = &pdev->dev; @@ -949,15 +947,15 @@ static int sprd_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sctlr); ret = sprd_spi_clk_init(pdev, ss); if (ret) - goto free_controller; + return ret; ret = sprd_spi_irq_init(pdev, ss); if (ret) - goto free_controller; + return ret; ret = sprd_spi_dma_init(pdev, ss); if (ret) - goto free_controller; + return ret; ret = clk_prepare_enable(ss->clk); if (ret) @@ -992,8 +990,6 @@ disable_clk: clk_disable_unprepare(ss->clk); release_dma: sprd_spi_dma_release(ss); -free_controller: - spi_controller_put(sctlr); return ret; } @@ -1008,8 +1004,6 @@ static void sprd_spi_remove(struct platform_device *pdev) if (ret < 0) dev_err(ss->dev, "failed to resume SPI controller\n"); - spi_controller_get(sctlr); - spi_unregister_controller(sctlr); if (ret >= 0) { @@ -1019,8 +1013,6 @@ static void sprd_spi_remove(struct platform_device *pdev) } pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); - - spi_controller_put(sctlr); } static int __maybe_unused sprd_spi_runtime_suspend(struct device *dev) From d3cf5ebdf1c9fa909ae8de5be041eac2658c0c68 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:00 +0200 Subject: [PATCH 211/655] spi: st-ssc4: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-12-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-st-ssc4.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index 9c8099fe6e19..df61094fc444 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -279,7 +279,7 @@ static int spi_st_probe(struct platform_device *pdev) int irq, ret = 0; u32 var; - host = spi_alloc_host(&pdev->dev, sizeof(*spi_st)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi_st)); if (!host) return -ENOMEM; @@ -296,13 +296,12 @@ static int spi_st_probe(struct platform_device *pdev) spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); if (IS_ERR(spi_st->clk)) { dev_err(&pdev->dev, "Unable to request clock\n"); - ret = PTR_ERR(spi_st->clk); - goto put_host; + return PTR_ERR(spi_st->clk); } ret = clk_prepare_enable(spi_st->clk); if (ret) - goto put_host; + return ret; init_completion(&spi_st->done); @@ -361,8 +360,7 @@ rpm_disable: pm_runtime_disable(&pdev->dev); clk_disable: clk_disable_unprepare(spi_st->clk); -put_host: - spi_controller_put(host); + return ret; } @@ -371,16 +369,12 @@ static void spi_st_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct spi_st *spi_st = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_disable(&pdev->dev); clk_disable_unprepare(spi_st->clk); - spi_controller_put(host); - pinctrl_pm_select_sleep_state(&pdev->dev); } From 02b36d644ded410e8f70cdd78d0c5d523252bafd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:01 +0200 Subject: [PATCH 212/655] spi: sun4i: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-13-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sun4i.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index b7fbb5270edb..d5c16392cd4d 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -434,32 +434,26 @@ static int sun4i_spi_probe(struct platform_device *pdev) struct sun4i_spi *sspi; int ret = 0, irq; - host = spi_alloc_host(&pdev->dev, sizeof(struct sun4i_spi)); - if (!host) { - dev_err(&pdev->dev, "Unable to allocate SPI Host\n"); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct sun4i_spi)); + if (!host) return -ENOMEM; - } platform_set_drvdata(pdev, host); sspi = spi_controller_get_devdata(host); sspi->base_addr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(sspi->base_addr)) { - ret = PTR_ERR(sspi->base_addr); - goto err_free_host; - } + if (IS_ERR(sspi->base_addr)) + return PTR_ERR(sspi->base_addr); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = -ENXIO; - goto err_free_host; - } + if (irq < 0) + return -ENXIO; ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler, 0, "sun4i-spi", sspi); if (ret) { dev_err(&pdev->dev, "Cannot request IRQ\n"); - goto err_free_host; + return ret; } sspi->host = host; @@ -477,15 +471,13 @@ static int sun4i_spi_probe(struct platform_device *pdev) sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(sspi->hclk)) { dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); - ret = PTR_ERR(sspi->hclk); - goto err_free_host; + return PTR_ERR(sspi->hclk); } sspi->mclk = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(sspi->mclk)) { dev_err(&pdev->dev, "Unable to acquire module clock\n"); - ret = PTR_ERR(sspi->mclk); - goto err_free_host; + return PTR_ERR(sspi->mclk); } init_completion(&sspi->done); @@ -497,7 +489,7 @@ static int sun4i_spi_probe(struct platform_device *pdev) ret = sun4i_spi_runtime_resume(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Couldn't resume the device\n"); - goto err_free_host; + return ret; } pm_runtime_set_active(&pdev->dev); @@ -515,8 +507,7 @@ static int sun4i_spi_probe(struct platform_device *pdev) err_pm_disable: pm_runtime_disable(&pdev->dev); sun4i_spi_runtime_suspend(&pdev->dev); -err_free_host: - spi_controller_put(host); + return ret; } @@ -524,13 +515,9 @@ static void sun4i_spi_remove(struct platform_device *pdev) { struct spi_controller *host = platform_get_drvdata(pdev); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_force_suspend(&pdev->dev); - - spi_controller_put(host); } static const struct of_device_id sun4i_spi_match[] = { From 9864636b1cd95dd2b3c702a2ff22e9d169f6523a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:02 +0200 Subject: [PATCH 213/655] spi: sun6i: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-14-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 5ac73d324d06..4631e9c7ca1d 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -633,7 +633,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) struct resource *mem; int ret = 0, irq; - host = spi_alloc_host(&pdev->dev, sizeof(struct sun6i_spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct sun6i_spi)); if (!host) { dev_err(&pdev->dev, "Unable to allocate SPI Host\n"); return -ENOMEM; @@ -643,22 +643,18 @@ static int sun6i_spi_probe(struct platform_device *pdev) sspi = spi_controller_get_devdata(host); sspi->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); - if (IS_ERR(sspi->base_addr)) { - ret = PTR_ERR(sspi->base_addr); - goto err_free_host; - } + if (IS_ERR(sspi->base_addr)) + return PTR_ERR(sspi->base_addr); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = -ENXIO; - goto err_free_host; - } + if (irq < 0) + return -ENXIO; ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler, 0, "sun6i-spi", sspi); if (ret) { dev_err(&pdev->dev, "Cannot request IRQ\n"); - goto err_free_host; + return ret; } sspi->host = host; @@ -679,15 +675,13 @@ static int sun6i_spi_probe(struct platform_device *pdev) sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(sspi->hclk)) { dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); - ret = PTR_ERR(sspi->hclk); - goto err_free_host; + return PTR_ERR(sspi->hclk); } sspi->mclk = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(sspi->mclk)) { dev_err(&pdev->dev, "Unable to acquire module clock\n"); - ret = PTR_ERR(sspi->mclk); - goto err_free_host; + return PTR_ERR(sspi->mclk); } init_completion(&sspi->done); @@ -696,17 +690,14 @@ static int sun6i_spi_probe(struct platform_device *pdev) sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(sspi->rstc)) { dev_err(&pdev->dev, "Couldn't get reset controller\n"); - ret = PTR_ERR(sspi->rstc); - goto err_free_host; + return PTR_ERR(sspi->rstc); } host->dma_tx = dma_request_chan(&pdev->dev, "tx"); if (IS_ERR(host->dma_tx)) { /* Check tx to see if we need defer probing driver */ - if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_free_host; - } + if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) + return -EPROBE_DEFER; dev_warn(&pdev->dev, "Failed to request TX DMA channel\n"); host->dma_tx = NULL; } @@ -759,8 +750,7 @@ err_free_dma_rx: err_free_dma_tx: if (host->dma_tx) dma_release_channel(host->dma_tx); -err_free_host: - spi_controller_put(host); + return ret; } @@ -768,8 +758,6 @@ static void sun6i_spi_remove(struct platform_device *pdev) { struct spi_controller *host = platform_get_drvdata(pdev); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_force_suspend(&pdev->dev); @@ -778,8 +766,6 @@ static void sun6i_spi_remove(struct platform_device *pdev) dma_release_channel(host->dma_tx); if (host->dma_rx) dma_release_channel(host->dma_rx); - - spi_controller_put(host); } static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = { From 5d5bbf177d18bdec01b9356f85d5883cbc6acf29 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:03 +0200 Subject: [PATCH 214/655] spi: syncuacer: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-15-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-synquacer.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c index 290c439897c4..c14225e39fd1 100644 --- a/drivers/spi/spi-synquacer.c +++ b/drivers/spi/spi-synquacer.c @@ -605,7 +605,7 @@ static int synquacer_spi_probe(struct platform_device *pdev) int ret; int rx_irq, tx_irq; - host = spi_alloc_host(&pdev->dev, sizeof(*sspi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*sspi)); if (!host) return -ENOMEM; @@ -617,10 +617,8 @@ static int synquacer_spi_probe(struct platform_device *pdev) init_completion(&sspi->transfer_done); sspi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(sspi->regs)) { - ret = PTR_ERR(sspi->regs); - goto put_spi; - } + if (IS_ERR(sspi->regs)) + return PTR_ERR(sspi->regs); sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */ device_property_read_u32(&pdev->dev, "socionext,ihclk-rate", @@ -637,21 +635,19 @@ static int synquacer_spi_probe(struct platform_device *pdev) sspi->clk = devm_clk_get(sspi->dev, "iPCLK"); } else { dev_err(&pdev->dev, "specified wrong clock source\n"); - ret = -EINVAL; - goto put_spi; + return -EINVAL; } if (IS_ERR(sspi->clk)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(sspi->clk), - "clock not found\n"); - goto put_spi; + return dev_err_probe(&pdev->dev, PTR_ERR(sspi->clk), + "clock not found\n"); } ret = clk_prepare_enable(sspi->clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret); - goto put_spi; + return ret; } host->max_speed_hz = clk_get_rate(sspi->clk); @@ -726,8 +722,6 @@ disable_pm: pm_runtime_disable(sspi->dev); disable_clk: clk_disable_unprepare(sspi->clk); -put_spi: - spi_controller_put(host); return ret; } @@ -737,15 +731,11 @@ static void synquacer_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct synquacer_spi *sspi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); pm_runtime_disable(sspi->dev); clk_disable_unprepare(sspi->clk); - - spi_controller_put(host); } static int __maybe_unused synquacer_spi_suspend(struct device *dev) From 3068e7063cc42032b30e3eaef34066a86cb0aa68 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:04 +0200 Subject: [PATCH 215/655] spi: tegra114: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-16-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index b8b0ebe0fe93..aa44ffd09e61 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1302,7 +1302,7 @@ static int tegra_spi_probe(struct platform_device *pdev) int ret, spi_irq; int bus_num; - host = spi_alloc_host(&pdev->dev, sizeof(*tspi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*tspi)); if (!host) { dev_err(&pdev->dev, "host allocation failed\n"); return -ENOMEM; @@ -1336,36 +1336,31 @@ static int tegra_spi_probe(struct platform_device *pdev) tspi->soc_data = of_device_get_match_data(&pdev->dev); if (!tspi->soc_data) { dev_err(&pdev->dev, "unsupported tegra\n"); - ret = -ENODEV; - goto exit_free_host; + return -ENODEV; } tspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); - if (IS_ERR(tspi->base)) { - ret = PTR_ERR(tspi->base); - goto exit_free_host; - } + if (IS_ERR(tspi->base)) + return PTR_ERR(tspi->base); + tspi->phys = r->start; spi_irq = platform_get_irq(pdev, 0); - if (spi_irq < 0) { - ret = spi_irq; - goto exit_free_host; - } + if (spi_irq < 0) + return spi_irq; + tspi->irq = spi_irq; tspi->clk = devm_clk_get(&pdev->dev, "spi"); if (IS_ERR(tspi->clk)) { dev_err(&pdev->dev, "can not get clock\n"); - ret = PTR_ERR(tspi->clk); - goto exit_free_host; + return PTR_ERR(tspi->clk); } tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); if (IS_ERR(tspi->rst)) { dev_err(&pdev->dev, "can not get reset\n"); - ret = PTR_ERR(tspi->rst); - goto exit_free_host; + return PTR_ERR(tspi->rst); } tspi->max_buf_size = SPI_FIFO_DEPTH << 2; @@ -1373,7 +1368,7 @@ static int tegra_spi_probe(struct platform_device *pdev) ret = tegra_spi_init_dma_param(tspi, true); if (ret < 0) - goto exit_free_host; + return ret; ret = tegra_spi_init_dma_param(tspi, false); if (ret < 0) goto exit_rx_dma_free; @@ -1431,8 +1426,7 @@ exit_pm_disable: tegra_spi_deinit_dma_param(tspi, false); exit_rx_dma_free: tegra_spi_deinit_dma_param(tspi, true); -exit_free_host: - spi_controller_put(host); + return ret; } @@ -1441,8 +1435,6 @@ static void tegra_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct tegra_spi_data *tspi = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); free_irq(tspi->irq, tspi); @@ -1456,8 +1448,6 @@ static void tegra_spi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra_spi_runtime_suspend(&pdev->dev); - - spi_controller_put(host); } #ifdef CONFIG_PM_SLEEP From 3a14bf4f5453121cae3cbdfb6180317c5d74f424 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:05 +0200 Subject: [PATCH 216/655] spi: tegra20-sflash: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-17-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-sflash.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 9256729f2d49..2caa33f0a52c 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -427,11 +427,9 @@ static int tegra_sflash_probe(struct platform_device *pdev) return -ENODEV; } - host = spi_alloc_host(&pdev->dev, sizeof(*tsd)); - if (!host) { - dev_err(&pdev->dev, "host allocation failed\n"); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*tsd)); + if (!host) return -ENOMEM; - } /* the spi->mode bits understood by this driver: */ host->mode_bits = SPI_CPOL | SPI_CPHA; @@ -450,14 +448,13 @@ static int tegra_sflash_probe(struct platform_device *pdev) host->max_speed_hz = 25000000; /* 25MHz */ tsd->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(tsd->base)) { - ret = PTR_ERR(tsd->base); - goto exit_free_host; - } + if (IS_ERR(tsd->base)) + return PTR_ERR(tsd->base); ret = platform_get_irq(pdev, 0); if (ret < 0) - goto exit_free_host; + return ret; + tsd->irq = ret; ret = request_irq(tsd->irq, tegra_sflash_isr, 0, @@ -465,7 +462,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", tsd->irq); - goto exit_free_host; + return ret; } tsd->clk = devm_clk_get(&pdev->dev, NULL); @@ -518,8 +515,7 @@ exit_pm_disable: tegra_sflash_runtime_suspend(&pdev->dev); exit_free_irq: free_irq(tsd->irq, tsd); -exit_free_host: - spi_controller_put(host); + return ret; } @@ -528,8 +524,6 @@ static void tegra_sflash_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct tegra_sflash_data *tsd = spi_controller_get_devdata(host); - spi_controller_get(host); - spi_unregister_controller(host); free_irq(tsd->irq, tsd); @@ -537,8 +531,6 @@ static void tegra_sflash_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra_sflash_runtime_suspend(&pdev->dev); - - spi_controller_put(host); } #ifdef CONFIG_PM_SLEEP From 76a24627b98ca712df8724985a4601c502b7875f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:06 +0200 Subject: [PATCH 217/655] spi: ti-qspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-18-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 1fbd710d616f..2a8548810f84 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -765,7 +765,7 @@ static int ti_qspi_probe(struct platform_device *pdev) int ret = 0, num_cs, irq; dma_cap_mask_t mask; - host = spi_alloc_host(&pdev->dev, sizeof(*qspi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*qspi)); if (!host) return -ENOMEM; @@ -793,8 +793,7 @@ static int ti_qspi_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&pdev->dev, "missing platform data\n"); - ret = -ENODEV; - goto free_host; + return -ENODEV; } } @@ -812,28 +811,22 @@ static int ti_qspi_probe(struct platform_device *pdev) qspi->mmap_size = resource_size(res_mmap); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto free_host; - } + if (irq < 0) + return irq; mutex_init(&qspi->list_lock); qspi->base = devm_ioremap_resource(&pdev->dev, r); - if (IS_ERR(qspi->base)) { - ret = PTR_ERR(qspi->base); - goto free_host; - } + if (IS_ERR(qspi->base)) + return PTR_ERR(qspi->base); if (of_property_present(np, "syscon-chipselects")) { qspi->ctrl_base = syscon_regmap_lookup_by_phandle_args(np, "syscon-chipselects", 1, &qspi->ctrl_reg); - if (IS_ERR(qspi->ctrl_base)) { - ret = PTR_ERR(qspi->ctrl_base); - goto free_host; - } + if (IS_ERR(qspi->ctrl_base)) + return PTR_ERR(qspi->ctrl_base); } qspi->fclk = devm_clk_get(&pdev->dev, "fck"); @@ -895,8 +888,7 @@ no_dma: ti_qspi_dma_cleanup(qspi); pm_runtime_disable(&pdev->dev); -free_host: - spi_controller_put(host); + return ret; } @@ -904,16 +896,12 @@ static void ti_qspi_remove(struct platform_device *pdev) { struct ti_qspi *qspi = platform_get_drvdata(pdev); - spi_controller_get(qspi->host); - spi_unregister_controller(qspi->host); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); ti_qspi_dma_cleanup(qspi); - - spi_controller_put(qspi->host); } static const struct dev_pm_ops ti_qspi_pm_ops = { From f8689d5a9ee44a7cdd0ff469e5ee943c933fc830 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:07 +0200 Subject: [PATCH 218/655] spi: ti-qspi: cleanup registration error path Add a proper error path for when registration fails so that the probe tests for errors consistently. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-19-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 2a8548810f84..6b407c7b5d33 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -882,9 +882,12 @@ no_dma: qspi->current_cs = -1; ret = spi_register_controller(host); - if (!ret) - return 0; + if (ret) + goto err_free_dma; + return 0; + +err_free_dma: ti_qspi_dma_cleanup(qspi); pm_runtime_disable(&pdev->dev); From 789986b1456497837c542f64b1a0c7d9dafd1b2a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:08 +0200 Subject: [PATCH 219/655] spi: uniphier: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-20-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-uniphier.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index eac6c3e8908b..5f0abc59b716 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -649,7 +649,7 @@ static int uniphier_spi_probe(struct platform_device *pdev) int irq; int ret; - host = spi_alloc_host(&pdev->dev, sizeof(*priv)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*priv)); if (!host) return -ENOMEM; @@ -660,30 +660,26 @@ static int uniphier_spi_probe(struct platform_device *pdev) priv->is_save_param = false; priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(priv->base)) { - ret = PTR_ERR(priv->base); - goto out_host_put; - } + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + priv->base_dma_addr = res->start; priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(priv->clk); - goto out_host_put; + return PTR_ERR(priv->clk); } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto out_host_put; - } + if (irq < 0) + return irq; ret = devm_request_irq(&pdev->dev, irq, uniphier_spi_handler, 0, "uniphier-spi", priv); if (ret) { dev_err(&pdev->dev, "failed to request IRQ\n"); - goto out_host_put; + return ret; } init_completion(&priv->xfer_done); @@ -710,10 +706,9 @@ static int uniphier_spi_probe(struct platform_device *pdev) host->dma_tx = dma_request_chan(&pdev->dev, "tx"); if (IS_ERR_OR_NULL(host->dma_tx)) { - if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto out_host_put; - } + if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) + return -EPROBE_DEFER; + host->dma_tx = NULL; dma_tx_burst = INT_MAX; } else { @@ -762,8 +757,6 @@ out_release_dma: host->dma_tx = NULL; } -out_host_put: - spi_controller_put(host); return ret; } @@ -771,16 +764,12 @@ static void uniphier_spi_remove(struct platform_device *pdev) { struct spi_controller *host = platform_get_drvdata(pdev); - spi_controller_get(host); - spi_unregister_controller(host); if (host->dma_tx) dma_release_channel(host->dma_tx); if (host->dma_rx) dma_release_channel(host->dma_rx); - - spi_controller_put(host); } static const struct of_device_id uniphier_spi_match[] = { From be552efa43eec9972b490fce9a3dd9cb0da92a3c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 May 2026 09:29:09 +0200 Subject: [PATCH 220/655] spi: zync-qspi: switch to managed controller allocation Switch to device managed controller allocation to simplify error handling and to avoid having to take another reference during deregistration. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260505072909.618363-21-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 40 +++++++++++-------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 406fd9d5337e..d762aaf452af 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -637,7 +637,7 @@ static int zynq_qspi_probe(struct platform_device *pdev) struct zynq_qspi *xqspi; u32 num_cs; - ctlr = spi_alloc_host(&pdev->dev, sizeof(*xqspi)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*xqspi)); if (!ctlr) return -ENOMEM; @@ -645,16 +645,13 @@ static int zynq_qspi_probe(struct platform_device *pdev) xqspi->dev = dev; platform_set_drvdata(pdev, ctlr); xqspi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(xqspi->regs)) { - ret = PTR_ERR(xqspi->regs); - goto remove_ctlr; - } + if (IS_ERR(xqspi->regs)) + return PTR_ERR(xqspi->regs); xqspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); if (IS_ERR(xqspi->pclk)) { dev_err(&pdev->dev, "pclk clock not found.\n"); - ret = PTR_ERR(xqspi->pclk); - goto remove_ctlr; + return PTR_ERR(xqspi->pclk); } init_completion(&xqspi->data_completion); @@ -662,21 +659,18 @@ static int zynq_qspi_probe(struct platform_device *pdev) xqspi->refclk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); if (IS_ERR(xqspi->refclk)) { dev_err(&pdev->dev, "ref_clk clock not found.\n"); - ret = PTR_ERR(xqspi->refclk); - goto remove_ctlr; + return PTR_ERR(xqspi->refclk); } xqspi->irq = platform_get_irq(pdev, 0); - if (xqspi->irq < 0) { - ret = xqspi->irq; - goto remove_ctlr; - } + if (xqspi->irq < 0) + return xqspi->irq; + ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq, 0, pdev->name, xqspi); if (ret != 0) { - ret = -ENXIO; dev_err(&pdev->dev, "request_irq failed\n"); - goto remove_ctlr; + return -ENXIO; } ret = of_property_read_u32(np, "num-cs", @@ -684,9 +678,8 @@ static int zynq_qspi_probe(struct platform_device *pdev) if (ret < 0) { ctlr->num_chipselect = 1; } else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) { - ret = -EINVAL; dev_err(&pdev->dev, "only 2 chip selects are available\n"); - goto remove_ctlr; + return -EINVAL; } else { ctlr->num_chipselect = num_cs; } @@ -705,15 +698,10 @@ static int zynq_qspi_probe(struct platform_device *pdev) ret = spi_register_controller(ctlr); if (ret) { dev_err(&pdev->dev, "failed to register controller\n"); - goto remove_ctlr; + return ret; } - return ret; - -remove_ctlr: - spi_controller_put(ctlr); - - return ret; + return 0; } /** @@ -731,13 +719,9 @@ static void zynq_qspi_remove(struct platform_device *pdev) struct spi_controller *ctlr = platform_get_drvdata(pdev); struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); - spi_controller_get(ctlr); - spi_unregister_controller(ctlr); zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0); - - spi_controller_put(ctlr); } static const struct of_device_id zynq_qspi_of_match[] = { From 8262b1421dddab6d13d430aee34cef6a47a0b93f Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:47 +0800 Subject: [PATCH 221/655] spi: amlogic-spifc-a1: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Link: https://patch.msgid.link/20260430155456.36998-2-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-amlogic-spifc-a1.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-amlogic-spifc-a1.c b/drivers/spi/spi-amlogic-spifc-a1.c index 7ee4c92e6e09..77a2c11bec5e 100644 --- a/drivers/spi/spi-amlogic-spifc-a1.c +++ b/drivers/spi/spi-amlogic-spifc-a1.c @@ -206,10 +206,9 @@ static int amlogic_spifc_a1_read(struct amlogic_spifc_a1 *spifc, void *buf, u32 val = readl(spifc->base + SPIFC_A1_USER_CTRL3_REG); int ret; - val &= ~(SPIFC_A1_USER_DIN_MODE | SPIFC_A1_USER_DIN_BYTES); val |= SPIFC_A1_USER_DIN_ENABLE; - val |= FIELD_PREP(SPIFC_A1_USER_DIN_MODE, mode); - val |= FIELD_PREP(SPIFC_A1_USER_DIN_BYTES, size); + FIELD_MODIFY(SPIFC_A1_USER_DIN_MODE, &val, mode); + FIELD_MODIFY(SPIFC_A1_USER_DIN_BYTES, &val, size); writel(val, spifc->base + SPIFC_A1_USER_CTRL3_REG); ret = amlogic_spifc_a1_request(spifc, true); From b69bfa5933299b3cd84aae821f8890f10ea56df7 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:48 +0800 Subject: [PATCH 222/655] spi: amlogic-spisg: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Link: https://patch.msgid.link/20260430155456.36998-3-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-amlogic-spisg.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c index 19c5eba412ef..4c9f4088cb37 100644 --- a/drivers/spi/spi-amlogic-spisg.c +++ b/drivers/spi/spi-amlogic-spisg.c @@ -601,14 +601,11 @@ static int aml_spisg_prepare_message(struct spi_controller *ctlr, spisg->bytes_per_word = spi->bits_per_word >> 3; - spisg->cfg_spi &= ~CFG_SLAVE_SELECT; - spisg->cfg_spi |= FIELD_PREP(CFG_SLAVE_SELECT, spi_get_chipselect(spi, 0)); - - spisg->cfg_bus &= ~(CFG_CPOL | CFG_CPHA | CFG_B_L_ENDIAN | CFG_HALF_DUPLEX); - spisg->cfg_bus |= FIELD_PREP(CFG_CPOL, !!(spi->mode & SPI_CPOL)) | - FIELD_PREP(CFG_CPHA, !!(spi->mode & SPI_CPHA)) | - FIELD_PREP(CFG_B_L_ENDIAN, !!(spi->mode & SPI_LSB_FIRST)) | - FIELD_PREP(CFG_HALF_DUPLEX, !!(spi->mode & SPI_3WIRE)); + FIELD_MODIFY(CFG_SLAVE_SELECT, &spisg->cfg_spi, spi_get_chipselect(spi, 0)); + FIELD_MODIFY(CFG_CPOL, &spisg->cfg_bus, !!(spi->mode & SPI_CPOL)); + FIELD_MODIFY(CFG_CPHA, &spisg->cfg_bus, !!(spi->mode & SPI_CPHA)); + FIELD_MODIFY(CFG_B_L_ENDIAN, &spisg->cfg_bus, !!(spi->mode & SPI_LSB_FIRST)); + FIELD_MODIFY(CFG_HALF_DUPLEX, &spisg->cfg_bus, !!(spi->mode & SPI_3WIRE)); return 0; } From 6fa473f4c5dcc20db9799f90da48b977730e05f1 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:49 +0800 Subject: [PATCH 223/655] spi: cadence-xspi: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Link: https://patch.msgid.link/20260430155456.36998-4-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 895b4b3276a5..32fa19ebf7a9 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -453,8 +453,7 @@ static bool cdns_mrvl_xspi_setup_clock(struct cdns_xspi_dev *cdns_xspi, writel(clk_reg, cdns_xspi->auxbase + MRVL_XSPI_CLK_CTRL_AUX_REG); clk_reg = FIELD_PREP(MRVL_XSPI_CLK_DIV, i); - clk_reg &= ~MRVL_XSPI_CLK_DIV; - clk_reg |= FIELD_PREP(MRVL_XSPI_CLK_DIV, i); + FIELD_MODIFY(MRVL_XSPI_CLK_DIV, &clk_reg, i); clk_reg |= MRVL_XSPI_CLK_ENABLE; clk_reg |= MRVL_XSPI_IRQ_ENABLE; update_clk = true; From cfdab17cd2d7666ce164f64fbaadeb782dbb28d2 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:50 +0800 Subject: [PATCH 224/655] spi: meson-spicc: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Link: https://patch.msgid.link/20260430155456.36998-5-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index b80f9f457b66..682dda114412 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -539,9 +539,8 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, conf = conf_orig = readl_relaxed(spicc->base + SPICC_CONREG); /* Setup word width */ - conf &= ~SPICC_BITLENGTH_MASK; - conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, - (spicc->bytes_per_word << 3) - 1); + FIELD_MODIFY(SPICC_BITLENGTH_MASK, &conf, + (spicc->bytes_per_word << 3) - 1); /* Ignore if unchanged */ if (conf != conf_orig) From 0f2efc6d493833332dc9224e4e4c039b9824af51 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:51 +0800 Subject: [PATCH 225/655] spi: nxp-xspi: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Reviewed-by: Frank Li Link: https://patch.msgid.link/20260430155456.36998-6-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-nxp-xspi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-nxp-xspi.c b/drivers/spi/spi-nxp-xspi.c index 385302a6e62f..037eac24e6fd 100644 --- a/drivers/spi/spi-nxp-xspi.c +++ b/drivers/spi/spi-nxp-xspi.c @@ -493,9 +493,8 @@ static void nxp_xspi_disable_ddr(struct nxp_xspi *xspi) writel(reg, base + XSPI_MCR); reg &= ~XSPI_MCR_DDR_EN; - reg &= ~XSPI_MCR_DQS_FA_SEL_MASK; /* Use dummy pad loopback mode to sample data */ - reg |= FIELD_PREP(XSPI_MCR_DQS_FA_SEL_MASK, 0x01); + FIELD_MODIFY(XSPI_MCR_DQS_FA_SEL_MASK, ®, 0x01); writel(reg, base + XSPI_MCR); xspi->support_max_rate = 133000000; @@ -524,15 +523,13 @@ static void nxp_xspi_enable_ddr(struct nxp_xspi *xspi) writel(reg, base + XSPI_MCR); reg |= XSPI_MCR_DDR_EN; - reg &= ~XSPI_MCR_DQS_FA_SEL_MASK; /* Use external dqs to sample data */ - reg |= FIELD_PREP(XSPI_MCR_DQS_FA_SEL_MASK, 0x03); + FIELD_MODIFY(XSPI_MCR_DQS_FA_SEL_MASK, ®, 0x03); writel(reg, base + XSPI_MCR); xspi->support_max_rate = 200000000; reg = readl(base + XSPI_FLSHCR); - reg &= ~XSPI_FLSHCR_TDH_MASK; - reg |= FIELD_PREP(XSPI_FLSHCR_TDH_MASK, 0x01); + FIELD_MODIFY(XSPI_FLSHCR_TDH_MASK, ®, 0x01); writel(reg, base + XSPI_FLSHCR); reg = FIELD_PREP(XSPI_SMPR_DLLFSMPFA_MASK, 0x04); @@ -1096,8 +1093,7 @@ static int nxp_xspi_default_setup(struct nxp_xspi *xspi) /* Give read/write access right to EENV0 */ reg = readl(base + XSPI_FRAD0_WORD2); - reg &= ~XSPI_FRAD0_WORD2_MD0ACP_MASK; - reg |= FIELD_PREP(XSPI_FRAD0_WORD2_MD0ACP_MASK, 0x03); + FIELD_MODIFY(XSPI_FRAD0_WORD2_MD0ACP_MASK, ®, 0x03); writel(reg, base + XSPI_FRAD0_WORD2); /* Enable the FRAD check for EENV0 */ From 579fcc06576d760fd439cc3a1bea0507e14a266b Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:52 +0800 Subject: [PATCH 226/655] spi: sn-f-ospi: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Link: https://patch.msgid.link/20260430155456.36998-7-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-sn-f-ospi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c index b459d51cb3a8..f0320e96fe23 100644 --- a/drivers/spi/spi-sn-f-ospi.c +++ b/drivers/spi/spi-sn-f-ospi.c @@ -222,9 +222,8 @@ static void f_ospi_config_clk(struct f_ospi *ospi, u32 device_hz) */ val = readl(ospi->base + OSPI_CLK_CTL); - val &= ~(OSPI_CLK_CTL_PHA | OSPI_CLK_CTL_DIV); - val |= FIELD_PREP(OSPI_CLK_CTL_PHA, OSPI_CLK_CTL_PHA_180) - | FIELD_PREP(OSPI_CLK_CTL_DIV, div_reg); + FIELD_MODIFY(OSPI_CLK_CTL_PHA, &val, OSPI_CLK_CTL_PHA_180); + FIELD_MODIFY(OSPI_CLK_CTL_DIV, &val, div_reg); writel(val, ospi->base + OSPI_CLK_CTL); } From 21ee6902a5767e4e8488b061654aad5bb84182c8 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:53 +0800 Subject: [PATCH 227/655] spi: stm32-ospi: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Reviewed-by: Patrice Chotard Link: https://patch.msgid.link/20260430155456.36998-8-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32-ospi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c index 4461c6e24b9e..3757f6ba8fc6 100644 --- a/drivers/spi/spi-stm32-ospi.c +++ b/drivers/spi/spi-stm32-ospi.c @@ -470,10 +470,9 @@ static int stm32_ospi_send(struct spi_device *spi, const struct spi_mem_op *op) u8 cs = spi->chip_select[ffs(spi->cs_index_mask) - 1]; cr = readl_relaxed(ospi->regs_base + OSPI_CR); - cr &= ~CR_CSSEL; - cr |= FIELD_PREP(CR_CSSEL, cs); - cr &= ~CR_FMODE_MASK; - cr |= FIELD_PREP(CR_FMODE_MASK, ospi->fmode); + FIELD_MODIFY(CR_CSSEL, &cr, cs); + + FIELD_MODIFY(CR_FMODE_MASK, &cr, ospi->fmode); writel_relaxed(cr, regs_base + OSPI_CR); if (op->data.nbytes) From 3e0530c087a93a8477c9df6760629e326e97f795 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:54 +0800 Subject: [PATCH 228/655] spi: stm32-qspi: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Reviewed-by: Patrice Chotard Link: https://patch.msgid.link/20260430155456.36998-9-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32-qspi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index df1bbacec90a..ea69fe25686f 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -374,9 +374,8 @@ static int stm32_qspi_send(struct spi_device *spi, const struct spi_mem_op *op) int timeout, err = 0, err_poll_status = 0; cr = readl_relaxed(qspi->io_base + QSPI_CR); - cr &= ~CR_PRESC_MASK & ~CR_FSEL; - cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); - cr |= FIELD_PREP(CR_FSEL, flash->cs); + FIELD_MODIFY(CR_PRESC_MASK, &cr, flash->presc); + FIELD_MODIFY(CR_FSEL, &cr, flash->cs); writel_relaxed(cr, qspi->io_base + QSPI_CR); if (op->data.nbytes) From 673214ac9bcdf9326f96dfb56a5a432e77fcacd8 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:55 +0800 Subject: [PATCH 229/655] spi: sunplus-sp7021: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Link: https://patch.msgid.link/20260430155456.36998-10-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-sunplus-sp7021.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index 35601212fb78..c1870322d976 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -290,8 +290,7 @@ static void sp7021_spi_setup_clk(struct spi_controller *ctlr, struct spi_transfe div = max(2U, clk_rate / xfer->speed_hz); clk_sel = (div / 2) - 1; - pspim->xfer_conf &= ~SP7021_CLK_MASK; - pspim->xfer_conf |= FIELD_PREP(SP7021_CLK_MASK, clk_sel); + FIELD_MODIFY(SP7021_CLK_MASK, &pspim->xfer_conf, clk_sel); writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG); } From ce7984bea2a185d4a7cfbd1b8972fdff0ca615c0 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Thu, 30 Apr 2026 23:54:56 +0800 Subject: [PATCH 230/655] spi: uniphier: Use FIELD_MODIFY() Use FIELD_MODIFY() to remove open-coded bit manipulation. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> Link: https://patch.msgid.link/20260430155456.36998-11-18255117159@163.com Signed-off-by: Mark Brown --- drivers/spi/spi-uniphier.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index eac6c3e8908b..846f65ba9495 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -184,14 +184,12 @@ static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size) u32 val; val = readl(priv->base + SSI_TXWDS); - val &= ~(SSI_TXWDS_WDLEN_MASK | SSI_TXWDS_DTLEN_MASK); - val |= FIELD_PREP(SSI_TXWDS_WDLEN_MASK, size); - val |= FIELD_PREP(SSI_TXWDS_DTLEN_MASK, size); + FIELD_MODIFY(SSI_TXWDS_WDLEN_MASK, &val, size); + FIELD_MODIFY(SSI_TXWDS_DTLEN_MASK, &val, size); writel(val, priv->base + SSI_TXWDS); val = readl(priv->base + SSI_RXWDS); - val &= ~SSI_RXWDS_DTLEN_MASK; - val |= FIELD_PREP(SSI_RXWDS_DTLEN_MASK, size); + FIELD_MODIFY(SSI_RXWDS_DTLEN_MASK, &val, size); writel(val, priv->base + SSI_RXWDS); } @@ -308,9 +306,8 @@ static void uniphier_spi_set_fifo_threshold(struct uniphier_spi_priv *priv, u32 val; val = readl(priv->base + SSI_FC); - val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); - val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold); - val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold); + FIELD_MODIFY(SSI_FC_TXFTH_MASK, &val, SSI_FIFO_DEPTH - threshold); + FIELD_MODIFY(SSI_FC_RXFTH_MASK, &val, threshold); writel(val, priv->base + SSI_FC); } From 3e0483e93a8be320f70a1ff68d835f7f015af311 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 9 Apr 2026 15:48:11 +0800 Subject: [PATCH 231/655] mmc: core: Add validation for host-provided max_segs The max_segs field is of type unsigned short, and if a host driver sets an excessively large value, it may be truncated to zero. This can cause mmc_alloc_sg() to call kmalloc_objs() with a zero size allocation request, which leads to undefined behavior. Under the SLUB allocator, kmalloc(0) returns a special pointer (ZERO_SIZE_PTR). The subsequent 'if (sg)' check will evaluate to true, and sg_init_table() will then attempt to access invalid memory, resulting in a crash: dwmmc_rockchip 2a310000.mmc: Successfully tuned phase to 133 mmc1: new UHS-I speed SDR104 SDHC card at address aaaa Unable to handle kernel paging request at virtual address 0000001ffffffff0 Mem abort info: ESR = 0x0000000096000004 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x04: level 0 translation fault Data abort info: ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 CM = 0, WnR = 0, TnD = 0, TagAccess = 0 GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 user pgtable: 4k pages, 48-bit VAs, pgdp=0000000102c88000 [0000001ffffffff0] pgd=0000000000000000, p4d=0000000000000000 Internal error: Oops: 0000000096000004 [#1] SMP Modules linked in: CPU: 2 UID: 0 PID: 102 Comm: kworker/2:1 Not tainted 7.0.0-rc6-next-20260331-00013-g4d93c25963c5-dirty #80 PREEMPT Hardware name: Rockchip RK3576 EVB V10 Board (DT) Workqueue: events_freezable mmc_rescan pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : sg_init_table+0x2c/0x50 lr : sg_init_table+0x24/0x50 sp : ffff8000837db710 x29: ffff8000837db710 x28: 000000000000c000 x27: 0000000000000300 x26: 0000000000000000 x25: 0000000000000040 x24: ffff0000c46a0000 x23: 0000000000000000 x22: ffff0000c0c73c00 x21: 0000000000000010 x20: 0000000000000010 x19: 0000000000000000 x18: 000000000000002c x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000 x14: 0000000000000400 x13: ffff8000837dc000 x12: 0000000000000000 x11: ffff0000c0c73ca0 x10: 0000000000000040 x9 : 459ec1f0abbdbb00 x8 : 0000001fffffffe0 x7 : 0000000000000000 x6 : 000000000000003f x5 : 0000000000035579 x4 : 0000000000000901 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000010 Call trace: sg_init_table+0x2c/0x50 (P) mmc_mq_init_request+0x64/0x90 blk_mq_alloc_map_and_rqs+0x3ac/0x480 blk_mq_alloc_set_map_and_rqs+0x98/0x1e0 blk_mq_alloc_tag_set+0x1c0/0x290 mmc_init_queue+0x120/0x370 mmc_blk_alloc_req+0x150/0x420 To prevent this, add a validation check in mmc_mq_init_request() to detect when sg_len (derived from max_segs) is zero. If sg_len is zero, we return an error and print an error message, allowing host driver developers to identify and fix incorrect max_segs configuration. This is a defensive measure that ensures the MMC core fails gracefully when host drivers provide invalid max_segs values, rather than crashing with a page fault. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/queue.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 39fcb662c43f..c9028e4a7e56 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -214,8 +214,14 @@ static int mmc_mq_init_request(struct blk_mq_tag_set *set, struct request *req, struct mmc_queue *mq = set->driver_data; struct mmc_card *card = mq->card; struct mmc_host *host = card->host; + u16 sg_len = mmc_get_max_segments(host); - mq_rq->sg = mmc_alloc_sg(mmc_get_max_segments(host), GFP_KERNEL); + if (!sg_len) { + dev_err(mmc_dev(host), "Wrong max_segs assigned\n"); + return -EINVAL; + } + + mq_rq->sg = mmc_alloc_sg(sg_len, GFP_KERNEL); if (!mq_rq->sg) return -ENOMEM; From 915b559f7aca7612ab943f7905011e3e1bd131a2 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 9 Apr 2026 15:48:12 +0800 Subject: [PATCH 232/655] mmc: dw_mmc: Move misplaced comment It was originally part of the @cmd_status field description but became separated and now appears between @ring_size and @dms without proper context. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 42e58be74ce0..14fb2b309c7c 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -78,8 +78,8 @@ struct dw_mci_dma_slave { * @sg_cpu: Virtual address of DMA buffer. * @dma_ops: Pointer to DMA callbacks. * @cmd_status: Snapshot of SR taken upon completion of the current - * @ring_size: Buffer size for idma descriptors. * command. Only valid when EVENT_CMD_COMPLETE is pending. + * @ring_size: Buffer size for idma descriptors. * @dms: structure of slave-dma private data. * @phy_regs: physical address of controller's register map * @data_status: Snapshot of SR taken upon completion of the current From 14ca4868886f2188401fe06cd7bf01a330b3fb99 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 31 Dec 2025 13:07:21 +0100 Subject: [PATCH 233/655] watchdog: apple: Add "apple,t8103-wdt" compatible After discussion with the devicetree maintainers we agreed to not extend lists with the generic compatible "apple,wdt" anymore [1]. Use "apple,t8103-wdt" as base compatible as it is the SoC the driver and bindings were written for. [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/ Fixes: 4ed224aeaf66 ("watchdog: Add Apple SoC watchdog driver") Cc: stable@vger.kernel.org Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau Link: https://lore.kernel.org/r/20251231-watchdog-apple-t8103-base-compat-v1-1-1702a02e0c45@jannau.net Signed-off-by: Guenter Roeck --- drivers/watchdog/apple_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c index 66a158f67a71..6b9b0f9b05ce 100644 --- a/drivers/watchdog/apple_wdt.c +++ b/drivers/watchdog/apple_wdt.c @@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume); static const struct of_device_id apple_wdt_of_match[] = { + { .compatible = "apple,t8103-wdt" }, { .compatible = "apple,wdt" }, {}, }; From cb0c1fd6e64d53d29f449fd149defc94aee37af4 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 7 May 2026 09:33:08 +0200 Subject: [PATCH 234/655] dt-bindings: watchdog: apple,wdt: Add t8122 compatible The watchdog on the Apple silicon t8122 (M3) SoC is compatible with the existing driver. Add "apple,t8122-wdt" as SoC specific compatible under "apple,t8103-wdt" used by the driver. Acked-by: Rob Herring (Arm) Reviewed-by: Joshua Peisach Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau Link: https://lore.kernel.org/r/20260507-apple-m3-initial-devicetrees-v3-2-ca07c81b5dc7@jannau.net Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/apple,wdt.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml index 05602678c070..845b5e8b5abc 100644 --- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml @@ -16,7 +16,9 @@ properties: compatible: oneOf: - items: - - const: apple,t6020-wdt + - enum: + - apple,t6020-wdt + - apple,t8122-wdt - const: apple,t8103-wdt - items: - enum: From 4bac6b89e3cc8bd728aa40c3879e31ff85b8217e Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Wed, 15 Apr 2026 20:32:08 +0530 Subject: [PATCH 235/655] mmc: dw_mmc: implement option for configuring DMA threshold Some controllers, such as certain Exynos SDIO ones, are unable to perform DMA transfers of small amount of bytes properly. Following the device tree schema, implement the property to define the DMA transfer threshold (from a hard coded value of 16 bytes) so that lesser number of bytes can be transferred safely skipping DMA in such controllers. The value of 16 bytes stays as the default for controllers which do not define it. This value can be overridden by implementation-specific init sequences. Signed-off-by: Kaustabh Chakraborty Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 4 ++-- drivers/mmc/host/dw_mmc.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 20193ee7b73e..3b4157f34d11 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -40,7 +40,6 @@ SDMMC_INT_RESP_ERR | SDMMC_INT_HLE) #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ DW_MCI_CMD_ERROR_FLAGS) -#define DW_MCI_DMA_THRESHOLD 16 #define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */ #define DW_MCI_FREQ_MIN 100000 /* unit: HZ */ @@ -821,7 +820,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host, * non-word-aligned buffers or lengths. Also, we don't bother * with all the DMA setup overhead for short transfers. */ - if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) + if (data->blocks * data->blksz < host->dma_threshold) return -EINVAL; if (data->blksz & 3) @@ -3185,6 +3184,7 @@ struct dw_mci *dw_mci_alloc_host(struct device *dev) host = mmc_priv(mmc); host->mmc = mmc; host->dev = dev; + host->dma_threshold = 16; return host; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 14fb2b309c7c..2ce8585e2c1e 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -107,6 +107,7 @@ struct dw_mci_dma_slave { * @ciu_clk: Pointer to card interface unit clock instance. * @fifo_depth: depth of FIFO. * @data_addr_override: override fifo reg offset with this value. + * @dma_threshold: data threshold value in bytes to carry out a DMA transfer. * @wm_aligned: force fifo watermark equal with data length in PIO mode. * Set as true if alignment is needed. * @data_shift: log2 of FIFO item size. @@ -163,6 +164,7 @@ struct dw_mci { void __iomem *regs; void __iomem *fifo_reg; u32 data_addr_override; + u32 dma_threshold; bool wm_aligned; struct scatterlist *sg; From 65c132fa8c93a75b27860c3f03593937d8dc2c41 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Wed, 15 Apr 2026 20:32:09 +0530 Subject: [PATCH 236/655] mmc: dw_mmc: exynos: increase DMA threshold value for exynos7870 Exynos 7870 compatible controllers, such as SDIO ones are not able to perform DMA transfers for small sizes of data (~16 to ~512 bytes), resulting in cache issues in subsequent transfers. Increase the DMA transfer threshold to 512 to allow the shorter transfers to take place, bypassing DMA. Signed-off-by: Kaustabh Chakraborty Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-exynos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 261344d3a8cf..4b76b997ddc1 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -141,6 +141,7 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) { /* Quirk needed for certain Exynos SoCs */ host->quirks |= DW_MMC_QUIRK_FIFO64_32; + host->dma_threshold = 512; } if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) { From eb0ff5d010cf451deb810f9628396d43ad119147 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 4 May 2026 16:43:23 +0200 Subject: [PATCH 237/655] dt-bindings: mmc: renesas,sdhi: Document R-Car M3Le support Document support for the SD Card/MMC Interface in the Renesas R-Car M3Le (R8A779MD) SoC. Signed-off-by: Marek Vasut Acked-by: Conor Dooley Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml index 64fac0d11329..4d66966ce290 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml +++ b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml @@ -52,6 +52,7 @@ properties: - renesas,sdhi-r8a77980 # R-Car V3H - renesas,sdhi-r8a77990 # R-Car E3 - renesas,sdhi-r8a77995 # R-Car D3 + - renesas,sdhi-r8a779md # R-Car M3Le - const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2 - items: - enum: From 2c7210ded06da18b439b3a08b8a3caa42f2f1f72 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 4 May 2026 16:43:24 +0200 Subject: [PATCH 238/655] mmc: renesas_sdhi: add R-Car M3Le compatibility string Add support for the SD Card/MMC Interface in the Renesas R-Car M3Le (R8A779MD) SoC. R19UH0260EJ0100 Rev.1.00 , Dec 25, 2025 Notes 7.70. indicates that HS400 mode is not supported. Signed-off-by: Marek Vasut Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index f6ebb7bc7ede..b716a518f265 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -285,6 +285,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, }, { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, }, + { .compatible = "renesas,sdhi-r8a779md", .data = &of_rcar_gen3_nohs400_compatible, }, { .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, }, { .compatible = "renesas,sdhi-r9a09g057", .data = &of_rzg2l_compatible, }, { .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, }, From 4a3e92e8cfb9741cb687b14fc6ca81714b4c2c26 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 May 2026 12:33:24 +0200 Subject: [PATCH 239/655] mmc: host: Move MODULE_DEVICE_TABLE next to the table itself By convention MODULE_DEVICE_TABLE() immediately follows the ID table it exports, because this is easier to read and verify. It also makes more sense since #ifdef for ACPI or OF could hide both of them. Most of the privers already have this correctly placed, so adjust the missing ones. No functional impact. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Ulf Hansson --- drivers/mmc/host/cavium-thunderx.c | 2 +- drivers/mmc/host/tifm_sd.c | 2 +- drivers/mmc/host/wmt-sdmmc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/cavium-thunderx.c b/drivers/mmc/host/cavium-thunderx.c index 1373deb3f531..84ff6d82ae3c 100644 --- a/drivers/mmc/host/cavium-thunderx.c +++ b/drivers/mmc/host/cavium-thunderx.c @@ -188,6 +188,7 @@ static const struct pci_device_id thunder_mmc_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa010) }, { 0, } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, thunder_mmc_id_table); static struct pci_driver thunder_mmc_driver = { .name = KBUILD_MODNAME, @@ -201,4 +202,3 @@ module_pci_driver(thunder_mmc_driver); MODULE_AUTHOR("Cavium Inc."); MODULE_DESCRIPTION("Cavium ThunderX eMMC Driver"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, thunder_mmc_id_table); diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index c1f7d5b37911..aebffd3ebf60 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -1044,6 +1044,7 @@ static int tifm_sd_resume(struct tifm_dev *sock) static struct tifm_device_id tifm_sd_id_tbl[] = { { TIFM_TYPE_SD }, { } }; +MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl); static struct tifm_driver tifm_sd_driver = { .driver = { @@ -1070,7 +1071,6 @@ static void __exit tifm_sd_exit(void) MODULE_AUTHOR("Alex Dubov"); MODULE_DESCRIPTION("TI FlashMedia SD driver"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl); MODULE_VERSION(DRIVER_VERSION); module_init(tifm_sd_init); diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 1b1d691e19fc..489daee4f4fc 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -744,6 +744,7 @@ static const struct of_device_id wmt_mci_dt_ids[] = { { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps }, { /* Sentinel */ }, }; +MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids); static int wmt_mci_probe(struct platform_device *pdev) { @@ -980,4 +981,3 @@ module_platform_driver(wmt_mci_driver); MODULE_DESCRIPTION("Wondermedia MMC/SD Driver"); MODULE_AUTHOR("Tony Prisk"); MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids); From 5808ef063b5e9342cb223bb9d07a6d5f6ac8711d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 May 2026 12:39:28 +0200 Subject: [PATCH 240/655] memstick: Constify the driver id_table Just like all other driver structures, the id_table should never be modified by core subsystem parts. Constify this member and actual data structures for increased code safety. Signed-off-by: Krzysztof Kozlowski Acked-by: Greg Kroah-Hartman Signed-off-by: Ulf Hansson --- drivers/memstick/host/tifm_ms.c | 2 +- drivers/misc/tifm_core.c | 4 ++-- drivers/mmc/host/tifm_sd.c | 2 +- include/linux/tifm.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 0b6a90661eee..0a54586aa54e 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -647,7 +647,7 @@ static int tifm_ms_resume(struct tifm_dev *sock) #endif /* CONFIG_PM */ -static struct tifm_device_id tifm_ms_id_tbl[] = { +static const struct tifm_device_id tifm_ms_id_tbl[] = { { TIFM_TYPE_MS }, { 0 } }; diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index da0827724a61..aac8f0933e43 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -31,7 +31,7 @@ static const char *tifm_media_type_name(unsigned char type, unsigned char nt) return card_type_name[nt][type - 1]; } -static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id) +static int tifm_dev_match(struct tifm_dev *sock, const struct tifm_device_id *id) { if (sock->type == id->type) return 1; @@ -43,7 +43,7 @@ static int tifm_bus_match(struct device *dev, const struct device_driver *drv) struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); const struct tifm_driver *fm_drv = container_of_const(drv, struct tifm_driver, driver); - struct tifm_device_id *ids = fm_drv->id_table; + const struct tifm_device_id *ids = fm_drv->id_table; if (ids) { while (ids->type) { diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index aebffd3ebf60..28ab2526dab1 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -1041,7 +1041,7 @@ static int tifm_sd_resume(struct tifm_dev *sock) #endif /* CONFIG_PM */ -static struct tifm_device_id tifm_sd_id_tbl[] = { +static const struct tifm_device_id tifm_sd_id_tbl[] = { { TIFM_TYPE_SD }, { } }; MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl); diff --git a/include/linux/tifm.h b/include/linux/tifm.h index 44073d06710f..752fcfae27fe 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -97,7 +97,7 @@ struct tifm_dev { }; struct tifm_driver { - struct tifm_device_id *id_table; + const struct tifm_device_id *id_table; int (*probe)(struct tifm_dev *dev); void (*remove)(struct tifm_dev *dev); int (*suspend)(struct tifm_dev *dev, From 4f28846aaf8db9668e338b8987973f8935edff34 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Thu, 7 May 2026 00:05:37 +0500 Subject: [PATCH 241/655] mmc: davinci: avoid NULL deref of host->data in IRQ handler mmc_davinci_irq() returns early only when both host->cmd and host->data are NULL: if (host->cmd == NULL && host->data == NULL) { ... return IRQ_NONE; } So we may legitimately reach the rest of the handler with host->data == NULL (and therefore data == NULL). The DATDNE branch already guards against this with an explicit "if (data != NULL)" check, but the subsequent TOUTRD ("read data timeout") and CRCWR/CRCRD ("data CRC error") branches dereference data unconditionally: if (qstatus & MMCST0_TOUTRD) { data->error = -ETIMEDOUT; <-- NULL deref ... davinci_abort_data(host, data); } if (qstatus & (MMCST0_CRCWR | MMCST0_CRCRD)) { data->error = -EILSEQ; <-- NULL deref ... } If either bit is set in qstatus while host->data is NULL, the kernel will crash inside the IRQ handler. smatch flags this: drivers/mmc/host/davinci_mmc.c:933 mmc_davinci_irq() error: we previously assumed 'data' could be null (see line 914) Gate both branches on a non-NULL data, matching the existing pattern used by the DATDNE branch. No functional change for callers where data is non-NULL, which is the only case in which these branches did meaningful work before this change. Signed-off-by: Stepan Ionichev Reviewed-by: Bartosz Golaszewski Signed-off-by: Ulf Hansson --- drivers/mmc/host/davinci_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 42b0118a45a8..42ad87aa48f5 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -928,7 +928,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) } } - if (qstatus & MMCST0_TOUTRD) { + if (data && (qstatus & MMCST0_TOUTRD)) { /* Read data timeout */ data->error = -ETIMEDOUT; end_transfer = 1; @@ -940,7 +940,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) davinci_abort_data(host, data); } - if (qstatus & (MMCST0_CRCWR | MMCST0_CRCRD)) { + if (data && (qstatus & (MMCST0_CRCWR | MMCST0_CRCRD))) { /* Data CRC error */ data->error = -EILSEQ; end_transfer = 1; From d11f110c4ad2d431f4440baba9afb5b8e4190977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Thu, 7 May 2026 18:10:07 +0200 Subject: [PATCH 242/655] mmc: via-sdmmc: Simplify initialisation of pci_device_id array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of assigning the pci_device_id members using a list (which is hard to read as you need to look at the order of the members in that struct in parallel) use the PCI_VDEVICE() convenience macro to compact the initialisation while improving readability. Also drop trailing zeros that the compiler will care about then. The change doesn't introduce binary changes to the compiled driver, verified on both ARCH=x86 and ARCH=arm64. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Ulf Hansson --- drivers/mmc/host/via-sdmmc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index c628b3bbfd7a..8c049f8355cd 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -323,9 +323,8 @@ struct via_crdr_mmc_host { #define VIA_CMD_TIMEOUT_MS 1000 static const struct pci_device_id via_ids[] = { - {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_9530, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, - {0,} + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_9530) }, + { } }; MODULE_DEVICE_TABLE(pci, via_ids); From 04a8ddc39e5cfebffb06f383350a6ee393ba89a6 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Mon, 11 May 2026 10:53:56 +0200 Subject: [PATCH 243/655] dt-bindings: mmc: spacemit,sdhci: add pinctrl support for voltage switching Document pinctrl properties to support voltage-dependent pin configuration switching for UHS-I SD card modes. Add optional pinctrl-names property with two states: - "default": For 3.3V operation with standard drive strength - "state_uhs": For 1.8V operation with optimized drive strength These pinctrl states allow the SDHCI driver to coordinate voltage switching with pin configuration changes, ensuring proper signal integrity during UHS-I mode transitions. Acked-by: Conor Dooley Signed-off-by: Iker Pedrosa Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/spacemit,sdhci.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/spacemit,sdhci.yaml b/Documentation/devicetree/bindings/mmc/spacemit,sdhci.yaml index 9a055d963a7f..34d202af909f 100644 --- a/Documentation/devicetree/bindings/mmc/spacemit,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/spacemit,sdhci.yaml @@ -44,6 +44,18 @@ properties: - const: axi - const: sdh + pinctrl-names: + minItems: 1 + items: + - const: default + - const: uhs + + pinctrl-0: + description: Default pinctrl state for 3.3V operation + + pinctrl-1: + description: Optional pinctrl state for 1.8V UHS operation with "uhs" name + required: - compatible - reg @@ -62,4 +74,7 @@ examples: interrupt-parent = <&plic>; clocks = <&clk_apmu 10>, <&clk_apmu 13>; clock-names = "core", "io"; + pinctrl-names = "default", "uhs"; + pinctrl-0 = <&sdhci_default_cfg>; + pinctrl-1 = <&sdhci_uhs_cfg>; }; From f87b273e4b6dfe57dcd63c24cbe3764d1f6954ae Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Mon, 11 May 2026 10:53:57 +0200 Subject: [PATCH 244/655] mmc: sdhci-of-k1: enable essential clock infrastructure for SD operation Ensure SD card pins receive clock signals by enabling pad clock generation and overriding automatic clock gating. Required for all SD operation modes. The SDHC_GEN_PAD_CLK_ON setting in LEGACY_CTRL_REG is safe for both SD and eMMC operation as both protocols use the same physical MMC interface pins and require proper clock signal generation at the hardware level for signal integrity and timing. Additional SD-specific clock overrides (SDHC_OVRRD_CLK_OEN and SDHC_FORCE_CLK_ON) are conditionally applied only for SD-only controllers to handle removable card scenarios. Tested-by: Anand Moon Acked-by: Adrian Hunter Tested-by: Trevor Gamblin Reviewed-by: Troy Mitchell Tested-by: Vincent Legoll Signed-off-by: Iker Pedrosa Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-k1.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-k1.c b/drivers/mmc/host/sdhci-of-k1.c index 455656f9842d..0dd06fc19b85 100644 --- a/drivers/mmc/host/sdhci-of-k1.c +++ b/drivers/mmc/host/sdhci-of-k1.c @@ -21,6 +21,13 @@ #include "sdhci.h" #include "sdhci-pltfm.h" +#define SPACEMIT_SDHC_OP_EXT_REG 0x108 +#define SDHC_OVRRD_CLK_OEN BIT(11) +#define SDHC_FORCE_CLK_ON BIT(12) + +#define SPACEMIT_SDHC_LEGACY_CTRL_REG 0x10C +#define SDHC_GEN_PAD_CLK_ON BIT(6) + #define SPACEMIT_SDHC_MMC_CTRL_REG 0x114 #define SDHC_MISC_INT_EN BIT(1) #define SDHC_MISC_INT BIT(2) @@ -101,6 +108,12 @@ static void spacemit_sdhci_reset(struct sdhci_host *host, u8 mask) if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) spacemit_sdhci_setbits(host, SDHC_MMC_CARD_MODE, SPACEMIT_SDHC_MMC_CTRL_REG); + + spacemit_sdhci_setbits(host, SDHC_GEN_PAD_CLK_ON, SPACEMIT_SDHC_LEGACY_CTRL_REG); + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + spacemit_sdhci_setbits(host, SDHC_OVRRD_CLK_OEN | SDHC_FORCE_CLK_ON, + SPACEMIT_SDHC_OP_EXT_REG); } static void spacemit_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) From 00a97fc57c09ff1cf71107753d9b5629caeb8c8a Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Mon, 11 May 2026 10:53:58 +0200 Subject: [PATCH 245/655] mmc: sdhci-of-k1: add regulator and pinctrl voltage switching support Add voltage switching infrastructure for UHS-I modes by integrating both regulator framework (for supply voltage control) and pinctrl state switching (for pin drive strength optimization). - Add regulator supply parsing and voltage switching callback - Add optional pinctrl state switching between "default" (3.3V) and "state_uhs" (1.8V) configurations - Enable coordinated voltage and pin configuration changes for UHS modes This provides complete voltage switching support while maintaining backward compatibility when pinctrl states are not defined. Tested-by: Anand Moon Tested-by: Trevor Gamblin Acked-by: Adrian Hunter Reviewed-by: Troy Mitchell Tested-by: Vincent Legoll Signed-off-by: Iker Pedrosa Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-k1.c | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-k1.c b/drivers/mmc/host/sdhci-of-k1.c index 0dd06fc19b85..d9144537032a 100644 --- a/drivers/mmc/host/sdhci-of-k1.c +++ b/drivers/mmc/host/sdhci-of-k1.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "sdhci.h" @@ -71,6 +72,9 @@ struct spacemit_sdhci_host { struct clk *clk_core; struct clk *clk_io; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_default; + struct pinctrl_state *pinctrl_uhs; }; /* All helper functions will update clr/set while preserve rest bits */ @@ -219,6 +223,46 @@ static void spacemit_sdhci_pre_hs400_to_hs200(struct mmc_host *mmc) SPACEMIT_SDHC_PHY_CTRL_REG); } +static int spacemit_sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct spacemit_sdhci_host *sdhst = sdhci_pltfm_priv(pltfm_host); + struct pinctrl_state *state; + int ret; + + ret = sdhci_start_signal_voltage_switch(mmc, ios); + if (ret) + return ret; + + if (!sdhst->pinctrl) + return 0; + + /* Select appropriate pinctrl state based on signal voltage */ + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + state = sdhst->pinctrl_default; + break; + case MMC_SIGNAL_VOLTAGE_180: + state = sdhst->pinctrl_uhs; + break; + default: + dev_warn(mmc_dev(mmc), "unsupported voltage %d\n", ios->signal_voltage); + return 0; + } + + ret = pinctrl_select_state(sdhst->pinctrl, state); + if (ret) { + dev_warn(mmc_dev(mmc), "failed to select pinctrl state: %d\n", ret); + return 0; + } + dev_dbg(mmc_dev(mmc), "switched to %s pinctrl state\n", + ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180 ? "UHS" : "default"); + + return 0; +} + static inline int spacemit_sdhci_get_clocks(struct device *dev, struct sdhci_pltfm_host *pltfm_host) { @@ -252,6 +296,30 @@ static inline int spacemit_sdhci_get_resets(struct device *dev) return 0; } +static inline void spacemit_sdhci_get_pins(struct device *dev, + struct sdhci_pltfm_host *pltfm_host) +{ + struct spacemit_sdhci_host *sdhst = sdhci_pltfm_priv(pltfm_host); + + sdhst->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(sdhst->pinctrl)) { + sdhst->pinctrl = NULL; + dev_dbg(dev, "pinctrl not available, voltage switching will work without it\n"); + return; + } + + sdhst->pinctrl_default = pinctrl_lookup_state(sdhst->pinctrl, "default"); + if (IS_ERR(sdhst->pinctrl_default)) + sdhst->pinctrl_default = NULL; + + sdhst->pinctrl_uhs = pinctrl_lookup_state(sdhst->pinctrl, "uhs"); + if (IS_ERR(sdhst->pinctrl_uhs)) + sdhst->pinctrl_uhs = NULL; + + dev_dbg(dev, "pinctrl setup: default=%p, uhs=%p\n", + sdhst->pinctrl_default, sdhst->pinctrl_uhs); +} + static const struct sdhci_ops spacemit_sdhci_ops = { .get_max_clock = spacemit_sdhci_clk_get_max_clock, .reset = spacemit_sdhci_reset, @@ -324,6 +392,10 @@ static int spacemit_sdhci_probe(struct platform_device *pdev) host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY; + spacemit_sdhci_get_pins(dev, pltfm_host); + + host->mmc_host_ops.start_signal_voltage_switch = spacemit_sdhci_start_signal_voltage_switch; + ret = spacemit_sdhci_get_clocks(dev, pltfm_host); if (ret) goto err_pltfm; From e9cb83c10071808aa7db4582e007a650aa6aa183 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Mon, 11 May 2026 10:53:59 +0200 Subject: [PATCH 246/655] mmc: sdhci-of-k1: add comprehensive SDR tuning support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement software tuning algorithm to enable UHS-I SDR modes for SD card operation and HS200 mode for eMMC. This adds both TX and RX delay line tuning based on the SpacemiT K1 controller capabilities. Algorithm features: - Add tuning register definitions (RX_CFG, DLINE_CTRL, DLINE_CFG) - Conditional tuning: only for high-speed modes (≥100MHz) - TX tuning: configure transmit delay line with optimal values (dline_reg=0, delaycode=127) to ensure optimal signal output timing - RX tuning: single-pass window detection algorithm testing full delay range (0-255) to find optimal receive timing window - Retry mechanism: multiple fallback delays within optimal window for improved reliability Tested-by: Anand Moon Acked-by: Adrian Hunter Tested-by: Trevor Gamblin Tested-by: Vincent Legoll Signed-off-by: Iker Pedrosa Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-k1.c | 172 +++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-k1.c b/drivers/mmc/host/sdhci-of-k1.c index d9144537032a..37b0911e7cf2 100644 --- a/drivers/mmc/host/sdhci-of-k1.c +++ b/drivers/mmc/host/sdhci-of-k1.c @@ -69,6 +69,28 @@ #define SDHC_PHY_DRIVE_SEL GENMASK(2, 0) #define SDHC_RX_BIAS_CTRL BIT(5) +#define SPACEMIT_SDHC_RX_CFG_REG 0x118 +#define SDHC_RX_SDCLK_SEL0_MASK GENMASK(1, 0) +#define SDHC_RX_SDCLK_SEL1_MASK GENMASK(3, 2) +#define SDHC_RX_SDCLK_SEL1 FIELD_PREP(SDHC_RX_SDCLK_SEL1_MASK, 1) + +#define SPACEMIT_SDHC_DLINE_CTRL_REG 0x130 +#define SDHC_DLINE_PU BIT(0) +#define SDHC_RX_DLINE_CODE_MASK GENMASK(23, 16) +#define SDHC_TX_DLINE_CODE_MASK GENMASK(31, 24) + +#define SPACEMIT_SDHC_DLINE_CFG_REG 0x134 +#define SDHC_RX_DLINE_REG_MASK GENMASK(7, 0) +#define SDHC_RX_DLINE_GAIN BIT(8) +#define SDHC_TX_DLINE_REG_MASK GENMASK(23, 16) + +#define SPACEMIT_RX_DLINE_REG 9 +#define SPACEMIT_RX_TUNE_DELAY_MIN 0x0 +#define SPACEMIT_RX_TUNE_DELAY_MAX 0xFF + +#define SPACEMIT_TX_TUNING_DLINE_REG 0x00 +#define SPACEMIT_TX_TUNING_DELAYCODE 127 + struct spacemit_sdhci_host { struct clk *clk_core; struct clk *clk_io; @@ -96,6 +118,50 @@ static inline void spacemit_sdhci_clrsetbits(struct sdhci_host *host, u32 clr, u sdhci_writel(host, val, reg); } +static void spacemit_sdhci_set_rx_delay(struct sdhci_host *host, u8 delay) +{ + spacemit_sdhci_clrsetbits(host, SDHC_RX_DLINE_CODE_MASK, + FIELD_PREP(SDHC_RX_DLINE_CODE_MASK, delay), + SPACEMIT_SDHC_DLINE_CTRL_REG); +} + +static void spacemit_sdhci_set_tx_delay(struct sdhci_host *host, u8 delay) +{ + spacemit_sdhci_clrsetbits(host, SDHC_TX_DLINE_CODE_MASK, + FIELD_PREP(SDHC_TX_DLINE_CODE_MASK, delay), + SPACEMIT_SDHC_DLINE_CTRL_REG); +} + +static void spacemit_sdhci_set_tx_dline_reg(struct sdhci_host *host, u8 dline_reg) +{ + spacemit_sdhci_clrsetbits(host, SDHC_TX_DLINE_REG_MASK, + FIELD_PREP(SDHC_TX_DLINE_REG_MASK, dline_reg), + SPACEMIT_SDHC_DLINE_CFG_REG); +} + +static void spacemit_sdhci_tx_tuning_prepare(struct sdhci_host *host) +{ + spacemit_sdhci_setbits(host, SDHC_TX_MUX_SEL, SPACEMIT_SDHC_TX_CFG_REG); + spacemit_sdhci_setbits(host, SDHC_DLINE_PU, SPACEMIT_SDHC_DLINE_CTRL_REG); + udelay(5); +} + +static void spacemit_sdhci_prepare_tuning(struct sdhci_host *host) +{ + spacemit_sdhci_clrsetbits(host, SDHC_RX_DLINE_REG_MASK, + FIELD_PREP(SDHC_RX_DLINE_REG_MASK, SPACEMIT_RX_DLINE_REG), + SPACEMIT_SDHC_DLINE_CFG_REG); + + spacemit_sdhci_setbits(host, SDHC_DLINE_PU, SPACEMIT_SDHC_DLINE_CTRL_REG); + udelay(5); + + spacemit_sdhci_clrsetbits(host, SDHC_RX_SDCLK_SEL1_MASK, SDHC_RX_SDCLK_SEL1, + SPACEMIT_SDHC_RX_CFG_REG); + + if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200) + spacemit_sdhci_setbits(host, SDHC_HS200_USE_RFIFO, SPACEMIT_SDHC_PHY_FUNC_REG); +} + static void spacemit_sdhci_reset(struct sdhci_host *host, u8 mask) { sdhci_reset(host, mask); @@ -191,6 +257,111 @@ static unsigned int spacemit_sdhci_clk_get_max_clock(struct sdhci_host *host) return clk_get_rate(pltfm_host->clk); } +static int spacemit_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int current_len = 0, current_start = 0; + int max_pass_len = 0, max_pass_start = 0; + struct mmc_host *mmc = host->mmc; + struct mmc_ios ios = mmc->ios; + u8 final_delay; + int ret = 0; + int i; + + /* + * Tuning is required for SDR50/SDR104, HS200/HS400 cards and + * if clock frequency is greater than 100MHz in these modes. + */ + if (host->clock < 100 * 1000 * 1000 || + !(ios.timing == MMC_TIMING_MMC_HS200 || + ios.timing == MMC_TIMING_UHS_SDR50 || + ios.timing == MMC_TIMING_UHS_SDR104)) + return 0; + + if (mmc->caps2 & MMC_CAP2_NO_MMC) { + spacemit_sdhci_set_tx_dline_reg(host, SPACEMIT_TX_TUNING_DLINE_REG); + spacemit_sdhci_set_tx_delay(host, SPACEMIT_TX_TUNING_DELAYCODE); + spacemit_sdhci_tx_tuning_prepare(host); + + dev_dbg(mmc_dev(host->mmc), "TX tuning: dline_reg=%d, delaycode=%d\n", + SPACEMIT_TX_TUNING_DLINE_REG, SPACEMIT_TX_TUNING_DELAYCODE); + } + + spacemit_sdhci_prepare_tuning(host); + + for (i = SPACEMIT_RX_TUNE_DELAY_MIN; i <= SPACEMIT_RX_TUNE_DELAY_MAX; i++) { + spacemit_sdhci_set_rx_delay(host, i); + ret = mmc_send_tuning(host->mmc, opcode, NULL); + + dev_dbg(mmc_dev(host->mmc), "RX delay %d: %s\n", + i, ret == 0 ? "pass" : "fail"); + + if (ret == 0) { + /* Test passed - extend current window */ + if (current_len == 0) + current_start = i; + current_len++; + } else { + /* Test failed - check if current window is best so far */ + if (current_len > max_pass_len) { + max_pass_len = current_len; + max_pass_start = current_start; + } + current_len = 0; + } + } + + if (current_len > max_pass_len) { + max_pass_len = current_len; + max_pass_start = current_start; + } + + if (max_pass_len < 3) { + dev_err(mmc_dev(host->mmc), "Tuning failed: no stable window found\n"); + return -EIO; + } + + final_delay = max_pass_start + max_pass_len / 2; + spacemit_sdhci_set_rx_delay(host, final_delay); + ret = mmc_send_tuning(host->mmc, opcode, NULL); + if (ret) { + u8 retry_delays[] = { + max_pass_start + max_pass_len / 4, + max_pass_start + (3 * max_pass_len) / 4, + max_pass_start, + max_pass_start + max_pass_len - 1 + }; + int retry_count = ARRAY_SIZE(retry_delays); + + dev_warn(mmc_dev(mmc), "Primary delay %d failed, trying alternatives\n", + final_delay); + + for (i = 0; i < retry_count; i++) { + if (retry_delays[i] >= SPACEMIT_RX_TUNE_DELAY_MIN && + retry_delays[i] <= SPACEMIT_RX_TUNE_DELAY_MAX) { + spacemit_sdhci_set_rx_delay(host, retry_delays[i]); + ret = mmc_send_tuning(host->mmc, opcode, NULL); + if (!ret) { + final_delay = retry_delays[i]; + dev_info(mmc_dev(mmc), "Retry successful with delay %d\n", + final_delay); + break; + } + } + } + + if (ret) { + dev_err(mmc_dev(mmc), "All retry attempts failed\n"); + return -EIO; + } + } + + dev_dbg(mmc_dev(host->mmc), + "Tuning successful: window %d-%d, using delay %d\n", + max_pass_start, max_pass_start + max_pass_len - 1, final_delay); + + return 0; +} + static int spacemit_sdhci_pre_select_hs400(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); @@ -326,6 +497,7 @@ static const struct sdhci_ops spacemit_sdhci_ops = { .set_bus_width = sdhci_set_bus_width, .set_clock = spacemit_sdhci_set_clock, .set_uhs_signaling = spacemit_sdhci_set_uhs_signaling, + .platform_execute_tuning = spacemit_sdhci_execute_tuning, }; static const struct sdhci_pltfm_data spacemit_sdhci_k1_pdata = { From 679b7a57fda5543b447cb17503d4a8a26f0725e1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 7 May 2026 12:24:09 +0200 Subject: [PATCH 247/655] dt-bindings: watchdog: renesas,rzn1-wdt: interrupts are not required It is now understood how the watchdog can do its job without the need of an interrupt. So, it is not required anymore but optional. Signed-off-by: Wolfram Sang Reviewed-by: Herve Codina Reviewed-by: Guenter Roeck Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20260507102410.43384-5-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/renesas,rzn1-wdt.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/watchdog/renesas,rzn1-wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,rzn1-wdt.yaml index 7e3ee533cd56..0e4b5b529e9c 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,rzn1-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,rzn1-wdt.yaml @@ -29,7 +29,6 @@ properties: required: - compatible - reg - - interrupts - clocks allOf: From dc795d4c0282a4fbfbcd76a70c09ca0888678443 Mon Sep 17 00:00:00 2001 From: Shengming Hu Date: Thu, 30 Apr 2026 22:04:41 +0800 Subject: [PATCH 248/655] mm/slub: defer freelist construction until after bulk allocation from a new slab Allocations from a fresh slab can consume all of its objects, and the freelist built during slab allocation is discarded immediately as a result. Instead of special-casing the whole-slab bulk refill case, defer freelist construction until after objects are emitted from a fresh slab. new_slab() now only allocates the slab and initializes its metadata. refill_objects() then obtains a fresh slab and lets alloc_from_new_slab() emit objects directly, building a freelist only for the objects left unallocated; the same change is applied to alloc_single_from_new_slab(). To keep CONFIG_SLAB_FREELIST_RANDOM=y/n on the same path, introduce a small iterator abstraction for walking free objects in allocation order. The iterator is used both for filling the sheaf and for building the freelist of the remaining objects. Also mark setup_object() inline. After this optimization, the compiler no longer consistently inlines this helper in the hot path, which can hurt performance. Explicitly marking it inline restores the expected code generation. This reduces per-object overhead when allocating from a fresh slab. The most direct benefit is in the paths that allocate objects first and only build a freelist for the remainder afterward: bulk allocation from a new slab in refill_objects(), single-object allocation from a new slab in ___slab_alloc(), and the corresponding early-boot paths that now use the same deferred-freelist scheme. Since refill_objects() is also used to refill sheaves, the optimization is not limited to the small set of kmem_cache_alloc_bulk()/kmem_cache_free_bulk() users; regular allocation workloads may benefit as well when they refill from a fresh slab. In slub_bulk_bench, the time per object drops by about 42% to 70% with CONFIG_SLAB_FREELIST_RANDOM=n, and by about 58% to 69% with CONFIG_SLAB_FREELIST_RANDOM=y. This benchmark is intended to isolate the cost removed by this change: each iteration allocates exactly slab->objects from a fresh slab. That makes it a near best-case scenario for deferred freelist construction, because the old path still built a full freelist even when no objects remained, while the new path avoids that work. Realistic workloads may see smaller end-to-end gains depending on how often allocations reach this fresh-slab refill path. Benchmark results (slub_bulk_bench): Machine: qemu-system-x86 -m 1024M -smp 8 -enable-kvm -cpu host Kernel: Linux 7.1.0-rc1-next-20260429 Config: x86_64_defconfig Cpu: 0 Rounds: 20 Total: 256MB - CONFIG_SLAB_FREELIST_RANDOM=n - obj_size=16, batch=256: before: 5.44 +- 0.07 ns/object after: 3.12 +- 0.03 ns/object delta: -42.6% obj_size=32, batch=128: before: 7.57 +- 0.32 ns/object after: 3.79 +- 0.07 ns/object delta: -49.9% obj_size=64, batch=64: before: 11.27 +- 0.09 ns/object after: 4.83 +- 0.06 ns/object delta: -57.2% obj_size=128, batch=32: before: 19.38 +- 0.13 ns/object after: 6.43 +- 0.08 ns/object delta: -66.8% obj_size=256, batch=32: before: 23.59 +- 0.18 ns/object after: 6.97 +- 0.07 ns/object delta: -70.5% obj_size=512, batch=32: before: 21.06 +- 0.14 ns/object after: 7.12 +- 0.17 ns/object delta: -66.2% - CONFIG_SLAB_FREELIST_RANDOM=y - obj_size=16, batch=256: before: 9.42 +- 0.11 ns/object after: 4.36 +- 0.19 ns/object delta: -53.7% obj_size=32, batch=128: before: 12.19 +- 0.62 ns/object after: 4.93 +- 0.07 ns/object delta: -59.6% obj_size=64, batch=64: before: 17.01 +- 0.73 ns/object after: 6.14 +- 0.12 ns/object delta: -63.9% obj_size=128, batch=32: before: 23.71 +- 1.10 ns/object after: 8.35 +- 0.18 ns/object delta: -64.8% obj_size=256, batch=32: before: 29.20 +- 0.35 ns/object after: 9.44 +- 1.32 ns/object delta: -67.7% obj_size=512, batch=32: before: 29.35 +- 0.79 ns/object after: 9.21 +- 0.34 ns/object delta: -68.6% Link: https://github.com/HSM6236/slub_bulk_test.git Suggested-by: Harry Yoo (Oracle) Reviewed-by: Harry Yoo (Oracle) Reviewed-by: Hao Li Tested-by: Hao Li Signed-off-by: Shengming Hu Link: https://patch.msgid.link/202604302204413066CxdJnJ3RAGH_7iE4EBIO@zte.com.cn Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 300 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 156 insertions(+), 144 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 0baa906f39ab..a7bd929bcb26 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -227,6 +227,17 @@ struct partial_bulk_context { struct list_head slabs; }; +/* Structure used to iterate over objects within a slab */ +struct slab_obj_iter { + unsigned long pos; + void *start; +#ifdef CONFIG_SLAB_FREELIST_RANDOM + unsigned long freelist_count; + unsigned long page_limit; + bool random; +#endif +}; + static inline bool kmem_cache_debug(struct kmem_cache *s) { return kmem_cache_debug_flags(s, SLAB_DEBUG_FLAGS); @@ -2733,7 +2744,7 @@ bool slab_free_freelist_hook(struct kmem_cache *s, void **head, void **tail, return *head != NULL; } -static void *setup_object(struct kmem_cache *s, void *object) +static inline void *setup_object(struct kmem_cache *s, void *object) { setup_object_debug(s, object); object = kasan_init_slab_obj(s, object); @@ -3329,87 +3340,14 @@ static void __init init_freelist_randomization(void) mutex_unlock(&slab_mutex); } -/* Get the next entry on the pre-computed freelist randomized */ -static void *next_freelist_entry(struct kmem_cache *s, - unsigned long *pos, void *start, - unsigned long page_limit, - unsigned long freelist_count) -{ - unsigned int idx; - - /* - * If the target page allocation failed, the number of objects on the - * page might be smaller than the usual size defined by the cache. - */ - do { - idx = s->random_seq[*pos]; - *pos += 1; - if (*pos >= freelist_count) - *pos = 0; - } while (unlikely(idx >= page_limit)); - - return (char *)start + idx; -} - static DEFINE_PER_CPU(struct rnd_state, slab_rnd_state); -/* Shuffle the single linked freelist based on a random pre-computed sequence */ -static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab, - bool allow_spin) -{ - void *start; - void *cur; - void *next; - unsigned long idx, pos, page_limit, freelist_count; - - if (slab->objects < 2 || !s->random_seq) - return false; - - freelist_count = oo_objects(s->oo); - if (allow_spin) { - pos = get_random_u32_below(freelist_count); - } else { - struct rnd_state *state; - - /* - * An interrupt or NMI handler might interrupt and change - * the state in the middle, but that's safe. - */ - state = &get_cpu_var(slab_rnd_state); - pos = prandom_u32_state(state) % freelist_count; - put_cpu_var(slab_rnd_state); - } - - page_limit = slab->objects * s->size; - start = fixup_red_left(s, slab_address(slab)); - - /* First entry is used as the base of the freelist */ - cur = next_freelist_entry(s, &pos, start, page_limit, freelist_count); - cur = setup_object(s, cur); - slab->freelist = cur; - - for (idx = 1; idx < slab->objects; idx++) { - next = next_freelist_entry(s, &pos, start, page_limit, - freelist_count); - next = setup_object(s, next); - set_freepointer(s, cur, next); - cur = next; - } - set_freepointer(s, cur, NULL); - - return true; -} #else static inline int init_cache_random_seq(struct kmem_cache *s) { return 0; } static inline void init_freelist_randomization(void) { } -static inline bool shuffle_freelist(struct kmem_cache *s, struct slab *slab, - bool allow_spin) -{ - return false; -} #endif /* CONFIG_SLAB_FREELIST_RANDOM */ static __always_inline void account_slab(struct slab *slab, int order, @@ -3438,15 +3376,14 @@ static __always_inline void unaccount_slab(struct slab *slab, int order, -(PAGE_SIZE << order)); } +/* Allocate and initialize a slab without building its freelist. */ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) { bool allow_spin = gfpflags_allow_spinning(flags); struct slab *slab; struct kmem_cache_order_objects oo = s->oo; gfp_t alloc_gfp; - void *start, *p, *next; - int idx; - bool shuffle; + void *start; flags &= gfp_allowed_mask; @@ -3497,21 +3434,6 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) alloc_slab_obj_exts_early(s, slab); account_slab(slab, oo_order(oo), s, flags); - shuffle = shuffle_freelist(s, slab, allow_spin); - - if (!shuffle) { - start = fixup_red_left(s, start); - start = setup_object(s, start); - slab->freelist = start; - for (idx = 0, p = start; idx < slab->objects - 1; idx++) { - next = p + s->size; - next = setup_object(s, next); - set_freepointer(s, p, next); - p = next; - } - set_freepointer(s, p, NULL); - } - return slab; } @@ -3665,30 +3587,112 @@ static void *alloc_single_from_partial(struct kmem_cache *s, return object; } +/* Return the next free object in allocation order. */ +static inline void *next_slab_obj(struct kmem_cache *s, + struct slab_obj_iter *iter) +{ +#ifdef CONFIG_SLAB_FREELIST_RANDOM + if (iter->random) { + unsigned long idx; + + /* + * If the target page allocation failed, the number of objects on the + * page might be smaller than the usual size defined by the cache. + */ + do { + idx = s->random_seq[iter->pos]; + iter->pos++; + if (iter->pos >= iter->freelist_count) + iter->pos = 0; + } while (unlikely(idx >= iter->page_limit)); + + return setup_object(s, (char *)iter->start + idx); + } +#endif + return setup_object(s, (char *)iter->start + iter->pos++ * s->size); +} + +/* Build a freelist from the objects not yet allocated from a fresh slab. */ +static inline void build_slab_freelist(struct kmem_cache *s, struct slab *slab, + struct slab_obj_iter *iter) +{ + unsigned int nr = slab->objects - slab->inuse; + unsigned int i; + void *cur, *next; + + if (!nr) { + slab->freelist = NULL; + return; + } + + cur = next_slab_obj(s, iter); + slab->freelist = cur; + + for (i = 1; i < nr; i++) { + next = next_slab_obj(s, iter); + set_freepointer(s, cur, next); + cur = next; + } + + set_freepointer(s, cur, NULL); +} + +/* Initialize an iterator over free objects in allocation order. */ +static inline void init_slab_obj_iter(struct kmem_cache *s, struct slab *slab, + struct slab_obj_iter *iter, + bool allow_spin) +{ + iter->pos = 0; + iter->start = fixup_red_left(s, slab_address(slab)); + +#ifdef CONFIG_SLAB_FREELIST_RANDOM + iter->random = (slab->objects >= 2 && s->random_seq); + if (!iter->random) + return; + + iter->freelist_count = oo_objects(s->oo); + iter->page_limit = slab->objects * s->size; + + if (allow_spin) { + iter->pos = get_random_u32_below(iter->freelist_count); + } else { + struct rnd_state *state; + + /* + * An interrupt or NMI handler might interrupt and change + * the state in the middle, but that's safe. + */ + state = &get_cpu_var(slab_rnd_state); + iter->pos = prandom_u32_state(state) % iter->freelist_count; + put_cpu_var(slab_rnd_state); + } +#endif +} + /* * Called only for kmem_cache_debug() caches to allocate from a freshly * allocated slab. Allocate a single object instead of whole freelist * and put the slab to the partial (or full) list. */ static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab, - int orig_size, gfp_t gfpflags) + int orig_size, bool allow_spin) { - bool allow_spin = gfpflags_allow_spinning(gfpflags); - int nid = slab_nid(slab); - struct kmem_cache_node *n = get_node(s, nid); + struct kmem_cache_node *n; + struct slab_obj_iter iter; + bool needs_add_partial; unsigned long flags; void *object; - if (!allow_spin && !spin_trylock_irqsave(&n->list_lock, flags)) { - /* Unlucky, discard newly allocated slab. */ - free_new_slab_nolock(s, slab); - return NULL; - } - - object = slab->freelist; - slab->freelist = get_freepointer(s, object); + init_slab_obj_iter(s, slab, &iter, allow_spin); + object = next_slab_obj(s, &iter); slab->inuse = 1; + needs_add_partial = (slab->objects > 1); + build_slab_freelist(s, slab, &iter); + + /* alloc_debug_processing() always expects a valid freepointer */ + set_freepointer(s, object, slab->freelist); + if (!alloc_debug_processing(s, slab, object, orig_size)) { /* * It's not really expected that this would fail on a @@ -3696,20 +3700,32 @@ static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab, * corruption in theory could cause that. * Leak memory of allocated slab. */ - if (!allow_spin) - spin_unlock_irqrestore(&n->list_lock, flags); return NULL; } - if (allow_spin) + n = get_node(s, slab_nid(slab)); + if (allow_spin) { spin_lock_irqsave(&n->list_lock, flags); + } else if (!spin_trylock_irqsave(&n->list_lock, flags)) { + /* + * Unlucky, discard newly allocated slab. + * The slab is not fully free, but it's fine as + * objects are not allocated to users. + */ + free_new_slab_nolock(s, slab); + return NULL; + } - if (slab->inuse == slab->objects) - add_full(s, n, slab); - else + if (needs_add_partial) add_partial(n, slab, ADD_TO_HEAD); + else + add_full(s, n, slab); - inc_slabs_node(s, nid, slab->objects); + /* + * Debug caches require nr_slabs updates under n->list_lock so validation + * cannot race with slab (de)allocations and observe inconsistent state. + */ + inc_slabs_node(s, slab_nid(slab), slab->objects); spin_unlock_irqrestore(&n->list_lock, flags); return object; @@ -4348,44 +4364,41 @@ static unsigned int alloc_from_new_slab(struct kmem_cache *s, struct slab *slab, void **p, unsigned int count, bool allow_spin) { unsigned int allocated = 0; - struct kmem_cache_node *n; - bool needs_add_partial; + struct slab_obj_iter iter; + bool needs_add_partial = true; unsigned long flags; - void *object; /* * Are we going to put the slab on the partial list? * Note slab->inuse is 0 on a new slab. */ - needs_add_partial = (slab->objects > count); - - if (!allow_spin && needs_add_partial) { - - n = get_node(s, slab_nid(slab)); - - if (!spin_trylock_irqsave(&n->list_lock, flags)) { - /* Unlucky, discard newly allocated slab */ - free_new_slab_nolock(s, slab); - return 0; - } + if (count >= slab->objects) { + needs_add_partial = false; + count = slab->objects; } - object = slab->freelist; - while (object && allocated < count) { - p[allocated] = object; - object = get_freepointer(s, object); - maybe_wipe_obj_freeptr(s, p[allocated]); + init_slab_obj_iter(s, slab, &iter, allow_spin); - slab->inuse++; + while (allocated < count) { + p[allocated] = next_slab_obj(s, &iter); allocated++; } - slab->freelist = object; + slab->inuse = count; + build_slab_freelist(s, slab, &iter); if (needs_add_partial) { + struct kmem_cache_node *n = get_node(s, slab_nid(slab)); if (allow_spin) { - n = get_node(s, slab_nid(slab)); spin_lock_irqsave(&n->list_lock, flags); + } else if (!spin_trylock_irqsave(&n->list_lock, flags)) { + /* + * Unlucky, discard newly allocated slab. + * The slab is not fully free, but it's fine as + * objects are not allocated to users. + */ + free_new_slab_nolock(s, slab); + return 0; } add_partial(n, slab, ADD_TO_HEAD); spin_unlock_irqrestore(&n->list_lock, flags); @@ -4456,15 +4469,13 @@ new_objects: stat(s, ALLOC_SLAB); if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) { - object = alloc_single_from_new_slab(s, slab, orig_size, gfpflags); + object = alloc_single_from_new_slab(s, slab, orig_size, allow_spin); if (likely(object)) goto success; } else { - alloc_from_new_slab(s, slab, &object, 1, allow_spin); - /* we don't need to check SLAB_STORE_USER here */ - if (likely(object)) + if (alloc_from_new_slab(s, slab, &object, 1, allow_spin)) return object; } @@ -7258,10 +7269,6 @@ new_slab: stat(s, ALLOC_SLAB); - /* - * TODO: possible optimization - if we know we will consume the whole - * slab we might skip creating the freelist? - */ refilled += alloc_from_new_slab(s, slab, p + refilled, max - refilled, /* allow_spin = */ true); @@ -7592,6 +7599,7 @@ static void early_kmem_cache_node_alloc(int node) { struct slab *slab; struct kmem_cache_node *n; + struct slab_obj_iter iter; BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node)); @@ -7603,14 +7611,18 @@ static void early_kmem_cache_node_alloc(int node) pr_err("SLUB: Allocating a useless per node structure in order to be able to continue\n"); } - n = slab->freelist; + init_slab_obj_iter(kmem_cache_node, slab, &iter, true); + + n = next_slab_obj(kmem_cache_node, &iter); BUG_ON(!n); + + slab->inuse = 1; + build_slab_freelist(kmem_cache_node, slab, &iter); + #ifdef CONFIG_SLUB_DEBUG init_object(kmem_cache_node, n, SLUB_RED_ACTIVE); #endif n = kasan_slab_alloc(kmem_cache_node, n, GFP_KERNEL, false); - slab->freelist = get_freepointer(kmem_cache_node, n); - slab->inuse = 1; kmem_cache_node->per_node[node].node = n; init_kmem_cache_node(n); inc_slabs_node(kmem_cache_node, node, slab->objects); From feb662d9168b63e1d4c02671ec96005410c6f3ce Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 11 May 2026 22:00:48 +0200 Subject: [PATCH 249/655] slab: support for compiler-assisted type-based slab cache partitioning Rework the general infrastructure around RANDOM_KMALLOC_CACHES into more flexible KMALLOC_PARTITION_CACHES, with the former being a partitioning mode of the latter. Introduce a new mode, KMALLOC_PARTITION_TYPED, which leverages a feature available in Clang 22 and later, called "allocation tokens" via __builtin_infer_alloc_token() [1]. Unlike KMALLOC_PARTITION_RANDOM (formerly RANDOM_KMALLOC_CACHES), this mode deterministically assigns a slab cache to an allocation of type T, regardless of allocation site. The builtin __builtin_infer_alloc_token(, ...) instructs the compiler to infer an allocation type from arguments commonly passed to memory-allocating functions and returns a type-derived token ID. The implementation passes kmalloc-args to the builtin: the compiler performs best-effort type inference, and then recognizes common patterns such as `kmalloc(sizeof(T), ...)`, `kmalloc(sizeof(T) * n, ...)`, but also `(T *)kmalloc(...)`. Where the compiler fails to infer a type the fallback token (default: 0) is chosen. Note: kmalloc_obj(..) APIs fix the pattern how size and result type are expressed, and therefore ensures there's not much drift in which patterns the compiler needs to recognize. Specifically, kmalloc_obj() and friends expand to `(TYPE *)KMALLOC(__obj_size, GFP)`, which the compiler recognizes via the cast to TYPE*. Clang's default token ID calculation is described as [1]: typehashpointersplit: This mode assigns a token ID based on the hash of the allocated type's name, where the top half ID-space is reserved for types that contain pointers and the bottom half for types that do not contain pointers. Separating pointer-containing objects from pointerless objects and data allocations can help mitigate certain classes of memory corruption exploits [2]: attackers who gains a buffer overflow on a primitive buffer cannot use it to directly corrupt pointers or other critical metadata in an object residing in a different, isolated heap region. It is important to note that heap isolation strategies offer a best-effort approach, and do not provide a 100% security guarantee, albeit achievable at relatively low performance cost. Note that this also does not prevent cross-cache attacks: while waiting for future features like SLAB_VIRTUAL [3] to provide physical page isolation, this feature should be deployed alongside SHUFFLE_PAGE_ALLOCATOR and init_on_free=1 to mitigate cross-cache attacks and page-reuse attacks as much as possible today. With all that, my kernel (x86 defconfig) shows me a histogram of slab cache object distribution per /proc/slabinfo (after boot): kmalloc-part-15 1465 ++++++++++++++ kmalloc-part-14 2988 +++++++++++++++++++++++++++++ kmalloc-part-13 1656 ++++++++++++++++ kmalloc-part-12 1045 ++++++++++ kmalloc-part-11 1697 ++++++++++++++++ kmalloc-part-10 1489 ++++++++++++++ kmalloc-part-09 965 +++++++++ kmalloc-part-08 710 +++++++ kmalloc-part-07 100 + kmalloc-part-06 217 ++ kmalloc-part-05 105 + kmalloc-part-04 4047 ++++++++++++++++++++++++++++++++++++++++ kmalloc-part-03 183 + kmalloc-part-02 283 ++ kmalloc-part-01 316 +++ kmalloc 1422 ++++++++++++++ The above /proc/slabinfo snapshot shows me there are 6673 allocated objects (slabs 00 - 07) that the compiler claims contain no pointers or it was unable to infer the type of, and 12015 objects that contain pointers (slabs 08 - 15). On a whole, this looks relatively sane. Additionally, when I compile my kernel with -Rpass=alloc-token, which provides diagnostics where (after dead-code elimination) type inference failed, I see 186 allocation sites where the compiler failed to identify a type (down from 966 when I sent the RFC [4]). Some initial review confirms these are mostly variable sized buffers, but also include structs with trailing flexible length arrays. Link: https://clang.llvm.org/docs/AllocToken.html [1] Link: https://blog.dfsec.com/ios/2025/05/30/blasting-past-ios-18/ [2] Link: https://lwn.net/Articles/944647/ [3] Link: https://lore.kernel.org/all/20250825154505.1558444-1-elver@google.com/ [4] Link: https://discourse.llvm.org/t/rfc-a-framework-for-allocator-partitioning-hints/87434 Acked-by: GONG Ruiqi Co-developed-by: Harry Yoo (Oracle) Signed-off-by: Harry Yoo (Oracle) Signed-off-by: Marco Elver Reviewed-by: Harry Yoo (Oracle) Link: https://patch.msgid.link/20260511200136.3201646-1-elver@google.com Signed-off-by: Vlastimil Babka (SUSE) --- Makefile | 5 ++ include/linux/percpu.h | 2 +- include/linux/slab.h | 136 +++++++++++++++++++++----------- init/Kconfig | 3 + kernel/configs/hardening.config | 2 +- mm/Kconfig | 73 ++++++++++++++--- mm/kfence/kfence_test.c | 4 +- mm/slab.h | 4 +- mm/slab_common.c | 52 ++++++------ mm/slub.c | 54 +++++++------ 10 files changed, 220 insertions(+), 115 deletions(-) diff --git a/Makefile b/Makefile index b7b80e84e1eb..8a54c0adcceb 100644 --- a/Makefile +++ b/Makefile @@ -993,6 +993,11 @@ KBUILD_CFLAGS += $(CC_AUTO_VAR_INIT_ZERO_ENABLER) endif endif +ifdef CONFIG_KMALLOC_PARTITION_TYPED +# KMALLOC_PARTITION_CACHES_NR + 1 +KBUILD_CFLAGS += -falloc-token-max=16 +endif + ifdef CONFIG_CC_IS_CLANG ifdef CONFIG_CC_HAS_COUNTED_BY_PTR KBUILD_CFLAGS += -fexperimental-late-parse-attributes diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 85bf8dd9f087..bdb721dac0e3 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -36,7 +36,7 @@ #define PCPU_BITMAP_BLOCK_BITS (PCPU_BITMAP_BLOCK_SIZE >> \ PCPU_MIN_ALLOC_SHIFT) -#ifdef CONFIG_RANDOM_KMALLOC_CACHES +#ifdef CONFIG_KMALLOC_PARTITION_CACHES # if defined(CONFIG_LOCKDEP) && !defined(CONFIG_PAGE_SIZE_4KB) # define PERCPU_DYNAMIC_SIZE_SHIFT 13 # else diff --git a/include/linux/slab.h b/include/linux/slab.h index 15a60b501b95..795455256329 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -499,14 +499,38 @@ int kmem_cache_shrink(struct kmem_cache *s); .usersize = sizeof_field(struct __struct, __field), \ }, (__flags)) +#ifdef CONFIG_KMALLOC_PARTITION_CACHES +typedef struct { unsigned long v; } kmalloc_token_t; +#ifdef CONFIG_KMALLOC_PARTITION_RANDOM +extern unsigned long random_kmalloc_seed; +#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _RET_IP_ }) +#elif defined(CONFIG_KMALLOC_PARTITION_TYPED) +#define __kmalloc_token(...) ((kmalloc_token_t){ .v = __builtin_infer_alloc_token(__VA_ARGS__) }) +#endif +#define DECL_TOKEN_PARAM(_token) , kmalloc_token_t (_token) +#define _PASS_TOKEN_PARAM(_token) , (_token) +#define PASS_TOKEN_PARAM(_token) (_token) +#define DECL_TOKEN_PARAMS(_size, _token) size_t (_size), kmalloc_token_t (_token) +#define PASS_TOKEN_PARAMS(_size, _token) (_size), (_token) +#else /* !CONFIG_KMALLOC_PARTITION_CACHES */ +typedef struct {} kmalloc_token_t; +#define __kmalloc_token(...) ((kmalloc_token_t){}) /* no-op */ +#define DECL_TOKEN_PARAM(_token) +#define _PASS_TOKEN_PARAM(_token) +#define PASS_TOKEN_PARAM(_token) ((kmalloc_token_t){}) +#define DECL_TOKEN_PARAMS(_size, _token) size_t (_size) +#define PASS_TOKEN_PARAMS(_size, _token) (_size) +#endif /* CONFIG_KMALLOC_PARTITION_CACHES */ + /* * Common kmalloc functions provided by all allocators */ -void * __must_check krealloc_node_align_noprof(const void *objp, size_t new_size, +void * __must_check krealloc_node_align_noprof(const void *objp, + DECL_TOKEN_PARAMS(new_size, token), unsigned long align, gfp_t flags, int nid) __realloc_size(2); -#define krealloc_noprof(_o, _s, _f) krealloc_node_align_noprof(_o, _s, 1, _f, NUMA_NO_NODE) -#define krealloc_node_align(...) alloc_hooks(krealloc_node_align_noprof(__VA_ARGS__)) +#define krealloc_noprof(_o, _s, _f) krealloc_node_align_noprof(_o, PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), 1, _f, NUMA_NO_NODE) +#define krealloc_node_align(_o, _s, _a, _f, _n) alloc_hooks(krealloc_node_align_noprof(_o, PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), _a, _f, _n)) #define krealloc_node(_o, _s, _f, _n) krealloc_node_align(_o, _s, 1, _f, _n) #define krealloc(...) krealloc_node(__VA_ARGS__, NUMA_NO_NODE) @@ -612,10 +636,10 @@ static inline unsigned int arch_slab_minalign(void) #define SLAB_OBJ_MIN_SIZE (KMALLOC_MIN_SIZE < 16 ? \ (KMALLOC_MIN_SIZE) : 16) -#ifdef CONFIG_RANDOM_KMALLOC_CACHES -#define RANDOM_KMALLOC_CACHES_NR 15 // # of cache copies +#ifdef CONFIG_KMALLOC_PARTITION_CACHES +#define KMALLOC_PARTITION_CACHES_NR 15 // # of cache copies #else -#define RANDOM_KMALLOC_CACHES_NR 0 +#define KMALLOC_PARTITION_CACHES_NR 0 #endif /* @@ -634,8 +658,8 @@ enum kmalloc_cache_type { #ifndef CONFIG_MEMCG KMALLOC_CGROUP = KMALLOC_NORMAL, #endif - KMALLOC_RANDOM_START = KMALLOC_NORMAL, - KMALLOC_RANDOM_END = KMALLOC_RANDOM_START + RANDOM_KMALLOC_CACHES_NR, + KMALLOC_PARTITION_START = KMALLOC_NORMAL, + KMALLOC_PARTITION_END = KMALLOC_PARTITION_START + KMALLOC_PARTITION_CACHES_NR, #ifdef CONFIG_SLUB_TINY KMALLOC_RECLAIM = KMALLOC_NORMAL, #else @@ -662,19 +686,19 @@ extern kmem_buckets kmalloc_caches[NR_KMALLOC_TYPES]; (IS_ENABLED(CONFIG_ZONE_DMA) ? __GFP_DMA : 0) | \ (IS_ENABLED(CONFIG_MEMCG) ? __GFP_ACCOUNT : 0)) -extern unsigned long random_kmalloc_seed; - -static __always_inline enum kmalloc_cache_type kmalloc_type(gfp_t flags, unsigned long caller) +static __always_inline enum kmalloc_cache_type kmalloc_type(gfp_t flags, kmalloc_token_t token) { /* * The most common case is KMALLOC_NORMAL, so test for it * with a single branch for all the relevant flags. */ if (likely((flags & KMALLOC_NOT_NORMAL_BITS) == 0)) -#ifdef CONFIG_RANDOM_KMALLOC_CACHES - /* RANDOM_KMALLOC_CACHES_NR (=15) copies + the KMALLOC_NORMAL */ - return KMALLOC_RANDOM_START + hash_64(caller ^ random_kmalloc_seed, - ilog2(RANDOM_KMALLOC_CACHES_NR + 1)); +#ifdef CONFIG_KMALLOC_PARTITION_RANDOM + /* KMALLOC_PARTITION_CACHES_NR (=15) copies + the KMALLOC_NORMAL */ + return KMALLOC_PARTITION_START + hash_64(token.v ^ random_kmalloc_seed, + ilog2(KMALLOC_PARTITION_CACHES_NR + 1)); +#elif defined(CONFIG_KMALLOC_PARTITION_TYPED) + return KMALLOC_PARTITION_START + token.v; #else return KMALLOC_NORMAL; #endif @@ -858,16 +882,22 @@ unsigned int kmem_cache_sheaf_size(struct slab_sheaf *sheaf); #define PASS_BUCKET_PARAM(_b) NULL #endif +#define DECL_KMALLOC_PARAMS(_size, _b, _token) DECL_BUCKET_PARAMS(_size, _b) \ + DECL_TOKEN_PARAM(_token) + +#define PASS_KMALLOC_PARAMS(_size, _b, _token) PASS_BUCKET_PARAMS(_size, _b) \ + _PASS_TOKEN_PARAM(_token) + /* * The following functions are not to be used directly and are intended only * for internal use from kmalloc() and kmalloc_node() * with the exception of kunit tests */ -void *__kmalloc_noprof(size_t size, gfp_t flags) +void *__kmalloc_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags) __assume_kmalloc_alignment __alloc_size(1); -void *__kmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flags, int node) +void *__kmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), gfp_t flags, int node) __assume_kmalloc_alignment __alloc_size(1); void *__kmalloc_cache_noprof(struct kmem_cache *s, gfp_t flags, size_t size) @@ -938,7 +968,7 @@ void *__kmalloc_large_node_noprof(size_t size, gfp_t flags, int node) * Try really hard to succeed the allocation but fail * eventually. */ -static __always_inline __alloc_size(1) void *kmalloc_noprof(size_t size, gfp_t flags) +static __always_inline __alloc_size(1) void *_kmalloc_noprof(size_t size, gfp_t flags, kmalloc_token_t token) { if (__builtin_constant_p(size) && size) { unsigned int index; @@ -948,14 +978,16 @@ static __always_inline __alloc_size(1) void *kmalloc_noprof(size_t size, gfp_t f index = kmalloc_index(size); return __kmalloc_cache_noprof( - kmalloc_caches[kmalloc_type(flags, _RET_IP_)][index], + kmalloc_caches[kmalloc_type(flags, token)][index], flags, size); } - return __kmalloc_noprof(size, flags); + return __kmalloc_noprof(PASS_TOKEN_PARAMS(size, token), flags); } +#define kmalloc_noprof(...) _kmalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define kmalloc(...) alloc_hooks(kmalloc_noprof(__VA_ARGS__)) -void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node); +void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, int node); +#define kmalloc_nolock_noprof(_s, _f, _n) _kmalloc_nolock_noprof(PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), _f, _n) #define kmalloc_nolock(...) alloc_hooks(kmalloc_nolock_noprof(__VA_ARGS__)) /** @@ -1060,12 +1092,12 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node); __alloc_flex(kvzalloc, default_gfp(__VA_ARGS__), typeof(P), FAM, COUNT) #define kmem_buckets_alloc(_b, _size, _flags) \ - alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE)) + alloc_hooks(__kmalloc_node_noprof(PASS_KMALLOC_PARAMS(_size, _b, __kmalloc_token(_size)), _flags, NUMA_NO_NODE)) #define kmem_buckets_alloc_track_caller(_b, _size, _flags) \ - alloc_hooks(__kmalloc_node_track_caller_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE, _RET_IP_)) + alloc_hooks(__kmalloc_node_track_caller_noprof(PASS_KMALLOC_PARAMS(_size, _b, __kmalloc_token(_size)), _flags, NUMA_NO_NODE, _RET_IP_)) -static __always_inline __alloc_size(1) void *kmalloc_node_noprof(size_t size, gfp_t flags, int node) +static __always_inline __alloc_size(1) void *_kmalloc_node_noprof(size_t size, gfp_t flags, int node, kmalloc_token_t token) { if (__builtin_constant_p(size) && size) { unsigned int index; @@ -1075,11 +1107,12 @@ static __always_inline __alloc_size(1) void *kmalloc_node_noprof(size_t size, gf index = kmalloc_index(size); return __kmalloc_cache_node_noprof( - kmalloc_caches[kmalloc_type(flags, _RET_IP_)][index], + kmalloc_caches[kmalloc_type(flags, token)][index], flags, node, size); } - return __kmalloc_node_noprof(PASS_BUCKET_PARAMS(size, NULL), flags, node); + return __kmalloc_node_noprof(PASS_KMALLOC_PARAMS(size, NULL, token), flags, node); } +#define kmalloc_node_noprof(...) _kmalloc_node_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define kmalloc_node(...) alloc_hooks(kmalloc_node_noprof(__VA_ARGS__)) /** @@ -1088,14 +1121,15 @@ static __always_inline __alloc_size(1) void *kmalloc_node_noprof(size_t size, gf * @size: element size. * @flags: the type of memory to allocate (see kmalloc). */ -static inline __alloc_size(1, 2) void *kmalloc_array_noprof(size_t n, size_t size, gfp_t flags) +static inline __alloc_size(1, 2) void *_kmalloc_array_noprof(size_t n, size_t size, gfp_t flags, kmalloc_token_t token) { size_t bytes; if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; - return kmalloc_noprof(bytes, flags); + return _kmalloc_noprof(bytes, flags, token); } +#define kmalloc_array_noprof(...) _kmalloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define kmalloc_array(...) alloc_hooks(kmalloc_array_noprof(__VA_ARGS__)) /** @@ -1115,18 +1149,19 @@ static inline __alloc_size(1, 2) void *kmalloc_array_noprof(size_t n, size_t siz * In any case, the contents of the object pointed to are preserved up to the * lesser of the new and old sizes. */ -static inline __realloc_size(2, 3) void * __must_check krealloc_array_noprof(void *p, +static inline __realloc_size(2, 3) void * __must_check _krealloc_array_noprof(void *p, size_t new_n, size_t new_size, - gfp_t flags) + gfp_t flags, kmalloc_token_t token) { size_t bytes; if (unlikely(check_mul_overflow(new_n, new_size, &bytes))) return NULL; - return krealloc_noprof(p, bytes, flags); + return krealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(bytes, token), 1, flags, NUMA_NO_NODE); } +#define krealloc_array_noprof(...) _krealloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define krealloc_array(...) alloc_hooks(krealloc_array_noprof(__VA_ARGS__)) /** @@ -1137,10 +1172,10 @@ static inline __realloc_size(2, 3) void * __must_check krealloc_array_noprof(voi */ #define kcalloc(n, size, flags) kmalloc_array(n, size, (flags) | __GFP_ZERO) -void *__kmalloc_node_track_caller_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flags, int node, +void *__kmalloc_node_track_caller_noprof(DECL_KMALLOC_PARAMS(size, b, token), gfp_t flags, int node, unsigned long caller) __alloc_size(1); #define kmalloc_node_track_caller_noprof(size, flags, node, caller) \ - __kmalloc_node_track_caller_noprof(PASS_BUCKET_PARAMS(size, NULL), flags, node, caller) + __kmalloc_node_track_caller_noprof(PASS_KMALLOC_PARAMS(size, NULL, __kmalloc_token(size)), flags, node, caller) #define kmalloc_node_track_caller(...) \ alloc_hooks(kmalloc_node_track_caller_noprof(__VA_ARGS__, _RET_IP_)) @@ -1157,17 +1192,18 @@ void *__kmalloc_node_track_caller_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flag #define kmalloc_track_caller_noprof(...) \ kmalloc_node_track_caller_noprof(__VA_ARGS__, NUMA_NO_NODE, _RET_IP_) -static inline __alloc_size(1, 2) void *kmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, - int node) +static inline __alloc_size(1, 2) void *_kmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, + int node, kmalloc_token_t token) { size_t bytes; if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; if (__builtin_constant_p(n) && __builtin_constant_p(size)) - return kmalloc_node_noprof(bytes, flags, node); - return __kmalloc_node_noprof(PASS_BUCKET_PARAMS(bytes, NULL), flags, node); + return _kmalloc_node_noprof(bytes, flags, node, token); + return __kmalloc_node_noprof(PASS_KMALLOC_PARAMS(bytes, NULL, token), flags, node); } +#define kmalloc_array_node_noprof(...) _kmalloc_array_node_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define kmalloc_array_node(...) alloc_hooks(kmalloc_array_node_noprof(__VA_ARGS__)) #define kcalloc_node(_n, _size, _flags, _node) \ @@ -1183,39 +1219,43 @@ static inline __alloc_size(1, 2) void *kmalloc_array_node_noprof(size_t n, size_ * @size: how many bytes of memory are required. * @flags: the type of memory to allocate (see kmalloc). */ -static inline __alloc_size(1) void *kzalloc_noprof(size_t size, gfp_t flags) +static inline __alloc_size(1) void *_kzalloc_noprof(size_t size, gfp_t flags, kmalloc_token_t token) { - return kmalloc_noprof(size, flags | __GFP_ZERO); + return _kmalloc_noprof(size, flags | __GFP_ZERO, token); } +#define kzalloc_noprof(...) _kzalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define kzalloc(...) alloc_hooks(kzalloc_noprof(__VA_ARGS__)) #define kzalloc_node(_size, _flags, _node) kmalloc_node(_size, (_flags)|__GFP_ZERO, _node) -void *__kvmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), unsigned long align, +void *__kvmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), unsigned long align, gfp_t flags, int node) __alloc_size(1); #define kvmalloc_node_align_noprof(_size, _align, _flags, _node) \ - __kvmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, NULL), _align, _flags, _node) + __kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(_size, NULL, __kmalloc_token(_size)), _align, _flags, _node) #define kvmalloc_node_align(...) \ alloc_hooks(kvmalloc_node_align_noprof(__VA_ARGS__)) #define kvmalloc_node(_s, _f, _n) kvmalloc_node_align(_s, 1, _f, _n) +#define kvmalloc_node_noprof(size, flags, node) \ + kvmalloc_node_align_noprof(size, 1, flags, node) #define kvmalloc(...) kvmalloc_node(__VA_ARGS__, NUMA_NO_NODE) +#define kvmalloc_noprof(_size, _flags) kvmalloc_node_noprof(_size, _flags, NUMA_NO_NODE) #define kvzalloc(_size, _flags) kvmalloc(_size, (_flags)|__GFP_ZERO) #define kvzalloc_node(_size, _flags, _node) kvmalloc_node(_size, (_flags)|__GFP_ZERO, _node) #define kmem_buckets_valloc(_b, _size, _flags) \ - alloc_hooks(__kvmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), 1, _flags, NUMA_NO_NODE)) + alloc_hooks(__kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(_size, _b, __kmalloc_token(_size)), 1, _flags, NUMA_NO_NODE)) static inline __alloc_size(1, 2) void * -kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node) +_kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node, kmalloc_token_t token) { size_t bytes; if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; - return kvmalloc_node_align_noprof(bytes, 1, flags, node); + return __kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(bytes, NULL, token), 1, flags, node); } - +#define kvmalloc_array_node_noprof(...) _kvmalloc_array_node_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define kvmalloc_array_noprof(...) kvmalloc_array_node_noprof(__VA_ARGS__, NUMA_NO_NODE) #define kvcalloc_node_noprof(_n,_s,_f,_node) kvmalloc_array_node_noprof(_n,_s,(_f)|__GFP_ZERO,_node) #define kvcalloc_noprof(...) kvcalloc_node_noprof(__VA_ARGS__, NUMA_NO_NODE) @@ -1224,10 +1264,10 @@ kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node) #define kvcalloc_node(...) alloc_hooks(kvcalloc_node_noprof(__VA_ARGS__)) #define kvcalloc(...) alloc_hooks(kvcalloc_noprof(__VA_ARGS__)) -void *kvrealloc_node_align_noprof(const void *p, size_t size, unsigned long align, +void *kvrealloc_node_align_noprof(const void *p, DECL_TOKEN_PARAMS(size, token), unsigned long align, gfp_t flags, int nid) __realloc_size(2); -#define kvrealloc_node_align(...) \ - alloc_hooks(kvrealloc_node_align_noprof(__VA_ARGS__)) +#define kvrealloc_node_align(_p, _s, _a, _f, _n) \ + alloc_hooks(kvrealloc_node_align_noprof(_p, PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), _a, _f, _n)) #define kvrealloc_node(_p, _s, _f, _n) kvrealloc_node_align(_p, _s, 1, _f, _n) #define kvrealloc(...) kvrealloc_node(__VA_ARGS__, NUMA_NO_NODE) diff --git a/init/Kconfig b/init/Kconfig index 2937c4d308ae..dba97bc8e2ce 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -170,6 +170,9 @@ config CC_HAS_BROKEN_COUNTED_BY_REF # https://github.com/llvm/llvm-project/issues/182575 default y if CC_IS_CLANG && CLANG_VERSION < 220100 +config CC_HAS_ALLOC_TOKEN + def_bool $(cc-option,-falloc-token-max=123) + config CC_HAS_MULTIDIMENSIONAL_NONSTRING def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror) diff --git a/kernel/configs/hardening.config b/kernel/configs/hardening.config index 7c3924614e01..26831a2a5739 100644 --- a/kernel/configs/hardening.config +++ b/kernel/configs/hardening.config @@ -22,7 +22,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_BUCKETS=y CONFIG_SHUFFLE_PAGE_ALLOCATOR=y -CONFIG_RANDOM_KMALLOC_CACHES=y +CONFIG_KMALLOC_PARTITION_CACHES=y # Sanity check userspace page table mappings. CONFIG_PAGE_TABLE_CHECK=y diff --git a/mm/Kconfig b/mm/Kconfig index e8bf1e9e6ad9..4f187b07eb48 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -248,22 +248,75 @@ config SLUB_STATS out which slabs are relevant to a particular load. Try running: slabinfo -DA -config RANDOM_KMALLOC_CACHES - default n +config KMALLOC_PARTITION_CACHES depends on !SLUB_TINY - bool "Randomize slab caches for normal kmalloc" + bool "Partitioned slab caches for normal kmalloc" + default RANDOM_KMALLOC_CACHES help - A hardening feature that creates multiple copies of slab caches for - normal kmalloc allocation and makes kmalloc randomly pick one based - on code address, which makes the attackers more difficult to spray - vulnerable memory objects on the heap for the purpose of exploiting - memory vulnerabilities. + A hardening feature that creates multiple isolated copies of slab + caches for normal kmalloc allocations. This makes it more difficult + to exploit memory-safety vulnerabilities by attacking vulnerable + co-located memory objects. Several modes are provided. Currently the number of copies is set to 16, a reasonably large value that effectively diverges the memory objects allocated for different subsystems or modules into different caches, at the expense of a - limited degree of memory and CPU overhead that relates to hardware and - system workload. + limited degree of memory and CPU overhead that relates to hardware + and system workload. + +choice + prompt "Partitioned slab cache mode" + depends on KMALLOC_PARTITION_CACHES + default KMALLOC_PARTITION_TYPED if CC_HAS_ALLOC_TOKEN + default KMALLOC_PARTITION_RANDOM + help + Selects the slab cache partitioning mode. + +config KMALLOC_PARTITION_RANDOM + bool "Randomize slab caches for normal kmalloc" + help + Randomly pick a slab cache based on code address and a per-boot + random seed. + + This makes it harder for attackers to predict object co-location. + The placement is random: while attackers don't know which kmalloc + cache an object will be allocated from, they might circumvent + the randomization by retrying attacks across multiple machines until + the target objects are co-located. + +config KMALLOC_PARTITION_TYPED + bool "Type based slab cache selection for normal kmalloc" + depends on CC_HAS_ALLOC_TOKEN + help + Rely on Clang's allocation tokens to choose a slab cache, where token + IDs are derived from the allocated type. + + Unlike KMALLOC_PARTITION_RANDOM, cache assignment is deterministic based + on type, which guarantees that objects of certain types are not + placed in the same cache. This effectively mitigates certain classes + of exploits that probabilistic defenses like KMALLOC_PARTITION_RANDOM + only make harder but not impossible. However, this also means the + cache assignment is predictable. + + Clang's default token ID calculation returns a bounded hash with + disjoint ranges for pointer-containing and pointerless objects: when + used as the slab cache index, this prevents buffer overflows on + primitive buffers from directly corrupting pointer-containing + objects. + + The current effectiveness of Clang's type inference can be judged by + -Rpass=alloc-token, which provides diagnostics where (after dead-code + elimination) type inference failed. + + Requires Clang 22 or later. + +endchoice + +config RANDOM_KMALLOC_CACHES + bool + transitional + help + Transitional config for migration to KMALLOC_PARTITION_CACHES. endmenu # Slab allocator options diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c index 5725a367246d..8807ea8ed0d3 100644 --- a/mm/kfence/kfence_test.c +++ b/mm/kfence/kfence_test.c @@ -214,7 +214,7 @@ static void test_cache_destroy(void) static inline size_t kmalloc_cache_alignment(size_t size) { /* just to get ->align so no need to pass in the real caller */ - enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, 0); + enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, __kmalloc_token(0)); return kmalloc_caches[type][__kmalloc_index(size, false)]->align; } @@ -285,7 +285,7 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat if (is_kfence_address(alloc)) { struct slab *slab = virt_to_slab(alloc); - enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, _RET_IP_); + enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, __kmalloc_token(size)); struct kmem_cache *s = test_cache ?: kmalloc_caches[type][__kmalloc_index(size, false)]; diff --git a/mm/slab.h b/mm/slab.h index bf2f87acf5e3..1bf9c3021ae3 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -362,12 +362,12 @@ static inline unsigned int size_index_elem(unsigned int bytes) * KMALLOC_MAX_CACHE_SIZE and the caller must check that. */ static inline struct kmem_cache * -kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, unsigned long caller) +kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, kmalloc_token_t token) { unsigned int index; if (!b) - b = &kmalloc_caches[kmalloc_type(flags, caller)]; + b = &kmalloc_caches[kmalloc_type(flags, token)]; if (size <= 192) index = kmalloc_size_index[size_index_elem(size)]; else diff --git a/mm/slab_common.c b/mm/slab_common.c index d5a70a831a2a..388eb5980859 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -742,7 +742,7 @@ kmem_buckets kmalloc_caches[NR_KMALLOC_TYPES] __ro_after_init = { /* initialization for https://llvm.org/pr42570 */ }; EXPORT_SYMBOL(kmalloc_caches); -#ifdef CONFIG_RANDOM_KMALLOC_CACHES +#ifdef CONFIG_KMALLOC_PARTITION_RANDOM unsigned long random_kmalloc_seed __ro_after_init; EXPORT_SYMBOL(random_kmalloc_seed); #endif @@ -787,7 +787,7 @@ size_t kmalloc_size_roundup(size_t size) * The flags don't matter since size_index is common to all. * Neither does the caller for just getting ->object_size. */ - return kmalloc_slab(size, NULL, GFP_KERNEL, 0)->object_size; + return kmalloc_slab(size, NULL, GFP_KERNEL, __kmalloc_token(0))->object_size; } /* Above the smaller buckets, size is a multiple of page size. */ @@ -821,26 +821,26 @@ EXPORT_SYMBOL(kmalloc_size_roundup); #define KMALLOC_RCL_NAME(sz) #endif -#ifdef CONFIG_RANDOM_KMALLOC_CACHES -#define __KMALLOC_RANDOM_CONCAT(a, b) a ## b -#define KMALLOC_RANDOM_NAME(N, sz) __KMALLOC_RANDOM_CONCAT(KMA_RAND_, N)(sz) -#define KMA_RAND_1(sz) .name[KMALLOC_RANDOM_START + 1] = "kmalloc-rnd-01-" #sz, -#define KMA_RAND_2(sz) KMA_RAND_1(sz) .name[KMALLOC_RANDOM_START + 2] = "kmalloc-rnd-02-" #sz, -#define KMA_RAND_3(sz) KMA_RAND_2(sz) .name[KMALLOC_RANDOM_START + 3] = "kmalloc-rnd-03-" #sz, -#define KMA_RAND_4(sz) KMA_RAND_3(sz) .name[KMALLOC_RANDOM_START + 4] = "kmalloc-rnd-04-" #sz, -#define KMA_RAND_5(sz) KMA_RAND_4(sz) .name[KMALLOC_RANDOM_START + 5] = "kmalloc-rnd-05-" #sz, -#define KMA_RAND_6(sz) KMA_RAND_5(sz) .name[KMALLOC_RANDOM_START + 6] = "kmalloc-rnd-06-" #sz, -#define KMA_RAND_7(sz) KMA_RAND_6(sz) .name[KMALLOC_RANDOM_START + 7] = "kmalloc-rnd-07-" #sz, -#define KMA_RAND_8(sz) KMA_RAND_7(sz) .name[KMALLOC_RANDOM_START + 8] = "kmalloc-rnd-08-" #sz, -#define KMA_RAND_9(sz) KMA_RAND_8(sz) .name[KMALLOC_RANDOM_START + 9] = "kmalloc-rnd-09-" #sz, -#define KMA_RAND_10(sz) KMA_RAND_9(sz) .name[KMALLOC_RANDOM_START + 10] = "kmalloc-rnd-10-" #sz, -#define KMA_RAND_11(sz) KMA_RAND_10(sz) .name[KMALLOC_RANDOM_START + 11] = "kmalloc-rnd-11-" #sz, -#define KMA_RAND_12(sz) KMA_RAND_11(sz) .name[KMALLOC_RANDOM_START + 12] = "kmalloc-rnd-12-" #sz, -#define KMA_RAND_13(sz) KMA_RAND_12(sz) .name[KMALLOC_RANDOM_START + 13] = "kmalloc-rnd-13-" #sz, -#define KMA_RAND_14(sz) KMA_RAND_13(sz) .name[KMALLOC_RANDOM_START + 14] = "kmalloc-rnd-14-" #sz, -#define KMA_RAND_15(sz) KMA_RAND_14(sz) .name[KMALLOC_RANDOM_START + 15] = "kmalloc-rnd-15-" #sz, -#else // CONFIG_RANDOM_KMALLOC_CACHES -#define KMALLOC_RANDOM_NAME(N, sz) +#ifdef CONFIG_KMALLOC_PARTITION_CACHES +#define __KMALLOC_PARTITION_CONCAT(a, b) a ## b +#define KMALLOC_PARTITION_NAME(N, sz) __KMALLOC_PARTITION_CONCAT(KMA_PART_, N)(sz) +#define KMA_PART_1(sz) .name[KMALLOC_PARTITION_START + 1] = "kmalloc-part-01-" #sz, +#define KMA_PART_2(sz) KMA_PART_1(sz) .name[KMALLOC_PARTITION_START + 2] = "kmalloc-part-02-" #sz, +#define KMA_PART_3(sz) KMA_PART_2(sz) .name[KMALLOC_PARTITION_START + 3] = "kmalloc-part-03-" #sz, +#define KMA_PART_4(sz) KMA_PART_3(sz) .name[KMALLOC_PARTITION_START + 4] = "kmalloc-part-04-" #sz, +#define KMA_PART_5(sz) KMA_PART_4(sz) .name[KMALLOC_PARTITION_START + 5] = "kmalloc-part-05-" #sz, +#define KMA_PART_6(sz) KMA_PART_5(sz) .name[KMALLOC_PARTITION_START + 6] = "kmalloc-part-06-" #sz, +#define KMA_PART_7(sz) KMA_PART_6(sz) .name[KMALLOC_PARTITION_START + 7] = "kmalloc-part-07-" #sz, +#define KMA_PART_8(sz) KMA_PART_7(sz) .name[KMALLOC_PARTITION_START + 8] = "kmalloc-part-08-" #sz, +#define KMA_PART_9(sz) KMA_PART_8(sz) .name[KMALLOC_PARTITION_START + 9] = "kmalloc-part-09-" #sz, +#define KMA_PART_10(sz) KMA_PART_9(sz) .name[KMALLOC_PARTITION_START + 10] = "kmalloc-part-10-" #sz, +#define KMA_PART_11(sz) KMA_PART_10(sz) .name[KMALLOC_PARTITION_START + 11] = "kmalloc-part-11-" #sz, +#define KMA_PART_12(sz) KMA_PART_11(sz) .name[KMALLOC_PARTITION_START + 12] = "kmalloc-part-12-" #sz, +#define KMA_PART_13(sz) KMA_PART_12(sz) .name[KMALLOC_PARTITION_START + 13] = "kmalloc-part-13-" #sz, +#define KMA_PART_14(sz) KMA_PART_13(sz) .name[KMALLOC_PARTITION_START + 14] = "kmalloc-part-14-" #sz, +#define KMA_PART_15(sz) KMA_PART_14(sz) .name[KMALLOC_PARTITION_START + 15] = "kmalloc-part-15-" #sz, +#else // CONFIG_KMALLOC_PARTITION_CACHES +#define KMALLOC_PARTITION_NAME(N, sz) #endif #define INIT_KMALLOC_INFO(__size, __short_size) \ @@ -849,7 +849,7 @@ EXPORT_SYMBOL(kmalloc_size_roundup); KMALLOC_RCL_NAME(__short_size) \ KMALLOC_CGROUP_NAME(__short_size) \ KMALLOC_DMA_NAME(__short_size) \ - KMALLOC_RANDOM_NAME(RANDOM_KMALLOC_CACHES_NR, __short_size) \ + KMALLOC_PARTITION_NAME(KMALLOC_PARTITION_CACHES_NR, __short_size) \ .size = __size, \ } @@ -961,8 +961,8 @@ new_kmalloc_cache(int idx, enum kmalloc_cache_type type) flags |= SLAB_CACHE_DMA; } -#ifdef CONFIG_RANDOM_KMALLOC_CACHES - if (type >= KMALLOC_RANDOM_START && type <= KMALLOC_RANDOM_END) +#ifdef CONFIG_KMALLOC_PARTITION_CACHES + if (type >= KMALLOC_PARTITION_START && type <= KMALLOC_PARTITION_END) flags |= SLAB_NO_MERGE; #endif @@ -1010,7 +1010,7 @@ void __init create_kmalloc_caches(void) for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) new_kmalloc_cache(i, type); } -#ifdef CONFIG_RANDOM_KMALLOC_CACHES +#ifdef CONFIG_KMALLOC_PARTITION_RANDOM random_kmalloc_seed = get_random_u64(); #endif diff --git a/mm/slub.c b/mm/slub.c index 0baa906f39ab..74652bbdd591 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2129,11 +2129,11 @@ static inline size_t obj_exts_alloc_size(struct kmem_cache *s, if (!is_kmalloc_normal(s)) return sz; - obj_exts_cache = kmalloc_slab(sz, NULL, gfp, 0); + obj_exts_cache = kmalloc_slab(sz, NULL, gfp, __kmalloc_token(0)); /* - * We can't simply compare s with obj_exts_cache, because random kmalloc - * caches have multiple caches per size, selected by caller address. - * Since caller address may differ between kmalloc_slab() and actual + * We can't simply compare s with obj_exts_cache, because partitioned kmalloc + * caches have multiple caches per size, selected by caller address or type. + * Since caller address or type may differ between kmalloc_slab() and actual * allocation, bump size when sizes are equal. */ if (s->object_size == obj_exts_cache->object_size) @@ -5274,7 +5274,7 @@ EXPORT_SYMBOL(__kmalloc_large_node_noprof); static __always_inline void *__do_kmalloc_node(size_t size, kmem_buckets *b, gfp_t flags, int node, - unsigned long caller) + unsigned long caller, kmalloc_token_t token) { struct kmem_cache *s; void *ret; @@ -5289,22 +5289,24 @@ void *__do_kmalloc_node(size_t size, kmem_buckets *b, gfp_t flags, int node, if (unlikely(!size)) return ZERO_SIZE_PTR; - s = kmalloc_slab(size, b, flags, caller); + s = kmalloc_slab(size, b, flags, token); ret = slab_alloc_node(s, NULL, flags, node, caller, size); ret = kasan_kmalloc(s, ret, size, flags); trace_kmalloc(caller, ret, size, s->size, flags, node); return ret; } -void *__kmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flags, int node) +void *__kmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), gfp_t flags, int node) { - return __do_kmalloc_node(size, PASS_BUCKET_PARAM(b), flags, node, _RET_IP_); + return __do_kmalloc_node(size, PASS_BUCKET_PARAM(b), flags, node, + _RET_IP_, PASS_TOKEN_PARAM(token)); } EXPORT_SYMBOL(__kmalloc_node_noprof); -void *__kmalloc_noprof(size_t size, gfp_t flags) +void *__kmalloc_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags) { - return __do_kmalloc_node(size, NULL, flags, NUMA_NO_NODE, _RET_IP_); + return __do_kmalloc_node(size, NULL, flags, NUMA_NO_NODE, _RET_IP_, + PASS_TOKEN_PARAM(token)); } EXPORT_SYMBOL(__kmalloc_noprof); @@ -5319,7 +5321,7 @@ EXPORT_SYMBOL(__kmalloc_noprof); * NULL does not mean EBUSY or EAGAIN. It means ENOMEM. * There is no reason to call it again and expect !NULL. */ -void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) +void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, int node) { gfp_t alloc_gfp = __GFP_NOWARN | __GFP_NOMEMALLOC | gfp_flags; struct kmem_cache *s; @@ -5346,7 +5348,7 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return NULL; - s = kmalloc_slab(size, NULL, alloc_gfp, _RET_IP_); + s = kmalloc_slab(size, NULL, alloc_gfp, PASS_TOKEN_PARAM(token)); if (!(s->flags & __CMPXCHG_DOUBLE) && !kmem_cache_debug(s)) /* @@ -5399,12 +5401,13 @@ success: ret = kasan_kmalloc(s, ret, size, alloc_gfp); return ret; } -EXPORT_SYMBOL_GPL(kmalloc_nolock_noprof); +EXPORT_SYMBOL_GPL(_kmalloc_nolock_noprof); -void *__kmalloc_node_track_caller_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flags, +void *__kmalloc_node_track_caller_noprof(DECL_KMALLOC_PARAMS(size, b, token), gfp_t flags, int node, unsigned long caller) { - return __do_kmalloc_node(size, PASS_BUCKET_PARAM(b), flags, node, caller); + return __do_kmalloc_node(size, PASS_BUCKET_PARAM(b), flags, node, + caller, PASS_TOKEN_PARAM(token)); } EXPORT_SYMBOL(__kmalloc_node_track_caller_noprof); @@ -6635,7 +6638,7 @@ void kfree_nolock(const void *object) EXPORT_SYMBOL_GPL(kfree_nolock); static __always_inline __realloc_size(2) void * -__do_krealloc(const void *p, size_t new_size, unsigned long align, gfp_t flags, int nid) +__do_krealloc(const void *p, size_t new_size, unsigned long align, gfp_t flags, int nid, kmalloc_token_t token) { void *ret; size_t ks = 0; @@ -6707,7 +6710,7 @@ __do_krealloc(const void *p, size_t new_size, unsigned long align, gfp_t flags, return (void *)p; alloc_new: - ret = kmalloc_node_track_caller_noprof(new_size, flags, nid, _RET_IP_); + ret = __kmalloc_node_track_caller_noprof(PASS_KMALLOC_PARAMS(new_size, NULL, token), flags, nid, _RET_IP_); if (ret && p) { /* Disable KASAN checks as the object's redzone is accessed. */ kasan_disable_current(); @@ -6756,7 +6759,7 @@ alloc_new: * * Return: pointer to the allocated memory or %NULL in case of error */ -void *krealloc_node_align_noprof(const void *p, size_t new_size, unsigned long align, +void *krealloc_node_align_noprof(const void *p, DECL_TOKEN_PARAMS(new_size, token), unsigned long align, gfp_t flags, int nid) { void *ret; @@ -6766,7 +6769,7 @@ void *krealloc_node_align_noprof(const void *p, size_t new_size, unsigned long a return ZERO_SIZE_PTR; } - ret = __do_krealloc(p, new_size, align, flags, nid); + ret = __do_krealloc(p, new_size, align, flags, nid, PASS_TOKEN_PARAM(token)); if (ret && kasan_reset_tag(p) != kasan_reset_tag(ret)) kfree(p); @@ -6803,6 +6806,7 @@ static gfp_t kmalloc_gfp_adjust(gfp_t flags, size_t size) * failure, fall back to non-contiguous (vmalloc) allocation. * @size: size of the request. * @b: which set of kmalloc buckets to allocate from. + * @token: allocation token. * @align: desired alignment. * @flags: gfp mask for the allocation - must be compatible (superset) with GFP_KERNEL. * @node: numa node to allocate from @@ -6819,7 +6823,7 @@ static gfp_t kmalloc_gfp_adjust(gfp_t flags, size_t size) * * Return: pointer to the allocated memory of %NULL in case of failure */ -void *__kvmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), unsigned long align, +void *__kvmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), unsigned long align, gfp_t flags, int node) { bool allow_block; @@ -6831,7 +6835,7 @@ void *__kvmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), unsigned long align, */ ret = __do_kmalloc_node(size, PASS_BUCKET_PARAM(b), kmalloc_gfp_adjust(flags, size), - node, _RET_IP_); + node, _RET_IP_, PASS_TOKEN_PARAM(token)); if (ret || size <= PAGE_SIZE) return ret; @@ -6927,7 +6931,7 @@ EXPORT_SYMBOL(kvfree_sensitive); * * Return: pointer to the allocated memory or %NULL in case of error */ -void *kvrealloc_node_align_noprof(const void *p, size_t size, unsigned long align, +void *kvrealloc_node_align_noprof(const void *p, DECL_TOKEN_PARAMS(size, token), unsigned long align, gfp_t flags, int nid) { void *n; @@ -6935,10 +6939,10 @@ void *kvrealloc_node_align_noprof(const void *p, size_t size, unsigned long alig if (is_vmalloc_addr(p)) return vrealloc_node_align_noprof(p, size, align, flags, nid); - n = krealloc_node_align_noprof(p, size, align, kmalloc_gfp_adjust(flags, size), nid); + n = krealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(size, token), align, kmalloc_gfp_adjust(flags, size), nid); if (!n) { /* We failed to krealloc(), fall back to kvmalloc(). */ - n = kvmalloc_node_align_noprof(size, align, flags, nid); + n = __kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(size, NULL, token), align, flags, nid); if (!n) return NULL; @@ -8453,7 +8457,7 @@ static void __init bootstrap_kmalloc_sheaves(void) { enum kmalloc_cache_type type; - for (type = KMALLOC_NORMAL; type <= KMALLOC_RANDOM_END; type++) { + for (type = KMALLOC_NORMAL; type <= KMALLOC_PARTITION_END; type++) { for (int idx = 0; idx < KMALLOC_SHIFT_HIGH + 1; idx++) { if (kmalloc_caches[type][idx]) bootstrap_cache_sheaves(kmalloc_caches[type][idx]); From 0fc1bd38a19c108395d8338fb034f90c2d3fbe55 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 11 May 2026 22:00:49 +0200 Subject: [PATCH 250/655] slab: improve KMALLOC_PARTITION_RANDOM randomness When using CONFIG_KMALLOC_PARTITION_RANDOM, _RET_IP_ was previously used to identify the allocation site. _RET_IP_, however, evaluates to the caller's parent's instruction pointer rather than the actual allocation site; this would lead to collisions where a function performs multiple allocations. With the generalization to kmalloc_token_t, we now generate the token at the outermost macro, and using _THIS_IP_ would fix this for all cases. Unfortunately, the generic implementation of _THIS_IP_ relies on taking the address of a local label, which is considered broken by both GCC [1] and Clang [2] because label addresses are only expected to be used with computed gotos. While the generic version more or less works today, it is known to be brittle. For example, Clang -O2 always returns 1 when this function is inlined: static inline unsigned long get_ip(void) { return ({ __label__ __here; __here: (unsigned long)&&__here; }); } To provide a reliable unique identifier without breaking architectures relying on the generic _THIS_IP_, introduce _CODE_LOCATION_: it resolves to _THIS_IP_ where architectures provide a safe implementation, and falls back to a zero-cost static marker where _THIS_IP_ is broken. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120071 [1] Link: https://github.com/llvm/llvm-project/issues/138272 [2] Signed-off-by: Marco Elver Reviewed-by: Harry Yoo (Oracle) Link: https://patch.msgid.link/20260511200136.3201646-2-elver@google.com Signed-off-by: Vlastimil Babka (SUSE) --- include/linux/instruction_pointer.h | 24 ++++++++++++++++++++++++ include/linux/slab.h | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/linux/instruction_pointer.h b/include/linux/instruction_pointer.h index aa0b3ffea935..ea5bc756bd99 100644 --- a/include/linux/instruction_pointer.h +++ b/include/linux/instruction_pointer.h @@ -8,6 +8,30 @@ #ifndef _THIS_IP_ #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) +/* + * The current generic definition of _THIS_IP_ is considered broken by GCC [1] + * and Clang [2]. In particular, the address of a label is only expected to be + * used with a computed goto. + * + * [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120071 + * [2] https://github.com/llvm/llvm-project/issues/138272 + * + * Mark it as broken, so that appropriate fallback options can be implemented + * for architectures that do not define their own _THIS_IP_. + */ +#define HAS_BROKEN_THIS_IP +#endif + +/* + * _CODE_LOCATION_ provides a unique identifier for the current code location. + * When _THIS_IP_ is broken (generic version), we fall back to a static marker + * which guarantees uniqueness and resolves to a constant address at link time, + * avoiding runtime overhead and compiler optimizations breaking it. + */ +#ifdef HAS_BROKEN_THIS_IP +#define _CODE_LOCATION_ ({ static const char __here; (unsigned long)&__here; }) +#else +#define _CODE_LOCATION_ _THIS_IP_ #endif #endif /* _LINUX_INSTRUCTION_POINTER_H */ diff --git a/include/linux/slab.h b/include/linux/slab.h index 795455256329..90a0b9e9a766 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -503,7 +503,7 @@ int kmem_cache_shrink(struct kmem_cache *s); typedef struct { unsigned long v; } kmalloc_token_t; #ifdef CONFIG_KMALLOC_PARTITION_RANDOM extern unsigned long random_kmalloc_seed; -#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _RET_IP_ }) +#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _CODE_LOCATION_ }) #elif defined(CONFIG_KMALLOC_PARTITION_TYPED) #define __kmalloc_token(...) ((kmalloc_token_t){ .v = __builtin_infer_alloc_token(__VA_ARGS__) }) #endif From e0f54249a491c62ef8196b9f13bd7d95dba47c6f Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 11 May 2026 22:00:50 +0200 Subject: [PATCH 251/655] slab: fix kernel-docs for mm-api The mm-api kernel-docs have been disconnected from their symbols. While the scripts were previously taught to handle the _noprof suffix added by allocation tagging (in 51a7bf0238c2 "scripts/kernel-doc: drop "_noprof" on function prototypes"), this does not handle cases where the internal implementation function has an additional leading underscore. The added optional parameters (via DECL_KMALLOC_PARAMS) further complicate parsing the internal signatures. When the kernel-doc block remains above the internal implementation function but uses the public API name, the documentation generator fails to associate the documented symbol. Simply moving the docs to the macros in slab.h fixes the association but causes loss of types in the generated documentation (rendering as e.g. untyped 'kmalloc(size, flags)' macro). Fix this by: 1. Moving the kernel-doc comment blocks from slub.c to slab.h, placing them directly above the user-facing macros. 2. Providing explicit, typed C prototypes for the documented APIs inside '#if 0 /* kernel-doc */' blocks. 3. Converting the variadic macros for the documented APIs to use explicit arguments to match the documentation. No functional change intended. Signed-off-by: Marco Elver Link: https://patch.msgid.link/20260511200136.3201646-3-elver@google.com Signed-off-by: Vlastimil Babka (SUSE) --- include/linux/slab.h | 218 +++++++++++++++++++++++++++++++++---------- mm/slub.c | 98 ------------------- 2 files changed, 169 insertions(+), 147 deletions(-) diff --git a/include/linux/slab.h b/include/linux/slab.h index 90a0b9e9a766..07f13e3363a9 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -530,7 +530,49 @@ void * __must_check krealloc_node_align_noprof(const void *objp, unsigned long align, gfp_t flags, int nid) __realloc_size(2); #define krealloc_noprof(_o, _s, _f) krealloc_node_align_noprof(_o, PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), 1, _f, NUMA_NO_NODE) -#define krealloc_node_align(_o, _s, _a, _f, _n) alloc_hooks(krealloc_node_align_noprof(_o, PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), _a, _f, _n)) +#if 0 /* kernel-doc */ +/** + * krealloc_node_align - reallocate memory. The contents will remain unchanged. + * @p: object to reallocate memory for. + * @new_size: how many bytes of memory are required. + * @align: desired alignment. + * @flags: the type of memory to allocate. + * @nid: NUMA node or NUMA_NO_NODE + * + * If @p is %NULL, krealloc() behaves exactly like kmalloc(). If @new_size + * is 0 and @p is not a %NULL pointer, the object pointed to is freed. + * + * Only alignments up to those guaranteed by kmalloc() will be honored. Please see + * Documentation/core-api/memory-allocation.rst for more details. + * + * If __GFP_ZERO logic is requested, callers must ensure that, starting with the + * initial memory allocation, every subsequent call to this API for the same + * memory allocation is flagged with __GFP_ZERO. Otherwise, it is possible that + * __GFP_ZERO is not fully honored by this API. + * + * When slub_debug_orig_size() is off, krealloc() only knows about the bucket + * size of an allocation (but not the exact size it was allocated with) and + * hence implements the following semantics for shrinking and growing buffers + * with __GFP_ZERO:: + * + * new bucket + * 0 size size + * |--------|----------------| + * | keep | zero | + * + * Otherwise, the original allocation size 'orig_size' could be used to + * precisely clear the requested size, and the new size will also be stored + * as the new 'orig_size'. + * + * In any case, the contents of the object pointed to are preserved up to the + * lesser of the new and old sizes. + * + * Return: pointer to the allocated memory or %NULL in case of error + */ +void *krealloc_node_align(const void *p, size_t new_size, unsigned long align, gfp_t flags, int nid); +#endif +#define krealloc_node_align(p, new_size, align, flags, nid) \ + alloc_hooks(krealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(new_size, __kmalloc_token(new_size)), align, flags, nid)) #define krealloc_node(_o, _s, _f, _n) krealloc_node_align(_o, _s, 1, _f, _n) #define krealloc(...) krealloc_node(__VA_ARGS__, NUMA_NO_NODE) @@ -913,6 +955,23 @@ void *__kmalloc_large_noprof(size_t size, gfp_t flags) void *__kmalloc_large_node_noprof(size_t size, gfp_t flags, int node) __assume_page_alignment __alloc_size(1); +static __always_inline __alloc_size(1) void *_kmalloc_noprof(size_t size, gfp_t flags, kmalloc_token_t token) +{ + if (__builtin_constant_p(size) && size) { + unsigned int index; + + if (size > KMALLOC_MAX_CACHE_SIZE) + return __kmalloc_large_noprof(size, flags); + + index = kmalloc_index(size); + return __kmalloc_cache_noprof( + kmalloc_caches[kmalloc_type(flags, token)][index], + flags, size); + } + return __kmalloc_noprof(PASS_TOKEN_PARAMS(size, token), flags); +} +#define kmalloc_noprof(...) _kmalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) +#if 0 /* kernel-doc */ /** * kmalloc - allocate kernel memory * @size: how many bytes of memory are required. @@ -968,27 +1027,27 @@ void *__kmalloc_large_node_noprof(size_t size, gfp_t flags, int node) * Try really hard to succeed the allocation but fail * eventually. */ -static __always_inline __alloc_size(1) void *_kmalloc_noprof(size_t size, gfp_t flags, kmalloc_token_t token) -{ - if (__builtin_constant_p(size) && size) { - unsigned int index; - - if (size > KMALLOC_MAX_CACHE_SIZE) - return __kmalloc_large_noprof(size, flags); - - index = kmalloc_index(size); - return __kmalloc_cache_noprof( - kmalloc_caches[kmalloc_type(flags, token)][index], - flags, size); - } - return __kmalloc_noprof(PASS_TOKEN_PARAMS(size, token), flags); -} -#define kmalloc_noprof(...) _kmalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) -#define kmalloc(...) alloc_hooks(kmalloc_noprof(__VA_ARGS__)) +void *kmalloc(size_t size, gfp_t flags); +#endif +#define kmalloc(size, flags) alloc_hooks(kmalloc_noprof(size, flags)) void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, int node); #define kmalloc_nolock_noprof(_s, _f, _n) _kmalloc_nolock_noprof(PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), _f, _n) -#define kmalloc_nolock(...) alloc_hooks(kmalloc_nolock_noprof(__VA_ARGS__)) +#if 0 /* kernel-doc */ +/** + * kmalloc_nolock - Allocate an object of given size from any context. + * @size: size to allocate + * @gfp_flags: GFP flags. Only __GFP_ACCOUNT, __GFP_ZERO, __GFP_NO_OBJ_EXT + * allowed. + * @node: node number of the target node. + * + * Return: pointer to the new object or NULL in case of error. + * NULL does not mean EBUSY or EAGAIN. It means ENOMEM. + * There is no reason to call it again and expect !NULL. + */ +void *kmalloc_nolock(size_t size, gfp_t gfp_flags, int node); +#endif +#define kmalloc_nolock(size, gfp_flags, node) alloc_hooks(kmalloc_nolock_noprof(size, gfp_flags, node)) /** * __alloc_objs - Allocate objects of a given type using @@ -1115,12 +1174,6 @@ static __always_inline __alloc_size(1) void *_kmalloc_node_noprof(size_t size, g #define kmalloc_node_noprof(...) _kmalloc_node_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) #define kmalloc_node(...) alloc_hooks(kmalloc_node_noprof(__VA_ARGS__)) -/** - * kmalloc_array - allocate memory for an array. - * @n: number of elements. - * @size: element size. - * @flags: the type of memory to allocate (see kmalloc). - */ static inline __alloc_size(1, 2) void *_kmalloc_array_noprof(size_t n, size_t size, gfp_t flags, kmalloc_token_t token) { size_t bytes; @@ -1130,8 +1183,31 @@ static inline __alloc_size(1, 2) void *_kmalloc_array_noprof(size_t n, size_t si return _kmalloc_noprof(bytes, flags, token); } #define kmalloc_array_noprof(...) _kmalloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) -#define kmalloc_array(...) alloc_hooks(kmalloc_array_noprof(__VA_ARGS__)) +#if 0 /* kernel-doc */ +/** + * kmalloc_array - allocate memory for an array. + * @n: number of elements. + * @size: element size. + * @flags: the type of memory to allocate (see kmalloc). + */ +void *kmalloc_array(size_t n, size_t size, gfp_t flags); +#endif +#define kmalloc_array(n, size, flags) alloc_hooks(kmalloc_array_noprof(n, size, flags)) +static inline __realloc_size(2, 3) void * __must_check _krealloc_array_noprof(void *p, + size_t new_n, + size_t new_size, + gfp_t flags, kmalloc_token_t token) +{ + size_t bytes; + + if (unlikely(check_mul_overflow(new_n, new_size, &bytes))) + return NULL; + + return krealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(bytes, token), 1, flags, NUMA_NO_NODE); +} +#define krealloc_array_noprof(...) _krealloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) +#if 0 /* kernel-doc */ /** * krealloc_array - reallocate memory for an array. * @p: pointer to the memory chunk to reallocate @@ -1149,20 +1225,9 @@ static inline __alloc_size(1, 2) void *_kmalloc_array_noprof(size_t n, size_t si * In any case, the contents of the object pointed to are preserved up to the * lesser of the new and old sizes. */ -static inline __realloc_size(2, 3) void * __must_check _krealloc_array_noprof(void *p, - size_t new_n, - size_t new_size, - gfp_t flags, kmalloc_token_t token) -{ - size_t bytes; - - if (unlikely(check_mul_overflow(new_n, new_size, &bytes))) - return NULL; - - return krealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(bytes, token), 1, flags, NUMA_NO_NODE); -} -#define krealloc_array_noprof(...) _krealloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) -#define krealloc_array(...) alloc_hooks(krealloc_array_noprof(__VA_ARGS__)) +void *krealloc_array(void *p, size_t new_n, size_t new_size, gfp_t flags); +#endif +#define krealloc_array(p, new_n, new_size, flags) alloc_hooks(krealloc_array_noprof(p, new_n, new_size, flags)) /** * kcalloc - allocate memory for an array. The memory is set to zero. @@ -1214,17 +1279,20 @@ static inline __alloc_size(1, 2) void *_kmalloc_array_node_noprof(size_t n, size */ #define kmem_cache_zalloc(_k, _flags) kmem_cache_alloc(_k, (_flags)|__GFP_ZERO) -/** - * kzalloc - allocate memory. The memory is set to zero. - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate (see kmalloc). - */ static inline __alloc_size(1) void *_kzalloc_noprof(size_t size, gfp_t flags, kmalloc_token_t token) { return _kmalloc_noprof(size, flags | __GFP_ZERO, token); } #define kzalloc_noprof(...) _kzalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__)) -#define kzalloc(...) alloc_hooks(kzalloc_noprof(__VA_ARGS__)) +#if 0 /* kernel-doc */ +/** + * kzalloc - allocate memory. The memory is set to zero. + * @size: how many bytes of memory are required. + * @flags: the type of memory to allocate (see kmalloc). + */ +void *kzalloc(size_t size, gfp_t flags); +#endif +#define kzalloc(size, flags) alloc_hooks(kzalloc_noprof(size, flags)) #define kzalloc_node(_size, _flags, _node) kmalloc_node(_size, (_flags)|__GFP_ZERO, _node) void *__kvmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), unsigned long align, @@ -1233,7 +1301,29 @@ void *__kvmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), unsigned long __kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(_size, NULL, __kmalloc_token(_size)), _align, _flags, _node) #define kvmalloc_node_align(...) \ alloc_hooks(kvmalloc_node_align_noprof(__VA_ARGS__)) -#define kvmalloc_node(_s, _f, _n) kvmalloc_node_align(_s, 1, _f, _n) +#if 0 /* kernel-doc */ +/** + * kvmalloc_node - attempt to allocate physically contiguous memory, but upon + * failure, fall back to non-contiguous (vmalloc) allocation. + * @size: size of the request. + * @flags: gfp mask for the allocation - must be compatible (superset) with GFP_KERNEL. + * @node: numa node to allocate from + * + * Only alignments up to those guaranteed by kmalloc() will be honored. Please see + * Documentation/core-api/memory-allocation.rst for more details. + * + * Uses kmalloc to get the memory but if the allocation fails then falls back + * to the vmalloc allocator. Use kvfree for freeing the memory. + * + * GFP_NOWAIT and GFP_ATOMIC are supported, the __GFP_NORETRY modifier is not. + * __GFP_RETRY_MAYFAIL is supported, and it should be used only if kmalloc is + * preferable to the vmalloc fallback, due to visible performance drawbacks. + * + * Return: pointer to the allocated memory of %NULL in case of failure + */ +void *kvmalloc_node(size_t size, gfp_t flags, int node); +#endif +#define kvmalloc_node(size, flags, node) kvmalloc_node_align(size, 1, flags, node) #define kvmalloc_node_noprof(size, flags, node) \ kvmalloc_node_align_noprof(size, 1, flags, node) #define kvmalloc(...) kvmalloc_node(__VA_ARGS__, NUMA_NO_NODE) @@ -1266,8 +1356,38 @@ _kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node, kmallo void *kvrealloc_node_align_noprof(const void *p, DECL_TOKEN_PARAMS(size, token), unsigned long align, gfp_t flags, int nid) __realloc_size(2); -#define kvrealloc_node_align(_p, _s, _a, _f, _n) \ - alloc_hooks(kvrealloc_node_align_noprof(_p, PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), _a, _f, _n)) +#if 0 /* kernel-doc */ +/** + * kvrealloc_node_align - reallocate memory; contents remain unchanged + * @p: object to reallocate memory for + * @size: the size to reallocate + * @align: desired alignment + * @flags: the flags for the page level allocator + * @nid: NUMA node id + * + * If @p is %NULL, kvrealloc() behaves exactly like kvmalloc(). If @size is 0 + * and @p is not a %NULL pointer, the object pointed to is freed. + * + * Only alignments up to those guaranteed by kmalloc() will be honored. Please see + * Documentation/core-api/memory-allocation.rst for more details. + * + * If __GFP_ZERO logic is requested, callers must ensure that, starting with the + * initial memory allocation, every subsequent call to this API for the same + * memory allocation is flagged with __GFP_ZERO. Otherwise, it is possible that + * __GFP_ZERO is not fully honored by this API. + * + * In any case, the contents of the object pointed to are preserved up to the + * lesser of the new and old sizes. + * + * This function must not be called concurrently with itself or kvfree() for the + * same memory allocation. + * + * Return: pointer to the allocated memory or %NULL in case of error + */ +void *kvrealloc_node_align(const void *p, size_t size, unsigned long align, gfp_t flags, int nid); +#endif +#define kvrealloc_node_align(p, size, align, flags, nid) \ + alloc_hooks(kvrealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(size, __kmalloc_token(size)), align, flags, nid)) #define kvrealloc_node(_p, _s, _f, _n) kvrealloc_node_align(_p, _s, 1, _f, _n) #define kvrealloc(...) kvrealloc_node(__VA_ARGS__, NUMA_NO_NODE) diff --git a/mm/slub.c b/mm/slub.c index 74652bbdd591..abbed1d2bd5e 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5310,17 +5310,6 @@ void *__kmalloc_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags) } EXPORT_SYMBOL(__kmalloc_noprof); -/** - * kmalloc_nolock - Allocate an object of given size from any context. - * @size: size to allocate - * @gfp_flags: GFP flags. Only __GFP_ACCOUNT, __GFP_ZERO, __GFP_NO_OBJ_EXT - * allowed. - * @node: node number of the target node. - * - * Return: pointer to the new object or NULL in case of error. - * NULL does not mean EBUSY or EAGAIN. It means ENOMEM. - * There is no reason to call it again and expect !NULL. - */ void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, int node) { gfp_t alloc_gfp = __GFP_NOWARN | __GFP_NOMEMALLOC | gfp_flags; @@ -6721,44 +6710,6 @@ alloc_new: return ret; } -/** - * krealloc_node_align - reallocate memory. The contents will remain unchanged. - * @p: object to reallocate memory for. - * @new_size: how many bytes of memory are required. - * @align: desired alignment. - * @flags: the type of memory to allocate. - * @nid: NUMA node or NUMA_NO_NODE - * - * If @p is %NULL, krealloc() behaves exactly like kmalloc(). If @new_size - * is 0 and @p is not a %NULL pointer, the object pointed to is freed. - * - * Only alignments up to those guaranteed by kmalloc() will be honored. Please see - * Documentation/core-api/memory-allocation.rst for more details. - * - * If __GFP_ZERO logic is requested, callers must ensure that, starting with the - * initial memory allocation, every subsequent call to this API for the same - * memory allocation is flagged with __GFP_ZERO. Otherwise, it is possible that - * __GFP_ZERO is not fully honored by this API. - * - * When slub_debug_orig_size() is off, krealloc() only knows about the bucket - * size of an allocation (but not the exact size it was allocated with) and - * hence implements the following semantics for shrinking and growing buffers - * with __GFP_ZERO:: - * - * new bucket - * 0 size size - * |--------|----------------| - * | keep | zero | - * - * Otherwise, the original allocation size 'orig_size' could be used to - * precisely clear the requested size, and the new size will also be stored - * as the new 'orig_size'. - * - * In any case, the contents of the object pointed to are preserved up to the - * lesser of the new and old sizes. - * - * Return: pointer to the allocated memory or %NULL in case of error - */ void *krealloc_node_align_noprof(const void *p, DECL_TOKEN_PARAMS(new_size, token), unsigned long align, gfp_t flags, int nid) { @@ -6801,28 +6752,6 @@ static gfp_t kmalloc_gfp_adjust(gfp_t flags, size_t size) return flags; } -/** - * __kvmalloc_node - attempt to allocate physically contiguous memory, but upon - * failure, fall back to non-contiguous (vmalloc) allocation. - * @size: size of the request. - * @b: which set of kmalloc buckets to allocate from. - * @token: allocation token. - * @align: desired alignment. - * @flags: gfp mask for the allocation - must be compatible (superset) with GFP_KERNEL. - * @node: numa node to allocate from - * - * Only alignments up to those guaranteed by kmalloc() will be honored. Please see - * Documentation/core-api/memory-allocation.rst for more details. - * - * Uses kmalloc to get the memory but if the allocation fails then falls back - * to the vmalloc allocator. Use kvfree for freeing the memory. - * - * GFP_NOWAIT and GFP_ATOMIC are supported, the __GFP_NORETRY modifier is not. - * __GFP_RETRY_MAYFAIL is supported, and it should be used only if kmalloc is - * preferable to the vmalloc fallback, due to visible performance drawbacks. - * - * Return: pointer to the allocated memory of %NULL in case of failure - */ void *__kvmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), unsigned long align, gfp_t flags, int node) { @@ -6904,33 +6833,6 @@ void kvfree_sensitive(const void *addr, size_t len) } EXPORT_SYMBOL(kvfree_sensitive); -/** - * kvrealloc_node_align - reallocate memory; contents remain unchanged - * @p: object to reallocate memory for - * @size: the size to reallocate - * @align: desired alignment - * @flags: the flags for the page level allocator - * @nid: NUMA node id - * - * If @p is %NULL, kvrealloc() behaves exactly like kvmalloc(). If @size is 0 - * and @p is not a %NULL pointer, the object pointed to is freed. - * - * Only alignments up to those guaranteed by kmalloc() will be honored. Please see - * Documentation/core-api/memory-allocation.rst for more details. - * - * If __GFP_ZERO logic is requested, callers must ensure that, starting with the - * initial memory allocation, every subsequent call to this API for the same - * memory allocation is flagged with __GFP_ZERO. Otherwise, it is possible that - * __GFP_ZERO is not fully honored by this API. - * - * In any case, the contents of the object pointed to are preserved up to the - * lesser of the new and old sizes. - * - * This function must not be called concurrently with itself or kvfree() for the - * same memory allocation. - * - * Return: pointer to the allocated memory or %NULL in case of error - */ void *kvrealloc_node_align_noprof(const void *p, DECL_TOKEN_PARAMS(size, token), unsigned long align, gfp_t flags, int nid) { From f83da91c7e038c8753c44a85dc9fe2fcf68db17a Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Mon, 11 May 2026 20:10:23 +0530 Subject: [PATCH 252/655] dt-bindings: watchdog: qcom-wdt: Document IPQ9650 watchdog Document the watchdog device found on the Qualcomm IPQ9650 SoC. Signed-off-by: Kathiravan Thirumoorthy Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260511-ipq9650_wdt_binding-v2-1-dca22892d3d3@oss.qualcomm.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index b3f8f063f282..d647bf5f19a4 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -24,6 +24,7 @@ properties: - qcom,apss-wdt-ipq5332 - qcom,apss-wdt-ipq5424 - qcom,apss-wdt-ipq9574 + - qcom,apss-wdt-ipq9650 - qcom,apss-wdt-kaanapali - qcom,apss-wdt-msm8226 - qcom,apss-wdt-msm8974 From 15f5bc6748a63b0c19f2a6d96219be6ff5d128eb Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 29 Apr 2026 10:10:20 +0200 Subject: [PATCH 253/655] dt-bindings: crypto: qcom-qce: document the Nord crypto engine Document the crypto engine on the Qualcomm Nord Platform. Signed-off-by: Bartosz Golaszewski Acked-by: Rob Herring (Arm) Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom-qce.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index 69101cead3bc..08febd66c22b 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -49,6 +49,7 @@ properties: - qcom,glymur-qce - qcom,kaanapali-qce - qcom,milos-qce + - qcom,nord-qce - qcom,qcs615-qce - qcom,qcs8300-qce - qcom,sa8775p-qce From 650f09718adc327c7dc50f6347580079fdb361f6 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 4 May 2026 10:28:50 +0200 Subject: [PATCH 254/655] crypto: jitterentropy - drop redundant delta check in jent_entropy_init Since start_time = end_time - delta, start_time can only equal end_time when delta is 0, making the explicit end_time == start_time check redundant. Remove it. Signed-off-by: Thorsten Blum Reviewed-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/jitterentropy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c index d5832caa8ab3..6ac0257e8e0a 100644 --- a/crypto/jitterentropy.c +++ b/crypto/jitterentropy.c @@ -775,7 +775,7 @@ int jent_entropy_init(unsigned int osr, unsigned int flags, * delta even when called shortly after each other -- this * implies that we also have a high resolution timer */ - if (!delta || (end_time == start_time)) { + if (!delta) { ret = JENT_ECOARSETIME; goto out; } From 69e7b807ba7464fe9fd46bc72562cdeabe9a374c Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 4 May 2026 10:28:51 +0200 Subject: [PATCH 255/655] crypto: jitterentropy - fix URL The URL https://www.chronox.de/jent.html resolves to a 404 Not Found. Use https://www.chronox.de/jent/ instead. Signed-off-by: Thorsten Blum Reviewed-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/jitterentropy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c index 6ac0257e8e0a..b024bff7024a 100644 --- a/crypto/jitterentropy.c +++ b/crypto/jitterentropy.c @@ -7,7 +7,7 @@ * Design * ====== * - * See https://www.chronox.de/jent.html + * See https://www.chronox.de/jent/ * * License * ======= @@ -47,7 +47,7 @@ /* * This Jitterentropy RNG is based on the jitterentropy library - * version 3.4.0 provided at https://www.chronox.de/jent.html + * version 3.4.0 provided at https://www.chronox.de/jent/ */ #ifdef __OPTIMIZE__ From 69f93dbb40377edc4c4bf3fc67bbd63ba35fde3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 4 May 2026 11:20:14 +0200 Subject: [PATCH 256/655] hwrng: drivers - Drop unused assignment to pci driver_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly assigning 0 to driver_data in drivers not using this member has no benefit. Drop these and similarly depend on the compiler to zero-initialize the list terminator. This is a preparation for making struct pci_device_id::driver_data an anonymous union (which makes initializing using a list expression fail), but it's also a nice cleanup by itself. It was verified on x86 and arm64 that this change doesn't introduce changes to the compiled drivers. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Herbert Xu --- drivers/char/hw_random/amd-rng.c | 6 +++--- drivers/char/hw_random/cavium-rng.c | 4 ++-- drivers/char/hw_random/geode-rng.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 332d594bdf70..dff80daae587 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -47,9 +47,9 @@ * want to register another driver on the same PCI id. */ static const struct pci_device_id pci_tbl[] = { - { PCI_VDEVICE(AMD, 0x7443), 0, }, - { PCI_VDEVICE(AMD, 0x746b), 0, }, - { 0, }, /* terminate list */ + { PCI_VDEVICE(AMD, 0x7443) }, + { PCI_VDEVICE(AMD, 0x746b) }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/char/hw_random/cavium-rng.c b/drivers/char/hw_random/cavium-rng.c index d9d7b6038c06..3e2c042009f6 100644 --- a/drivers/char/hw_random/cavium-rng.c +++ b/drivers/char/hw_random/cavium-rng.c @@ -73,8 +73,8 @@ static void cavium_rng_remove(struct pci_dev *pdev) } static const struct pci_device_id cavium_rng_pf_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa018), 0, 0, 0}, /* Thunder RNM */ - {0,}, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa018) }, /* Thunder RNM */ + { }, }; MODULE_DEVICE_TABLE(pci, cavium_rng_pf_id_table); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index 1b21d58e1768..ae63eff64344 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -46,8 +46,8 @@ * want to register another driver on the same PCI id. */ static const struct pci_device_id pci_tbl[] = { - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), 0, }, - { 0, }, /* terminate list */ + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES) }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pci_tbl); From 15d253c5d7fa17d3499c885bdb82070546180e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 4 May 2026 17:24:21 +0200 Subject: [PATCH 257/655] crypto: ccp - Define pci_device_ids using named initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .driver_data member of the struct pci_device_id array was initialized by list expressions. This isn't easily readable if you're not into PCI. Using the PCI_DEVICE macro and named initializers is more explicit and thus easier to parse. Also skip explicit assignment of 0 (which the compiler then takes care of) in the terminating entry. Signed-off-by: Uwe Kleine-König (The Capable Hub) Acked-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sp-pci.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 6ac805d99ccb..ede6ff9ad0c2 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -552,21 +552,21 @@ static const struct sp_dev_vdata dev_vdata[] = { }; static const struct pci_device_id sp_pci_table[] = { - { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] }, - { PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] }, - { PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] }, - { PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] }, - { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] }, - { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, - { PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] }, - { PCI_VDEVICE(AMD, 0x1649), (kernel_ulong_t)&dev_vdata[6] }, - { PCI_VDEVICE(AMD, 0x1134), (kernel_ulong_t)&dev_vdata[7] }, - { PCI_VDEVICE(AMD, 0x17E0), (kernel_ulong_t)&dev_vdata[7] }, - { PCI_VDEVICE(AMD, 0x156E), (kernel_ulong_t)&dev_vdata[8] }, - { PCI_VDEVICE(AMD, 0x17D8), (kernel_ulong_t)&dev_vdata[8] }, - { PCI_VDEVICE(AMD, 0x115A), (kernel_ulong_t)&dev_vdata[9] }, + { PCI_VDEVICE(AMD, 0x1537), .driver_data = (kernel_ulong_t)&dev_vdata[0] }, + { PCI_VDEVICE(AMD, 0x1456), .driver_data = (kernel_ulong_t)&dev_vdata[1] }, + { PCI_VDEVICE(AMD, 0x1468), .driver_data = (kernel_ulong_t)&dev_vdata[2] }, + { PCI_VDEVICE(AMD, 0x1486), .driver_data = (kernel_ulong_t)&dev_vdata[3] }, + { PCI_VDEVICE(AMD, 0x15DF), .driver_data = (kernel_ulong_t)&dev_vdata[4] }, + { PCI_VDEVICE(AMD, 0x14CA), .driver_data = (kernel_ulong_t)&dev_vdata[5] }, + { PCI_VDEVICE(AMD, 0x15C7), .driver_data = (kernel_ulong_t)&dev_vdata[6] }, + { PCI_VDEVICE(AMD, 0x1649), .driver_data = (kernel_ulong_t)&dev_vdata[6] }, + { PCI_VDEVICE(AMD, 0x1134), .driver_data = (kernel_ulong_t)&dev_vdata[7] }, + { PCI_VDEVICE(AMD, 0x17E0), .driver_data = (kernel_ulong_t)&dev_vdata[7] }, + { PCI_VDEVICE(AMD, 0x156E), .driver_data = (kernel_ulong_t)&dev_vdata[8] }, + { PCI_VDEVICE(AMD, 0x17D8), .driver_data = (kernel_ulong_t)&dev_vdata[8] }, + { PCI_VDEVICE(AMD, 0x115A), .driver_data = (kernel_ulong_t)&dev_vdata[9] }, /* Last entry must be zero */ - { 0, } + { } }; MODULE_DEVICE_TABLE(pci, sp_pci_table); From 97d1d35b573163176ab817489f2322d97f7bc84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 4 May 2026 17:32:21 +0200 Subject: [PATCH 258/655] crypto: drivers - Drop explicit assigment of 0 in pci_device_id array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assigning .driver_data for drivers that don't use this struct member is just noise that can better be dropped. The same applies for an explicit zero in the terminating entry. Drop these. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Herbert Xu --- drivers/crypto/cavium/cpt/cptvf_main.c | 4 ++-- drivers/crypto/cavium/nitrox/nitrox_main.c | 4 ++-- drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 4 ++-- drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c index 2c9a2af38876..6af2650b1ebe 100644 --- a/drivers/crypto/cavium/cpt/cptvf_main.c +++ b/drivers/crypto/cavium/cpt/cptvf_main.c @@ -835,8 +835,8 @@ static void cptvf_shutdown(struct pci_dev *pdev) /* Supported devices */ static const struct pci_device_id cptvf_id_table[] = { - {PCI_VDEVICE(CAVIUM, CPT_81XX_PCI_VF_DEVICE_ID), 0}, - { 0, } /* end of table */ + { PCI_VDEVICE(CAVIUM, CPT_81XX_PCI_VF_DEVICE_ID) }, + { } /* end of table */ }; static struct pci_driver cptvf_pci_driver = { diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index 8664d97261fe..e474c84d8d38 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -38,9 +38,9 @@ static unsigned int num_devices; * nitrox_pci_tbl - PCI Device ID Table */ static const struct pci_device_id nitrox_pci_tbl[] = { - {PCI_VDEVICE(CAVIUM, CNN55XX_DEV_ID), 0}, + { PCI_VDEVICE(CAVIUM, CNN55XX_DEV_ID) }, /* required last entry */ - {0, } + { } }; MODULE_DEVICE_TABLE(pci, nitrox_pci_tbl); diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c index 587609db6c69..5cc5c84069a9 100644 --- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c @@ -957,8 +957,8 @@ static void otx_cptvf_remove(struct pci_dev *pdev) /* Supported devices */ static const struct pci_device_id otx_cptvf_id_table[] = { - {PCI_VDEVICE(CAVIUM, OTX_CPT_PCI_VF_DEVICE_ID), 0}, - { 0, } /* end of table */ + { PCI_VDEVICE(CAVIUM, OTX_CPT_PCI_VF_DEVICE_ID) }, + { } /* end of table */ }; static struct pci_driver otx_cptvf_pci_driver = { diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c index 858f851c9c8a..62b08116f808 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c @@ -460,9 +460,9 @@ static void otx2_cptvf_remove(struct pci_dev *pdev) /* Supported devices */ static const struct pci_device_id otx2_cptvf_id_table[] = { - {PCI_VDEVICE(CAVIUM, OTX2_CPT_PCI_VF_DEVICE_ID), 0}, - {PCI_VDEVICE(CAVIUM, CN10K_CPT_PCI_VF_DEVICE_ID), 0}, - { 0, } /* end of table */ + { PCI_VDEVICE(CAVIUM, OTX2_CPT_PCI_VF_DEVICE_ID) }, + { PCI_VDEVICE(CAVIUM, CN10K_CPT_PCI_VF_DEVICE_ID) }, + { } /* end of table */ }; static struct pci_driver otx2_cptvf_pci_driver = { From fb1758e74b8061aacfbce7bbb7a7cc650537e167 Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Mon, 4 May 2026 10:51:44 -0600 Subject: [PATCH 259/655] crypto: ccp - Do not initialize SNP for SEV ioctls Sashiko notes: > if SEV initialization fails and KVM is actively running normal VMs, could a > userspace process trigger this code path via /dev/sev ioctls (e.g., > SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN > execution for an active VM trigger a general protection fault and crash the > host? sev_move_to_init_state() is called for ioctls requiring only SEV firmware: SEV_PEK_GEN, SEV_PDH_GEN, SEV_PEK_CSR, SEV_PEK_CERT_IMPORT, and SEV_PDH_CERT_EXPORT. After the firmware command, it does SEV_SHUTDOWN on the SEV firmware. Since these commands do not require SNP to be initialized, skip it by calling __sev_platform_init_locked() which only initializes the SEV firmware. This way SNP is not Initialized at all, and HSAVE_PA is not cleared. The previous code saved any SEV initialization firmware error to init_args.error and then threw it away and hardcoded the return value of INVALID_PLATFORM_STATE regardless of the real firmware error. This patch changes it to surface the underlying error, which is hopefully both more useful and doesn't cause any problems. Note that it is still safe to call __sev_firmware_shutdown() directly: it calls __sev_snp_shutdown_locked(), which skips SNP shutdown if SNP was not initialized. Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") Reported-by: Sashiko Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org CC: Signed-off-by: Tycho Andersen (AMD) Reviewed-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 8a85439cfa76..46c5d7ee7955 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1719,14 +1719,11 @@ static int sev_get_platform_state(int *state, int *error) static int sev_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) { - struct sev_platform_init_args init_args = {0}; int rc; - rc = _sev_platform_init_locked(&init_args); - if (rc) { - argp->error = SEV_RET_INVALID_PLATFORM_STATE; + rc = __sev_platform_init_locked(&argp->error); + if (rc) return rc; - } *shutdown_required = true; From 5a1364da2f04217a36e2fdfa2db4ee025b383a20 Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Mon, 4 May 2026 10:51:45 -0600 Subject: [PATCH 260/655] crypto: ccp - Do not initialize SNP for ioctl(SNP_COMMIT) Sashiko notes: > if SEV initialization fails and KVM is actively running normal VMs, could a > userspace process trigger this code path via /dev/sev ioctls (e.g., > SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN > execution for an active VM trigger a general protection fault and crash the > host? The SNP_COMMIT command does not require the firmware to be in any particular state. Skip initializing it if it was previously uninitialized. The SEV-SNP firmware specification doc 56860 does not mention SNP_COMMIT in Table 5 as a command that is allowed in the UNINIT state, but it is in fact allowed and a future documentation update will reflect that. Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") Reported-by: Sashiko Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org CC: Signed-off-by: Tycho Andersen (AMD) Reviewed-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 46c5d7ee7955..de472f0503cb 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -2440,24 +2440,13 @@ cleanup: static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp) { - struct sev_device *sev = psp_master->sev_data; struct sev_data_snp_commit buf; - bool shutdown_required = false; - int ret, error; - - if (!sev->snp_initialized) { - ret = snp_move_to_init_state(argp, &shutdown_required); - if (ret) - return ret; - } + int ret; buf.len = sizeof(buf); ret = __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error); - if (shutdown_required) - __sev_snp_shutdown_locked(&error, false); - return ret; } From f91e9dbb5845d1e5abf1028e6df57dcf61583e1b Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Mon, 4 May 2026 10:51:46 -0600 Subject: [PATCH 261/655] crypto: ccp - Do not initialize SNP for ioctl(SNP_VLEK_LOAD) Sashiko notes: > if SEV initialization fails and KVM is actively running normal VMs, could a > userspace process trigger this code path via /dev/sev ioctls (e.g., > SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN > execution for an active VM trigger a general protection fault and crash the > host? The SEV firmware docs for SNP_VLEK_LOAD note: > On SNP_SHUTDOWN, the VLEK is deleted. That is, the initialization/shutdown wrapper here is pointless, because the firmware immediately throws away the key anyway. Instead, refuse to do anything if SNP has not been previously initialized. This is an ABI break: before, this was a no-op and almost certainly a mistake by userspace, and now it returns -ENODEV. ABI compatibility could be maintained here by simply returning 0 in the check instead. Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") Reported-by: Sashiko Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org CC: Signed-off-by: Tycho Andersen (AMD) Reviewed-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index de472f0503cb..9fb9267d7636 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -2484,9 +2484,8 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) { struct sev_device *sev = psp_master->sev_data; struct sev_user_data_snp_vlek_load input; - bool shutdown_required = false; - int ret, error; void *blob; + int ret; if (!argp->data) return -EINVAL; @@ -2494,6 +2493,9 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) if (!writable) return -EPERM; + if (!sev->snp_initialized) + return -ENODEV; + if (copy_from_user(&input, u64_to_user_ptr(argp->data), sizeof(input))) return -EFAULT; @@ -2507,18 +2509,7 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) input.vlek_wrapped_address = __psp_pa(blob); - if (!sev->snp_initialized) { - ret = snp_move_to_init_state(argp, &shutdown_required); - if (ret) - goto cleanup; - } - ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error); - - if (shutdown_required) - __sev_snp_shutdown_locked(&error, false); - -cleanup: kfree(blob); return ret; From 08f0e65e784c4b20e6e620dd4f68d8636073a3d2 Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Mon, 4 May 2026 10:51:47 -0600 Subject: [PATCH 262/655] crypto: ccp - Do not initialize SNP for ioctl(SNP_CONFIG) Sashiko notes: > if SEV initialization fails and KVM is actively running normal VMs, could a > userspace process trigger this code path via /dev/sev ioctls (e.g., > SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN > execution for an active VM trigger a general protection fault and crash the > host? Refuse to re-try initialization if SNP is not already initialized for SNP_CONFIG. This is technically an ABI break: before if SNP initialization failed it could be transparently retriggered by this ioctl, and if no VMs were running, everything worked fine. Hopefully this is enough of a corner case that nobody will notice, but someone does, there are a few options: * do something like symbol_get() for kvm and refuse to initialize if KVM is loaded * check each cpu's HSAVE_PA for non-zero data before re-initializing * once initialization has failed, continue to refuse to initialize until the ccp module is unloaded Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") Reported-by: Sashiko Assisted-by: Gemini:gemini-3.1-pro-preview Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org CC: Signed-off-by: Tycho Andersen (AMD) Reviewed-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 9fb9267d7636..14df519ae7ee 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1730,21 +1730,6 @@ static int sev_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_req return 0; } -static int snp_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) -{ - int error, rc; - - rc = __sev_snp_init_locked(&error, 0); - if (rc) { - argp->error = SEV_RET_INVALID_PLATFORM_STATE; - return rc; - } - - *shutdown_required = true; - - return 0; -} - static int sev_ioctl_do_reset(struct sev_issue_cmd *argp, bool writable) { int state, rc; @@ -2454,8 +2439,6 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable { struct sev_device *sev = psp_master->sev_data; struct sev_user_data_snp_config config; - bool shutdown_required = false; - int ret, error; if (!argp->data) return -EINVAL; @@ -2463,21 +2446,13 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable if (!writable) return -EPERM; + if (!sev->snp_initialized) + return -ENODEV; + if (copy_from_user(&config, (void __user *)argp->data, sizeof(config))) return -EFAULT; - if (!sev->snp_initialized) { - ret = snp_move_to_init_state(argp, &shutdown_required); - if (ret) - return ret; - } - - ret = __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); - - if (shutdown_required) - __sev_snp_shutdown_locked(&error, false); - - return ret; + return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); } static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) From 49f73a9f00c9c825f28132855689ba50833a8157 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Mon, 4 May 2026 19:32:47 +0200 Subject: [PATCH 263/655] crypto: safexcel - Remove repeated plus Remove repeated "+". Signed-off-by: Aleksander Jan Bajkowski Reviewed-by: Antoine Tenart Signed-off-by: Herbert Xu --- drivers/crypto/inside-secure/safexcel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index fb4936e7afa2..812ebabd1309 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -1475,7 +1475,7 @@ static int safexcel_probe_generic(void *pdev, peid = version & 255; /* Detect EIP206 processing pipe */ - version = readl(EIP197_PE(priv) + + EIP197_PE_VERSION(0)); + version = readl(EIP197_PE(priv) + EIP197_PE_VERSION(0)); if (EIP197_REG_LO16(version) != EIP206_VERSION_LE) { dev_err(priv->dev, "EIP%d: EIP206 not detected\n", peid); return -ENODEV; From ef8c9dacda2871accd64e3eda951fef6b788b1ea Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 4 May 2026 15:28:12 -0700 Subject: [PATCH 264/655] crypto: ccp - Treat zero-length cert chain as query for blob lengths When handling a PDH export, treat a zero-length userspace cert chain buffer as a request to query the length of the relevant blobs. Failure to account for the zero-length buffer trips a BUG_ON() when running with CONFIG_DEBUG_VIRTUAL=y due to trying to get the physical address of the ZERO_SIZE_PTR (returned by kzalloc() on the bogus allocation). kernel BUG at arch/x86/mm/physaddr.c:28 ! Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 30 UID: 0 PID: 28580 Comm: syz.2.18 Kdump: loaded Tainted: G W 6.18.16-smp-DEV #1 NONE Tainted: [W]=WARN Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.62.0-0 11/19/2025 RIP: 0010:__phys_addr+0x16a/0x180 arch/x86/mm/physaddr.c:28 RSP: 0018:ffffc9008329fc80 EFLAGS: 00010293 RAX: ffffffff8179110a RBX: 0000778000000010 RCX: ffff8884e6992600 RDX: 0000000000000000 RSI: 0000000080000010 RDI: 0000778000000010 RBP: ffffc9008329fdf0 R08: 0000000000000dc0 R09: 00000000ffffffff R10: dffffc0000000000 R11: fffffbfff126d297 R12: dffffc0000000000 R13: 1ffff92010653fc8 R14: 0000000080000010 R15: dffffc0000000000 FS: 0000555556bec9c0(0000) GS:ffff88aa4ce1c000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fd3159e7000 CR3: 00000004fbc44000 CR4: 0000000000350ef0 Call Trace: [] sev_ioctl_do_pdh_export+0x559/0x7a0 drivers/crypto/ccp/sev-dev.c:2308 [] sev_ioctl+0x2cd/0x480 drivers/crypto/ccp/sev-dev.c:2556 [] vfs_ioctl fs/ioctl.c:52 [inline] [] __do_sys_ioctl fs/ioctl.c:598 [inline] [] __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:584 [] do_syscall_x64 arch/x86/entry/syscall_64.c:64 [inline] [] do_syscall_64+0x9f/0xf40 arch/x86/entry/syscall_64.c:98 [] entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7fd3158eac39 Thankfully, the bug is benign outside of CONFIG_DEBUG_VIRTUAL=y as getting the physical address is just arithmetic, and the PSP errors out before trying to write to the garbage address (which it must, otherwise querying the blob lengths would clobber memory at pfn=0). Fixes: 76a2b524a4b1 ("crypto: ccp: Implement SEV_PDH_CERT_EXPORT ioctl command") Signed-off-by: Sean Christopherson Reviewed-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 14df519ae7ee..068b901034cb 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -2286,7 +2286,8 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) /* Userspace wants to query the certificate length. */ if (!input.pdh_cert_address || !input.pdh_cert_len || - !input.cert_chain_address) + !input.cert_chain_address || + !input.cert_chain_len) goto cmd; /* Allocate a physically contiguous buffer to store the PDH blob. */ From ffdd2bc378953b525aca61902534e753f1f8e734 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 4 May 2026 15:53:28 -0700 Subject: [PATCH 265/655] crypto: af_alg - Remove zero-copy support from skcipher and aead The zero-copy support is one of the riskiest aspects of AF_ALG. It allows userspace to request cryptographic operations directly on pagecache pages of files like the 'su' binary. It also allows userspace to concurrently modify the memory which is being operated on, a recipe for TOCTOU vulnerabilities. While zero-copy support is more valuable in other areas of the kernel like the frequently used networking and file I/O code, it has far less value in AF_ALG, which is a niche UAPI. AF_ALG primarily just exists for backwards compatibility with a small set of userspace programs such as 'iwd' that haven't yet been fixed to use userspace crypto code. Originally AF_ALG was intended to be used to access hardware crypto accelerators. However, it isn't an efficient interface for that anyway, and it turned out to be rarely used in this way in practice. Thus, the risks of the zero-copy support in AF_ALG vastly outweigh its benefits. Let's just remove it. This commit removes it from the "skcipher" and "aead" algorithm types. "hash" will be handled separately. This is a soft break, not a hard break. Even after this commit, it still works to use splice() or sendfile() to transfer data to an AF_ALG request socket from a pipe or any file, respectively. What changes is just that the kernel now makes an internal, stable copy of the data before doing the crypto operation. So performance is slightly reduced, but the UAPI isn't broken. And, very importantly, it's much safer. Tested with libkcapi/test.sh. All its test cases still pass. I also verified that this would have prevented the copy.fail exploit as well. I also used a custom test program to verify that sendfile() still works. Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations") Fixes: 400c40cf78da ("crypto: algif - add AEAD support") Reported-by: Taeyang Lee <0wn@theori.io> Link: https://copy.fail/ Reported-by: Feng Ning Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local Reviewed-by: Demi Marie Obenour Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- Documentation/crypto/userspace-if.rst | 31 ++---------- crypto/af_alg.c | 69 +++++++++------------------ crypto/algif_aead.c | 8 ++-- 3 files changed, 31 insertions(+), 77 deletions(-) diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst index 2c4e9a1ac3e5..ea1b1b3f4049 100644 --- a/Documentation/crypto/userspace-if.rst +++ b/Documentation/crypto/userspace-if.rst @@ -369,33 +369,10 @@ CRYPTO_USER_API_RNG_CAVP option: Zero-Copy Interface ------------------- -In addition to the send/write/read/recv system call family, the AF_ALG -interface can be accessed with the zero-copy interface of -splice/vmsplice. As the name indicates, the kernel tries to avoid a copy -operation into kernel space. - -The zero-copy operation requires data to be aligned at the page -boundary. Non-aligned data can be used as well, but may require more -operations of the kernel which would defeat the speed gains obtained -from the zero-copy interface. - -The system-inherent limit for the size of one zero-copy operation is 16 -pages. If more data is to be sent to AF_ALG, user space must slice the -input into segments with a maximum size of 16 pages. - -Zero-copy can be used with the following code example (a complete -working example is provided with libkcapi): - -:: - - int pipes[2]; - - pipe(pipes); - /* input data in iov */ - vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT); - /* opfd is the file descriptor returned from accept() system call */ - splice(pipes[0], NULL, opfd, NULL, ret, 0); - read(opfd, out, outlen); +AF_ALG used to have zero-copy support, but it was removed due to it being a +frequent source of vulnerabilities. For backwards compatibility the splice() +and sendfile() system calls are still supported, but the kernel will make an +internal copy of the data before passing it to the crypto code. Setsockopt Interface diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 5a00c18eb145..fce0b87c2b65 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -973,7 +973,7 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, ssize_t plen; /* use the existing memory in an allocated page */ - if (ctx->merge && !(msg->msg_flags & MSG_SPLICE_PAGES)) { + if (ctx->merge) { sgl = list_entry(ctx->tsgl_list.prev, struct af_alg_tsgl, list); sg = sgl->sg + sgl->cur - 1; @@ -1017,60 +1017,37 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, if (sgl->cur) sg_unmark_end(sg + sgl->cur - 1); - if (msg->msg_flags & MSG_SPLICE_PAGES) { - struct sg_table sgtable = { - .sgl = sg, - .nents = sgl->cur, - .orig_nents = sgl->cur, - }; + do { + struct page *pg; + unsigned int i = sgl->cur; - plen = extract_iter_to_sg(&msg->msg_iter, len, &sgtable, - MAX_SGL_ENTS - sgl->cur, 0); - if (plen < 0) { - err = plen; + plen = min_t(size_t, len, PAGE_SIZE); + + pg = alloc_page(GFP_KERNEL); + if (!pg) { + err = -ENOMEM; goto unlock; } - for (; sgl->cur < sgtable.nents; sgl->cur++) - get_page(sg_page(&sg[sgl->cur])); + sg_assign_page(sg + i, pg); + + err = memcpy_from_msg(page_address(sg_page(sg + i)), + msg, plen); + if (err) { + __free_page(sg_page(sg + i)); + sg_assign_page(sg + i, NULL); + goto unlock; + } + + sg[i].length = plen; len -= plen; ctx->used += plen; copied += plen; size -= plen; - } else { - do { - struct page *pg; - unsigned int i = sgl->cur; + sgl->cur++; + } while (len && sgl->cur < MAX_SGL_ENTS); - plen = min_t(size_t, len, PAGE_SIZE); - - pg = alloc_page(GFP_KERNEL); - if (!pg) { - err = -ENOMEM; - goto unlock; - } - - sg_assign_page(sg + i, pg); - - err = memcpy_from_msg( - page_address(sg_page(sg + i)), - msg, plen); - if (err) { - __free_page(sg_page(sg + i)); - sg_assign_page(sg + i, NULL); - goto unlock; - } - - sg[i].length = plen; - len -= plen; - ctx->used += plen; - copied += plen; - size -= plen; - sgl->cur++; - } while (len && sgl->cur < MAX_SGL_ENTS); - - ctx->merge = plen & (PAGE_SIZE - 1); - } + ctx->merge = plen & (PAGE_SIZE - 1); if (!size) sg_mark_end(sg + sgl->cur - 1); diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index cb651ab58d62..c6c2ce21895d 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -9,10 +9,10 @@ * The following concept of the memory management is used: * * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is - * filled by user space with the data submitted via sendmsg (maybe with - * MSG_SPLICE_PAGES). Filling up the TX SGL does not cause a crypto operation - * -- the data will only be tracked by the kernel. Upon receipt of one recvmsg - * call, the caller must provide a buffer which is tracked with the RX SGL. + * filled by user space with the data submitted via sendmsg. Filling up the TX + * SGL does not cause a crypto operation -- the data will only be tracked by the + * kernel. Upon receipt of one recvmsg call, the caller must provide a buffer + * which is tracked with the RX SGL. * * During the processing of the recvmsg operation, the cipher request is * allocated and prepared. As part of the recvmsg operation, the processed From e4c06479d7059888adf2f22bc1ebcf053bf691a2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 5 May 2026 17:02:45 +0800 Subject: [PATCH 266/655] crypto: af_alg - Cap AEAD AD length to 0x80000000 In order to prevent arithmetic overflows when checking the TX buffer size, cap the associated data length to 0x80000000. Reported-by: Yiming Qian Fixes: 400c40cf78da ("crypto: algif - add AEAD support") Signed-off-by: Herbert Xu --- crypto/af_alg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index fce0b87c2b65..48c53f488e0f 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -584,6 +584,8 @@ static int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) return -EINVAL; con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg); + if (con->aead_assoclen >= 0x80000000u) + return -EINVAL; break; default: From 101f56451d0af2af9659cca009aeb14343dbd10c Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 5 May 2026 11:45:55 +0200 Subject: [PATCH 267/655] hwrng: core - drop unnecessary forward declarations The forward declarations for drop_current_rng() and rng_get_data() are not needed - remove them. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index aba92d777f72..68add1a97f31 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -54,13 +54,9 @@ module_param(default_quality, ushort, 0644); MODULE_PARM_DESC(default_quality, "default maximum entropy content of hwrng per 1024 bits of input"); -static void drop_current_rng(void); static int hwrng_init(struct hwrng *rng); static int hwrng_fillfn(void *unused); -static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, - int wait); - static size_t rng_buffer_size(void) { return RNG_BUFFER_SIZE; From 3541710791922e6ba090eb18f60b932f76c9b8cb Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 5 May 2026 11:45:56 +0200 Subject: [PATCH 268/655] hwrng: core - use bool for wait parameter in rng_get_data The wait parameter in rng_get_data() is a boolean flag - use bool instead of int to better reflect its actual type. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 68add1a97f31..870e77c9ec20 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -210,8 +210,8 @@ static int rng_dev_open(struct inode *inode, struct file *filp) return 0; } -static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, - int wait) { +static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, bool wait) +{ int present; BUG_ON(!mutex_is_locked(&reading_mutex)); @@ -534,8 +534,7 @@ static int hwrng_fillfn(void *unused) } mutex_lock(&reading_mutex); - rc = rng_get_data(rng, rng_fillbuf, - rng_buffer_size(), 1); + rc = rng_get_data(rng, rng_fillbuf, rng_buffer_size(), true); if (current_quality != rng->quality) rng->quality = current_quality; /* obsolete */ quality = rng->quality; From dc3ec9af62a92a46378960e599521c2ac5f81343 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 5 May 2026 11:45:57 +0200 Subject: [PATCH 269/655] hwrng: core - use MAX to simplify RNG_BUFFER_SIZE Replace the open-coded variant with MAX(). Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 870e77c9ec20..26c46cd90a83 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -30,7 +30,7 @@ #define RNG_MODULE_NAME "hw_random" -#define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) +#define RNG_BUFFER_SIZE MAX(32, SMP_CACHE_BYTES) static struct hwrng __rcu *current_rng; /* the current rng has been explicitly chosen by user via sysfs */ From cdf940215537d6028177eea88e89bd8788719a99 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 5 May 2026 11:45:58 +0200 Subject: [PATCH 270/655] hwrng: core - use sysfs_emit_at in rng_available_show Replace strlcat() with sysfs_emit_at() in rng_available_show() and add 'int len' to keep track of the number of bytes written. sysfs_emit_at() is preferred for formatting sysfs output because it provides safer bounds checking. Inline mutex_lock_interruptible() and drop the now-unused local error variable. Remove the unnecessary 'buf' NUL initialization. Return 'len' directly instead of strlen(buf). Reviewed-by: Andy Shevchenko Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 26c46cd90a83..6931657ad2ca 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -414,21 +415,17 @@ static ssize_t rng_available_show(struct device *dev, struct device_attribute *attr, char *buf) { - int err; struct hwrng *rng; + int len = 0; - err = mutex_lock_interruptible(&rng_mutex); - if (err) + if (mutex_lock_interruptible(&rng_mutex)) return -ERESTARTSYS; - buf[0] = '\0'; - list_for_each_entry(rng, &rng_list, list) { - strlcat(buf, rng->name, PAGE_SIZE); - strlcat(buf, " ", PAGE_SIZE); - } - strlcat(buf, "none\n", PAGE_SIZE); + list_for_each_entry(rng, &rng_list, list) + len += sysfs_emit_at(buf, len, "%s ", rng->name); + len += sysfs_emit_at(buf, len, "none\n"); mutex_unlock(&rng_mutex); - return strlen(buf); + return len; } static ssize_t rng_selected_show(struct device *dev, From 81d7e2979e371e5f359a544b53f38601f5150470 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 May 2026 12:29:49 +0200 Subject: [PATCH 271/655] crypto: drivers - Move MODULE_DEVICE_TABLE next to the table itself By convention MODULE_DEVICE_TABLE() immediately follows the ID table it exports, because this is easier to read and verify. It also makes more sense since #ifdef for ACPI or OF could hide both of them. Most of the privers already have this correctly placed, so adjust the missing ones. No functional impact. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/crypto/cavium/cpt/cptpf_main.c | 2 +- drivers/crypto/cavium/cpt/cptvf_main.c | 2 +- drivers/crypto/marvell/octeontx/otx_cptpf_main.c | 2 +- drivers/crypto/marvell/octeontx/otx_cptvf_main.c | 2 +- drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c | 2 +- drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/cavium/cpt/cptpf_main.c b/drivers/crypto/cavium/cpt/cptpf_main.c index 54de869e5374..9358c1c041d4 100644 --- a/drivers/crypto/cavium/cpt/cptpf_main.c +++ b/drivers/crypto/cavium/cpt/cptpf_main.c @@ -651,6 +651,7 @@ static const struct pci_device_id cpt_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, CPT_81XX_PCI_PF_DEVICE_ID) }, { 0, } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, cpt_id_table); static struct pci_driver cpt_pci_driver = { .name = DRV_NAME, @@ -666,4 +667,3 @@ MODULE_AUTHOR("George Cherian "); MODULE_DESCRIPTION("Cavium Thunder CPT Physical Function Driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, cpt_id_table); diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c index 6af2650b1ebe..db76df14c4a0 100644 --- a/drivers/crypto/cavium/cpt/cptvf_main.c +++ b/drivers/crypto/cavium/cpt/cptvf_main.c @@ -838,6 +838,7 @@ static const struct pci_device_id cptvf_id_table[] = { { PCI_VDEVICE(CAVIUM, CPT_81XX_PCI_VF_DEVICE_ID) }, { } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, cptvf_id_table); static struct pci_driver cptvf_pci_driver = { .name = DRV_NAME, @@ -853,4 +854,3 @@ MODULE_AUTHOR("George Cherian "); MODULE_DESCRIPTION("Cavium Thunder CPT Virtual Function Driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, cptvf_id_table); diff --git a/drivers/crypto/marvell/octeontx/otx_cptpf_main.c b/drivers/crypto/marvell/octeontx/otx_cptpf_main.c index 14a42559f81d..e4c828606a73 100644 --- a/drivers/crypto/marvell/octeontx/otx_cptpf_main.c +++ b/drivers/crypto/marvell/octeontx/otx_cptpf_main.c @@ -283,6 +283,7 @@ static const struct pci_device_id otx_cpt_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX_CPT_PCI_PF_DEVICE_ID) }, { 0, } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, otx_cpt_id_table); static struct pci_driver otx_cpt_pci_driver = { .name = DRV_NAME, @@ -298,4 +299,3 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell OcteonTX CPT Physical Function Driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, otx_cpt_id_table); diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c index 5cc5c84069a9..159c1d290a36 100644 --- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c +++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c @@ -960,6 +960,7 @@ static const struct pci_device_id otx_cptvf_id_table[] = { { PCI_VDEVICE(CAVIUM, OTX_CPT_PCI_VF_DEVICE_ID) }, { } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, otx_cptvf_id_table); static struct pci_driver otx_cptvf_pci_driver = { .name = DRV_NAME, @@ -974,4 +975,3 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell OcteonTX CPT Virtual Function Driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, otx_cptvf_id_table); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c index 346d1345f11c..f6f47f4e5d83 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c @@ -867,6 +867,7 @@ static const struct pci_device_id otx2_cpt_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, CN10K_CPT_PCI_PF_DEVICE_ID) }, { 0, } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, otx2_cpt_id_table); static struct pci_driver otx2_cpt_pci_driver = { .name = OTX2_CPT_DRV_NAME, @@ -883,4 +884,3 @@ MODULE_IMPORT_NS("CRYPTO_DEV_OCTEONTX2_CPT"); MODULE_AUTHOR("Marvell"); MODULE_DESCRIPTION(OTX2_CPT_DRV_STRING); MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(pci, otx2_cpt_id_table); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c index 62b08116f808..09ab85e6061c 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c @@ -464,6 +464,7 @@ static const struct pci_device_id otx2_cptvf_id_table[] = { { PCI_VDEVICE(CAVIUM, CN10K_CPT_PCI_VF_DEVICE_ID) }, { } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, otx2_cptvf_id_table); static struct pci_driver otx2_cptvf_pci_driver = { .name = OTX2_CPTVF_DRV_NAME, @@ -479,4 +480,3 @@ MODULE_IMPORT_NS("CRYPTO_DEV_OCTEONTX2_CPT"); MODULE_AUTHOR("Marvell"); MODULE_DESCRIPTION("Marvell RVU CPT Virtual Function Driver"); MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(pci, otx2_cptvf_id_table); From 97b376ac3c23cf7f64c38d04653b40a93414b94b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 5 May 2026 17:02:17 -0700 Subject: [PATCH 272/655] crypto: drbg - Rename MAX_ADDTL => MAX_ADDTL_BYTES Give this constant a name which is clearer and consistent with DRBG_MAX_REQUEST_BYTES. No functional change. Suggested-by: Joachim Vandersmissen Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index ad7b9577479e..ab443be199a0 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -122,7 +122,7 @@ * so that the value never quite completely fills the range of a size_t, * allowing the health check to verify that larger values are rejected. */ -#define DRBG_MAX_ADDTL (U32_MAX - 1) +#define DRBG_MAX_ADDTL_BYTES (U32_MAX - 1) struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ @@ -237,7 +237,7 @@ static int drbg_seed(struct drbg_state *drbg, const u8 *pers, size_t pers_len, const u8 *entropy; /* 9.1 / 9.2 / 9.3.1 step 3 */ - if (pers_len > DRBG_MAX_ADDTL) { + if (pers_len > DRBG_MAX_ADDTL_BYTES) { pr_devel("DRBG: personalization string too long %zu\n", pers_len); return -EINVAL; @@ -355,7 +355,7 @@ static int drbg_generate(struct drbg_state *drbg, u8 *out, size_t outlen, /* 9.3.1 step 3 is implicit with the chosen DRBG */ /* 9.3.1 step 4 */ - if (addtl_len > DRBG_MAX_ADDTL) { + if (addtl_len > DRBG_MAX_ADDTL_BYTES) { pr_devel("DRBG: additional information string too long %zu\n", addtl_len); return -EINVAL; @@ -570,14 +570,15 @@ static inline int __init drbg_healthcheck_sanity(void) */ /* overflow addtllen with additional info string */ - ret = drbg_generate(drbg, buf, OUTBUFLEN, buf, DRBG_MAX_ADDTL + 1); + ret = drbg_generate(drbg, buf, OUTBUFLEN, buf, + DRBG_MAX_ADDTL_BYTES + 1); BUG_ON(ret == 0); /* overflow max_bits */ ret = drbg_generate(drbg, buf, DRBG_MAX_REQUEST_BYTES + 1, NULL, 0); BUG_ON(ret == 0); /* overflow max addtllen with personalization string */ - ret = drbg_seed(drbg, buf, DRBG_MAX_ADDTL + 1, false); + ret = drbg_seed(drbg, buf, DRBG_MAX_ADDTL_BYTES + 1, false); BUG_ON(ret == 0); /* all tests passed */ From bd13e630f9d03510012f1a530f08e9cf533e946a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 5 May 2026 17:02:58 -0700 Subject: [PATCH 273/655] crypto: drbg - Remove support for "prediction resistance" "Prediction resistance", i.e. the property that the RNG's output is unpredictable even after a state compromise, might sound like a nice property to have. In reality, it's not very practical, as it requires that fresh entropy be pulled on every request. (The normal Linux RNG doesn't provide prediction resistance.) In the case of drbg.c, that means pulling from "jitterentropy", which is extremely slow. For some perspective, running a simple benchmark, generating 32 random bytes takes the following amount of time: get_random_bytes(): 90 ns drbg_nopr_hmac_sha512: 3707 ns drbg_pr_hmac_sha512: 773082 ns So at least in this case, the "pr" (prediction-resistant) DRBG is over 200 times slower than the "nopr" (non-prediction-resistant) DRBG, or over 8000 times slower than the normal Linux RNG. While anyone using drbg.c has always had to tolerate that it's slower than the normal Linux RNG, the "pr" DRBG is clearly at another level of slowness. Thus, the following is also entirely unsurprising: - FIPS 140-3 doesn't actually require that SP800-90A DRBG implementations support prediction resistance. The non-prediction resistant DRBGs can be, and have been, certified. - drbg.c registers "drbg_nopr_hmac_sha512" with a higher cra_priority than "drbg_pr_hmac_sha512". So "drbg_nopr_hmac_sha512" is already the one actually being used in practice. Given these considerations, it's clear that "drbg_pr_hmac_sha512" isn't actually useful, and it essentially just existed as another curiosity in the museum of crypto algorithms. Remove it to simplify the code. Suggested-by: Joachim Vandersmissen Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/drbg.c | 82 ++++++------------- crypto/testmgr.c | 21 +---- crypto/testmgr.h | 202 ----------------------------------------------- 3 files changed, 27 insertions(+), 278 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index ab443be199a0..d66c7211d6bb 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1,7 +1,6 @@ /* * DRBG: Deterministic Random Bits Generator - * Implementation of the HMAC SHA-512 DRBG from NIST SP800-90A, - * both with and without prediction resistance + * Implementation of the HMAC SHA-512 DRBG from NIST SP800-90A * * Copyright Stephan Mueller , 2014 * Copyright 2026 Google LLC @@ -131,7 +130,6 @@ struct drbg_state { /* Number of RNG requests since last reseed -- 10.1.2.1 1c */ size_t reseed_ctr; bool instantiated; - bool pr; /* Prediction resistance enabled? */ struct crypto_rng *jent; const u8 *test_entropy; size_t test_entropylen; @@ -370,9 +368,8 @@ static int drbg_generate(struct drbg_state *drbg, u8 *out, size_t outlen, * drbg_seed() then too, since drbg_hmac_generate() adds bytes from * random.c to the additional input, which is a de facto reseed anyway. */ - if (drbg->pr || drbg->reseed_ctr > DRBG_MAX_REQUESTS) { - pr_devel("DRBG: reseeding before generation (prediction resistance: %s)\n", - str_true_false(drbg->pr)); + if (drbg->reseed_ctr > DRBG_MAX_REQUESTS) { + pr_devel("DRBG: reseeding before generation\n"); /* 9.3.1 steps 7.1 through 7.3 */ err = drbg_seed(drbg, addtl, addtl_len, true); if (err) @@ -431,14 +428,13 @@ static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, /* Seed (i.e. instantiate) or re-seed the DRBG. */ static int drbg_kcapi_seed(struct crypto_rng *tfm, - const u8 *pers, size_t pers_len, bool pr) + const u8 *pers, unsigned int pers_len) { static const u8 initial_key[DRBG_STATE_LEN]; /* all zeroes */ struct drbg_state *drbg = crypto_rng_ctx(tfm); int ret; - pr_devel("DRBG: Initializing DRBG with prediction resistance %s\n", - str_enabled_disabled(pr)); + pr_devel("DRBG: Initializing DRBG\n"); guard(mutex)(&drbg->drbg_mutex); if (drbg->instantiated) @@ -447,13 +443,12 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, /* 9.1 step 1 is implicit with the selected DRBG type */ /* - * 9.1 step 2 is implicit as caller can select prediction resistance - * all DRBG types support prediction resistance + * 9.1 step 2 is implicit, as this implementation doesn't support + * prediction resistance */ /* 9.1 step 4 is implicit in DRBG_SEC_STRENGTH */ - drbg->pr = pr; memset(drbg->V, 1, DRBG_STATE_LEN); hmac_sha512_preparekey(&drbg->key, initial_key, DRBG_STATE_LEN); @@ -479,18 +474,6 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm, return 0; } -static int drbg_kcapi_seed_pr(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen) -{ - return drbg_kcapi_seed(tfm, seed, slen, /* pr= */ true); -} - -static int drbg_kcapi_seed_nopr(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen) -{ - return drbg_kcapi_seed(tfm, seed, slen, /* pr= */ false); -} - /* * Generate random numbers invoked by the kernel crypto API: * @@ -589,31 +572,17 @@ static inline int __init drbg_healthcheck_sanity(void) return 0; } -static struct rng_alg drbg_algs[] = { - { - .base.cra_name = "stdrng", - .base.cra_driver_name = "drbg_pr_hmac_sha512", - .base.cra_priority = 200, - .base.cra_ctxsize = sizeof(struct drbg_state), - .base.cra_module = THIS_MODULE, - .base.cra_init = drbg_kcapi_init, - .set_ent = drbg_kcapi_set_entropy, - .seed = drbg_kcapi_seed_pr, - .generate = drbg_kcapi_generate, - .base.cra_exit = drbg_kcapi_exit, - }, - { - .base.cra_name = "stdrng", - .base.cra_driver_name = "drbg_nopr_hmac_sha512", - .base.cra_priority = 201, - .base.cra_ctxsize = sizeof(struct drbg_state), - .base.cra_module = THIS_MODULE, - .base.cra_init = drbg_kcapi_init, - .set_ent = drbg_kcapi_set_entropy, - .seed = drbg_kcapi_seed_nopr, - .generate = drbg_kcapi_generate, - .base.cra_exit = drbg_kcapi_exit, - }, +static struct rng_alg drbg_alg = { + .base.cra_name = "stdrng", + .base.cra_driver_name = "drbg_nopr_hmac_sha512", + .base.cra_priority = 201, + .base.cra_ctxsize = sizeof(struct drbg_state), + .base.cra_module = THIS_MODULE, + .base.cra_init = drbg_kcapi_init, + .set_ent = drbg_kcapi_set_entropy, + .seed = drbg_kcapi_seed, + .generate = drbg_kcapi_generate, + .base.cra_exit = drbg_kcapi_exit, }; static int __init drbg_init(void) @@ -625,20 +594,18 @@ static int __init drbg_init(void) return ret; /* - * In FIPS mode, boost the algorithm priorities to ensure that when - * users request "stdrng", they really get an algorithm from here. + * In FIPS mode, boost the algorithm priority to ensure that when users + * request "stdrng", they really get the algorithm from here. */ - if (fips_enabled) { - for (size_t i = 0; i < ARRAY_SIZE(drbg_algs); i++) - drbg_algs[i].base.cra_priority += 2000; - } + if (fips_enabled) + drbg_alg.base.cra_priority += 2000; - return crypto_register_rngs(drbg_algs, ARRAY_SIZE(drbg_algs)); + return crypto_register_rng(&drbg_alg); } static void __exit drbg_exit(void) { - crypto_unregister_rngs(drbg_algs, ARRAY_SIZE(drbg_algs)); + crypto_unregister_rng(&drbg_alg); } module_init(drbg_init); @@ -647,5 +614,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Stephan Mueller "); MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG)"); MODULE_ALIAS_CRYPTO("stdrng"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 9059bea7a5b0..a3e80de91d4d 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3481,8 +3481,8 @@ static int alg_test_comp(const struct alg_test_desc *desc, const char *driver, return err; } -static int drbg_cavs_test(const struct drbg_testvec *test, int pr, - const char *driver, u32 type, u32 mask) +static int drbg_cavs_test(const struct drbg_testvec *test, const char *driver, + u32 type, u32 mask) { int ret = -EAGAIN; struct crypto_rng *drng; @@ -3519,8 +3519,6 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr, } } - if (pr) - crypto_rng_set_entropy(drng, test->entpra, test->entprlen); ret = crypto_rng_generate(drng, test->addtla, test->addtllen, buf, test->expectedlen); if (ret < 0) { @@ -3529,8 +3527,6 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr, goto outbuf; } - if (pr) - crypto_rng_set_entropy(drng, test->entprb, test->entprlen); ret = crypto_rng_generate(drng, test->addtlb, test->addtllen, buf, test->expectedlen); if (ret < 0) { @@ -3552,16 +3548,12 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { int err = 0; - int pr = 0; int i = 0; const struct drbg_testvec *template = desc->suite.drbg.vecs; unsigned int tcount = desc->suite.drbg.count; - if (0 == memcmp(driver, "drbg_pr_", 8)) - pr = 1; - for (i = 0; i < tcount; i++) { - err = drbg_cavs_test(&template[i], pr, driver, type, mask); + err = drbg_cavs_test(&template[i], driver, type, mask); if (err) { printk(KERN_ERR "alg: drbg: Test %d failed for %s\n", i, driver); @@ -4656,13 +4648,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) } - }, { - .alg = "drbg_pr_hmac_sha512", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = __VECS(drbg_pr_hmac_sha512_tv_template) - } }, { .alg = "ecb(aes)", .generic_driver = "ecb(aes-lib)", diff --git a/crypto/testmgr.h b/crypto/testmgr.h index c47203f73fd1..b7dcf40af6db 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -133,9 +133,6 @@ struct drbg_testvec { size_t addtl_reseed_len; /* Generate (twice) */ - const unsigned char *entpra; - const unsigned char *entprb; - size_t entprlen; const unsigned char *addtla; const unsigned char *addtlb; size_t addtllen; @@ -23433,205 +23430,6 @@ static const struct aead_testvec aegis128_tv_template[] = { }, }; -static const struct drbg_testvec drbg_pr_hmac_sha512_tv_template[] = { - /* - * Borrowed from the first applicable test vector from ACVP: - * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/prompt.json#L1161 - * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/expectedResults.json#L271 - */ - { - /* .entropy = ACVP entropyInput || nonce */ - .entropy = "\x9B\xE9\xB2\x87\xA3\x9A\x08\x44\x1D\x67\x82\x20" - "\xC9\x53\xFB\xEB\xA4\xB9\x0F\x44\x0B\x98\x33\x18" - "\xAC\x6E\x25\x4A\x85\x83\x2D\x26\x21\x9F\x93\x64" - "\xC8\x5A\x5F\x72\xDB\x88\x45\x96\x71\x41\xF4\xBF" - "\x6E\xA7\x98\x00\x9D\xD1\x0C\x2E\x4D\x7A\xE2\x03" - "\x0D\xE3\xCD\x62\xFE\xF3\x62\xBD\x12\x69\x92\x3D" - "\xBA\xAC\x15\x17\xC7\x80\x93\x8E\x72\x32\x2D\x52" - "\xE5\x2C\x19\x84\x5C\xA5\xCE\x5B\x98\x19\x1F\xF1" - "\x9F\x0C\x17\x04\xD0\x66\xF1\x9B\xFA\x7E\x2C\xB6" - "\x55\x68\xD4\x1B\xD6\x7A\x1D\x2C\xD4\x6D\x6E\x15" - "\xF7\x32\x23\x04\x05\x8C\xBB\xE6\x63\x6B\x80\x9B" - "\x9C\x69\x09\x8F\x5F\x02\xBF\x53\x42\x11\xB7\x80" - "\xAA\xD4\xE8\x54\x00\x83\x5C\x20\xA8\xB3\x6E\xD9" - "\xF5\x51\x9E\xB9\xD1\x6E\xC7\x0C\xE9\x7F\xF0\xBF" - "\xCE\x1D\xB0\x31\x8D\x16\xC9\x65\x0C\x18\x55\xA4" - "\x46\x8D\x54\x2B\x78\x69\x1B\x8C\x29\xD7\xAC\x0F" - "\x34\x4D\x69\x0B\x76\xC3\x98\x00\x78\x2F\xE2\x54" - "\xAF\xD5\x8A\xC3\x40\x97\xB1\xA2\x60\xD3\x07\x3B" - "\x7A\x3E\xD0\x82\x80\x68\xEE\xB0\x72\x5F\x07\x17" - "\xD9\x0A\xFC\xBD\xBA\xB6\x77\x4E\xC9\xCE\x6A\x48" - "\xEB\x9C\xF5\x18\x88\x1E\x6E\x3B\x65\x43\x16\x73" - "\x80\x53\xB7\xF0\x7E\xAB\x23\x19\x1E\x75\x60\x36" - "\xAF\x39\xC0\xCF\x0F\x6D\x7F\x90\xB2\x50\xD5\x37" - "\x58\x6D\x5C\x95\x78\x25\x8D\x3A\x40\xAB\xF6\x7B" - "\x85\x86\xBB\x48\x5E\x1C\x99\xC1\xD3\x4E\x85\xE5" - "\xB4\xE7\x61\xF3\x7D\x56\x1F\x77\xCF\x3C\x76\x3A" - "\xF4\x82\x36\xB7\x37\x33\x84\x34\xBA\x0E\xE2\xE1" - "\xAF\x0C\xD2\xAE\x97\x5C\x80\xD4\xD2\xFD\x37\x71" - "\xC8\x70\x04\x29\x8B\x44\xB9\xD7\xC9\x8F\xE7\x99" - "\x94\x9E\xFC\x49\x66\x24\xCB\x8B\x41\x40\x66\xC5" - "\xA4\x00\xD5\x3F\x68\xDD\xB5\xA5\x62\x96\x7C\xAC" - "\x63\x58\x95\x85\x99\x24\x21\x15\xD2\x76\xAF\x6D", - .entropylen = 384, - .pers = "\xDD\x07\x10\x10\x17\x34\xD5\xBD\x43\xAF\x03\x79\xE4" - "\x64\x2C\x58\x06\xEA\xE0\x39\xDA\x42\x96\x16\x0B\xF9" - "\xB8\xCE\x57\x7D\x53\x67\xBF\xF8\x0C\x40\x02\xB2\x77" - "\x16\xD5\x23\x75\x9F\x6A\x42\x0E\xE8\xCC\xD0\x9F\x40" - "\x64\xE9\x3B\xE9\x48\x13\xC3\x8E\x4B\xAB\xE1\xB9\x4F" - "\x6D\xBB\xF2\x4C\xF8\x29\xA5\x2B\x44\x23\x15\x2C\xDE" - "\x2A\xCF\x88\x04\x7A\x38\x37\xA2\xD5\x7B\xEA\x59\x39" - "\x2C\x58\xA2\x5B\xF9\x39\xA2\x7E\x94\x11\x97\xEC\x47" - "\x08\xD6\xE2\x39\x65\x26\x43\x81\x3F\x1B\x31\xA6\xA4" - "\x1A\x5C\xCD\x02\xCC\x89\x38\x3F\x32\x7C\x0E\x7E\x88" - "\x3B\x6F\x60\x69\xEA\xBA\xAA\x1F\x53\x93\x70\xD7\x48" - "\x74\x91\x79\x5E\xD4\xB0\xD9\x82\x74\x12\xDE\xFE\xFB" - "\x51\x96\x66\x5C\x6A\x53\x11\xAD\x9A\xD4\xFA\x9D\xF0" - "\xE2\x7F\x26\x8F\x6F\xAC\x00\xC8\xDB\xCF\xA5\x8E\xE6" - "\x61\x8F\x36\xD6\x44\x5B\x07\xDA\x9C\x2A\x46\xE3\x03" - "\x1C\xD8\x11\x4F\x61\x1F\xEC\xBA\x12\x68\xB9\x4B\x57" - "\x39\x05\xD6\xEE\xC1\xAC\x3F\x6D\x6F\xE9\xBF\xEA\x36" - "\x1A\x8A\xAA\xF4\xE8\xE0\xDB\xC6\xE5\x06\x9F\xC9\x91" - "\x52\xCD\x53\xD0\x78\xF6\xC1\x7B\x75\x91\x85\x91\x13" - "\x26\xBE\xC9\x02\xDE\xB0\x19\xF2\x71", - .perslen = 256, - - .entpra = "\xDB\xBA\x25\xC7\x02\x0D\x3D\x95\x9C\xEB\xF5\x42" - "\x52\x3A\x6B\xDA\xE8\xAF\xE9\x3D\x76\x2A\x9E\xB5" - "\xD7\xE7\x5D\xC9\xB8\x1F\x3A\xC2\x91\x95\x9D\xFD" - "\xE5\x48\x5F\x63\xD8\x84\x44\x82\x6A\x71\xF9\xDD" - "\xAF\x4B\xE2\x28\xB4\x30\xCF\x78\xB7\x0B\x0F\x61" - "\x71\x16\x1A\xE0\x6D\x5F\xB4\x4B\x17\x1A\x26\xCA" - "\xD8\x9D\x6D\x46\xA3\x56\xC0\xE7\x49\xCF\xE0\xD2" - "\xFF\xA8\x22\x45\xE0\xB4\x18\x0B\x13\x37\x01\x46" - "\xCB\xE7\xD8\x2A\x59\x43\xAD\x90\x1E\xE1\xD0\xD7" - "\x76\xB0\x2D\xCF\x17\x23\x99\x73\x5D\xE5\xC7\x46" - "\x8A\x0D\x8E\xC4\xAB\x45\xAC\xA8\x74\xE4\xF7\xD0" - "\x26\xD7\x0A\xE2\x43\x3D\xB8\xC7\xEE\xAD\x53\x6F" - "\x78\xC3\x51\xC0\xE0\x76\x2A\xC2\xB7\xFE\x02\x64" - "\x25\xF0\xCE\xD7\xA9\xBF\x85\xCA\x20\xA6\x93\x68" - "\xE3\x79\xE9\x88\xA8\x7F\x45\x8D\x71\xB4\xB4\x79" - "\x1C\x56\x68\xF9\xAE\x18\x76\xB9\x3F\xEE\x5B\x2C" - "\xC6\x61\x47\x34\x3B\xC5\x24\x2D\x3C\x6D\x16\x48" - "\x70\xD9\xDB\x2E\xB8\x42\x52\x81\x1C\x94\x39\xF0" - "\xF4\xC0\x8F\x44\xD3\xCF\xD5\xF9\xC1\x59\x61\x83" - "\xAE\xFD\xD0\xC4\x35\xD1\x0E\x55\x46\x5C\xBA\x3D" - "\x5C\x4A\x89\x15\xE8\x1D\x86\x28\xE5\xF5\x31\x0B" - "\x89\x59\xFE\x4A\xC3\x5D\xA5\x2A\x16\x37\x78\x41" - "\x58\x3A\x9E\xA3\xBD\x1F\xE6\x25\xCC\x18\x9E\xD2" - "\x1A\x99\x56\x66\x83\x78\xBB\x27\x3E\x28\xFE\xD4" - "\x74\xCB\x75\x2D\x82\x86\x55\xFB\x1C\xA4\xAF\x3F" - "\x84\x0A\xA0\xA1\x1C\x70\x34\x87\x2E\x73\x15\x38" - "\x8A\x27\xB1\x6C\x33\x95\xE5\x07", - .entprb = "\x38\xF2\xC4\x8F\x4B\x9C\x2F\x03\x67\x8C\x8A\x47" - "\xE1\xF2\x18\xC5\xB8\x4C\x05\x77\x77\x15\xA8\x94" - "\x1F\x1F\x45\x6D\xD0\xEF\x60\x67\x63\x12\x5D\x38" - "\x89\x22\x76\xF5\xF2\xC4\xE1\x15\x26\x7E\x8F\x52" - "\x79\x1E\x96\x71\xCD\xE7\x32\x95\x2B\x4E\xB2\xC2" - "\x92\x21\xC7\x48\xA2\xB1\xC5\x71\x44\x91\xE4\x4F" - "\xBE\xD3\x5E\xA9\xAB\xD3\xE2\xD1\xE2\xD8\x8F\x98" - "\x38\x03\x18\x29\x84\xA2\xCA\x6E\x72\x34\xC9\x51" - "\x6D\x8C\xE8\x09\x50\x71\x2A\x08\xB7\xCF\x74\xE6" - "\x11\xB6\x38\xF5\xBC\x24\xF7\x5B\x73\x34\xD5\x8B" - "\xBB\x15\xE3\x6F\x9A\x9B\x1E\x32\xB9\x6F\x5F\xE3" - "\xC9\x9F\xF6\xD9\x33\x03\xCD\x0D\x8E\xD4\x3F\x67" - "\x11\x65\x0A\x90\x67\x83\xC1\xCC\x70\xB1\xA9\x46" - "\x4B\x5E\x0B\x84\xDC\x02\xBA\x50\x1D\x4A\x5B\xC7" - "\xB4\x5E\xDF\x35\x01\x45\x3D\x64\x5C\x2E\xCD\xA6" - "\x20\xFB\x35\x74\xC0\x7C\x2D\x24\x66\xAB\x38\x12" - "\x38\xCE\x52\xCB\x38\x9B\x95\xDE\x0C\x2A\x8C\x9D" - "\xF7\x81\x48\x9E\xD6\x10\xF1\x83\x71\x44\x53\x2F" - "\xCE\xF3\xEC\xB3\x29\x67\xF1\x41\xFC\xD6\xB6\x49" - "\xE3\x13\x74\x4D\xB2\x3E\xEA\x73\x2B\x03\x68\xAC" - "\x2F\x57\x8C\x58\xEC\x34\xE9\xEF\x18\x36\xDE\xAD" - "\xE9\x48\x1D\xF7\x9E\xB7\xA1\x60\x2E\x78\xF5\x62" - "\x68\xDD\xB8\x5B\x33\x6B\x66\xAD\xA1\xD5\xFB\x46" - "\x5E\x8F\xF8\x9D\x37\xE5\xC2\xD8\x76\xDC\x2B\x6A" - "\x99\x1E\xDF\x91\xB1\x0A\x81\x2A\x9D\xEB\xE7\xE4" - "\xD1\x21\xD4\xDA\x0E\x55\x8A\x14\xB2\xB6\x15\x7D" - "\x48\x52\x6A\xB0\xA2\x92\x4D\x50", - .entprlen = 320, - .addtla = "\xC2\x89\x7C\x07\x46\x74\x02\x2C\xEA\xAD\xFD\x74" - "\x0C\x40\xEF\xA2\x95\x64\x6B\xC4\x2D\xED\xF4\x16" - "\x26\x25\x06\xB3\x36\x6B\xD8\x9A\x5F\xF4\x25\xC1" - "\xC3\x69\x3F\x7A\x19\xB7\x02\xA6\xCC\x3B\xA2\x4E" - "\x05\xA1\x1C\x7B\x2D\xAD\x44\xE7\x4A\x40\x71\x85" - "\xEF\x1C\xE4\xEC\x54\xCA\xB0\xAF\x8F\xF5\x43\xB1" - "\xE0\x99\x71\x71\xD4\x3E\x56\x97\xAA\xF5\xD0\x1A" - "\x58\x2D\x65\x0F\xA4\xB4\xB6\x07\x1B\x1F\x13\x8B" - "\x29\xD6\xE5\x23\xD3\x4D\x43\xD6\xBC\x74\xA8\x92" - "\xBD\xE9\x9B\x01\x47\x8C\xA5\x02\xA8\x0D\xC3\x3A" - "\xED\x83\xFD\xD2\xCB\xFF\x25\x89\x2C\x2F\x5B\x70" - "\x3F\x9E\x24\x50\xF8\x78\x28\x1B\x67\x52\x92\xA2" - "\x87\x81\x07\x40\xA9\x40\xBA\x84\x47\x25\xC1\xF7" - "\x9E\x3B\x4E\xE4\x8F\x10\xE5\x50\x8B\x22\x83\x4F" - "\xCD\x4E\x42\x63\x92\x0A\x5F\xAF\x7A\x9B\x0E\x1A" - "\xE3\xB4\x99\x11\x7F\xE6\x93\xC3\xED\xF1\x9F\x3A", - .addtlb = "\x1E\x75\xB6\x70\x60\xFD\xE6\xD1\xC7\xA5\x74\xCF" - "\xA7\x50\x17\xAE\xDD\xC4\x6E\xC4\xE0\x15\xF0\x3B" - "\xF7\x1C\x46\x45\xEE\x60\x66\x48\x1D\x2C\x36\xCC" - "\x95\x3E\xB7\xEB\x1B\xFF\x8C\xC0\x78\x6D\x56\x3A" - "\xC7\x24\x18\x9E\x7C\xA1\x60\x54\x41\x4B\xAF\x18" - "\xE8\x02\xD1\x54\x65\xEC\x3D\xFD\x8B\xDF\xD2\xF5" - "\x62\xEA\x66\x41\x6A\x32\x87\xA6\x34\x2F\x48\xBF" - "\xB5\xCC\x35\x5A\x2A\xC1\xAB\x68\x34\x1A\xD6\x82" - "\x40\xF7\xF2\x00\x14\x8B\x69\x0F\xE4\xCD\x6B\xB1" - "\xFC\x8B\x16\xEC\xB4\xE3\x33\xBF\x84\x12\x4B\x58" - "\xED\x51\x88\xF5\xEF\xB6\xC3\xCE\x9B\x63\xCC\x80" - "\x1F\x3C\x8A\x67\xEE\xCD\xD2\x01\x25\x22\xAC\xB3" - "\xB6\x9B\x1F\xF8\xE8\x71\xE6\x0D\x78\x11\x3C\x9E" - "\xF2\x57\xDC\xB6\xCF\x90\xD3\xA8\x3E\xCD\x88\xD4" - "\xDC\x1C\x31\x6B\x1F\xC3\x6A\x29\xF0\x7B\x4C\xCC" - "\x6D\x92\x5E\x6F\x0C\x0B\x4D\xA7\x10\x66\x84\x1F", - .addtllen = 192, - - .expected = "\xAA\x76\x91\xAE\x99\xCD\x8D\x83\x49\x9D\xC5\x51" - "\xA5\x95\xC6\x9D\xAD\x4B\x40\x2B\x5F\x8C\x30\x5D" - "\x1E\x89\x58\xD1\x8A\x86\xF9\x61\x2C\x45\x41\x8E" - "\xC5\xC6\x0E\x33\x7C\xFE\x91\x71\xC9\x53\x76\xD6" - "\xC2\x8D\x05\x09\xB8\x2A\x2B\x9B\x36\x1D\x31\xD7" - "\x50\x45\xB1\x08\x58\xC4\x99\x25\xEA\x2F\x18\xDB" - "\x34\x8A\x02\xD8\x38\xDD\x7B\x9E\x0E\xEF\x9C\x45" - "\xC7\x4F\x7E\x36\x3A\x90\x8B\x41\x51\x4A\x1B\xE9" - "\x8A\x61\xE9\xB5\x4E\xA5\xE2\xBD\x16\x59\x61\x0F" - "\x9C\x5A\x63\xA7\x87\x79\x5C\x0A\x16\xDF\x6D\x88" - "\x11\x25\x56\x8B\x5D\xA6\xF8\x4F\xB9\x01\x19\xAE" - "\x57\x3B\xC4\x06\xBB\xE7\xCB\xAF\xB3\x8D\xE2\x40" - "\xED\x42\x29\xB3\x0D\x64\x20\xF2\x66\x58\xB1\xDD" - "\x59\xB1\x39\x7C\xD9\xB2\x34\x08\x53\x9B\x3A\xB7" - "\x18\x35\xD0\x90\x7F\xB5\x30\xF2\x27\xA0\x90\x63" - "\x6F\xF2\x72\x49\xBF\xD0\xAE\x4A\xF4\xCA\xB3\x1A" - "\xAE\x7F\x93\xF3\xB9\x84\x99\x09\x50\xB9\xA0\x43" - "\x4F\x83\x33\x92\xA5\xC7\x25\x44\x6A\x74\xF4\xFA" - "\xBA\x60\x43\x13\x97\x53\x99\x98\xA3\x05\x02\xC1" - "\x03\xDF\x53\x76\x9E\x74\xE7\xA0\xB5\xD7\xA7\x87" - "\x1E\x00\x1D\x29\x47\x8F\x65\x4E\x0F\x76\xCA\xA9" - "\x2A\xC5\x05\x4F\xA6\xFE\x96\xC6\x81\xC0\x55\xFC" - "\x92\x89\xA6\x81\xF0\x37\xF1\x41\xA6\x88\x0B\x01" - "\xE0\xA5\x78\x4C\xF4\x61\xA7\x91\xD8\x4B\xE9\x2C" - "\xF0\x68\xEE\x46\x41\xD2\x74\xE5\x5F\x6F\x1F\xE6" - "\xBE\x5C\xB1\x3C\x60\x1A\xAA\xB9\x88\x3C\xB9\x1C" - "\xCD\x67\x78\x1F\x45\x18\xE7\x8B\xBD\xE4\x24\xDA" - "\xA8\x26\xD1\x03\xF1\xC7\x6B\x28\x62\xAB\x5C\xAB" - "\x98\xCA\xFB\xCB\x0B\x2D\x01\xD9\xC1\xA6\xFA\x91" - "\x71\x3D\x9B\x3B\x60\xEB\xD7\xA2\x61\xC1\x92\x60" - "\xB1\x02\x44\x0C\x97\x70\x77\x83\xF9\x35\xEA\x24" - "\x85\xF8\x0A\x32\xA2\xC7\x05\x40\x90\x83\x4F\x87" - "\x57\x66\xB5\xDE\xEE\xFF\x8B\x01\xBC\x96\xB0\xC5" - "\x29\xB6\xC1\xF0\x11\x31\x51\x11\xB0\xC2\x0F\x08" - "\xCF\x09\x69\x74\xE1\x0D\x6C\x0A\x10\xD0\x73\xF0" - "\x8E\xDC\x5F\xB1\xBD\x47\x8A\xA7\x90\xB3\x08\x86" - "\xD2\xE4\x58\xE5\x68\x33\x67\x3B\x37\xF1\x28\x28" - "\x59\x91\xB5\x5F\x8D\x84\x54\xCE\x18\x76\xE3\x5C" - "\x55\x37\x8E\x10\x34\x9B\x6E\x1F\x73\x88\x31\xBF" - "\x0D\x5C\xED\x7A\xBC\xF2\xCE\x7A\x2E\x2E\xE7\x04" - "\xE7\xF2\x8F\x33\xCC\x06\x77\x96\xBB\xA8\x65\x03" - "\x26\x79\xC0\xF0\x52\x3B\xD4\xF2\x5D\x00\xE4\x80" - "\x7F\x78\xC0\x45\x29\x55\xCA\x63", - .expectedlen = 512, - } -}; - static const struct drbg_testvec drbg_nopr_hmac_sha512_tv_template[] = { /* * Borrowed from the first applicable test vector from ACVP: From 24818f77603b3fcb7f3da5802b28bcc5ac7604aa Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 6 May 2026 01:56:53 -0700 Subject: [PATCH 274/655] crypto: talitos - allocate channels with main struct Use a flexible array member to combine allocations. Add __counted_by for extra runtime analysis. Error in case of no channels as they are required. Signed-off-by: Rosen Penev Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 19 +++++++------------ drivers/crypto/talitos.h | 5 +++-- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index bc61d0fe3514..bd4cc06ee13c 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -3409,14 +3409,20 @@ static int talitos_probe(struct platform_device *ofdev) struct device *dev = &ofdev->dev; struct device_node *np = ofdev->dev.of_node; struct talitos_private *priv; + unsigned int num_channels; int i, err; int stride; struct resource *res; - priv = devm_kzalloc(dev, sizeof(struct talitos_private), GFP_KERNEL); + if (of_property_read_u32(np, "fsl,num-channels", &num_channels)) + return -EINVAL; + + priv = devm_kzalloc(dev, struct_size(priv, chan, num_channels), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->num_channels = num_channels; + INIT_LIST_HEAD(&priv->alg_list); dev_set_drvdata(dev, priv); @@ -3436,7 +3442,6 @@ static int talitos_probe(struct platform_device *ofdev) } /* get SEC version capabilities from device tree */ - of_property_read_u32(np, "fsl,num-channels", &priv->num_channels); of_property_read_u32(np, "fsl,channel-fifo-len", &priv->chfifo_len); of_property_read_u32(np, "fsl,exec-units-mask", &priv->exec_units); of_property_read_u32(np, "fsl,descriptor-types-mask", @@ -3511,16 +3516,6 @@ static int talitos_probe(struct platform_device *ofdev) } } - priv->chan = devm_kcalloc(dev, - priv->num_channels, - sizeof(struct talitos_channel), - GFP_KERNEL); - if (!priv->chan) { - dev_err(dev, "failed to allocate channel management space\n"); - err = -ENOMEM; - goto err_out; - } - priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); for (i = 0; i < priv->num_channels; i++) { diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index 1a93ee355929..34b0b5fab7e7 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -139,8 +139,6 @@ struct talitos_private { */ unsigned int fifo_len; - struct talitos_channel *chan; - /* next channel to be assigned next incoming descriptor */ atomic_t last_chan ____cacheline_aligned; @@ -153,6 +151,9 @@ struct talitos_private { /* hwrng device */ struct hwrng rng; bool rng_registered; + + struct talitos_channel chan[] __counted_by(num_channels); + }; /* .features flag */ From 4e6063436cd21ac813494df4062e8b49c5f93bd6 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 6 May 2026 11:16:28 +0200 Subject: [PATCH 275/655] crypto: artpec6 - refactor crypto_setup_out_descr for readability Replace if-else with an early return to reduce code nesting, and move the variable declarations to the top of the function. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/axis/artpec6_crypto.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index a4793b76300c..2bf8d71c86f4 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -706,22 +706,19 @@ artpec6_crypto_setup_out_descr(struct artpec6_crypto_req_common *common, void *dst, unsigned int len, bool eop, bool use_short) { - if (use_short && len < 7) { + dma_addr_t dma_addr; + int ret; + + if (use_short && len < 7) return artpec6_crypto_setup_out_descr_short(common, dst, len, eop); - } else { - int ret; - dma_addr_t dma_addr; - ret = artpec6_crypto_dma_map_single(common, dst, len, - DMA_TO_DEVICE, - &dma_addr); - if (ret) - return ret; + ret = artpec6_crypto_dma_map_single(common, dst, len, DMA_TO_DEVICE, + &dma_addr); + if (ret) + return ret; - return artpec6_crypto_setup_out_descr_phys(common, dma_addr, - len, eop); - } + return artpec6_crypto_setup_out_descr_phys(common, dma_addr, len, eop); } /** artpec6_crypto_setup_in_descr_phys - Setup an in channel with a From 5a44059f02fdc0a0c905c724a25487319f1933cb Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 6 May 2026 11:21:51 +0200 Subject: [PATCH 276/655] crypto: ccree - replace snprintf("%s") with strscpy Replace snprintf("%s") with the faster and more direct strscpy(). In cc_aead.c, group the includes while at it. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/ccree/cc_aead.c | 9 ++++----- drivers/crypto/ccree/cc_cipher.c | 7 +++---- drivers/crypto/ccree/cc_hash.c | 13 +++++-------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/crypto/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c index 81533681f7fb..088c4603047f 100644 --- a/drivers/crypto/ccree/cc_aead.c +++ b/drivers/crypto/ccree/cc_aead.c @@ -3,11 +3,12 @@ #include #include +#include +#include #include #include #include #include -#include #include #include "cc_driver.h" #include "cc_buffer_mgr.h" @@ -2569,11 +2570,9 @@ static struct cc_crypto_alg *cc_create_aead_alg(struct cc_alg_template *tmpl, alg = &tmpl->template_aead; - if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->name) >= CRYPTO_MAX_ALG_NAME) + if (strscpy(alg->base.cra_name, tmpl->name) < 0) return ERR_PTR(-EINVAL); - if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->driver_name) >= CRYPTO_MAX_ALG_NAME) + if (strscpy(alg->base.cra_driver_name, tmpl->driver_name) < 0) return ERR_PTR(-EINVAL); alg->base.cra_module = THIS_MODULE; diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index e2cbfdf7a0e4..5339b3796c80 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -1386,11 +1387,9 @@ static struct cc_crypto_alg *cc_create_alg(const struct cc_alg_template *tmpl, memcpy(alg, &tmpl->template_skcipher, sizeof(*alg)); - if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->name) >= CRYPTO_MAX_ALG_NAME) + if (strscpy(alg->base.cra_name, tmpl->name) < 0) return ERR_PTR(-EINVAL); - if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->driver_name) >= CRYPTO_MAX_ALG_NAME) + if (strscpy(alg->base.cra_driver_name, tmpl->driver_name) < 0) return ERR_PTR(-EINVAL); alg->base.cra_module = THIS_MODULE; diff --git a/drivers/crypto/ccree/cc_hash.c b/drivers/crypto/ccree/cc_hash.c index 73179bf725a7..5de721a2ca30 100644 --- a/drivers/crypto/ccree/cc_hash.c +++ b/drivers/crypto/ccree/cc_hash.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -1835,16 +1836,12 @@ static struct cc_hash_alg *cc_alloc_hash_alg(struct cc_hash_template *template, alg = &halg->halg.base; if (keyed) { - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", - template->mac_name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->mac_driver_name); + strscpy(alg->cra_name, template->mac_name); + strscpy(alg->cra_driver_name, template->mac_driver_name); } else { halg->setkey = NULL; - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", - template->name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->driver_name); + strscpy(alg->cra_name, template->name); + strscpy(alg->cra_driver_name, template->driver_name); } alg->cra_module = THIS_MODULE; alg->cra_ctxsize = sizeof(struct cc_hash_ctx) + crypto_dma_padding(); From c64ba13e2033c3c6dc1a097bf35f9f1fe457c3f7 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 6 May 2026 15:27:49 +0200 Subject: [PATCH 277/655] crypto: ecc - Unbreak the build on arm with CONFIG_KASAN_STACK=y Andrew reports build breakage of arm allmodconfig, reproducible with gcc 14.2.0 and 15.2.0: crypto/ecc.c: In function 'ecc_point_mult': crypto/ecc.c:1380:1: error: the frame size of 1360 bytes is larger than 1280 bytes [-Werror=frame-larger-than=] gcc aggressively inlines functions called by ecc_point_mult() (without there being any explicit inline declarations), which pushes stack usage close to the limit imposed by CONFIG_FRAME_WARN. allmodconfig implies CONFIG_KASAN_STACK=y, which increases the stack above that limit. In the bugzilla entry linked below, gcc maintainers explain that gcc estimates extra stack usage caused by inlining, but ASAN instrumentation is added in post-IPA passes and thus the inlining heuristics cannot account for it. It could be argued that -Werror=frame-larger-than=1280 instructs the compiler to avoid inlining beyond that limit lest the build breaks, which would imply gcc behaves incorrectly. But gcc maintainers reject this notion and believe that a warning switch should never affect code generation, even if it is promoted to an error. One way to unbreak the build is to limit inlining via -finline-limit=100 or by explicitly declaring some functions noinline. However while it does keep stack usage of individual functions below the limit, *total* stack usage increases. A longterm solution is to refactor ecc.c for reduced stack usage. It currently performs ECC point multiplication with a Montgomery ladder which uses co-Z (conjugate) addition to trade off memory for speed. The algorithm is susceptible to timing attacks and needs to be replaced with a constant time Montgomery ladder, which should consume less memory and thus resolve the stack usage issue as a side effect. In the interim, raise the limit for ecc.c, as is already done for several other files in the source tree. Constrain to gcc because clang 19.1.7 does not exhibit the issue. It makes do with a 724 bytes stack frame even though it inlines almost the same functions as gcc. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124949 Reported-by: Andrew Morton # off-list Signed-off-by: Lukas Wunner Acked-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Herbert Xu --- crypto/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crypto/Makefile b/crypto/Makefile index 162242593c7c..c73f4d51d036 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -178,6 +178,11 @@ obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o obj-$(CONFIG_CRYPTO_ECC) += ecc.o obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124949 +ifeq ($(CONFIG_ARM)$(CONFIG_KASAN_STACK)$(CONFIG_CC_IS_GCC),yyy) +CFLAGS_ecc.o += $(call cc-option,-Wframe-larger-than=1536) +endif + ecdh_generic-y += ecdh.o ecdh_generic-y += ecdh_helper.o obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o From 5b085b2a038a1458f9398cb3b3b03cba6e38e1e0 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 7 May 2026 15:55:27 +0200 Subject: [PATCH 278/655] crypto: atmel-ecc - replace min_t with min Use the simpler min() macro since the values are all unsigned and compatible. Signed-off-by: Thorsten Blum Reviewed-by: David Laight Signed-off-by: Herbert Xu --- drivers/crypto/atmel-ecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 3738a4eb8701..e47381020606 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -56,7 +56,7 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, goto free_work_data; /* might want less than we've got */ - n_sz = min_t(size_t, ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len); + n_sz = min(ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len); /* copy the shared secret */ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, n_sz), @@ -150,7 +150,7 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req) return -EINVAL; /* might want less than we've got */ - nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len); + nbytes = min(ATMEL_ECC_PUBKEY_SIZE, req->dst_len); /* public key was saved at private key generation */ copied = sg_copy_from_buffer(req->dst, From 930d9d36ea618a775985446a125aedeb401db522 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Thu, 7 May 2026 19:06:08 +0500 Subject: [PATCH 279/655] crypto: ccp/sev-dev-tsm - bail out early when pdev->bus is NULL dsm_create() initially checks pdev->bus when computing segment_id: u8 segment_id = pdev->bus ? pci_domain_nr(pdev->bus) : 0; But the next two lines unconditionally dereference pdev->bus via pcie_find_root_port() and especially pci_dev_id(pdev), which expands to PCI_DEVID(dev->bus->number, dev->devfn). If pdev->bus is in fact NULL, segment_id is initialised to 0 but the very next statement crashes the kernel. smatch flags this: drivers/crypto/ccp/sev-dev-tsm.c:253 dsm_create() error: we previously assumed 'pdev->bus' could be null (see line 251) Make the NULL handling consistent: if pdev->bus is NULL the device has no PCI context to work with and SEV TIO setup cannot proceed, so return -ENODEV before any of the bus-dependent lookups. The remaining initialisation now runs only on the path where pdev->bus is known to be valid. No change for callers where pdev->bus is non-NULL, which is the only case where dsm_create() did meaningful work before this change. Fixes: 4be423572da1 ("crypto/ccp: Implement SEV-TIO PCIe IDE (phase1)") Signed-off-by: Stepan Ionichev Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev-tsm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev-tsm.c b/drivers/crypto/ccp/sev-dev-tsm.c index b07ae529b591..f303d8f55991 100644 --- a/drivers/crypto/ccp/sev-dev-tsm.c +++ b/drivers/crypto/ccp/sev-dev-tsm.c @@ -248,12 +248,19 @@ static void dsm_remove(struct pci_tsm *tsm) static int dsm_create(struct tio_dsm *dsm) { struct pci_dev *pdev = dsm->tsm.base_tsm.pdev; - u8 segment_id = pdev->bus ? pci_domain_nr(pdev->bus) : 0; - struct pci_dev *rootport = pcie_find_root_port(pdev); - u16 device_id = pci_dev_id(pdev); + struct pci_dev *rootport; + u8 segment_id; + u16 device_id; u16 root_port_id; u32 lnkcap = 0; + if (!pdev->bus) + return -ENODEV; + + segment_id = pci_domain_nr(pdev->bus); + rootport = pcie_find_root_port(pdev); + device_id = pci_dev_id(pdev); + if (pci_read_config_dword(rootport, pci_pcie_cap(rootport) + PCI_EXP_LNKCAP, &lnkcap)) return -ENODEV; From e17ff3d6ff907dc8406261e8fd3e1fc8a908f0f6 Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:47 +0200 Subject: [PATCH 280/655] crypto: talitos - use dma_sync_single_for_cpu() before reading descriptor header In order to know if a descriptor has been processed by the device, the driver polls the FIFO to see if DESC_HDR_DONE is set on a descriptor header to confirm completion. The current code does not make sure that the CPU gets up to date data before reading the descriptor. Fix this by calling dma_sync_single_for_cpu() before reading memory written by the device. Cc: stable@vger.kernel.org Fixes: 58cdbc6d2263 ("crypto: talitos - fix hash on SEC1.") Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index bd4cc06ee13c..e7ef286f4306 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -322,19 +322,31 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, return -EINPROGRESS; } -static __be32 get_request_hdr(struct talitos_request *request, bool is_sec1) +static __be32 get_request_hdr(struct device *dev, + struct talitos_request *request, bool is_sec1) { struct talitos_edesc *edesc; - if (!is_sec1) + if (!is_sec1) { + dma_sync_single_for_cpu(dev, request->dma_desc, + TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); + return request->desc->hdr; + } - if (!request->desc->next_desc) + if (!request->desc->next_desc) { + dma_sync_single_for_cpu(dev, request->dma_desc, + TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); return request->desc->hdr1; + } else { + dma_sync_single_for_cpu(dev, + be32_to_cpu(request->desc->next_desc), + TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); + edesc = container_of(request->desc, struct talitos_edesc, desc); - edesc = container_of(request->desc, struct talitos_edesc, desc); - - return ((struct talitos_desc *)(edesc->buf + edesc->dma_len))->hdr1; + return ((struct talitos_desc *)(edesc->buf + edesc->dma_len)) + ->hdr1; + } } /* @@ -358,7 +370,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) /* descriptors with their done bits set don't get the error */ rmb(); - hdr = get_request_hdr(request, is_sec1); + hdr = get_request_hdr(dev, request, is_sec1); if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE) status = 0; From f126384ed55279c3b676f89d5ab547b8de8df782 Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:48 +0200 Subject: [PATCH 281/655] crypto: talitos - add chaining of arbitrary number of descriptor for the SEC1 The SEC1 hardware can process a chain of descriptors without host intervention. Only the hash implementation currently use this feature, but with a chain of at most 2 descriptors added in commit 37b5e8897eb5 ("crypto: talitos - chain in buffered data for ahash on SEC1"). Add supports for chaining an arbitrary number of descriptors in a chain. Adapt the ahash implementation to make it compatible. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 180 ++++++++++++++++++++++++++------------- drivers/crypto/talitos.h | 2 + 2 files changed, 124 insertions(+), 58 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index e7ef286f4306..b26b4672a457 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -273,7 +273,10 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, void *context, int error), void *context) { + struct talitos_edesc *edesc = container_of(desc, struct talitos_edesc, desc); struct talitos_private *priv = dev_get_drvdata(dev); + dma_addr_t dma_desc, prev_dma_desc; + struct talitos_edesc *prev_edesc = NULL; struct talitos_request *request; unsigned long flags; int head; @@ -292,10 +295,31 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, /* map descriptor and save caller data */ if (is_sec1) { - desc->hdr1 = desc->hdr; - request->dma_desc = dma_map_single(dev, &desc->hdr1, + while (edesc) { + edesc->desc.hdr1 = edesc->desc.hdr; + + dma_desc = dma_map_single(dev, &edesc->desc.hdr1, + TALITOS_DESC_SIZE, + DMA_BIDIRECTIONAL); + + if (!prev_edesc) { + request->dma_desc = dma_desc; + goto next; + } + + /* Chain in any previous descriptors. */ + + prev_edesc->desc.next_desc = cpu_to_be32(dma_desc); + + dma_sync_single_for_device(dev, prev_dma_desc, TALITOS_DESC_SIZE, - DMA_BIDIRECTIONAL); + DMA_TO_DEVICE); + +next: + prev_edesc = edesc; + prev_dma_desc = dma_desc; + edesc = edesc->next_desc; + } } else { request->dma_desc = dma_map_single(dev, desc, TALITOS_DESC_SIZE, @@ -326,6 +350,7 @@ static __be32 get_request_hdr(struct device *dev, struct talitos_request *request, bool is_sec1) { struct talitos_edesc *edesc; + dma_addr_t dma_desc; if (!is_sec1) { dma_sync_single_for_cpu(dev, request->dma_desc, @@ -334,19 +359,17 @@ static __be32 get_request_hdr(struct device *dev, return request->desc->hdr; } - if (!request->desc->next_desc) { - dma_sync_single_for_cpu(dev, request->dma_desc, - TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); - return request->desc->hdr1; - } else { - dma_sync_single_for_cpu(dev, - be32_to_cpu(request->desc->next_desc), - TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); - edesc = container_of(request->desc, struct talitos_edesc, desc); - - return ((struct talitos_desc *)(edesc->buf + edesc->dma_len)) - ->hdr1; + edesc = container_of(request->desc, struct talitos_edesc, desc); + dma_desc = request->dma_desc; + while (edesc->next_desc) { + dma_desc = be32_to_cpu(edesc->desc.next_desc); + edesc = edesc->next_desc; } + + dma_sync_single_for_cpu(dev, dma_desc, TALITOS_DESC_SIZE, + DMA_BIDIRECTIONAL); + + return edesc->desc.hdr1; } /* @@ -356,6 +379,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) { struct talitos_private *priv = dev_get_drvdata(dev); struct talitos_request *request, saved_req; + struct talitos_edesc *edesc; unsigned long flags; int tail, status; bool is_sec1 = has_ftr_sec1(priv); @@ -380,9 +404,22 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) else status = error; - dma_unmap_single(dev, request->dma_desc, - TALITOS_DESC_SIZE, - DMA_BIDIRECTIONAL); + if (is_sec1) { + dma_unmap_single(dev, request->dma_desc, + TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); + edesc = container_of(request->desc, + struct talitos_edesc, desc); + while (edesc->next_desc) { + dma_unmap_single( + dev, be32_to_cpu(edesc->desc.next_desc), + TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); + edesc = edesc->next_desc; + } + } else { + dma_unmap_single(dev, request->dma_desc, + TALITOS_DESC_SIZE, + DMA_BIDIRECTIONAL); + } /* copy entries so we can call callback outside lock */ saved_req.desc = request->desc; @@ -477,8 +514,12 @@ DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE) static __be32 current_desc_hdr(struct device *dev, int ch) { struct talitos_private *priv = dev_get_drvdata(dev); + bool is_sec1 = has_ftr_sec1(priv); + struct talitos_request *request; + struct talitos_edesc *edesc; int tail, iter; dma_addr_t cur_desc; + __be32 hdr = 0; cur_desc = ((u64)in_be32(priv->chan[ch].reg + TALITOS_CDPR)) << 32; cur_desc |= in_be32(priv->chan[ch].reg + TALITOS_CDPR_LO); @@ -489,27 +530,35 @@ static __be32 current_desc_hdr(struct device *dev, int ch) } tail = priv->chan[ch].tail; - iter = tail; - while (priv->chan[ch].fifo[iter].dma_desc != cur_desc && - priv->chan[ch].fifo[iter].desc->next_desc != cpu_to_be32(cur_desc)) { - iter = (iter + 1) & (priv->fifo_len - 1); - if (iter == tail) { - dev_err(dev, "couldn't locate current descriptor\n"); - return 0; + do { + request = &priv->chan[ch].fifo[iter]; + + if (request->dma_desc == cur_desc) { + hdr = request->desc->hdr; + } else if (is_sec1) { + edesc = container_of(request->desc, + struct talitos_edesc, desc); + while (edesc->next_desc) { + if (edesc->desc.next_desc == + cpu_to_be32(cur_desc)) { + hdr = edesc->next_desc->desc.hdr1; + break; + } + edesc = edesc->next_desc; + } } - } - if (priv->chan[ch].fifo[iter].desc->next_desc == cpu_to_be32(cur_desc)) { - struct talitos_edesc *edesc; + if (hdr) + break; - edesc = container_of(priv->chan[ch].fifo[iter].desc, - struct talitos_edesc, desc); - return ((struct talitos_desc *) - (edesc->buf + edesc->dma_len))->hdr; - } + iter = (iter + 1) & (priv->fifo_len - 1); + } while (iter != tail); - return priv->chan[ch].fifo[iter].desc->hdr; + if (!hdr) + dev_err(dev, "couldn't locate current descriptor\n"); + + return hdr; } /* @@ -1408,10 +1457,6 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, dma_len = 0; } alloc_len += icv_stashing ? authsize : 0; - - /* if its a ahash, add space for a second desc next to the first one */ - if (is_sec1 && !dst) - alloc_len += sizeof(struct talitos_desc); alloc_len += ivsize; edesc = kmalloc(ALIGN(alloc_len, dma_get_cache_alignment()), flags); @@ -1427,6 +1472,7 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, edesc->dst_nents = dst_nents; edesc->iv_dma = iv_dma; edesc->dma_len = dma_len; + edesc->next_desc = NULL; if (dma_len) edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0], edesc->dma_len, @@ -1727,8 +1773,10 @@ static void common_nonsnoop_hash_unmap(struct device *dev, struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); struct talitos_desc *desc = &edesc->desc; - struct talitos_desc *desc2 = (struct talitos_desc *) - (edesc->buf + edesc->dma_len); + struct talitos_desc *desc2; + + if (desc->next_desc) + desc2 = &edesc->next_desc->desc; unmap_single_talitos_ptr(dev, &desc->ptr[5], DMA_FROM_DEVICE); if (desc->next_desc && @@ -1756,10 +1804,17 @@ static void common_nonsnoop_hash_unmap(struct device *dev, if (edesc->dma_len) dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); +} - if (desc->next_desc) - dma_unmap_single(dev, be32_to_cpu(desc->next_desc), - TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); +static void free_edesc_list_from(struct talitos_edesc *edesc) +{ + struct talitos_edesc *next; + + while (edesc) { + next = edesc->next_desc; + kfree(edesc); + edesc = next; + } } static void ahash_done(struct device *dev, @@ -1778,7 +1833,7 @@ static void ahash_done(struct device *dev, } common_nonsnoop_hash_unmap(dev, edesc, areq); - kfree(edesc); + free_edesc_list_from(edesc); if (err) { ahash_request_complete(areq, err); @@ -1894,14 +1949,23 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]); if (is_sec1 && req_ctx->nbuf && length) { - struct talitos_desc *desc2 = (struct talitos_desc *) - (edesc->buf + edesc->dma_len); - dma_addr_t next_desc; + struct talitos_edesc *edesc2; + struct talitos_desc *desc2; + + edesc2 = kzalloc(sizeof(*edesc2), + areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? + GFP_KERNEL : + GFP_ATOMIC); + if (!edesc2) { + ret = -ENOMEM; + goto err; + } + edesc->next_desc = edesc2; + + desc2 = &edesc2->desc; - memset(desc2, 0, sizeof(*desc2)); desc2->hdr = desc->hdr; desc2->hdr &= ~DESC_HDR_MODE0_MDEU_INIT; - desc2->hdr1 = desc2->hdr; desc->hdr &= ~DESC_HDR_MODE0_MDEU_PAD; desc->hdr |= DESC_HDR_MODE0_MDEU_CONT; desc->hdr &= ~DESC_HDR_DONE_NOTIFY; @@ -1925,21 +1989,21 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, req_ctx->hw_context_size, req_ctx->hw_context, DMA_FROM_DEVICE); - - next_desc = dma_map_single(dev, &desc2->hdr1, TALITOS_DESC_SIZE, - DMA_BIDIRECTIONAL); - desc->next_desc = cpu_to_be32(next_desc); } if (sync_needed) dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); - ret = talitos_submit(dev, ctx->ch, desc, callback, areq); - if (ret != -EINPROGRESS) { - common_nonsnoop_hash_unmap(dev, edesc, areq); - kfree(edesc); - } + ret = talitos_submit(dev, ctx->ch, desc, callback, + areq); + if (ret != -EINPROGRESS) + goto err; + + return -EINPROGRESS; +err: + common_nonsnoop_hash_unmap(dev, edesc, areq); + kfree(edesc); return ret; } diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index 34b0b5fab7e7..1553afa57b0b 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -49,6 +49,7 @@ struct talitos_desc { * @iv_dma: dma address of iv for checking continuity and link table * @dma_len: length of dma mapped link_tbl space * @dma_link_tbl: bus physical address of link_tbl/buf + * @next_desc: next descriptor * @desc: h/w descriptor * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2) * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1) @@ -63,6 +64,7 @@ struct talitos_edesc { dma_addr_t iv_dma; int dma_len; dma_addr_t dma_link_tbl; + struct talitos_edesc *next_desc; struct talitos_desc desc; union { DECLARE_FLEX_ARRAY(struct talitos_ptr, link_tbl); From 4d9b0b7415b9e79a3d54d18b5ff230974ea78740 Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:49 +0200 Subject: [PATCH 282/655] crypto: talitos - move dma unmapping code in flush_channel() into a standalone dma_unmap_request() function Previously added code to flush_channel() in order to unmap an entire descriptor. Move that code into a standalone function to improve readability. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index b26b4672a457..cffd4a2bd587 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -372,6 +372,27 @@ static __be32 get_request_hdr(struct device *dev, return edesc->desc.hdr1; } +static void dma_unmap_request(struct device *dev, + struct talitos_request *request, bool is_sec1) +{ + struct talitos_edesc *edesc; + + if (is_sec1) { + dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE, + DMA_BIDIRECTIONAL); + edesc = container_of(request->desc, struct talitos_edesc, desc); + while (edesc->next_desc) { + dma_unmap_single(dev, + be32_to_cpu(edesc->desc.next_desc), + TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); + edesc = edesc->next_desc; + } + } else { + dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE, + DMA_BIDIRECTIONAL); + } +} + /* * process what was done, notify callback of error if not */ @@ -379,7 +400,6 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) { struct talitos_private *priv = dev_get_drvdata(dev); struct talitos_request *request, saved_req; - struct talitos_edesc *edesc; unsigned long flags; int tail, status; bool is_sec1 = has_ftr_sec1(priv); @@ -404,22 +424,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) else status = error; - if (is_sec1) { - dma_unmap_single(dev, request->dma_desc, - TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); - edesc = container_of(request->desc, - struct talitos_edesc, desc); - while (edesc->next_desc) { - dma_unmap_single( - dev, be32_to_cpu(edesc->desc.next_desc), - TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); - edesc = edesc->next_desc; - } - } else { - dma_unmap_single(dev, request->dma_desc, - TALITOS_DESC_SIZE, - DMA_BIDIRECTIONAL); - } + dma_unmap_request(dev, request, is_sec1); /* copy entries so we can call callback outside lock */ saved_req.desc = request->desc; From 5c0aa8cad7745505297103f05dda3fa06e8ac670 Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:50 +0200 Subject: [PATCH 283/655] crypto: talitos - move dma mapping code in talitos_submit() into a standalone dma_map_request() function Previously added code to talitos_submit() in order to map an entire descriptor chain. Move that code into a standalone function to improve readability. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 81 ++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index cffd4a2bd587..d8f838add0ff 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -255,45 +255,14 @@ static int init_device(struct device *dev) return 0; } -/** - * talitos_submit - submits a descriptor to the device for processing - * @dev: the SEC device to be used - * @ch: the SEC device channel to be used - * @desc: the descriptor to be processed by the device - * @callback: whom to call when processing is complete - * @context: a handle for use by caller (optional) - * - * desc must contain valid dma-mapped (bus physical) address pointers. - * callback must check err and feedback in descriptor header - * for device processing status. - */ -static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, - void (*callback)(struct device *dev, - struct talitos_desc *desc, - void *context, int error), - void *context) +static void dma_map_request(struct device *dev, struct talitos_request *request, + struct talitos_desc *desc, bool is_sec1) { - struct talitos_edesc *edesc = container_of(desc, struct talitos_edesc, desc); - struct talitos_private *priv = dev_get_drvdata(dev); + struct talitos_edesc *edesc = + container_of(desc, struct talitos_edesc, desc); dma_addr_t dma_desc, prev_dma_desc; struct talitos_edesc *prev_edesc = NULL; - struct talitos_request *request; - unsigned long flags; - int head; - bool is_sec1 = has_ftr_sec1(priv); - spin_lock_irqsave(&priv->chan[ch].head_lock, flags); - - if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) { - /* h/w fifo is full */ - spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); - return -EAGAIN; - } - - head = priv->chan[ch].head; - request = &priv->chan[ch].fifo[head]; - - /* map descriptor and save caller data */ if (is_sec1) { while (edesc) { edesc->desc.hdr1 = edesc->desc.hdr; @@ -321,10 +290,48 @@ next: edesc = edesc->next_desc; } } else { - request->dma_desc = dma_map_single(dev, desc, - TALITOS_DESC_SIZE, + request->dma_desc = dma_map_single(dev, desc, TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL); } +} + +/** + * talitos_submit - submits a descriptor to the device for processing + * @dev: the SEC device to be used + * @ch: the SEC device channel to be used + * @desc: the descriptor to be processed by the device + * @callback: whom to call when processing is complete + * @context: a handle for use by caller (optional) + * + * desc must contain valid dma-mapped (bus physical) address pointers. + * callback must check err and feedback in descriptor header + * for device processing status. + */ +static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, + void (*callback)(struct device *dev, + struct talitos_desc *desc, + void *context, int error), + void *context) +{ + struct talitos_private *priv = dev_get_drvdata(dev); + struct talitos_request *request; + unsigned long flags; + int head; + bool is_sec1 = has_ftr_sec1(priv); + + spin_lock_irqsave(&priv->chan[ch].head_lock, flags); + + if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) { + /* h/w fifo is full */ + spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); + return -EAGAIN; + } + + head = priv->chan[ch].head; + request = &priv->chan[ch].fifo[head]; + + /* map descriptor and save caller data */ + dma_map_request(dev, request, desc, is_sec1); request->callback = callback; request->context = context; From f8713d9e6091755dd30f7f1cfa25f8440cddf81b Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:51 +0200 Subject: [PATCH 284/655] crypto: talitos - move code in current_desc_hdr() into a standalone function Previously added code in current_desc_hdr() in order to add support for searching an offending descriptor inside a descriptor chain. Move that code into a standalone function to improve readability. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index d8f838add0ff..c9c5d195b317 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -520,6 +520,24 @@ DEF_TALITOS2_DONE(ch0, TALITOS2_ISR_CH_0_DONE) DEF_TALITOS2_DONE(ch0_2, TALITOS2_ISR_CH_0_2_DONE) DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE) +static __be32 search_desc_hdr_in_request(struct talitos_request *request, + dma_addr_t cur_desc, bool is_sec1) +{ + struct talitos_edesc *edesc; + + if (request->dma_desc == cur_desc) { + return request->desc->hdr; + } else if (is_sec1) { + edesc = container_of(request->desc, struct talitos_edesc, desc); + while (edesc->next_desc) { + if (edesc->desc.next_desc == cpu_to_be32(cur_desc)) + return edesc->next_desc->desc.hdr1; + edesc = edesc->next_desc; + } + } + return 0; +} + /* * locate current (offending) descriptor */ @@ -528,7 +546,6 @@ static __be32 current_desc_hdr(struct device *dev, int ch) struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); struct talitos_request *request; - struct talitos_edesc *edesc; int tail, iter; dma_addr_t cur_desc; __be32 hdr = 0; @@ -546,21 +563,7 @@ static __be32 current_desc_hdr(struct device *dev, int ch) do { request = &priv->chan[ch].fifo[iter]; - if (request->dma_desc == cur_desc) { - hdr = request->desc->hdr; - } else if (is_sec1) { - edesc = container_of(request->desc, - struct talitos_edesc, desc); - while (edesc->next_desc) { - if (edesc->desc.next_desc == - cpu_to_be32(cur_desc)) { - hdr = edesc->next_desc->desc.hdr1; - break; - } - edesc = edesc->next_desc; - } - } - + hdr = search_desc_hdr_in_request(request, cur_desc, is_sec1); if (hdr) break; From 59b5d899e33701665f18abe6bebf987427876e3e Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:52 +0200 Subject: [PATCH 285/655] crypto: talitos/hash - prepare SEC1 descriptor chaining, remove additional descriptor Currently, when SEC1 has buffered data (nbuf != 0), the ahash code creates an additional descriptor on the fly inside common_nonsnoop_hash() to handle the remainder of the data. This approach is incompatible with the arbitrary-length descriptor chaining that follows. Remove the "additional descriptor" logic from common_nonsnoop_hash() and common_nonsnoop_hash_unmap(). Also remove the nbytes adjustment for SEC1 in ahash_edesc_alloc() that subtracted nbuf. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 101 +++------------------------------------ 1 file changed, 6 insertions(+), 95 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index c9c5d195b317..72d9c50b055e 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1788,15 +1788,9 @@ static void common_nonsnoop_hash_unmap(struct device *dev, struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); struct talitos_desc *desc = &edesc->desc; - struct talitos_desc *desc2; - - if (desc->next_desc) - desc2 = &edesc->next_desc->desc; unmap_single_talitos_ptr(dev, &desc->ptr[5], DMA_FROM_DEVICE); - if (desc->next_desc && - desc->ptr[5].ptr != desc2->ptr[5].ptr) - unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE); + if (req_ctx->last_desc) memcpy(areq->result, req_ctx->hw_context, crypto_ahash_digestsize(tfm)); @@ -1808,13 +1802,6 @@ static void common_nonsnoop_hash_unmap(struct device *dev, if (from_talitos_ptr_len(&desc->ptr[1], is_sec1)) unmap_single_talitos_ptr(dev, &desc->ptr[1], DMA_TO_DEVICE); - else if (desc->next_desc) - unmap_single_talitos_ptr(dev, &desc2->ptr[1], - DMA_TO_DEVICE); - - if (is_sec1 && req_ctx->nbuf) - unmap_single_talitos_ptr(dev, &desc->ptr[3], - DMA_TO_DEVICE); if (edesc->dma_len) dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len, @@ -1922,9 +1909,6 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, to_talitos_ptr(&desc->ptr[2], ctx->dma_key, ctx->keylen, is_sec1); - if (is_sec1 && req_ctx->nbuf) - length -= req_ctx->nbuf; - sg_count = edesc->src_nents ?: 1; if (is_sec1 && sg_count > 1) sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length); @@ -1934,16 +1918,10 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, /* * data in */ - if (is_sec1 && req_ctx->nbuf) { - map_single_talitos_ptr(dev, &desc->ptr[3], req_ctx->nbuf, - req_ctx->buf[req_ctx->buf_idx], - DMA_TO_DEVICE); - } else { - sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc, - &desc->ptr[3], sg_count, 0, 0); - if (sg_count > 1) - sync_needed = true; - } + sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc, + &desc->ptr[3], sg_count, 0, 0); + if (sg_count > 1) + sync_needed = true; /* fifth DWORD empty */ @@ -1963,49 +1941,6 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, if (is_sec1 && from_talitos_ptr_len(&desc->ptr[3], true) == 0) talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]); - if (is_sec1 && req_ctx->nbuf && length) { - struct talitos_edesc *edesc2; - struct talitos_desc *desc2; - - edesc2 = kzalloc(sizeof(*edesc2), - areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? - GFP_KERNEL : - GFP_ATOMIC); - if (!edesc2) { - ret = -ENOMEM; - goto err; - } - edesc->next_desc = edesc2; - - desc2 = &edesc2->desc; - - desc2->hdr = desc->hdr; - desc2->hdr &= ~DESC_HDR_MODE0_MDEU_INIT; - desc->hdr &= ~DESC_HDR_MODE0_MDEU_PAD; - desc->hdr |= DESC_HDR_MODE0_MDEU_CONT; - desc->hdr &= ~DESC_HDR_DONE_NOTIFY; - - if (desc->ptr[1].ptr) - copy_talitos_ptr(&desc2->ptr[1], &desc->ptr[1], - is_sec1); - else - map_single_talitos_ptr_nosync(dev, &desc2->ptr[1], - req_ctx->hw_context_size, - req_ctx->hw_context, - DMA_TO_DEVICE); - copy_talitos_ptr(&desc2->ptr[2], &desc->ptr[2], is_sec1); - sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc, - &desc2->ptr[3], sg_count, 0, 0); - if (sg_count > 1) - sync_needed = true; - copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1); - if (req_ctx->last_desc) - map_single_talitos_ptr_nosync(dev, &desc->ptr[5], - req_ctx->hw_context_size, - req_ctx->hw_context, - DMA_FROM_DEVICE); - } - if (sync_needed) dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); @@ -2028,11 +1963,6 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq, struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); - struct talitos_private *priv = dev_get_drvdata(ctx->dev); - bool is_sec1 = has_ftr_sec1(priv); - - if (is_sec1) - nbytes -= req_ctx->nbuf; return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, NULL, 0, nbytes, 0, 0, 0, areq->base.flags, false); @@ -2051,8 +1981,6 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes unsigned int nsg; int nents; struct device *dev = ctx->dev; - struct talitos_private *priv = dev_get_drvdata(dev); - bool is_sec1 = has_ftr_sec1(priv); u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx]; if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) { @@ -2084,30 +2012,13 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes } /* Chain in any previously buffered data */ - if (!is_sec1 && req_ctx->nbuf) { + if (req_ctx->nbuf) { nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1; sg_init_table(req_ctx->bufsl, nsg); sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf); if (nsg > 1) sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl); req_ctx->psrc = req_ctx->bufsl; - } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) { - int offset; - - if (nbytes_to_hash > blocksize) - offset = blocksize - req_ctx->nbuf; - else - offset = nbytes_to_hash - req_ctx->nbuf; - nents = sg_nents_for_len(req_ctx->request_sl, offset); - if (nents < 0) { - dev_err(dev, "Invalid number of src SG.\n"); - return nents; - } - sg_copy_to_buffer(req_ctx->request_sl, nents, - ctx_buf + req_ctx->nbuf, offset); - req_ctx->nbuf += offset; - req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, req_ctx->request_sl, - offset); } else req_ctx->psrc = req_ctx->request_sl; From f1ede6d95d8ad3b32c6a552d2baab805bd00fc38 Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:53 +0200 Subject: [PATCH 286/655] crypto: talitos/hash - use descriptor chaining for SEC1 instead of workqueue Rework the SEC1 ahash implementation to build a chain of hardware descriptors, replacing the previous approach of submitting one descriptor at a time via a workqueue, introduced by commit 655ef638a2bc ("crypto: talitos - fix SEC1 32k ahash request limitation"). Introduce ahash_process_req_prepare() which iterates over the request data, allocating enough descriptors to cover the entire ahash request. The new fields (bufsl, src, first, last) are added to talitos_edesc for this purpose. common_nonsnoop_hash() no longer calls talitos_submit(); it only maps and sets up the descriptor. Submission is now done by the caller after the chain is built. ahash_free_desc_list_from() takes over calling common_nonsnoop_hash_unmap() for each descriptor during cleanup. Compared to the workqueue based solution, request are slightly faster since there is no more scheduling latency induced by the workqueue, and only one interrupt is generated by the device at the end of a chain. Commit 655ef638a2bc ("crypto: talitos - fix SEC1 32k ahash request limitation") : $ /usr/libexec/libkcapi/sha256sum ./test_5M.bin 013c5609d63c... ./test_5M.bin real 0m 0.41s user 0m 0.01s sys 0m 0.07s Now : $ /usr/libexec/libkcapi/sha256sum ./test_5M.bin 013c5609d63c... ./test_5M.bin real 0m 0.33s user 0m 0.01s sys 0m 0.20s Tested on a system with an MPC885 SoC featuring the SEC1 Lite. The increase in sys time is due to the fact that commit 37b5e8897eb5 ("crypto: talitos - chain in buffered data for ahash on SEC1") can no longer be applied. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 168 ++++++++++++++++++++++++--------------- drivers/crypto/talitos.h | 10 +++ 2 files changed, 115 insertions(+), 63 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 72d9c50b055e..5f8ee1f1346f 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1791,12 +1791,12 @@ static void common_nonsnoop_hash_unmap(struct device *dev, unmap_single_talitos_ptr(dev, &desc->ptr[5], DMA_FROM_DEVICE); - if (req_ctx->last_desc) + if (edesc->last && req_ctx->last_request) memcpy(areq->result, req_ctx->hw_context, crypto_ahash_digestsize(tfm)); - if (req_ctx->psrc) - talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0); + if (edesc->src) + talitos_sg_unmap(dev, edesc, edesc->src, NULL, 0, 0); /* When using hashctx-in, must unmap it. */ if (from_talitos_ptr_len(&desc->ptr[1], is_sec1)) @@ -1808,12 +1808,14 @@ static void common_nonsnoop_hash_unmap(struct device *dev, DMA_BIDIRECTIONAL); } -static void free_edesc_list_from(struct talitos_edesc *edesc) +static void free_edesc_list_from(struct ahash_request *areq, struct talitos_edesc *edesc) { + struct talitos_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct talitos_edesc *next; while (edesc) { next = edesc->next_desc; + common_nonsnoop_hash_unmap(ctx->dev, edesc, areq); kfree(edesc); edesc = next; } @@ -1828,19 +1830,18 @@ static void ahash_done(struct device *dev, container_of(desc, struct talitos_edesc, desc); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); + if (!req_ctx->last_desc && req_ctx->to_hash_later) { /* Position any partial block for next update/final/finup */ req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1; req_ctx->nbuf = req_ctx->to_hash_later; } - common_nonsnoop_hash_unmap(dev, edesc, areq); - free_edesc_list_from(edesc); + free_edesc_list_from(areq, edesc); - if (err) { - ahash_request_complete(areq, err); - return; - } + ahash_request_complete(areq, err); + + return; req_ctx->remaining_ahash_request_bytes -= req_ctx->current_ahash_request_bytes; @@ -1874,18 +1875,15 @@ static void talitos_handle_buggy_hash(struct talitos_ctx *ctx, (char *)padded_hash, DMA_TO_DEVICE); } -static int common_nonsnoop_hash(struct talitos_edesc *edesc, - struct ahash_request *areq, unsigned int length, - void (*callback) (struct device *dev, - struct talitos_desc *desc, - void *context, int error)) +static void common_nonsnoop_hash(struct talitos_edesc *edesc, + struct ahash_request *areq, + unsigned int length) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); struct device *dev = ctx->dev; struct talitos_desc *desc = &edesc->desc; - int ret; bool sync_needed = false; struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); @@ -1894,7 +1892,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, /* first DWORD empty */ /* hash context in */ - if (!req_ctx->first_desc || req_ctx->swinit) { + if (!edesc->first || !req_ctx->first_desc || req_ctx->swinit) { map_single_talitos_ptr_nosync(dev, &desc->ptr[1], req_ctx->hw_context_size, req_ctx->hw_context, @@ -1911,22 +1909,22 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, sg_count = edesc->src_nents ?: 1; if (is_sec1 && sg_count > 1) - sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length); + sg_copy_to_buffer(edesc->src, sg_count, edesc->buf, length); else if (length) - sg_count = dma_map_sg(dev, req_ctx->psrc, sg_count, - DMA_TO_DEVICE); + sg_count = dma_map_sg(dev, edesc->src, sg_count, DMA_TO_DEVICE); + /* * data in */ - sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc, - &desc->ptr[3], sg_count, 0, 0); + sg_count = talitos_sg_map(dev, edesc->src, length, edesc, &desc->ptr[3], + sg_count, 0, 0); if (sg_count > 1) sync_needed = true; /* fifth DWORD empty */ /* hash/HMAC out -or- hash context out */ - if (req_ctx->last_desc) + if (edesc->last && req_ctx->last_request) map_single_talitos_ptr(dev, &desc->ptr[5], crypto_ahash_digestsize(tfm), req_ctx->hw_context, DMA_FROM_DEVICE); @@ -1944,30 +1942,89 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, if (sync_needed) dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); - - ret = talitos_submit(dev, ctx->ch, desc, callback, - areq); - if (ret != -EINPROGRESS) - goto err; - - return -EINPROGRESS; -err: - common_nonsnoop_hash_unmap(dev, edesc, areq); - kfree(edesc); - return ret; } static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq, + struct scatterlist *src, unsigned int nbytes) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); - struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); - return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, NULL, 0, + return talitos_edesc_alloc(ctx->dev, src, NULL, NULL, 0, nbytes, 0, 0, 0, areq->base.flags, false); } +static struct talitos_edesc * +ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes, + unsigned int blocksize, bool is_sec1) +{ + struct talitos_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); + struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); + struct talitos_edesc *first = NULL, *prev_edesc = NULL, *edesc; + size_t desc_max = is_sec1 ? TALITOS1_MAX_DATA_LEN : SIZE_MAX; + struct scatterlist tmp[2]; + size_t to_hash_this_desc; + struct scatterlist *src; + size_t offset = 0; + + do { + src = scatterwalk_ffwd(tmp, req_ctx->psrc, offset); + + to_hash_this_desc = + min(nbytes, ALIGN_DOWN(desc_max, blocksize)); + + /* Allocate extended descriptor */ + edesc = ahash_edesc_alloc(areq, src, to_hash_this_desc); + if (IS_ERR(edesc)) { + if (first) + free_edesc_list_from(areq, first); + return edesc; + } + + edesc->src = + scatterwalk_ffwd(edesc->bufsl, req_ctx->psrc, offset); + edesc->desc.hdr = ctx->desc_hdr_template; + edesc->first = offset == 0; + edesc->last = nbytes - to_hash_this_desc == 0; + + /* On last one, request SEC to pad; otherwise continue */ + if (req_ctx->last_request && edesc->last) + edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD; + else + edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT; + + /* request SEC to INIT hash. */ + if (req_ctx->first_desc && edesc->first && !req_ctx->swinit) + edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT; + + /* + * When the tfm context has a keylen, it's an HMAC. + * A first or last (ie. not middle) descriptor must request HMAC. + */ + if (ctx->keylen && ((req_ctx->first_desc && edesc->first) || + (req_ctx->last_request && edesc->last))) + edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC; + + /* clear the DN bit */ + if (is_sec1 && !edesc->last) + edesc->desc.hdr &= ~DESC_HDR_DONE_NOTIFY; + + common_nonsnoop_hash(edesc, areq, to_hash_this_desc); + + offset += to_hash_this_desc; + nbytes -= to_hash_this_desc; + + if (!prev_edesc) + first = edesc; + else + prev_edesc->next_desc = edesc; + prev_edesc = edesc; + } while (nbytes); + + return first; +} + static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); @@ -1976,14 +2033,16 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes struct talitos_edesc *edesc; unsigned int blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); + bool is_sec1 = has_ftr_sec1(dev_get_drvdata(ctx->dev)); unsigned int nbytes_to_hash; unsigned int to_hash_later; unsigned int nsg; int nents; struct device *dev = ctx->dev; u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx]; + int ret; - if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) { + if (!req_ctx->last_request && (nbytes + req_ctx->nbuf <= blocksize)) { /* Buffer up to one whole block */ nents = sg_nents_for_len(req_ctx->request_sl, nbytes); if (nents < 0) { @@ -2000,7 +2059,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes nbytes_to_hash = nbytes + req_ctx->nbuf; to_hash_later = nbytes_to_hash & (blocksize - 1); - if (req_ctx->last_desc) + if (req_ctx->last_request) to_hash_later = 0; else if (to_hash_later) /* There is a partial block. Hash the full block(s) now */ @@ -2035,30 +2094,16 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes } req_ctx->to_hash_later = to_hash_later; - /* Allocate extended descriptor */ - edesc = ahash_edesc_alloc(req_ctx->areq, nbytes_to_hash); + edesc = ahash_process_req_prepare(areq, nbytes_to_hash, blocksize, + is_sec1); if (IS_ERR(edesc)) return PTR_ERR(edesc); - edesc->desc.hdr = ctx->desc_hdr_template; + ret = talitos_submit(dev, ctx->ch, &edesc->desc, ahash_done, areq); + if (ret != -EINPROGRESS) + free_edesc_list_from(areq, edesc); - /* On last one, request SEC to pad; otherwise continue */ - if (req_ctx->last_desc) - edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD; - else - edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT; - - /* request SEC to INIT hash. */ - if (req_ctx->first_desc && !req_ctx->swinit) - edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT; - - /* When the tfm context has a keylen, it's an HMAC. - * A first or last (ie. not middle) descriptor must request HMAC. - */ - if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc)) - edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC; - - return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done); + return ret; } static void sec1_ahash_process_remaining(struct work_struct *work) @@ -2102,16 +2147,13 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) req_ctx->remaining_ahash_request_bytes = nbytes; if (is_sec1) { - if (nbytes > TALITOS1_MAX_DATA_LEN) - nbytes = TALITOS1_MAX_DATA_LEN; - else if (req_ctx->last_request) + if (req_ctx->last_request) req_ctx->last_desc = 1; } req_ctx->current_ahash_request_bytes = nbytes; - return ahash_process_req_one(req_ctx->areq, - req_ctx->current_ahash_request_bytes); + return ahash_process_req_one(req_ctx->areq, nbytes); } static int ahash_init(struct ahash_request *areq) diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index 1553afa57b0b..d4ff8d589f46 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -44,6 +44,11 @@ struct talitos_desc { /* * talitos_edesc - s/w-extended descriptor + * @bufsl: scatterlist buffer + * @src: pointer to input scatterlist + * @first: first descriptor of a chain + * @last: last descriptor of a chain + * * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist * @iv_dma: dma address of iv for checking continuity and link table @@ -59,6 +64,11 @@ struct talitos_desc { * of link_tbl data */ struct talitos_edesc { + struct scatterlist bufsl[2]; + struct scatterlist *src; + int first; + int last; + int src_nents; int dst_nents; dma_addr_t iv_dma; From be4802afb1700534e48cb776d0d1e772c27de130 Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:54 +0200 Subject: [PATCH 287/655] crypto: talitos/hash - drop workqueue mechanism for SEC1 Now that SEC1 hash uses hardware descriptor chaining instead of a workqueue to process requests exceeding TALITOS1_MAX_DATA_LEN, the workqueue code is no longer needed. Remove sec1_ahash_process_remaining(), the related fields from talitos_ahash_req_ctx (request_bufsl, areq, request_sl, remaining_ahash_request_bytes, current_ahash_request_bytes, sec1_ahash_process_remaining), the dead code in ahash_done(), and simplify ahash_process_req() to call ahash_process_req_one() directly with the original areq->src and areq->nbytes. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 80 ++++------------------------------------ 1 file changed, 7 insertions(+), 73 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 5f8ee1f1346f..fe38bc6aaaab 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -12,7 +12,6 @@ * All rights reserved. */ -#include #include #include #include @@ -952,13 +951,6 @@ struct talitos_ahash_req_ctx { unsigned int nbuf; struct scatterlist bufsl[2]; struct scatterlist *psrc; - - struct scatterlist request_bufsl[2]; - struct ahash_request *areq; - struct scatterlist *request_sl; - unsigned int remaining_ahash_request_bytes; - unsigned int current_ahash_request_bytes; - struct work_struct sec1_ahash_process_remaining; }; struct talitos_export_state { @@ -1840,18 +1832,6 @@ static void ahash_done(struct device *dev, free_edesc_list_from(areq, edesc); ahash_request_complete(areq, err); - - return; - - req_ctx->remaining_ahash_request_bytes -= - req_ctx->current_ahash_request_bytes; - - if (!req_ctx->remaining_ahash_request_bytes) { - ahash_request_complete(areq, 0); - return; - } - - schedule_work(&req_ctx->sec1_ahash_process_remaining); } /* @@ -2044,12 +2024,12 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes if (!req_ctx->last_request && (nbytes + req_ctx->nbuf <= blocksize)) { /* Buffer up to one whole block */ - nents = sg_nents_for_len(req_ctx->request_sl, nbytes); + nents = sg_nents_for_len(areq->src, nbytes); if (nents < 0) { dev_err(dev, "Invalid number of src SG.\n"); return nents; } - sg_copy_to_buffer(req_ctx->request_sl, nents, + sg_copy_to_buffer(areq->src, nents, ctx_buf + req_ctx->nbuf, nbytes); req_ctx->nbuf += nbytes; return 0; @@ -2076,18 +2056,18 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes sg_init_table(req_ctx->bufsl, nsg); sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf); if (nsg > 1) - sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl); + sg_chain(req_ctx->bufsl, 2, areq->src); req_ctx->psrc = req_ctx->bufsl; } else - req_ctx->psrc = req_ctx->request_sl; + req_ctx->psrc = areq->src; if (to_hash_later) { - nents = sg_nents_for_len(req_ctx->request_sl, nbytes); + nents = sg_nents_for_len(areq->src, nbytes); if (nents < 0) { dev_err(dev, "Invalid number of src SG.\n"); return nents; } - sg_pcopy_to_buffer(req_ctx->request_sl, nents, + sg_pcopy_to_buffer(areq->src, nents, req_ctx->buf[(req_ctx->buf_idx + 1) & 1], to_hash_later, nbytes - to_hash_later); @@ -2106,54 +2086,9 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes return ret; } -static void sec1_ahash_process_remaining(struct work_struct *work) -{ - struct talitos_ahash_req_ctx *req_ctx = - container_of(work, struct talitos_ahash_req_ctx, - sec1_ahash_process_remaining); - int err = 0; - - req_ctx->request_sl = scatterwalk_ffwd(req_ctx->request_bufsl, - req_ctx->request_sl, TALITOS1_MAX_DATA_LEN); - - if (req_ctx->remaining_ahash_request_bytes > TALITOS1_MAX_DATA_LEN) - req_ctx->current_ahash_request_bytes = TALITOS1_MAX_DATA_LEN; - else { - req_ctx->current_ahash_request_bytes = - req_ctx->remaining_ahash_request_bytes; - - if (req_ctx->last_request) - req_ctx->last_desc = 1; - } - - err = ahash_process_req_one(req_ctx->areq, - req_ctx->current_ahash_request_bytes); - - if (err != -EINPROGRESS) - ahash_request_complete(req_ctx->areq, err); -} - static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); - struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); - struct device *dev = ctx->dev; - struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); - struct talitos_private *priv = dev_get_drvdata(dev); - bool is_sec1 = has_ftr_sec1(priv); - - req_ctx->areq = areq; - req_ctx->request_sl = areq->src; - req_ctx->remaining_ahash_request_bytes = nbytes; - - if (is_sec1) { - if (req_ctx->last_request) - req_ctx->last_desc = 1; - } - - req_ctx->current_ahash_request_bytes = nbytes; - - return ahash_process_req_one(req_ctx->areq, nbytes); + return ahash_process_req_one(areq, nbytes); } static int ahash_init(struct ahash_request *areq) @@ -2176,7 +2111,6 @@ static int ahash_init(struct ahash_request *areq) req_ctx->hw_context_size = size; req_ctx->last_request = 0; req_ctx->last_desc = 0; - INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining); dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size, DMA_TO_DEVICE); From 8bcf00671400ac3b3a4cc3011e6c1496dbd880fd Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:55 +0200 Subject: [PATCH 288/655] crypto: talitos/hash - rename first_desc/last_desc to first_request/last_request In talitos_ahash_req_ctx and talitos_export_state, the fields first_desc and last_desc describe request-level (not descriptor-level) state. Rename them to first_request and last_request for clarity. last_desc is also removed from talitos_ahash_req_ctx as it is no longer used. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index fe38bc6aaaab..1d108aec4ab3 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -944,8 +944,7 @@ struct talitos_ahash_req_ctx { u8 buf[2][HASH_MAX_BLOCK_SIZE]; int buf_idx; unsigned int swinit; - unsigned int first_desc; - unsigned int last_desc; + unsigned int first_request; unsigned int last_request; unsigned int to_hash_later; unsigned int nbuf; @@ -957,8 +956,8 @@ struct talitos_export_state { u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)]; u8 buf[HASH_MAX_BLOCK_SIZE]; unsigned int swinit; - unsigned int first_desc; - unsigned int last_desc; + unsigned int first_request; + unsigned int last_request; unsigned int to_hash_later; unsigned int nbuf; }; @@ -1822,8 +1821,7 @@ static void ahash_done(struct device *dev, container_of(desc, struct talitos_edesc, desc); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); - - if (!req_ctx->last_desc && req_ctx->to_hash_later) { + if (!req_ctx->last_request && req_ctx->to_hash_later) { /* Position any partial block for next update/final/finup */ req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1; req_ctx->nbuf = req_ctx->to_hash_later; @@ -1872,7 +1870,7 @@ static void common_nonsnoop_hash(struct talitos_edesc *edesc, /* first DWORD empty */ /* hash context in */ - if (!edesc->first || !req_ctx->first_desc || req_ctx->swinit) { + if (!edesc->first || !req_ctx->first_request || req_ctx->swinit) { map_single_talitos_ptr_nosync(dev, &desc->ptr[1], req_ctx->hw_context_size, req_ctx->hw_context, @@ -1880,7 +1878,7 @@ static void common_nonsnoop_hash(struct talitos_edesc *edesc, req_ctx->swinit = 0; } /* Indicate next op is not the first. */ - req_ctx->first_desc = 0; + req_ctx->first_request = 0; /* HMAC key */ if (ctx->keylen) @@ -1975,14 +1973,14 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes, edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT; /* request SEC to INIT hash. */ - if (req_ctx->first_desc && edesc->first && !req_ctx->swinit) + if (req_ctx->first_request && edesc->first && !req_ctx->swinit) edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT; /* * When the tfm context has a keylen, it's an HMAC. * A first or last (ie. not middle) descriptor must request HMAC. */ - if (ctx->keylen && ((req_ctx->first_desc && edesc->first) || + if (ctx->keylen && ((req_ctx->first_request && edesc->first) || (req_ctx->last_request && edesc->last))) edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC; @@ -2103,14 +2101,13 @@ static int ahash_init(struct ahash_request *areq) /* Initialize the context */ req_ctx->buf_idx = 0; req_ctx->nbuf = 0; - req_ctx->first_desc = 1; /* first_desc indicates h/w must init its context */ + req_ctx->first_request = 1; req_ctx->swinit = 0; /* assume h/w init of context */ size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE) ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256 : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512; req_ctx->hw_context_size = size; req_ctx->last_request = 0; - req_ctx->last_desc = 0; dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size, DMA_TO_DEVICE); @@ -2202,8 +2199,8 @@ static int ahash_export(struct ahash_request *areq, void *out) req_ctx->hw_context_size); memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf); export->swinit = req_ctx->swinit; - export->first_desc = req_ctx->first_desc; - export->last_desc = req_ctx->last_desc; + export->first_request = req_ctx->first_request; + export->last_request = req_ctx->last_request; export->to_hash_later = req_ctx->to_hash_later; export->nbuf = req_ctx->nbuf; @@ -2228,8 +2225,8 @@ static int ahash_import(struct ahash_request *areq, const void *in) memcpy(req_ctx->hw_context, export->hw_context, size); memcpy(req_ctx->buf[0], export->buf, export->nbuf); req_ctx->swinit = export->swinit; - req_ctx->first_desc = export->first_desc; - req_ctx->last_desc = export->last_desc; + req_ctx->first_request = export->first_request; + req_ctx->last_request = export->last_request; req_ctx->to_hash_later = export->to_hash_later; req_ctx->nbuf = export->nbuf; From 907ae6088c82c9abae2d26477fddd60df6ad003b Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:56 +0200 Subject: [PATCH 289/655] crypto: talitos/hash - remove useless wrapper ahash_process_req() was a wrapper used in commit 655ef638a2bc ("crypto: talitos - fix SEC1 32k ahash request limitation"). Rename ahash_process_req_one() to ahash_process_req() and remove the wrapper. Cc: stable@vger.kernel.org Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 1d108aec4ab3..551b41e813f0 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2003,7 +2003,7 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes, return first; } -static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes) +static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); @@ -2084,11 +2084,6 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes return ret; } -static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) -{ - return ahash_process_req_one(areq, nbytes); -} - static int ahash_init(struct ahash_request *areq) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); From 6e12daff6ec125102a6fdcafc5aa7199f7ce8933 Mon Sep 17 00:00:00 2001 From: Paul Louvel Date: Thu, 7 May 2026 16:41:57 +0200 Subject: [PATCH 290/655] crypto: talitos/hash - fix SEC2 64k - 1 ahash request limitation The problem described in commit 655ef638a2bc ("crypto: talitos - fix SEC1 32k ahash request limitation") also apply for the SEC2 hardware, but with a limitation of 64k - 1 bytes. Split ahash_done() into SEC1 and SEC2 paths: SEC1 continues to free the whole descriptor list at once, while SEC2 now iterates through descriptors one by one, submitting the next only after the previous completes, which is required since SEC2 cannot chain descriptors in hardware. Cc: stable@vger.kernel.org Fixes: c662b043cdca ("crypto: af_alg/hash: Support MSG_SPLICE_PAGES") Signed-off-by: Paul Louvel Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 551b41e813f0..2d69ee608665 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1820,16 +1820,46 @@ static void ahash_done(struct device *dev, struct talitos_edesc *edesc = container_of(desc, struct talitos_edesc, desc); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); + bool is_sec1 = has_ftr_sec1(dev_get_drvdata(dev)); + struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); + struct talitos_edesc *next; - if (!req_ctx->last_request && req_ctx->to_hash_later) { - /* Position any partial block for next update/final/finup */ - req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1; - req_ctx->nbuf = req_ctx->to_hash_later; + if (is_sec1) { + if (!req_ctx->last_request && req_ctx->to_hash_later) { + /* Position any partial block for next update/final/finup */ + req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1; + req_ctx->nbuf = req_ctx->to_hash_later; + } + + free_edesc_list_from(areq, edesc); + ahash_request_complete(areq, err); + } else { + next = edesc->next_desc; + + common_nonsnoop_hash_unmap(dev, edesc, areq); + kfree(edesc); + + if (err) + goto out; + + if (next) { + err = talitos_submit(dev, ctx->ch, &next->desc, + ahash_done, areq); + if (err != -EINPROGRESS) + goto out; + return; + } +out: + if (!req_ctx->last_request && req_ctx->to_hash_later) { + /* Position any partial block for next update/final/finup */ + req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1; + req_ctx->nbuf = req_ctx->to_hash_later; + } + if (err && next) + free_edesc_list_from(areq, next); + ahash_request_complete(areq, err); } - - free_edesc_list_from(areq, edesc); - - ahash_request_complete(areq, err); } /* @@ -1940,7 +1970,8 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes, struct talitos_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); struct talitos_edesc *first = NULL, *prev_edesc = NULL, *edesc; - size_t desc_max = is_sec1 ? TALITOS1_MAX_DATA_LEN : SIZE_MAX; + size_t desc_max = is_sec1 ? TALITOS1_MAX_DATA_LEN : + TALITOS2_MAX_DATA_LEN; struct scatterlist tmp[2]; size_t to_hash_this_desc; struct scatterlist *src; From 463be1c718fb9f07bdce3d51363a17eac4522538 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Thu, 7 May 2026 16:44:16 -0700 Subject: [PATCH 291/655] crypto: talitos - use devm_platform_ioremap_resource() platform_get_resource and devm_ioremap effectively open codes this. The return type of devm_platform_ioremap_resource() is also nice as it has multiple errors that it can return. Because it internally calls devm_request_mem_region(), reg values and sizes cannot overlap. This was manually verified to be the case for all talitos users. Signed-off-by: Rosen Penev Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 2d69ee608665..584508963241 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -3413,7 +3413,6 @@ static int talitos_probe(struct platform_device *ofdev) unsigned int num_channels; int i, err; int stride; - struct resource *res; if (of_property_read_u32(np, "fsl,num-channels", &num_channels)) return -EINVAL; @@ -3432,13 +3431,10 @@ static int talitos_probe(struct platform_device *ofdev) spin_lock_init(&priv->reg_lock); - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - priv->reg = devm_ioremap(dev, res->start, resource_size(res)); - if (!priv->reg) { + priv->reg = devm_platform_ioremap_resource(ofdev, 0); + if (IS_ERR(priv->reg)) { dev_err(dev, "failed to of_iomap\n"); - err = -ENOMEM; + err = PTR_ERR(priv->reg); goto err_out; } From 6d827ade51a24e18d81afb9f32756d339520a14c Mon Sep 17 00:00:00 2001 From: Dawei Feng Date: Fri, 8 May 2026 12:24:16 +0800 Subject: [PATCH 292/655] crypto: amlogic - avoid double cleanup in meson_crypto_probe() When meson_allocate_chanlist() fails after a partial allocation, it already unwinds the allocated chanlist state through its local error path. meson_crypto_probe() then jump to error_flow and calls meson_free_chanlist() again, causing the same per-flow resources to be torn down twice. In the reproduced failure path, the second teardown re-entered crypto_engine_exit() on an already destroyed worker and KASAN reported a slab-use-after-free in kthread_destroy_worker(). Prevent double-free by handling partial allocation failures locally within meson_allocate_chanlist() and skipping the outer cleanup path. The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. The bug was reproduced in a QEMU x86_64 guest booted with KASAN on v7.1, using the reproducer under tools/testing/meson_crypto_probe. The reproducer forces the second dma_alloc_attrs() call in the gxl-crypto probe path to return NULL, making meson_allocate_chanlist() fail after partial initialization. On the unpatched kernel this reliably triggered a slab-use-after-free. With this fix applied, the same reproducer no longer emits any KASAN report and the probe fails cleanly with -ENOMEM. ================================================================== BUG: KASAN: slab-use-after-free in kthread_destroy_worker+0xb2/0xd0 Read of size 8 at addr ff1100010c057a68 by task insmod/265 CPU: 1 UID: 0 PID: 265 Comm: insmod Tainted: G O 7.1.0-rc2-00376-g810af9adc907-dirty #10 PREEMPT(lazy) Tainted: [O]=OOT_MODULE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014 Call Trace: dump_stack_lvl+0x68/0xa0 print_report+0xcb/0x5e0 ? __virt_addr_valid+0x21d/0x3f0 ? kthread_destroy_worker+0xb2/0xd0 ? kthread_destroy_worker+0xb2/0xd0 kasan_report+0xca/0x100 ? kthread_destroy_worker+0xb2/0xd0 kthread_destroy_worker+0xb2/0xd0 meson_crypto_probe+0x4d0/0xc10 [amlogic_gxl_crypto] platform_probe+0x99/0x140 really_probe+0x1c6/0x6a0 ? __pfx___device_attach_driver+0x10/0x10 __driver_probe_device+0x248/0x310 ? acpi_driver_match_device+0xb0/0x100 driver_probe_device+0x48/0x210 ? __pfx___device_attach_driver+0x10/0x10 __device_attach_driver+0x160/0x320 bus_for_each_drv+0x104/0x190 ? __pfx_bus_for_each_drv+0x10/0x10 ? _raw_spin_unlock_irqrestore+0x2c/0x50 __device_attach+0x19d/0x3b0 ? __pfx___device_attach+0x10/0x10 ? do_raw_spin_unlock+0x53/0x220 device_initial_probe+0x78/0xa0 bus_probe_device+0x5b/0x130 device_add+0xcfd/0x1430 ? __pfx_device_add+0x10/0x10 ? insert_resource+0x34/0x50 ? lock_release+0xc9/0x290 platform_device_add+0x24e/0x590 ? __pfx_meson_crypto_probe_repro_init+0x10/0x10 [meson_crypto_probe_repro] meson_crypto_probe_repro_init+0x330/0xff0 [meson_crypto_probe_repro] do_one_initcall+0xc0/0x450 ? __pfx_do_one_initcall+0x10/0x10 ? _raw_spin_unlock_irqrestore+0x2c/0x50 ? __create_object+0x59/0x80 ? kasan_unpoison+0x27/0x60 do_init_module+0x27b/0x7d0 ? __pfx_do_init_module+0x10/0x10 ? kasan_quarantine_put+0x84/0x1d0 ? kfree+0x32c/0x510 ? load_module+0x561e/0x5ff0 load_module+0x54fe/0x5ff0 ? __pfx_load_module+0x10/0x10 ? security_file_permission+0x20/0x40 ? kernel_read_file+0x23d/0x6e0 ? mmap_region+0x235/0x4a0 ? __pfx_kernel_read_file+0x10/0x10 ? __file_has_perm+0x2c0/0x3e0 init_module_from_file+0x158/0x180 ? __pfx_init_module_from_file+0x10/0x10 ? __lock_acquire+0x45a/0x1ba0 ? idempotent_init_module+0x315/0x610 ? lock_release+0xc9/0x290 ? lockdep_init_map_type+0x4b/0x220 ? do_raw_spin_unlock+0x53/0x220 idempotent_init_module+0x330/0x610 ? __pfx_idempotent_init_module+0x10/0x10 ? __pfx_cred_has_capability.isra.0+0x10/0x10 ? ksys_mmap_pgoff+0x385/0x520 __x64_sys_finit_module+0xbe/0x120 do_syscall_64+0x115/0x690 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f7d6d31690d Code: 5b 41 5c c3 66 0f 1f 84 00 00 00 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d f3 b4 0f 00 f7 d8 > RSP: 002b:00007fffc027ac68 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 RAX: ffffffffffffffda RBX: 000055f7b81967c0 RCX: 00007f7d6d31690d RDX: 0000000000000000 RSI: 000055f79a0d6cd2 RDI: 0000000000000003 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000003 R11: 0000000000000246 R12: 000055f79a0d6cd2 R13: 000055f7b8196790 R14: 000055f79a0d5888 R15: 000055f7b81968e0 Fixes: 48fe583fe541 ("crypto: amlogic - Add crypto accelerator for amlogic GXL") Cc: stable@vger.kernel.org Signed-off-by: Zilin Guan Signed-off-by: Dawei Feng Signed-off-by: Herbert Xu --- drivers/crypto/amlogic/amlogic-gxl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/amlogic/amlogic-gxl-core.c b/drivers/crypto/amlogic/amlogic-gxl-core.c index 1c18a5b8470e..6cb33949915f 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-core.c +++ b/drivers/crypto/amlogic/amlogic-gxl-core.c @@ -291,8 +291,8 @@ static int meson_crypto_probe(struct platform_device *pdev) return 0; error_alg: meson_unregister_algs(mc); -error_flow: meson_free_chanlist(mc, MAXFLOW - 1); +error_flow: clk_disable_unprepare(mc->busclk); return err; } From c36faca103a685590281412e47df74b550f71886 Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Fri, 8 May 2026 14:33:45 +0530 Subject: [PATCH 293/655] crypto: safexcel - Fix potential memory leak in safexcel_pci_probe() The memory allocated for priv in safexcel_pci_probe() is not freed in the error paths, as well as in the PCI remove function. Fix this by using device managed allocation. Fixes: 625f269a5a7a ("crypto: inside-secure - add support for PCI based FPGA development board") Signed-off-by: Abdun Nihaal Reviewed-by: Antoine Tenart Signed-off-by: Herbert Xu --- drivers/crypto/inside-secure/safexcel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index 812ebabd1309..52809e57361a 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -1893,7 +1893,7 @@ static int safexcel_pci_probe(struct pci_dev *pdev, ent->vendor, ent->device, ent->subvendor, ent->subdevice, ent->driver_data); - priv = kzalloc_obj(*priv); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; From 6b261b9bae589b8bbcaca5ededc0caf0b2f3a0af Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 8 May 2026 12:57:17 +0200 Subject: [PATCH 294/655] crypto: api - use designated initializers for report structs Use designated initializers for the report structs instead of clearing the struct with memset() and then copying fixed strings with strscpy() at runtime. This keeps the structs zero-initialized, lets the compiler diagnose oversized string literals, and makes the code easier to read. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- crypto/acompress.c | 8 +++----- crypto/aead.c | 10 ++++------ crypto/ahash.c | 8 +++----- crypto/akcipher.c | 8 +++----- crypto/crypto_user.c | 14 ++++++-------- crypto/kpp.c | 8 +++----- crypto/lskcipher.c | 10 ++++------ crypto/rng.c | 8 +++----- crypto/scompress.c | 8 +++----- crypto/shash.c | 8 +++----- crypto/sig.c | 6 +++--- crypto/skcipher.c | 10 ++++------ 12 files changed, 42 insertions(+), 64 deletions(-) diff --git a/crypto/acompress.c b/crypto/acompress.c index 6025c1acce49..032de704eb2c 100644 --- a/crypto/acompress.c +++ b/crypto/acompress.c @@ -51,11 +51,9 @@ static inline struct acomp_alg *crypto_acomp_alg(struct crypto_acomp *tfm) static int __maybe_unused crypto_acomp_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_acomp racomp; - - memset(&racomp, 0, sizeof(racomp)); - - strscpy(racomp.type, "acomp", sizeof(racomp.type)); + struct crypto_report_acomp racomp = { + .type = "acomp", + }; return nla_put(skb, CRYPTOCFGA_REPORT_ACOMP, sizeof(racomp), &racomp); } diff --git a/crypto/aead.c b/crypto/aead.c index e009937bf3a5..045b74c3779f 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -136,13 +136,11 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) static int __maybe_unused crypto_aead_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_aead raead; struct aead_alg *aead = container_of(alg, struct aead_alg, base); - - memset(&raead, 0, sizeof(raead)); - - strscpy(raead.type, "aead", sizeof(raead.type)); - strscpy(raead.geniv, "", sizeof(raead.geniv)); + struct crypto_report_aead raead = { + .type = "aead", + .geniv = "", + }; raead.blocksize = alg->cra_blocksize; raead.maxauthsize = aead->maxauthsize; diff --git a/crypto/ahash.c b/crypto/ahash.c index 7a730324c50e..dd56b0e45c0d 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -789,11 +789,9 @@ static void crypto_ahash_free_instance(struct crypto_instance *inst) static int __maybe_unused crypto_ahash_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_hash rhash; - - memset(&rhash, 0, sizeof(rhash)); - - strscpy(rhash.type, "ahash", sizeof(rhash.type)); + struct crypto_report_hash rhash = { + .type = "ahash", + }; rhash.blocksize = alg->cra_blocksize; rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize; diff --git a/crypto/akcipher.c b/crypto/akcipher.c index dfe87b3ce183..630bb19738be 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -36,11 +36,9 @@ struct crypto_akcipher_sync_data { static int __maybe_unused crypto_akcipher_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_akcipher rakcipher; - - memset(&rakcipher, 0, sizeof(rakcipher)); - - strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type)); + struct crypto_report_akcipher rakcipher = { + .type = "akcipher", + }; return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, sizeof(rakcipher), &rakcipher); diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 3187e0d276f9..e8b6ae75f31f 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -70,11 +70,9 @@ static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact) static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_cipher rcipher; - - memset(&rcipher, 0, sizeof(rcipher)); - - strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); + struct crypto_report_cipher rcipher = { + .type = "cipher", + }; rcipher.blocksize = alg->cra_blocksize; rcipher.min_keysize = alg->cra_cipher.cia_min_keysize; @@ -103,10 +101,10 @@ static int crypto_report_one(struct crypto_alg *alg, if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority)) goto nla_put_failure; if (alg->cra_flags & CRYPTO_ALG_LARVAL) { - struct crypto_report_larval rl; + struct crypto_report_larval rl = { + .type = "larval", + }; - memset(&rl, 0, sizeof(rl)); - strscpy(rl.type, "larval", sizeof(rl.type)); if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL, sizeof(rl), &rl)) goto nla_put_failure; goto out; diff --git a/crypto/kpp.c b/crypto/kpp.c index 7451d39a7ad8..522c352a03af 100644 --- a/crypto/kpp.c +++ b/crypto/kpp.c @@ -20,11 +20,9 @@ static int __maybe_unused crypto_kpp_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_kpp rkpp; - - memset(&rkpp, 0, sizeof(rkpp)); - - strscpy(rkpp.type, "kpp", sizeof(rkpp.type)); + struct crypto_report_kpp rkpp = { + .type = "kpp", + }; return nla_put(skb, CRYPTOCFGA_REPORT_KPP, sizeof(rkpp), &rkpp); } diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c index bb166250b732..e4328df6e26c 100644 --- a/crypto/lskcipher.c +++ b/crypto/lskcipher.c @@ -264,12 +264,10 @@ static int __maybe_unused crypto_lskcipher_report( struct sk_buff *skb, struct crypto_alg *alg) { struct lskcipher_alg *skcipher = __crypto_lskcipher_alg(alg); - struct crypto_report_blkcipher rblkcipher; - - memset(&rblkcipher, 0, sizeof(rblkcipher)); - - strscpy(rblkcipher.type, "lskcipher", sizeof(rblkcipher.type)); - strscpy(rblkcipher.geniv, "", sizeof(rblkcipher.geniv)); + struct crypto_report_blkcipher rblkcipher = { + .type = "lskcipher", + .geniv = "", + }; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = skcipher->co.min_keysize; diff --git a/crypto/rng.c b/crypto/rng.c index 1d4b9177bad4..eec786c45bdd 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -65,11 +65,9 @@ static unsigned int seedsize(struct crypto_alg *alg) static int __maybe_unused crypto_rng_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_rng rrng; - - memset(&rrng, 0, sizeof(rrng)); - - strscpy(rrng.type, "rng", sizeof(rrng.type)); + struct crypto_report_rng rrng = { + .type = "rng", + }; rrng.seedsize = seedsize(alg); diff --git a/crypto/scompress.c b/crypto/scompress.c index 253655ece83f..de54227203ce 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -48,11 +48,9 @@ static DECLARE_WORK(scomp_scratch_work, scomp_scratch_workfn); static int __maybe_unused crypto_scomp_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_comp rscomp; - - memset(&rscomp, 0, sizeof(rscomp)); - - strscpy(rscomp.type, "scomp", sizeof(rscomp.type)); + struct crypto_report_comp rscomp = { + .type = "scomp", + }; return nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS, sizeof(rscomp), &rscomp); diff --git a/crypto/shash.c b/crypto/shash.c index 2f07d0bd1f61..d31a65570f69 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -333,12 +333,10 @@ static void crypto_shash_free_instance(struct crypto_instance *inst) static int __maybe_unused crypto_shash_report( struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_hash rhash; struct shash_alg *salg = __crypto_shash_alg(alg); - - memset(&rhash, 0, sizeof(rhash)); - - strscpy(rhash.type, "shash", sizeof(rhash.type)); + struct crypto_report_hash rhash = { + .type = "shash", + }; rhash.blocksize = alg->cra_blocksize; rhash.digestsize = salg->digestsize; diff --git a/crypto/sig.c b/crypto/sig.c index beba745b6405..7d2048da5c3a 100644 --- a/crypto/sig.c +++ b/crypto/sig.c @@ -53,9 +53,9 @@ static void __maybe_unused crypto_sig_show(struct seq_file *m, static int __maybe_unused crypto_sig_report(struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_sig rsig = {}; - - strscpy(rsig.type, "sig", sizeof(rsig.type)); + struct crypto_report_sig rsig = { + .type = "sig", + }; return nla_put(skb, CRYPTOCFGA_REPORT_SIG, sizeof(rsig), &rsig); } diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 2b31d1d5d268..617e840432b1 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -591,12 +591,10 @@ static int __maybe_unused crypto_skcipher_report( struct sk_buff *skb, struct crypto_alg *alg) { struct skcipher_alg *skcipher = __crypto_skcipher_alg(alg); - struct crypto_report_blkcipher rblkcipher; - - memset(&rblkcipher, 0, sizeof(rblkcipher)); - - strscpy(rblkcipher.type, "skcipher", sizeof(rblkcipher.type)); - strscpy(rblkcipher.geniv, "", sizeof(rblkcipher.geniv)); + struct crypto_report_blkcipher rblkcipher = { + .type = "skcipher", + .geniv = "", + }; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = skcipher->min_keysize; From 917faaf2bd02da23286172863e3adab363233864 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sat, 9 May 2026 12:11:55 +0200 Subject: [PATCH 295/655] crypto: atmel-sha204a - drop __maybe_unused and of_match_ptr Since MODULE_DEVICE_TABLE() keeps atmel_sha204a_dt_ids referenced, drop the unnecessary __maybe_unused annotation. Also remove of_match_ptr() because OF matching is stubbed out when CONFIG_OF=n. Reformat atmel_sha204a_dt_ids to silence a checkpatch error and atmel_sha204a_id for consistency. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha204a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index ed7d69bf6890..6e6ac4770416 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -207,17 +207,17 @@ static void atmel_sha204a_remove(struct i2c_client *client) kfree((void *)i2c_priv->hwrng.priv); } -static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = { +static const struct of_device_id atmel_sha204a_dt_ids[] = { { .compatible = "atmel,atsha204", .data = &atsha204_quality }, { .compatible = "atmel,atsha204a", }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); static const struct i2c_device_id atmel_sha204a_id[] = { { "atsha204", (kernel_ulong_t)&atsha204_quality }, { "atsha204a" }, - { /* sentinel */ } + { } }; MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id); @@ -227,7 +227,7 @@ static struct i2c_driver atmel_sha204a_driver = { .id_table = atmel_sha204a_id, .driver.name = "atmel-sha204a", - .driver.of_match_table = of_match_ptr(atmel_sha204a_dt_ids), + .driver.of_match_table = atmel_sha204a_dt_ids, }; static int __init atmel_sha204a_init(void) From 8e4e40b0d03a11cde9e341b4a422232cb25d2c61 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sat, 9 May 2026 12:11:56 +0200 Subject: [PATCH 296/655] crypto: atmel-ecc - drop CONFIG_OF guard and of_match_ptr Drop the CONFIG_OF preprocessor guard and remove of_match_ptr() because OF matching is stubbed out when CONFIG_OF=n. Reformat atmel_ecc_dt_ids for consistency. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-ecc.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index e47381020606..9660f6426a84 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -368,18 +368,12 @@ static void atmel_ecc_remove(struct i2c_client *client) spin_unlock(&driver_data.i2c_list_lock); } -#ifdef CONFIG_OF static const struct of_device_id atmel_ecc_dt_ids[] = { - { - .compatible = "atmel,atecc508a", - }, { - .compatible = "atmel,atecc608b", - }, { - /* sentinel */ - } + { .compatible = "atmel,atecc508a", }, + { .compatible = "atmel,atecc608b", }, + { } }; MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids); -#endif static const struct i2c_device_id atmel_ecc_id[] = { { "atecc508a" }, @@ -391,7 +385,7 @@ MODULE_DEVICE_TABLE(i2c, atmel_ecc_id); static struct i2c_driver atmel_ecc_driver = { .driver = { .name = "atmel-ecc", - .of_match_table = of_match_ptr(atmel_ecc_dt_ids), + .of_match_table = atmel_ecc_dt_ids, }, .probe = atmel_ecc_probe, .remove = atmel_ecc_remove, From ea8eca95a25256dcafc11eee31f19a70b91917aa Mon Sep 17 00:00:00 2001 From: Deepti Jaggi Date: Sun, 10 May 2026 10:18:09 +0800 Subject: [PATCH 297/655] dt-bindings: crypto: qcom,prng: Document TRNG on Nord SoC Document True Random Number Generator on Qualcomm Nord SoC. Signed-off-by: Deepti Jaggi Signed-off-by: Shawn Guo Acked-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom,prng.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml index 498d6914135e..d054cc114707 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml @@ -23,6 +23,7 @@ properties: - qcom,ipq9574-trng - qcom,kaanapali-trng - qcom,milos-trng + - qcom,nord-trng - qcom,qcs615-trng - qcom,qcs8300-trng - qcom,sa8255p-trng From 6c9dddeb582fde005360f4fe02c760d45ca05fb5 Mon Sep 17 00:00:00 2001 From: Michael Bommarito Date: Sun, 10 May 2026 19:24:55 -0400 Subject: [PATCH 298/655] crypto: krb5 - filter out async aead implementations at alloc krb5_aead_encrypt(), krb5_aead_decrypt() in rfc3961_simplified.c and rfc8009_encrypt(), rfc8009_decrypt() in rfc8009_aes2.c set a NULL completion callback and treat any negative return from crypto_aead_{encrypt,decrypt}() as terminal, falling through to kfree_sensitive(buffer). When the encrypt_name resolves to an async AEAD instance the request returns -EINPROGRESS, the buffer is freed while the backend's worker still holds a pointer, and the worker dereferences the freed slab on completion. KASAN report under UML+SLUB with a synthetic async aead backend bound to krb5->encrypt_name: BUG: KASAN: slab-use-after-free in t5_stub_complete+0x7d/0xc7 The helpers were written synchronously, so filter the async instances out at allocation time instead of plumbing crypto_wait_req() through every call site. Reachable via net/rxrpc/rxgk.c, fs/afs/cm_security.c and net/ceph/crypto.c on systems with an async AEAD provider bound to the krb5 enctype name. Fixes: 00244da40f78 ("crypto/krb5: Implement the Kerberos5 rfc3961 encrypt and decrypt functions") Fixes: 6c3c0e86c2ac ("crypto/krb5: Implement the AES enctypes from rfc8009") Cc: stable@vger.kernel.org Suggested-by: Herbert Xu Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito Signed-off-by: Herbert Xu --- crypto/krb5/krb5_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/krb5/krb5_api.c b/crypto/krb5/krb5_api.c index 23026d4206c8..2b20284fa0ab 100644 --- a/crypto/krb5/krb5_api.c +++ b/crypto/krb5/krb5_api.c @@ -165,7 +165,7 @@ struct crypto_aead *krb5_prepare_encryption(const struct krb5_enctype *krb5, struct crypto_aead *ci = NULL; int ret = -ENOMEM; - ci = crypto_alloc_aead(krb5->encrypt_name, 0, 0); + ci = crypto_alloc_aead(krb5->encrypt_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(ci)) { ret = PTR_ERR(ci); if (ret == -ENOENT) From 59b991990a04b1d1ce95373983b7c8b65bdf7acc Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Fri, 15 May 2026 18:26:20 +0800 Subject: [PATCH 299/655] spi: hisi-kunpeng: Use dev_err_probe() for host registration failure When the SPI core registers the Kunpeng controller it may need to acquire chip-select GPIO descriptors. If the GPIO provider has not probed yet, spi_register_controller() returns -EPROBE_DEFER. On a Kunpeng system this currently prints an alarming error even though the next deferred-probe retry succeeds: hisi-kunpeng-spi HISI03E1:00: failed to register spi host, ret=-517 hisi-kunpeng-spi HISI03E1:00: hw version:0x30 max-freq:12500 kHz Use dev_err_probe() so that -EPROBE_DEFER is reported through the deferred probe mechanism instead of as a hard error, while preserving normal error reporting for real registration failures. Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") Signed-off-by: Qiang Ma Link: https://patch.msgid.link/20260515102620.1926930-1-maqianga@uniontech.com Signed-off-by: Mark Brown --- drivers/spi/spi-hisi-kunpeng.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 046bd894040b..395214b81179 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -520,10 +520,8 @@ static int hisi_spi_probe(struct platform_device *pdev) } ret = spi_register_controller(host); - if (ret) { - dev_err(dev, "failed to register spi host, ret=%d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to register spi host\n"); if (hisi_spi_debugfs_init(hs)) dev_info(dev, "failed to create debugfs dir\n"); From 17a92946d7c06ed07b77d4fb1873d68eac28ae08 Mon Sep 17 00:00:00 2001 From: Clinton Phillips Date: Wed, 13 May 2026 15:59:04 -0400 Subject: [PATCH 300/655] docs: sphinx-static: fix typo "wich" -> "which" Trivial typo fix in a CSS comment for the documentation theme. Signed-off-by: Clinton Phillips Signed-off-by: Jonathan Corbet Message-ID: <20260513195956.25307-1-clintdotphillips@gmail.com> --- Documentation/sphinx-static/custom.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css index f91393426a50..5aa0a1ed9864 100644 --- a/Documentation/sphinx-static/custom.css +++ b/Documentation/sphinx-static/custom.css @@ -30,7 +30,7 @@ img.logo { margin-bottom: 20px; } -/* The default is to use -1em, wich makes it override text */ +/* The default is to use -1em, which makes it override text */ li { text-indent: 0em; } /* From 8d624d687d1b6f7f913e28ec4bcc73e7ac59e9fa Mon Sep 17 00:00:00 2001 From: Chen-Shi-Hong Date: Thu, 14 May 2026 16:27:33 +0800 Subject: [PATCH 301/655] docs: reporting-issues: replace "these advices" with "all of this advice" "Advice" is an uncountable noun, so "these advices" is grammatically incorrect. Replace it with "all of this advice" instead, which keeps the sentence grammatical while also making it clear that it refers to the full set of recommendations in the paragraph. Signed-off-by: Chen-Shi-Hong Reviewed-by: WangYuli Signed-off-by: Jonathan Corbet Message-ID: <20260514082808.655-1-eric039eric@gmail.com> --- Documentation/admin-guide/reporting-issues.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/reporting-issues.rst b/Documentation/admin-guide/reporting-issues.rst index 16a66a1f1975..87dd874fffcf 100644 --- a/Documentation/admin-guide/reporting-issues.rst +++ b/Documentation/admin-guide/reporting-issues.rst @@ -129,7 +129,7 @@ After these preparations you'll now enter the main part: situations; during the merge window that actually might be even the best approach, but in that development phase it can be an even better idea to suspend your efforts for a few days anyway. Whatever version you choose, - ideally use a 'vanilla' build. Ignoring these advices will dramatically + ideally use a 'vanilla' build. Ignoring all of this advice will dramatically increase the risk your report will be rejected or ignored. * Ensure the kernel you just installed does not 'taint' itself when @@ -795,7 +795,7 @@ Install a fresh kernel for testing situations; during the merge window that actually might be even the best approach, but in that development phase it can be an even better idea to suspend your efforts for a few days anyway. Whatever version you choose, - ideally use a 'vanilla' built. Ignoring these advices will dramatically + ideally use a 'vanilla' built. Ignoring all of this advice will dramatically increase the risk your report will be rejected or ignored.* As mentioned in the detailed explanation for the first step already: Like most From 3859c1a7967be31b63b9c0f51ad1d23f54f0b280 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:34 +0200 Subject: [PATCH 302/655] docs: maintainers_include: keep hidden TOC sorted There's no practical difference on keeping it sorted, but it helps a lot when checking for differences after patches to the tool. Signed-off-by: Mauro Carvalho Chehab Message-ID: Signed-off-by: Jonathan Corbet Message-ID: <2742993764f2193101536a1cea40e034d75e0539.1778309595.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 436e7ac42ffc..694cdbdc4caf 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -265,7 +265,7 @@ class MaintainersProfile(Include): output += "\n.. toctree::\n" output += " :hidden:\n\n" - for fname in maint_parser.profile_toc: + for fname in sorted(maint_parser.profile_toc): output += f" {fname}\n" output += "\n" From 4cd160e4eaa894d65a04716ced87b0dccdfe290d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:35 +0200 Subject: [PATCH 303/655] docs: maintainers_include: split state machine on multiple funcs Instead of one big __init__ code, split the MaintainersParser code in a way that the state machine remains on __init__, but the actual parser for descriptions and subsystems are moved to separate functions. To make parser easier, instead storing parsed results on a list, place them directly on a string. That granted 15% of performance increase(*) with Python 3.14 and made the logic simpler. (*) measured by creating a new directory under Documentation/, and placing justmaintainers.rst and an index file there, building it via sphinx-build-wrapper. Signed-off-by: Mauro Carvalho Chehab Message-ID: <0b72530cf496ce5e2987ca784058a50f4dc814d2.1777987027.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: <26376e92a5e31e5d285b8676ed443a247b42e4c5.1778309595.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 297 +++++++++++--------- 1 file changed, 158 insertions(+), 139 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 694cdbdc4caf..6d47d55f5b73 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -47,167 +47,186 @@ class MaintainersParser: self.profile_toc = set() self.profile_entries = {} - result = list() - result.append(".. _maintainers:") - result.append("") + self.output = ".. _maintainers:\n\n" # Poor man's state machine. - descriptions = False - maintainers = False - subsystems = False + self.descriptions = False + self.maintainers = False + self.subsystems = False # Field letter to field name mapping. - field_letter = None - fields = dict() + self.field_letter = None + self.fields = dict() + + self.field_prev = "" + self.field_content = "" + self.subsystem_name = None + + self.app_dir = app_dir + self.base_dir, self.doc_dir, self.sphinx_dir = app_dir.partition("Documentation") + + self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)') prev = None - field_prev = "" - field_content = "" - subsystem_name = None - - base_dir, doc_dir, sphinx_dir = app_dir.partition("Documentation") - for line in open(path): - # Have we reached the end of the preformatted Descriptions text? - if descriptions and line.startswith('Maintainers'): - descriptions = False - # Ensure a blank line following the last "|"-prefixed line. - result.append("") - - # Start subsystem processing? This is to skip processing the text - # between the Maintainers heading and the first subsystem name. - if maintainers and not subsystems: + if self.descriptions: + self.parse_descriptions(line) + elif self.maintainers and not self.subsystems: if re.search('^[A-Z0-9]', line): - subsystems = True - - # Drop needless input whitespace. - line = line.rstrip() - - # - # Handle profile entries - either as files or as https refs - # - match = re.match(rf"P:\s*({doc_dir})(/\S+)\.rst", line) - if match: - name = "".join(match.groups()) - entry = os.path.relpath(base_dir + name, app_dir) - - full_name = os.path.join(base_dir, name) - path = os.path.relpath(full_name, app_dir) - # - # When SPHINXDIRS is used, it will try to reference files - # outside srctree, causing warnings. To avoid that, point - # to the latest official documentation - # - if path.startswith("../"): - entry = KERNELDOC_URL + match.group(2) + ".html" + self.subsystems = True + self.parse_subsystems(line) else: - entry = "/" + entry - - if "*" in entry: - for e in glob(entry): - self.profile_toc.add(e) - self.profile_entries[subsystem_name] = e - else: - self.profile_toc.add(entry) - self.profile_entries[subsystem_name] = entry + self.output += line + elif self.subsystems: + self.parse_subsystems(line) else: - match = re.match(r"P:\s*(https?://.*)", line) - if match: - entry = match.group(1).strip() - self.profile_entries[subsystem_name] = entry - - # Linkify all non-wildcard refs to ReST files in Documentation/. - pat = r'(Documentation/([^\s\?\*]*)\.rst)' - m = re.search(pat, line) - if m: - # maintainers.rst is in a subdirectory, so include "../". - line = re.sub(pat, ':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line) - - # Check state machine for output rendering behavior. - output = None - if descriptions: - # Escape the escapes in preformatted text. - output = "| %s" % (line.replace("\\", "\\\\")) - # Look for and record field letter to field name mappings: - # R: Designated *reviewer*: FullName - m = re.search(r"\s(\S):\s", line) - if m: - field_letter = m.group(1) - if field_letter and not field_letter in fields: - m = re.search(r"\*([^\*]+)\*", line) - if m: - fields[field_letter] = m.group(1) - elif subsystems: - # Skip empty lines: subsystem parser adds them as needed. - if len(line) == 0: - continue - # Subsystem fields are batched into "field_content" - if line[1] != ':': - # Render a subsystem entry as: - # SUBSYSTEM NAME - # ~~~~~~~~~~~~~~ - - # Flush pending field content. - output = field_content + "\n\n" - field_content = "" - - subsystem_name = line.title() - - # Collapse whitespace in subsystem name. - heading = re.sub(r"\s+", " ", line) - output = output + "%s\n%s" % (heading, "~" * len(heading)) - field_prev = "" - else: - # Render a subsystem field as: - # :Field: entry - # entry... - field, details = line.split(':', 1) - details = details.strip() - - # Mark paths (and regexes) as literal text for improved - # readability and to escape any escapes. - if field in ['F', 'N', 'X', 'K']: - # But only if not already marked :) - if not ':doc:' in details: - details = '``%s``' % (details) - - # Comma separate email field continuations. - if field == field_prev and field_prev in ['M', 'R', 'L']: - field_content = field_content + "," - - # Do not repeat field names, so that field entries - # will be collapsed together. - if field != field_prev: - output = field_content + "\n" - field_content = ":%s:" % (fields.get(field, field)) - field_content = field_content + "\n\t%s" % (details) - field_prev = field - else: - output = line - - # Re-split on any added newlines in any above parsing. - if output != None: - for separated in output.split('\n'): - result.append(separated) + self.output += line # Update the state machine when we find heading separators. if line.startswith('----------'): if prev.startswith('Descriptions'): - descriptions = True + self.descriptions = True if prev.startswith('Maintainers'): - maintainers = True + self.maintainers = True # Retain previous line for state machine transitions. prev = line # Flush pending field contents. - if field_content != "": - for separated in field_content.split('\n'): - result.append(separated) + if self.field_content: + self.output += self.field_content + "\n\n" - self.output = "\n".join(result) + self.output = self.output.rstrip() + + def parse_descriptions(self, line): + """Handle contents of the descriptions section.""" + + # Have we reached the end of the preformatted Descriptions text? + if line.startswith('Maintainers'): + self.descriptions = False + self.output += "\n" + line + return + + # Linkify all non-wildcard refs to ReST files in Documentation/. + m = self.re_doc.search(line) + if m: + # maintainers.rst is in a subdirectory, so include "../". + line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line) + + # Escape the escapes in preformatted text. + output = "| %s" % (line.replace("\\", "\\\\")) + + # Look for and record field letter to field name mappings: + # R: Designated *reviewer*: FullName + m = re.search(r"\s(\S):\s", line) + if m: + self.field_letter = m.group(1) + + if self.field_letter and self.field_letter not in self.fields: + m = re.search(r"\*([^\*]+)\*", line) + if m: + self.fields[self.field_letter] = m.group(1) + + # Append parsed content to self.output + self.output += output + + def parse_subsystems(self, line): + """Handle contents of the per-subsystem sections.""" + + # Drop needless input whitespace. + line = line.rstrip() + + # + # Handle profile entries - either as files or as https refs + # + match = re.match(rf"P:\s*({self.doc_dir})(/\S+)\.rst", line) + if match: + name = "".join(match.groups()) + entry = os.path.relpath(self.base_dir + name, self.app_dir) + + full_name = os.path.join(self.base_dir, name) + path = os.path.relpath(full_name, self.app_dir) + # + # When SPHINXDIRS is used, it will try to reference files + # outside srctree, causing warnings. To avoid that, point + # to the latest official documentation + # + if path.startswith("../"): + entry = KERNELDOC_URL + match.group(2) + ".html" + else: + entry = "/" + entry + + if "*" in entry: + for e in glob(entry): + self.profile_toc.add(e) + self.profile_entries[self.subsystem_name] = e + else: + self.profile_toc.add(entry) + self.profile_entries[self.subsystem_name] = entry + else: + match = re.match(r"P:\s*(https?://.*)", line) + if match: + entry = match.group(1).strip() + self.profile_entries[self.subsystem_name] = entry + + # Linkify all non-wildcard refs to ReST files in Documentation/. + m = self.re_doc.search(line) + if m: + # maintainers.rst is in a subdirectory, so include "../". + line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line) + + # Check state machine for output rendering behavior. + output = None + if self.subsystems: + # Skip empty lines: subsystem parser adds them as needed. + if len(line) == 0: + return + # Subsystem fields are batched into "field_content" + if line[1] != ':': + # Render a subsystem entry as: + # SUBSYSTEM NAME + # ~~~~~~~~~~~~~~ + # Flush pending field content. + output = self.field_content + "\n\n" + self.field_content = "" + + self.subsystem_name = line.title() + + # Collapse whitespace in subsystem name. + heading = re.sub(r"\s+", " ", line) + output = output + "%s\n%s" % (heading, "~" * len(heading)) + self.field_prev = "" + else: + # Render a subsystem field as: + # :Field: entry + # entry... + field, details = line.split(':', 1) + details = details.strip() + + # Mark paths (and regexes) as literal text for improved + # readability and to escape any escapes. + if field in ['F', 'N', 'X', 'K']: + # But only if not already marked :) + if not ':doc:' in details: + details = '``%s``' % (details) + + # Comma separate email field continuations. + if field == self.field_prev and self.field_prev in ['M', 'R', 'L']: + self.field_content = self.field_content + "," + + # Do not repeat field names, so that field entries + # will be collapsed together. + if field != self.field_prev: + output = self.field_content + "\n" + self.field_content = ":%s:" % (self.fields.get(field, field)) + self.field_content = self.field_content + "\n\t%s" % (details) + self.field_prev = field + elif not self.descriptions: + output = line + + if output is not None: + self.output += output + "\n" - # Create a TOC class class MaintainersInclude(Include): """MaintainersInclude (``maintainers-include``) directive""" From ec027efe85308b6b8e87637f2675c16b86a3ac99 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:36 +0200 Subject: [PATCH 304/655] docs: maintainers_include: cleanup the code Simplify the logic without affecting the output result. Signed-off-by: Mauro Carvalho Chehab Message-ID: <24a83995778de8710cac40a3089c2f2fe5c38dbd.1777987027.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: <5f48bf411925e923d206239a4de0a3e34592de88.1778309595.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 184 ++++++++++---------- 1 file changed, 91 insertions(+), 93 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 6d47d55f5b73..615af227a8f8 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -44,10 +44,6 @@ class MaintainersParser: def __init__(self, app_dir, path): self.path = path - self.profile_toc = set() - self.profile_entries = {} - - self.output = ".. _maintainers:\n\n" # Poor man's state machine. self.descriptions = False @@ -67,6 +63,13 @@ class MaintainersParser: self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)') + # + # Output variables with maintainers content to be stored + # + self.profile_toc = set() + self.profile_entries = {} + self.output = ".. _maintainers:\n\n" + prev = None for line in open(path): if self.descriptions: @@ -98,6 +101,16 @@ class MaintainersParser: self.output = self.output.rstrip() + + def linkify(self, text): + """Linkify all non-wildcard refs to ReST files in Documentation/""" + m = self.re_doc.search(text) + if m: + # maintainers.rst is in a subdirectory, so include "../". + text = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), text) + + return text + def parse_descriptions(self, line): """Handle contents of the descriptions section.""" @@ -107,14 +120,8 @@ class MaintainersParser: self.output += "\n" + line return - # Linkify all non-wildcard refs to ReST files in Documentation/. - m = self.re_doc.search(line) - if m: - # maintainers.rst is in a subdirectory, so include "../". - line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line) - # Escape the escapes in preformatted text. - output = "| %s" % (line.replace("\\", "\\\\")) + self.output += "| " + self.linkify(line).replace("\\", "\\\\") # Look for and record field letter to field name mappings: # R: Designated *reviewer*: FullName @@ -127,105 +134,96 @@ class MaintainersParser: if m: self.fields[self.field_letter] = m.group(1) - # Append parsed content to self.output - self.output += output - def parse_subsystems(self, line): """Handle contents of the per-subsystem sections.""" # Drop needless input whitespace. line = line.rstrip() + # Skip empty lines: subsystem parser adds them as needed. + if not line: + return + + # Subsystem fields are batched into "field_content" + if line[1] != ':': + line = self.linkify(line) + + # Render a subsystem entry as: + # SUBSYSTEM NAME + # ~~~~~~~~~~~~~~ + # Flush pending field content. + self.output += self.field_content + "\n\n" + self.field_content = "" + + self.subsystem_name = line.title() + + # Collapse whitespace in subsystem name. + heading = re.sub(r"\s+", " ", line) + self.output += "%s\n%s" % (heading, "~" * len(heading)) + "\n" + self.field_prev = "" + + return + + # Render a subsystem field as: + # :Field: entry + # entry... + field, details = line.split(':', 1) + details = details.strip() + # # Handle profile entries - either as files or as https refs # - match = re.match(rf"P:\s*({self.doc_dir})(/\S+)\.rst", line) - if match: - name = "".join(match.groups()) - entry = os.path.relpath(self.base_dir + name, self.app_dir) - - full_name = os.path.join(self.base_dir, name) - path = os.path.relpath(full_name, self.app_dir) - # - # When SPHINXDIRS is used, it will try to reference files - # outside srctree, causing warnings. To avoid that, point - # to the latest official documentation - # - if path.startswith("../"): - entry = KERNELDOC_URL + match.group(2) + ".html" - else: - entry = "/" + entry - - if "*" in entry: - for e in glob(entry): - self.profile_toc.add(e) - self.profile_entries[self.subsystem_name] = e - else: - self.profile_toc.add(entry) - self.profile_entries[self.subsystem_name] = entry - else: - match = re.match(r"P:\s*(https?://.*)", line) + if field == "P": + match = self.re_doc.match(details) if match: - entry = match.group(1).strip() - self.profile_entries[self.subsystem_name] = entry + name = "".join(match.groups()) + entry = os.path.relpath(self.base_dir + name, self.app_dir) - # Linkify all non-wildcard refs to ReST files in Documentation/. - m = self.re_doc.search(line) - if m: - # maintainers.rst is in a subdirectory, so include "../". - line = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line) + full_name = os.path.join(self.base_dir, name) + path = os.path.relpath(full_name, self.app_dir) + # + # When SPHINXDIRS is used, it will try to reference files + # outside srctree, causing warnings. To avoid that, point + # to the latest official documentation + # + if path.startswith("../"): + entry = KERNELDOC_URL + "/" + match.group(2) + ".html" + else: + entry = "/" + entry - # Check state machine for output rendering behavior. - output = None - if self.subsystems: - # Skip empty lines: subsystem parser adds them as needed. - if len(line) == 0: - return - # Subsystem fields are batched into "field_content" - if line[1] != ':': - # Render a subsystem entry as: - # SUBSYSTEM NAME - # ~~~~~~~~~~~~~~ - # Flush pending field content. - output = self.field_content + "\n\n" - self.field_content = "" - - self.subsystem_name = line.title() - - # Collapse whitespace in subsystem name. - heading = re.sub(r"\s+", " ", line) - output = output + "%s\n%s" % (heading, "~" * len(heading)) - self.field_prev = "" + if "*" in entry: + for e in glob(entry): + self.profile_toc.add(e) + self.profile_entries[self.subsystem_name] = e + else: + self.profile_toc.add(entry) + self.profile_entries[self.subsystem_name] = entry else: - # Render a subsystem field as: - # :Field: entry - # entry... - field, details = line.split(':', 1) - details = details.strip() + match = re.match(r"(https?://.*)", details) + if match: + entry = match.group(1).strip() + self.profile_entries[self.subsystem_name] = entry - # Mark paths (and regexes) as literal text for improved - # readability and to escape any escapes. - if field in ['F', 'N', 'X', 'K']: - # But only if not already marked :) - if not ':doc:' in details: - details = '``%s``' % (details) + details = self.linkify(details) - # Comma separate email field continuations. - if field == self.field_prev and self.field_prev in ['M', 'R', 'L']: - self.field_content = self.field_content + "," + # Mark paths (and regexes) as literal text for improved + # readability and to escape any escapes. + if field in ['F', 'N', 'X', 'K']: + # But only if not already marked :) + if not ':doc:' in details: + details = '``%s``' % (details) - # Do not repeat field names, so that field entries - # will be collapsed together. - if field != self.field_prev: - output = self.field_content + "\n" - self.field_content = ":%s:" % (self.fields.get(field, field)) - self.field_content = self.field_content + "\n\t%s" % (details) - self.field_prev = field - elif not self.descriptions: - output = line + # Comma separate email field continuations. + if field == self.field_prev and self.field_prev in ['M', 'R', 'L']: + self.field_content = self.field_content + "," - if output is not None: - self.output += output + "\n" + # Do not repeat field names, so that field entries + # will be collapsed together. + if field != self.field_prev: + self.output += self.field_content + "\n\n" + self.field_content = ":%s:" % (self.fields.get(field, field)) + self.field_content = self.field_content + "\n\t%s" % (details) + self.field_prev = field class MaintainersInclude(Include): From 8cf515e2597f90b0a460777a56d6dd3e8495f533 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:37 +0200 Subject: [PATCH 305/655] docs: maintainers_include: clean most SPHINXDIRS=process warnings building docs with SPHINXDIRS=process is too noisy, as it generates lots of undefined refs. Fixing it is easy: just let linkify generate html URLs for the broken links when SPHINXDIRS is used. Signed-off-by: Mauro Carvalho Chehab Message-ID: Signed-off-by: Jonathan Corbet Message-ID: <567200712771590d08e4da096b4def92bf729ffe.1778309595.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 44 +++++++++++++++------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 615af227a8f8..d3ad01e5309e 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -58,8 +58,8 @@ class MaintainersParser: self.field_content = "" self.subsystem_name = None - self.app_dir = app_dir - self.base_dir, self.doc_dir, self.sphinx_dir = app_dir.partition("Documentation") + self.app_dir = os.path.abspath(app_dir) + self.base_dir, _, self.sphinx_dir = self.app_dir.partition("Documentation") self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)') @@ -104,10 +104,25 @@ class MaintainersParser: def linkify(self, text): """Linkify all non-wildcard refs to ReST files in Documentation/""" + m = self.re_doc.search(text) if m: - # maintainers.rst is in a subdirectory, so include "../". - text = self.re_doc.sub(':doc:`%s <../%s>`' % (m.group(2), m.group(2)), text) + fname = m.group(1) + ename = m.group(2) + + entry = os.path.relpath(self.base_dir + fname, self.app_dir) + entry = entry.removesuffix(".rst") + + # + # When SPHINXDIRS is used, it will try to reference files + # outside srctree, causing warnings. To avoid that, point + # to the latest official documentation + # + if entry.startswith("../"): + html = KERNELDOC_URL + ename + ".html" + text = self.re_doc.sub(f'`{ename} <{html}>`_', text) + else: + text = self.re_doc.sub(f':doc:`{ename} `', text) return text @@ -176,27 +191,32 @@ class MaintainersParser: if field == "P": match = self.re_doc.match(details) if match: - name = "".join(match.groups()) - entry = os.path.relpath(self.base_dir + name, self.app_dir) + fname = match.group(1) + ename = match.group(2) - full_name = os.path.join(self.base_dir, name) - path = os.path.relpath(full_name, self.app_dir) + entry = os.path.relpath(self.base_dir + fname, self.app_dir) + entry = entry.removesuffix(".rst") # # When SPHINXDIRS is used, it will try to reference files # outside srctree, causing warnings. To avoid that, point # to the latest official documentation # - if path.startswith("../"): - entry = KERNELDOC_URL + "/" + match.group(2) + ".html" + + if entry.startswith("../"): + entry = KERNELDOC_URL + ename + ".html" else: entry = "/" + entry if "*" in entry: for e in glob(entry): - self.profile_toc.add(e) + if "html" not in e: + self.profile_toc.add(e) + self.profile_entries[self.subsystem_name] = e else: - self.profile_toc.add(entry) + if "html" not in entry: + self.profile_toc.add(entry) + self.profile_entries[self.subsystem_name] = entry else: match = re.match(r"(https?://.*)", details) From b15fd8c043f79d57c6bf56edb4cf036644842647 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:38 +0200 Subject: [PATCH 306/655] docs: maintainers_include: do some coding style cleanups Minor coding style adjustments to use the style most python doc scripts are following. No functional changes. Assisted-by: pylint, black Signed-off-by: Mauro Carvalho Chehab Message-ID: <460aabd0518f080b34e12fdc0beb7ec7685d5866.1777987027.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/sphinx/maintainers_include.py | 101 ++++++++++---------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index d3ad01e5309e..345eb28804ff 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -1,30 +1,25 @@ #!/usr/bin/env python # SPDX-License-Identifier: GPL-2.0 # -*- coding: utf-8; mode: python -*- -# pylint: disable=R0903, C0330, R0914, R0912, E0401 +# pylint: disable=C0209, C0301, E0401, R0022, R0902, R0903, R0912, R0914 """ - maintainers-include - ~~~~~~~~~~~~~~~~~~~ +Implementation of the ``maintainers-include`` reST-directive. - Implementation of the ``maintainers-include`` reST-directive. +:copyright: Copyright (C) 2019 Kees Cook +:license: GPL Version 2, June 1991 see linux/COPYING for details. - :copyright: Copyright (C) 2019 Kees Cook - :license: GPL Version 2, June 1991 see linux/COPYING for details. - - The ``maintainers-include`` reST-directive performs extensive parsing - specific to the Linux kernel's standard "MAINTAINERS" file, in an - effort to avoid needing to heavily mark up the original plain text. +The ``maintainers-include`` reST-directive performs extensive parsing +specific to the Linux kernel's standard "MAINTAINERS" file, in an +effort to avoid needing to heavily mark up the original plain text. """ -import sys -import re import os.path +import re from glob import glob from docutils import statemachine -from docutils.parsers.rst import Directive from docutils.parsers.rst.directives.misc import Include # @@ -32,12 +27,14 @@ from docutils.parsers.rst.directives.misc import Include # KERNELDOC_URL = "https://docs.kernel.org/" -def ErrorString(exc): # Shamelessly stolen from docutils - return f'{exc.__class__.__name}: {exc}' +__version__ = "1.0" -__version__ = '1.0' +maint_parser = None # pylint: disable=C0103 -maint_parser = None + +# Shamelessly stolen from docutils +def ErrorString(exc): # pylint: disable=C0103, C0116 + return f"{exc.__class__.__name}: {exc}" # pylint: disable=W0212 class MaintainersParser: """Parse MAINTAINERS file(s) content""" @@ -52,7 +49,7 @@ class MaintainersParser: # Field letter to field name mapping. self.field_letter = None - self.fields = dict() + self.fields = {} self.field_prev = "" self.field_content = "" @@ -71,29 +68,30 @@ class MaintainersParser: self.output = ".. _maintainers:\n\n" prev = None - for line in open(path): - if self.descriptions: - self.parse_descriptions(line) - elif self.maintainers and not self.subsystems: - if re.search('^[A-Z0-9]', line): - self.subsystems = True + with open(path, "r", encoding="utf-8") as fp: + for line in fp: + if self.descriptions: + self.parse_descriptions(line) + elif self.maintainers and not self.subsystems: + if re.search('^[A-Z0-9]', line): + self.subsystems = True + self.parse_subsystems(line) + else: + self.output += line + elif self.subsystems: self.parse_subsystems(line) else: self.output += line - elif self.subsystems: - self.parse_subsystems(line) - else: - self.output += line - # Update the state machine when we find heading separators. - if line.startswith('----------'): - if prev.startswith('Descriptions'): - self.descriptions = True - if prev.startswith('Maintainers'): - self.maintainers = True + # Update the state machine when we find heading separators. + if line.startswith("----------"): + if prev.startswith("Descriptions"): + self.descriptions = True + if prev.startswith("Maintainers"): + self.maintainers = True - # Retain previous line for state machine transitions. - prev = line + # Retain previous line for state machine transitions. + prev = line # Flush pending field contents. if self.field_content: @@ -130,7 +128,7 @@ class MaintainersParser: """Handle contents of the descriptions section.""" # Have we reached the end of the preformatted Descriptions text? - if line.startswith('Maintainers'): + if line.startswith("Maintainers"): self.descriptions = False self.output += "\n" + line return @@ -182,7 +180,7 @@ class MaintainersParser: # Render a subsystem field as: # :Field: entry # entry... - field, details = line.split(':', 1) + field, details = line.split(":", 1) details = details.strip() # @@ -248,12 +246,11 @@ class MaintainersParser: class MaintainersInclude(Include): """MaintainersInclude (``maintainers-include``) directive""" + required_arguments = 0 def emit(self): """Parse all the MAINTAINERS lines into ReST for human-readability""" - global maint_parser - path = maint_parser.path output = maint_parser.output @@ -269,20 +266,21 @@ class MaintainersInclude(Include): raise self.warning('"%s" directive disabled.' % self.name) try: - lines = self.emit() + self.emit() except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) return [] + class MaintainersProfile(Include): + """Generate a list with all maintainer's profiles""" + required_arguments = 0 def emit(self): """Parse all the MAINTAINERS lines looking for profile entries""" - global maint_parser - path = maint_parser.path # @@ -316,15 +314,17 @@ class MaintainersProfile(Include): raise self.warning('"%s" directive disabled.' % self.name) try: - lines = self.emit() + self.emit() except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) return [] + def setup(app): - global maint_parser + """Setup Sphinx extension""" + global maint_parser # pylint: disable=W0603 # # NOTE: we're using os.fspath() here because of a Sphinx warning: @@ -338,8 +338,9 @@ def setup(app): app.add_directive("maintainers-include", MaintainersInclude) app.add_directive("maintainers-profile-toc", MaintainersProfile) - return dict( - version = __version__, - parallel_read_safe = True, - parallel_write_safe = True - ) + + return { + "version": __version__, + "parallel_read_safe": True, + "parallel_write_safe": True, + } From 1aac8eff9a9e6d6e23909bd4aaa583a98a8f850a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:39 +0200 Subject: [PATCH 307/655] docs: maintainers_include: store maintainers entries on a dict Instead of creating just a big output data, store entries inside a dictionary. Doing that simplifies the parser a little bit and make the code clearer. Signed-off-by: Mauro Carvalho Chehab Message-ID: <4ad88179e03436984f29780ae380d50591f86c67.1777987027.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/sphinx/maintainers_include.py | 70 +++++++++------------ 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 345eb28804ff..ed9cd7b3dc66 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -49,10 +49,7 @@ class MaintainersParser: # Field letter to field name mapping. self.field_letter = None - self.fields = {} - self.field_prev = "" - self.field_content = "" self.subsystem_name = None self.app_dir = os.path.abspath(app_dir) @@ -65,7 +62,9 @@ class MaintainersParser: # self.profile_toc = set() self.profile_entries = {} - self.output = ".. _maintainers:\n\n" + self.header = ".. _maintainers:\n\n" + self.maint_entries = {} + self.fields = {} prev = None with open(path, "r", encoding="utf-8") as fp: @@ -77,11 +76,11 @@ class MaintainersParser: self.subsystems = True self.parse_subsystems(line) else: - self.output += line + self.header += line elif self.subsystems: self.parse_subsystems(line) else: - self.output += line + self.header += line # Update the state machine when we find heading separators. if line.startswith("----------"): @@ -93,13 +92,6 @@ class MaintainersParser: # Retain previous line for state machine transitions. prev = line - # Flush pending field contents. - if self.field_content: - self.output += self.field_content + "\n\n" - - self.output = self.output.rstrip() - - def linkify(self, text): """Linkify all non-wildcard refs to ReST files in Documentation/""" @@ -130,11 +122,11 @@ class MaintainersParser: # Have we reached the end of the preformatted Descriptions text? if line.startswith("Maintainers"): self.descriptions = False - self.output += "\n" + line + self.header += "\n" + line return # Escape the escapes in preformatted text. - self.output += "| " + self.linkify(line).replace("\\", "\\\\") + self.header += "| " + self.linkify(line).replace("\\", "\\\\") # Look for and record field letter to field name mappings: # R: Designated *reviewer*: FullName @@ -157,24 +149,8 @@ class MaintainersParser: if not line: return - # Subsystem fields are batched into "field_content" if line[1] != ':': - line = self.linkify(line) - - # Render a subsystem entry as: - # SUBSYSTEM NAME - # ~~~~~~~~~~~~~~ - # Flush pending field content. - self.output += self.field_content + "\n\n" - self.field_content = "" - - self.subsystem_name = line.title() - - # Collapse whitespace in subsystem name. - heading = re.sub(r"\s+", " ", line) - self.output += "%s\n%s" % (heading, "~" * len(heading)) + "\n" - self.field_prev = "" - + self.subsystem_name = re.sub(r"\s+", " ", self.linkify(line)) return # Render a subsystem field as: @@ -224,23 +200,23 @@ class MaintainersParser: details = self.linkify(details) + # # Mark paths (and regexes) as literal text for improved # readability and to escape any escapes. + # if field in ['F', 'N', 'X', 'K']: # But only if not already marked :) if not ':doc:' in details: details = '``%s``' % (details) - # Comma separate email field continuations. - if field == self.field_prev and self.field_prev in ['M', 'R', 'L']: - self.field_content = self.field_content + "," + if self.subsystem_name not in self.maint_entries: + self.maint_entries[self.subsystem_name] = {} + + if field not in self.maint_entries[self.subsystem_name]: + self.maint_entries[self.subsystem_name][field] = [] + + self.maint_entries[self.subsystem_name][field].append(details) - # Do not repeat field names, so that field entries - # will be collapsed together. - if field != self.field_prev: - self.output += self.field_content + "\n\n" - self.field_content = ":%s:" % (self.fields.get(field, field)) - self.field_content = self.field_content + "\n\t%s" % (details) self.field_prev = field @@ -252,7 +228,15 @@ class MaintainersInclude(Include): def emit(self): """Parse all the MAINTAINERS lines into ReST for human-readability""" path = maint_parser.path - output = maint_parser.output + output = maint_parser.header + + for name, fields in sorted(maint_parser.maint_entries.items()): + output += "\n" + name + "\n" + output += "~" * len(name) + "\n" + + for field, lines in fields.items(): + field_name = maint_parser.fields.get(field, field) + output += f":{field_name}:\n\t" + ",\n\t".join(lines) + "\n\n" # For debugging the pre-rendered results... #print(output, file=open("/tmp/MAINTAINERS.rst", "w")) @@ -288,6 +272,8 @@ class MaintainersProfile(Include): # output = "" for profile, entry in sorted(maint_parser.profile_entries.items()): + profile = profile.title() + if entry.startswith("http"): output += f"- `{profile} <{entry}>`_\n" else: From 083f0b10f540ae16009a26cd441d7dc6f94e1c13 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:40 +0200 Subject: [PATCH 308/655] docs: maintainers_include: properly handle file patterns handling asterisks inside file patterns atdescription part is problematic, as ReST has special meaning for them. Due to that, convert such patterns to literal strings. Reported-by: Matteo Croce Fixes: 420849332f9f ("get_maintainer: add ** glob pattern support") Signed-off-by: Mauro Carvalho Chehab Message-ID: <89127706fb3493d00ecb21e528c8a27081e5ed40.1777987027.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/sphinx/maintainers_include.py | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index ed9cd7b3dc66..5361774b61bc 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -47,9 +47,6 @@ class MaintainersParser: self.maintainers = False self.subsystems = False - # Field letter to field name mapping. - self.field_letter = None - self.subsystem_name = None self.app_dir = os.path.abspath(app_dir) @@ -125,19 +122,22 @@ class MaintainersParser: self.header += "\n" + line return - # Escape the escapes in preformatted text. - self.header += "| " + self.linkify(line).replace("\\", "\\\\") - # Look for and record field letter to field name mappings: # R: Designated *reviewer*: FullName - m = re.search(r"\s(\S):\s", line) + m = re.match(r"\s+(\S):\s+(\S+)", line) if m: - self.field_letter = m.group(1) + field = m.group(1) + details = m.group(2) + + if field not in self.fields: + m = re.search(r"\*([^\*]+)\*", line) + if m: + self.fields[field] = m.group(1) + elif field in ['F', 'N', 'X', 'K']: + line = line.replace(details, f'``{details}``') + + self.header += "| " + self.linkify(line) - if self.field_letter and self.field_letter not in self.fields: - m = re.search(r"\*([^\*]+)\*", line) - if m: - self.fields[self.field_letter] = m.group(1) def parse_subsystems(self, line): """Handle contents of the per-subsystem sections.""" @@ -206,7 +206,7 @@ class MaintainersParser: # if field in ['F', 'N', 'X', 'K']: # But only if not already marked :) - if not ':doc:' in details: + if ':doc:' not in details and "http" not in details: details = '``%s``' % (details) if self.subsystem_name not in self.maint_entries: From 11bb115dd5b04d2188894da096555466537480b3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:41 +0200 Subject: [PATCH 309/655] docs: maintainers_include: add a filtering javascript The maintainers table is big. Add a javascript to allow filtering it. Such script is only added at the page which contains the maintainers-include tag. I opted to keep the search case-sensitive, as, this way, upper case searches at subsystem. Signed-off-by: Mauro Carvalho Chehab Message-ID: Signed-off-by: Jonathan Corbet Message-ID: <6f87c233351595358fddba11d42171be464f0a65.1778309595.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 78 +++++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 5361774b61bc..7035754a1c66 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -31,6 +31,49 @@ __version__ = "1.0" maint_parser = None # pylint: disable=C0103 +JS_FILTER = """ +(function() { + function filterTable(table) { + const filter = document.getElementById("filter-table").value.trim(); + const rows = table.querySelectorAll("tbody tr"); + for (let i = 0; i < rows.length; i++) { + const tds = rows[i].getElementsByTagName("td"); + let match = false; + for (let j = 0; j < tds.length; j++) { + const cellText = (tds[j].textContent || tds[j].innerText); + if (cellText.includes(filter)) { + match = true; + break; + } + } + rows[i].style.display = match ? "table-row" : "none"; + } + } + function addInput() { + const table = document.getElementById("maintainers-table"); + if (!table) return; + let input = document.getElementById("filter-table"); + if (!input) { + const filt_div = document.createElement('div'); + filt_div.innerHTML = ` +

Filter: + + subsystem or property (case-sensitive) +

+ `; + table.parentNode.insertBefore(filt_div, table); + const input = document.getElementById("filter-table") + input.addEventListener('input', () => filterTable(table)); + } + } + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', addInput); + } else { + addInput(); + } +})(); +""" + # Shamelessly stolen from docutils def ErrorString(exc): # pylint: disable=C0103, C0116 @@ -59,7 +102,7 @@ class MaintainersParser: # self.profile_toc = set() self.profile_entries = {} - self.header = ".. _maintainers:\n\n" + self.header = "" self.maint_entries = {} self.fields = {} @@ -228,15 +271,28 @@ class MaintainersInclude(Include): def emit(self): """Parse all the MAINTAINERS lines into ReST for human-readability""" path = maint_parser.path - output = maint_parser.header + output = ".. _maintainers:\n\n" + output += maint_parser.header + + output += ".. _maintainers_table:\n\n" + output += ".. flat-table::\n" + output += " :header-rows: 1\n\n" + output += " * - Subsystem\n" + output += " - Properties\n\n" + + self.state.document['maintainers_included'] = True for name, fields in sorted(maint_parser.maint_entries.items()): - output += "\n" + name + "\n" - output += "~" * len(name) + "\n" - + output += f" * - {name}\n" + tag = "-" for field, lines in fields.items(): field_name = maint_parser.fields.get(field, field) - output += f":{field_name}:\n\t" + ",\n\t".join(lines) + "\n\n" + + output += f" {tag} :{field_name}:\n " + output += ",\n ".join(lines) + "\n" + tag = " " + + output += "\n" # For debugging the pre-rendered results... #print(output, file=open("/tmp/MAINTAINERS.rst", "w")) @@ -308,6 +364,14 @@ class MaintainersProfile(Include): return [] +# pylint: disable=W0613 +def add_filter_script(app, pagename, templatename, context, doctree): + """Add Filter javascript only to maintainers page""" + + if doctree and doctree.get('maintainers_included'): + app.add_js_file(None, body=JS_FILTER) + + def setup(app): """Setup Sphinx extension""" global maint_parser # pylint: disable=W0603 @@ -325,6 +389,8 @@ def setup(app): app.add_directive("maintainers-include", MaintainersInclude) app.add_directive("maintainers-profile-toc", MaintainersProfile) + app.connect("html-page-context", add_filter_script) + return { "version": __version__, "parallel_read_safe": True, From 247cb381a5a474aee3865980404e33403cb6d10a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:42 +0200 Subject: [PATCH 310/655] docs: maintainers_include: don't ignore invalid profile entries Currently, there is a "P" entry for Rust pin-init that is neither a valid ReST file inside Documentation nor an URL. A proper fix is to either convert/move the file or point to a URL. Yet, the parser should be able to pick what's there and show on its output. Add a logic to produce a warning when this happens. Message-ID: <63228e005fcf3dc4583cee06905341e8bce84181.1777987027.git.mchehab+huawei@kernel.org> Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <98915f35442fa12c6d59611083aea3adbf8c6aff.1778309595.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 7035754a1c66..073a10575872 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -240,6 +240,8 @@ class MaintainersParser: if match: entry = match.group(1).strip() self.profile_entries[self.subsystem_name] = entry + else: + self.profile_entries[self.subsystem_name] = f"``{details}``" details = self.linkify(details) @@ -328,12 +330,15 @@ class MaintainersProfile(Include): # output = "" for profile, entry in sorted(maint_parser.profile_entries.items()): - profile = profile.title() + name = profile.title() if entry.startswith("http"): - output += f"- `{profile} <{entry}>`_\n" + output += f"- `{name} <{entry}>`_\n" + elif entry.startswith("`"): + output += f"- {name}: {entry}\n" + self.warning(f"{profile}: Invalid 'P' tag: {entry}\n") else: - output += f"- :doc:`{profile} <{entry}>`\n" + output += f"- :doc:`{name} <{entry}>`\n" # # Create a hidden TOC table with all profiles. That allows adding From 84a9658e842b86b949f39e42f26f5400ba972ab0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:43 +0200 Subject: [PATCH 311/655] docs: maintainers_include: better handle directories The TOC tree needs to use paths relative to the document containing the maintainers-profile-toc directive. Fix it. While here, address a warning from sashiko-bot, which points that using partition can be problematic if the root Linux path ends being something like: foo/Documentation/linux/ causing the documentation dir to be at: foo/Documentation/linux/Documentation Very unlikely, but fixing it is trivial: just use regex to pick the last one. Notice that I dropped the comment about using os.fspath() as the logic already uses os.path.abspath() which should work equally well. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <2b07e12eaa07bf81824ad427335783b170e01dba.1778309595.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 073a10575872..8c7b79721edd 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -82,7 +82,7 @@ def ErrorString(exc): # pylint: disable=C0103, C0116 class MaintainersParser: """Parse MAINTAINERS file(s) content""" - def __init__(self, app_dir, path): + def __init__(self, base_dir, app_dir, path): self.path = path # Poor man's state machine. @@ -92,8 +92,8 @@ class MaintainersParser: self.subsystem_name = None - self.app_dir = os.path.abspath(app_dir) - self.base_dir, _, self.sphinx_dir = self.app_dir.partition("Documentation") + self.base_dir = base_dir + self.app_dir = app_dir self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)') @@ -323,6 +323,8 @@ class MaintainersProfile(Include): def emit(self): """Parse all the MAINTAINERS lines looking for profile entries""" + env = self.state.document.settings.env + docdir = os.path.dirname(os.path.join(env.srcdir, env.docname)) path = maint_parser.path # @@ -347,7 +349,9 @@ class MaintainersProfile(Include): output += "\n.. toctree::\n" output += " :hidden:\n\n" - for fname in sorted(maint_parser.profile_toc): + for f in sorted(maint_parser.profile_toc): + fname = os.path.join(maint_parser.base_dir, "Documentation", f) + fname = os.path.relpath(fname, docdir) output += f" {fname}\n" output += "\n" @@ -381,15 +385,15 @@ def setup(app): """Setup Sphinx extension""" global maint_parser # pylint: disable=W0603 - # - # NOTE: we're using os.fspath() here because of a Sphinx warning: - # RemovedInSphinx90Warning: Sphinx 9 will drop support for representing paths as strings. Use "pathlib.Path" or "os.fspath" instead. - # - app_dir = os.fspath(app.srcdir) - srctree = os.path.abspath(os.environ["srctree"]) - path = os.path.join(srctree, "MAINTAINERS") + app_dir = os.path.abspath(app.srcdir) + match = re.match(r"(.*/)Documentation", app_dir) + if not match: + raise ValueError('Documentation directory not found.') - maint_parser = MaintainersParser(app_dir, path) + base_dir = match.group(1) + path = os.path.join(base_dir, "MAINTAINERS") + + maint_parser = MaintainersParser(base_dir, app_dir, path) app.add_directive("maintainers-include", MaintainersInclude) app.add_directive("maintainers-profile-toc", MaintainersProfile) From d5ab486874696074c99a0912ab09ae9e3ddc0f27 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:44 +0200 Subject: [PATCH 312/655] docs: maintainers_include: better handle doc wildcards As warned by sashiko-bot, the new logic doesn't handle wildcards on Documentation/. Change the logic to properly handle it, cleaning up the code to remove some code duplication. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/sphinx/maintainers_include.py | 103 ++++++++++---------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index 8c7b79721edd..be8e566e0363 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -95,7 +95,7 @@ class MaintainersParser: self.base_dir = base_dir self.app_dir = app_dir - self.re_doc = re.compile(r'(Documentation/([^\s\?\*]*)\.rst)') + self.re_doc = re.compile(r'(Documentation/(\S*)\.rst)') # # Output variables with maintainers content to be stored @@ -132,29 +132,47 @@ class MaintainersParser: # Retain previous line for state machine transitions. prev = line + def get_entries(self, text): + """Generate refs to ReST files in Documentation/""" + + if "Documentation/" not in text: + return None + + if "*" in text or "?" in text: + m = self.re_doc.search(text) + if not m: + return None + + doc_list = glob(m.group(1), root_dir=self.base_dir) + else: + doc_list = [text] + + entries = {} + for doc in doc_list: + m = self.re_doc.search(doc) + if m: + fname = m.group(1) + ename = m.group(2) + + entry = os.path.relpath(self.base_dir + fname, self.app_dir) + entry = entry.removesuffix(".rst") + + if entry.startswith("../"): + html = KERNELDOC_URL + ename + ".html" + entries[entry] = f'`{ename} <{html}>`_' + else: + entries[entry] = f':doc:`{ename} `' + + return entries + def linkify(self, text): - """Linkify all non-wildcard refs to ReST files in Documentation/""" + """Return a list of doc files converted to cross-references""" - m = self.re_doc.search(text) - if m: - fname = m.group(1) - ename = m.group(2) + entries = self.get_entries(text) + if not entries: + return text - entry = os.path.relpath(self.base_dir + fname, self.app_dir) - entry = entry.removesuffix(".rst") - - # - # When SPHINXDIRS is used, it will try to reference files - # outside srctree, causing warnings. To avoid that, point - # to the latest official documentation - # - if entry.startswith("../"): - html = KERNELDOC_URL + ename + ".html" - text = self.re_doc.sub(f'`{ename} <{html}>`_', text) - else: - text = self.re_doc.sub(f':doc:`{ename} `', text) - - return text + return self.re_doc.sub(", ".join(entries.values()), text) def parse_descriptions(self, line): """Handle contents of the descriptions section.""" @@ -206,35 +224,15 @@ class MaintainersParser: # Handle profile entries - either as files or as https refs # if field == "P": - match = self.re_doc.match(details) - if match: - fname = match.group(1) - ename = match.group(2) + entries = self.get_entries(details) + if entries: + for e, link in entries.items(): + if "html" not in link: + self.profile_toc.add(e) - entry = os.path.relpath(self.base_dir + fname, self.app_dir) - entry = entry.removesuffix(".rst") - # - # When SPHINXDIRS is used, it will try to reference files - # outside srctree, causing warnings. To avoid that, point - # to the latest official documentation - # + self.profile_entries[self.subsystem_name] = link - if entry.startswith("../"): - entry = KERNELDOC_URL + ename + ".html" - else: - entry = "/" + entry - - if "*" in entry: - for e in glob(entry): - if "html" not in e: - self.profile_toc.add(e) - - self.profile_entries[self.subsystem_name] = e - else: - if "html" not in entry: - self.profile_toc.add(entry) - - self.profile_entries[self.subsystem_name] = entry + details = ", ".join(entries.values()) else: match = re.match(r"(https?://.*)", details) if match: @@ -243,7 +241,9 @@ class MaintainersParser: else: self.profile_entries[self.subsystem_name] = f"``{details}``" - details = self.linkify(details) + details = self.linkify(details) + else: + details = self.linkify(details) # # Mark paths (and regexes) as literal text for improved @@ -340,7 +340,7 @@ class MaintainersProfile(Include): output += f"- {name}: {entry}\n" self.warning(f"{profile}: Invalid 'P' tag: {entry}\n") else: - output += f"- :doc:`{name} <{entry}>`\n" + output += f"- {entry}\n" # # Create a hidden TOC table with all profiles. That allows adding @@ -356,6 +356,9 @@ class MaintainersProfile(Include): output += "\n" + # For debugging the pre-rendered results... + #print(output, file=open("/tmp/profiles.rst", "w")) + self.state.document.settings.record_dependencies.add(path) self.state_machine.insert_input(statemachine.string2lines(output), path) From 446c78d6ab2dc8442c9e23d2042c396f1bc6cae2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:45 +0200 Subject: [PATCH 313/655] MAINTAINERS: make clearer about what's expected for "P" field The "P" field is meant to point to a subsystem maintainer's profile, stored either at the Kernel documentation or on an external site. Make it clearer. Signed-off-by: Mauro Carvalho Chehab Message-ID: <921e5e6a074f9d8cf77483d73e6801f49254bbb8.1777987027.git.mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet Message-ID: <21e6def8b69bac36795dcd4047d663bb31407dcb.1778309595.git.mchehab+huawei@kernel.org> --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..77244b7f9545 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25,9 +25,9 @@ Descriptions of section entries and preferred order C: URI for *chat* protocol, server and channel where developers usually hang out, for example irc://server/channel. P: *Subsystem Profile* document for more details submitting - patches to the given subsystem. This is either an in-tree file, - or a URI. See Documentation/maintainer/maintainer-entry-profile.rst - for details. + patches to the given subsystem. This is either an in-tree .rst file + inside Documentation/, or a URI. + See Documentation/maintainer/maintainer-entry-profile.rst for details. T: *SCM* tree type and location. Type is one of: git, hg, quilt, stgit, topgit F: *Files* and directories wildcard patterns. From 09958f69fa8f4e5d9ccb2e25f1b4700906f61632 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 May 2026 08:56:46 +0200 Subject: [PATCH 314/655] MAINTAINERS: use a URL for pin-init maintainer's profile entry This maintainer's entry is not inside documentation nor is ReST, preventing Sphinx to create a hyperlink to it. Change it to point to the already-formatted URL. Signed-off-by: Mauro Carvalho Chehab Message-ID: <1bceee886b9027d66bbb48d9d6c8d1250ce8dbcb.1777987028.git.mchehab+huawei@kernel.org> Signed-off-by: Mauro Carvalho Chehab Acked-by: Gary Guo Signed-off-by: Jonathan Corbet Message-ID: <59144e7323b95166e61a7c7f84096a0b9bb5d26e.1778309595.git.mchehab+huawei@kernel.org> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 77244b7f9545..dd424a4f9f3b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23402,7 +23402,7 @@ S: Maintained W: https://rust-for-linux.com/pin-init B: https://github.com/Rust-for-Linux/pin-init/issues C: zulip://rust-for-linux.zulipchat.com -P: rust/pin-init/CONTRIBUTING.md +P: https://github.com/Rust-for-Linux/pin-init/blob/main/CONTRIBUTING.md T: git https://github.com/Rust-for-Linux/linux.git pin-init-next F: rust/kernel/init.rs F: rust/pin-init/ From 8b9bff97df205c2d6dc65c7997b8d5ee63f5f8ea Mon Sep 17 00:00:00 2001 From: Mayank Gite Date: Wed, 6 May 2026 18:59:24 -0400 Subject: [PATCH 315/655] Documentation: fix typo and formattting in security/credentials.rst - Fixes a typo in "Keys and keyrings" section. Replaces "keying" with "keyring". - Updates formatting of keyring types. Signed-off-by: Mayank Gite Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260506225925.271163-1-drapl0n.kernel@gmail.com> --- Documentation/security/credentials.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/security/credentials.rst b/Documentation/security/credentials.rst index d0191c8b8060..4996838491b1 100644 --- a/Documentation/security/credentials.rst +++ b/Documentation/security/credentials.rst @@ -189,9 +189,9 @@ The Linux kernel supports the following types of credentials: be searched for the desired key. Each process may subscribe to a number of keyrings: - Per-thread keying - Per-process keyring - Per-session keyring + - Per-thread keyring + - Per-process keyring + - Per-session keyring When a process accesses a key, if not already present, it will normally be cached on one of these keyrings for future accesses to find. From 8bf5a177c318737c53e53299eac781a94ad632af Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 6 May 2026 11:04:12 +0000 Subject: [PATCH 316/655] docs: kernel-doc: python: strip __counted_by_ptr macro The `__counted_by_ptr` macro was recently introduced [1] to extend bounds checking semantics to standard dynamically allocated pointers. However, the new Python implementation of kernel-doc does not currently recognize it as a compiler attribute. When kernel-doc encounters a struct member annotated with this macro, it fails to parse the variable name correctly, resulting in false-positive warnings like: Warning: ... struct member '__counted_by_ptr(cmdcnt' not described Add `__counted_by_ptr` to the `struct_xforms` regex list so it gets safely stripped out during the parsing phase, mirroring the existing behavior for `__counted_by`. Update the corresponding unit tests. Link: https://git.kernel.org/torvalds/c/150a04d817d8 [1] Signed-off-by: Tudor Ambarus Reviewed-by: Mauro Carvalho Chehab Reviewed-by: Kees Cook Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260506-kdoc-__counted_by_ptr-v1-1-70763486871f@linaro.org> --- tools/lib/python/kdoc/xforms_lists.py | 1 + tools/unittests/test_cmatch.py | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/lib/python/kdoc/xforms_lists.py b/tools/lib/python/kdoc/xforms_lists.py index 496c52188273..8753dd539f23 100644 --- a/tools/lib/python/kdoc/xforms_lists.py +++ b/tools/lib/python/kdoc/xforms_lists.py @@ -29,6 +29,7 @@ class CTransforms: (CMatch("__aligned"), ""), (CMatch("__counted_by"), ""), (CMatch("__counted_by_(le|be)"), ""), + (CMatch("__counted_by_ptr"), ""), (CMatch("__guarded_by"), ""), (CMatch("__pt_guarded_by"), ""), (CMatch("__packed"), ""), diff --git a/tools/unittests/test_cmatch.py b/tools/unittests/test_cmatch.py index 7b996f83784d..109141cd2ab8 100755 --- a/tools/unittests/test_cmatch.py +++ b/tools/unittests/test_cmatch.py @@ -320,6 +320,7 @@ class TestSubWithLocalXforms(TestCaseDiff): (CMatch('__aligned'), ' '), (CMatch('__counted_by'), ' '), (CMatch('__counted_by_(le|be)'), ' '), + (CMatch('__counted_by_ptr'), ' '), (CMatch('__guarded_by'), ' '), (CMatch('__pt_guarded_by'), ' '), From 026d7010f13da6371317eb9269e95e5886abb39b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 5 May 2026 15:15:48 -0700 Subject: [PATCH 317/655] kdoc: xforms: move context attrs to function_xforms list The context analysis macros are function attributes that should be in the function_xforms list. Somewhere along the way they were inserted into the struct_xforms list instead. This causes docs build warnings to continue to be emitted for context macros. Move the context analysis macros to the function_xforms list where they should be to eliminate these warnings. Documentation/core-api/kref:328: ../include/linux/kref.h:72: WARNING: Invalid C declaration: Expected end of definition. [error at 96] int kref_put_mutex (struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex) __cond_acquires(true# mutex) Documentation/core-api/kref:328: ../include/linux/kref.h:94: WARNING: Invalid C declaration: Expected end of definition. [error at 92] int kref_put_lock (struct kref *kref, void (*release)(struct kref *kref), spinlock_t *lock) __cond_acquires(true# lock) Signed-off-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260505221548.163751-1-rdunlap@infradead.org> --- tools/lib/python/kdoc/xforms_lists.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/lib/python/kdoc/xforms_lists.py b/tools/lib/python/kdoc/xforms_lists.py index 8753dd539f23..aab70e5eaa6f 100644 --- a/tools/lib/python/kdoc/xforms_lists.py +++ b/tools/lib/python/kdoc/xforms_lists.py @@ -49,16 +49,6 @@ class CTransforms: (CMatch("DEFINE_DMA_UNMAP_ADDR"), r"dma_addr_t \1"), (CMatch("DEFINE_DMA_UNMAP_LEN"), r"__u32 \1"), (CMatch("VIRTIO_DECLARE_FEATURES"), r"union { u64 \1; u64 \1_array[VIRTIO_FEATURES_U64S]; }"), - (CMatch("__cond_acquires"), ""), - (CMatch("__cond_releases"), ""), - (CMatch("__acquires"), ""), - (CMatch("__releases"), ""), - (CMatch("__must_hold"), ""), - (CMatch("__must_not_hold"), ""), - (CMatch("__must_hold_shared"), ""), - (CMatch("__cond_acquires_shared"), ""), - (CMatch("__acquires_shared"), ""), - (CMatch("__releases_shared"), ""), (CMatch("__attribute__"), ""), # @@ -99,6 +89,16 @@ class CTransforms: (CMatch("__(?:re)?alloc_size"), ""), (CMatch("__diagnose_as"), ""), (CMatch("DECL_BUCKET_PARAMS"), r"\1, \2"), + (CMatch("__cond_acquires"), ""), + (CMatch("__cond_releases"), ""), + (CMatch("__acquires"), ""), + (CMatch("__releases"), ""), + (CMatch("__must_hold"), ""), + (CMatch("__must_not_hold"), ""), + (CMatch("__must_hold_shared"), ""), + (CMatch("__cond_acquires_shared"), ""), + (CMatch("__acquires_shared"), ""), + (CMatch("__releases_shared"), ""), (CMatch("__no_context_analysis"), ""), (CMatch("__attribute_const__"), ""), (CMatch("__attribute__"), ""), From 5349712418b6fe3de1dd1cbcad84ab3ecac63e31 Mon Sep 17 00:00:00 2001 From: Daniel Pereira Date: Sun, 3 May 2026 13:03:50 -0300 Subject: [PATCH 318/655] docs: pt_BR: translate process/license-rules.rst Translate the license-rules.rst document into Brazilian Portuguese. This document provides guidelines on how licenses should be identified and handled within the kernel source code. Additionally, update the pt_BR/process/index.rst to include the new translation in the documentation tree. Signed-off-by: Daniel Pereira Signed-off-by: Jonathan Corbet Message-ID: <20260503160352.160135-1-danielmaraboo@gmail.com> --- Documentation/translations/pt_BR/index.rst | 1 + .../pt_BR/process/license-rules.rst | 483 ++++++++++++++++++ 2 files changed, 484 insertions(+) create mode 100644 Documentation/translations/pt_BR/process/license-rules.rst diff --git a/Documentation/translations/pt_BR/index.rst b/Documentation/translations/pt_BR/index.rst index 4a094d8b794f..77c1a1cdc963 100644 --- a/Documentation/translations/pt_BR/index.rst +++ b/Documentation/translations/pt_BR/index.rst @@ -67,6 +67,7 @@ kernel e sobre como ver seu trabalho integrado. :maxdepth: 1 Introdução + Regras de licenciamento Como começar Requisitos mínimos Conclave (Continuidade do projeto) diff --git a/Documentation/translations/pt_BR/process/license-rules.rst b/Documentation/translations/pt_BR/process/license-rules.rst new file mode 100644 index 000000000000..1e395dfea875 --- /dev/null +++ b/Documentation/translations/pt_BR/process/license-rules.rst @@ -0,0 +1,483 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Regras de licenciamento do kernel Linux +======================================= + +O Kernel Linux é fornecido apenas sob os termos da licença GNU General Public +License versão 2 (GPL-2.0), conforme estabelecido em LICENSES/preferred/GPL-2.0, +com uma exceção explícita para syscalls descrita em +LICENSES/exceptions/Linux-syscall-note, conforme descrito no arquivo COPYING. + +Este arquivo de documentação fornece uma descrição de como cada arquivo-fonte +deve ser anotado para tornar sua licença clara e inequívoca. Ele não substitui +a licença do Kernel. + +A licença descrita no arquivo COPYING aplica-se ao código-fonte do kernel como +um todo, embora arquivos-fonte individuais possam ter uma licença diferente, a +qual deve ser obrigatoriamente compatível com a GPL-2.0:: + + GPL-1.0+ : GNU General Public License v1.0 ou posterior + GPL-2.0+ : GNU General Public License v2.0 ou posterior + LGPL-2.0 : GNU Library General Public License v2 apenas + LGPL-2.0+ : GNU Library General Public License v2 ou posterior + LGPL-2.1 : GNU Lesser General Public License v2.1 apenas + LGPL-2.1+ : GNU Lesser General Public License v2.1 ou posterior + +Além disso, arquivos individuais podem ser fornecidos sob uma licença dupla +(dual license), por exemplo, uma das variantes GPL compatíveis e, +alternativamente, sob uma licença permissiva como BSD, MIT, etc. + +Os arquivos de cabeçalho da API do espaço do usuário (UAPI), que descrevem a +interface dos programas do espaço do usuário com o kernel, são um caso especial. +De acordo com a nota no arquivo COPYING do kernel, a interface de syscall é um +limite claro, que não estende os requisitos da GPL a qualquer software que a +utilize para se comunicar com o kernel. Como os cabeçalhos UAPI devem ser +passíveis de inclusão em quaisquer arquivos-fonte que criem um executável +executado no kernel Linux, a exceção deve ser documentada por uma expressão de +licença especial. + +A forma comum de expressar a licença de um arquivo-fonte é adicionar o texto +padrão (boilerplate) correspondente no comentário inicial do arquivo. Devido a +variações de formatação, erros de digitação, etc., esses "textos padrão" são +difíceis de validar por ferramentas usadas no contexto de conformidade de +licença. + +Uma alternativa aos textos padrão é o uso de identificadores de licença +Software Package Data Exchange (SPDX) em cada arquivo-fonte. Os identificadores +de licença SPDX são abreviações precisas e analisáveis por máquina para a +licença sob a qual o conteúdo do arquivo é contribuído. Os identificadores de +licença SPDX são gerenciados pelo Grupo de Trabalho SPDX na Linux Foundation e +foram acordados por parceiros em toda a indústria, fornecedores de ferramentas +e equipes jurídicas. Para mais informações, consulte https://spdx.org/ + +O kernel Linux exige o identificador SPDX preciso em todos os arquivos-fonte. +Os identificadores válidos usados no kernel são explicados na seção +`Identificadores de Licença`_ e foram obtidos da lista de licenças +oficial do SPDX em https://spdx.org/licenses/ junto com os textos das licenças. + +Sintaxe do identificador de licença +----------------------------------- + +1. Posicionamento: + + O identificador de licença SPDX em arquivos do kernel deve ser adicionado na + primeira linha possível do arquivo que possa conter um comentário. Para a + maioria dos arquivos, esta é a primeira linha, exceto para scripts que + requerem o '#!CAMINHO_PARA_INTERPRETADOR' na primeira linha. Para esses + scripts, o identificador de licença SPDX deve ser colocado na segunda linha. + + A linha do identificador de licença pode então ser seguida por uma ou + múltiplas linhas de SPDX-FileCopyrightText, se desejado. + +2. Estilo: + + O identificador de licença SPDX é adicionado na forma de um comentário. O + estilo do comentário depende do tipo de arquivo:: + + Fonte C: // SPDX-License-Identifier: + Cabeçalho C:/* SPDX-License-Identifier: */ + ASM: /* SPDX-License-Identifier: */ + scripts: # SPDX-License-Identifier: + .rst: .. SPDX-License-Identifier: + .dts{i}: // SPDX-License-Identifier: + + Se uma ferramenta específica não conseguir lidar com o estilo de comentário + padrão, então deve ser utilizado o mecanismo de comentário apropriado que a + ferramenta aceite. Este é o motivo para ter o comentário no estilo ``/* */`` + em arquivos de cabeçalho C. Foi observada uma quebra de build com arquivos + .lds gerados, onde o 'ld' falhou ao analisar o comentário C++. Isso já foi + corrigido, mas ainda existem ferramentas de assembler mais antigas que não + conseguem lidar com comentários no estilo C++. + +3. Sintaxe: + + Uma pode ser um identificador SPDX simplificado + encontrado na Lista de Licenças SPDX, ou a combinação de dois desses + identificadores separados por "WITH", caso uma exceção de licença se aplique. + Quando múltiplas licenças são aplicáveis, a expressão utiliza as palavras-chave + "AND" ou "OR" para separar as sub-expressões, que devem ser delimitadas + por parênteses "(", ")". + + Para licenças como [L]GPL, utiliza-se o sufixo "+" para indicar a opção + 'ou posterior':: + + // SPDX-License-Identifier: GPL-2.0+ + // SPDX-License-Identifier: LGPL-2.1+ + + O termo "WITH" deve ser usado sempre que houver um modificador necessário + para a licença. Por exemplo, os arquivos UAPI do kernel Linux utilizam a + expressão:: + + // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + // SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note + + Outros exemplos de uso da cláusula "WITH" para exceções no kernel são:: + + // SPDX-License-Identifier: GPL-2.0 WITH mif-exception + // SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0 + + As exceções só podem ser aplicadas a identificadores de licença específicos. + Os identificadores válidos estão listados nas tags do arquivo de texto de + cada exceção. Para detalhes, veja o ponto `Exceções`_ no capítulo + `Identificadores de Licença`_. + + O termo "OR" deve ser usado se o arquivo possuir licenciamento duplo (dual + licensed) e apenas uma das licenças puder ser selecionada. Por exemplo, + alguns arquivos dtsi estão disponíveis sob licença dupla:: + + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + + Exemplos de expressões para arquivos com licenciamento duplo no kernel:: + + // SPDX-License-Identifier: GPL-2.0 OR MIT + // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause + // SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 + // SPDX-License-Identifier: GPL-2.0 OR MPL-1.1 + // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT + // SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause OR OpenSSL + + O termo "AND" deve ser usado se o arquivo possuir múltiplas licenças cujos + termos devem ser aplicados simultaneamente. Por exemplo, se um código herdado + de outro projeto foi incorporado ao kernel, mas os termos da licença original + ainda precisam ser respeitados:: + + // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT + + Outro exemplo onde ambos os conjuntos de termos devem ser cumpridos é:: + + // SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+ + +Identificadores de Licença +-------------------------- + +As licenças atualmente em uso, bem como as licenças para código adicionado ao +kernel, podem ser divididas em: + +4. _`Licenças preferenciais`: + + Sempre que possível, estas licenças devem ser utilizadas, pois são conhecidas + por serem totalmente compatíveis e amplamente usadas. Estas licenças estão + disponíveis no diretório:: + + LICENSES/preferred/ + + na árvore de diretórios do código-fonte do kernel. + + Os arquivos neste diretório contêm o texto completo da licença e as + `Metatags`_. Os nomes dos arquivos são idênticos ao identificador de licença + SPDX que deve ser utilizado para a licença nos arquivos-fonte. + + Exemplos:: + + LICENSES/preferred/GPL-2.0 + + Contém o texto da licença GPL versão 2 e as metatags obrigatórias:: + + LICENSES/preferred/MIT + + Contém o texto da licença MIT e as metatags obrigatórias. + + _`Metatags`: + + As seguintes metatags devem estar presentes em um arquivo de licença: + + - Valid-License-Identifier: + + Uma ou mais linhas que declaram quais Identificadores de Licença são válidos + dentro do projeto para referenciar este texto de licença específico. + Geralmente, trata-se de um único identificador válido, mas, por exemplo, + para licenças com as opções 'ou posterior' (or later), dois identificadores + são válidos. + + - SPDX-URL: + + A URL da página SPDX que contém informações adicionais relacionadas à licença. + + - Usage-Guidance: + + Texto livre para conselhos de uso. O texto deve incluir exemplos corretos + para os identificadores de licença SPDX, conforme eles devem ser colocados + nos arquivos-fonte de acordo com as diretrizes de + `Sintaxe do identificador de licença`_. + + - License-Text: + + Todo o texto após esta tag é tratado como o texto original da licença. + + Exemplos de formato de arquivo:: + + Valid-License-Identifier: GPL-2.0 + Valid-License-Identifier: GPL-2.0+ + SPDX-URL: https://spdx.org/licenses/GPL-2.0.html + Usage-Guide: + Para usar esta licença no código-fonte, coloque um dos seguintes pares + SPDX tag/valor em um comentário, de acordo com as diretrizes de + posicionamento na documentação das regras de licenciamento. + Para 'GNU General Public License (GPL) version 2 only', use: + SPDX-License-Identifier: GPL-2.0 + Para 'GNU General Public License (GPL) version 2 or any later version', use: + SPDX-License-Identifier: GPL-2.0+ + License-Text: + Texto completo da licença + + :: + + Valid-License-Identifier: MIT + SPDX-URL: https://spdx.org/licenses/MIT.html + Usage-Guide: + Para usar esta licença no código-fonte, coloque o seguinte par SPDX + tag/valor em um comentário, de acordo com as diretrizes de + posicionamento na documentação das regras de licenciamento. + SPDX-License-Identifier: MIT + License-Text: + Texto completo da licença + +5. Licenças obsoletas: + + Estas licenças devem ser utilizadas apenas para código já existente ou para + a importação de código de outros projetos. Estas licenças estão disponíveis + no diretório:: + + LICENSES/deprecated/ + + na árvore de fontes do kernel. + + Os arquivos neste diretório contêm o texto completo da licença e as + `Metatags`_. Os nomes dos arquivos são idênticos ao identificador de + licença SPDX que deve ser utilizado para a licença nos arquivos fonte. + + Exemplos:: + + LICENSES/deprecated/ISC + + Contém o texto da licença *Internet Systems Consortium* e as metatags + necessárias:: + + LICENSES/deprecated/GPL-1.0 + + Contém o texto da licença GPL versão 1 e as metatags necessárias. + + Metatags: + + Os requisitos de metatags para "outras" licenças são idênticos aos + requisitos das `Licenças preferenciais`_. + + Exemplo de formato de arquivo:: + + Valid-License-Identifier: ISC + SPDX-URL: https://spdx.org/licenses/ISC.html + Usage-Guide: + O uso desta licença no kernel para novos códigos é desencorajado + e deve ser utilizada exclusivamente para importar código de um + projeto já existente. + Para usar esta licença no código-fonte, coloque o seguinte par + tag/valor SPDX em um comentário, seguindo as diretrizes de + posicionamento na documentação das regras de licenciamento. + SPDX-License-Identifier: ISC + License-Text: + Texto completo da licença + +6. Apenas Licenciamento Duplo + + Estas licenças devem ser usadas apenas para o licenciamento duplo de código + com outra licença, além de uma licença preferencial. Estas licenças estão + disponíveis no diretório:: + + LICENSES/dual/ + + No código-fonte do kernel. + + Os arquivos neste diretório contêm o texto completo da licença e as + `Metatags`_. Os nomes dos arquivos são idênticos ao identificador de licença + SPDX que deve ser usado para a licença nos arquivos fonte. + + Exemplos:: + + LICENSES/dual/MPL-1.1 + + Contém o texto da licença Mozilla Public License versão 1.1 e as metatags + necessárias:: + + LICENSES/dual/Apache-2.0 + + Contém o texto da licença Apache License versão 2.0 e as metatags + necessárias. + + Metatags: + + Os requisitos de metatags para 'outras' licenças são idênticos aos + requisitos das `Licenças preferenciais`_. + + Exemplo de formato de arquivo:: + + Valid-License-Identifier: MPL-1.1 + SPDX-URL: https://spdx.org/licenses/MPL-1.1.html + Usage-Guide: + NÃO use. A licença MPL-1.1 não é compatível com a GPL2. Ela só pode ser + usada para arquivos com licenciamento duplo onde a outra licença seja + compatível com a GPL2. + Se você acabar utilizando-a, ela DEVE ser usada em conjunto com uma + licença compatível com a GPL2 utilizando "OR". + Para usar a Mozilla Public License versão 1.1, coloque o seguinte par + tag/valor SPDX em um comentário, de acordo com as diretrizes de + posicionamento na documentação das regras de licenciamento: + SPDX-License-Identifier: MPL-1.1 + License-Text: + Texto completo da licença + +| + +7. _`Exceções`: + +Algumas licenças podem ser alteradas com exceções que concedem certos direitos + que a licença original não concede. Estas exceções estão disponíveis no + diretório:: + + LICENSES/exceptions/ + + no código-fonte do kernel. Os arquivos neste diretório contêm o texto completo + da exceção e as `Metatags de Exceção`_ necessárias. + + Exemplos:: + + LICENSES/exceptions/Linux-syscall-note + + Contém a exceção de syscall do Linux, conforme documentado no arquivo COPYING + do kernel Linux, que é usada para arquivos de cabeçalho UAPI. + ex: /\* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note \*/:: + + LICENSES/exceptions/GCC-exception-2.0 + + Contém a 'exceção de vinculação' do GCC, que permite + vincular qualquer binário, independente de sua licença, à versão compilada + de um arquivo marcado com esta exceção. Isso é necessário para criar + executáveis funcionais a partir de código-fonte que não seja compatível + com a GPL. + + _`Metatags de Exceção`: + + As seguintes meta tags devem estar disponíveis em um arquivo de exceção: + + - SPDX-Exception-Identifier: + + Um identificador de exceção que pode ser usado com identificadores de + licença SPDX. + + - SPDX-URL: + + A URL da página SPDX que contém informações adicionais relacionadas + à exceção. + + - SPDX-Licenses: + + Uma lista separada por vírgulas de identificadores de licença SPDX para os + quais a exceção pode ser usada. + + - Usage-Guidance: + + Texto de formato livre para conselhos de uso. O texto deve ser seguido por + exemplos corretos para os identificadores de licença SPDX, conforme devem + ser colocados nos arquivos fonte de acordo com as diretrizes de + `Sintaxe do identificador de licença`_. + + - Exception-Text: + + Todo o texto após esta tag é tratado como o texto original da exceção. + + Exemplos de formato de arquivo:: + + SPDX-Exception-Identifier: Linux-syscall-note + SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html + SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+ + Usage-Guidance: + Esta exceção é usada em conjunto com uma das SPDX-Licenses acima para + marcar arquivos de cabeçalho de API do espaço do usuário (uapi), para que + possam ser incluídos em código de aplicativo de espaço do usuário que não + esteja em conformidade com a GPL. + Para usar esta exceção, adicione-a com a palavra-chave WITH a um dos + identificadores na tag SPDX-Licenses: + SPDX-License-Identifier: WITH Linux-syscall-note + Exception-Text: + Texto completo da exceção + +Exemplos de formato de arquivo:: + + SPDX-Exception-Identifier: GCC-exception-2.0 + SPDX-URL: https://spdx.org/licenses/GCC-exception-2.0.html + SPDX-Licenses: GPL-2.0, GPL-2.0+ + Usage-Guidance: + A "GCC Runtime Library exception 2.0" é usada em conjunto com uma das + SPDX-Licenses acima para código importado da biblioteca de tempo de + execução (runtime) do GCC. + Para usar esta exceção, adicione-a com a palavra-chave WITH a um dos + identificadores na tag SPDX-Licenses: + SPDX-License-Identifier: WITH GCC-exception-2.0 + Exception-Text: + Texto completo da exceção + +Todos os identificadores de licença e exceções SPDX devem ter um arquivo +correspondente nos subdiretórios LICENSES. Isso é necessário para permitir a +verificação por ferramentas (ex: checkpatch.pl) e para que as licenças estejam +prontas para leitura e extração diretamente da fonte, o que é recomendado por +várias organizações de FOSS (Software Livre e de Código Aberto), como a +`iniciativa REUSE da FSFE `_. + +_`MODULE_LICENSE` +----------------- + + Módulos carregáveis do kernel também exigem uma tag MODULE_LICENSE(). Esta tag + não substitui as informações adequadas de licença do código-fonte + (SPDX-License-Identifier), nem é de forma alguma relevante para expressar ou + determinar a licença exata sob a qual o código-fonte do módulo é fornecido. + + O único propósito desta tag é fornecer informações suficientes ao carregador + de módulos do kernel e às ferramentas de espaço do usuário sobre o módulo ser + software livre ou proprietário. + + As strings de licença válidas para MODULE_LICENSE() são:: + + ============================= ============================================= + "GPL" O módulo está licenciado sob a GPL versão 2. + Isso não expressa nenhuma distinção entre + GPL-2.0-only ou GPL-2.0-or-later. A informação + exata da licença só pode ser determinada por + meio das informações de licença nos arquivos + fonte correspondentes. + + "GPL v2" O mesmo que "GPL". Existe por razões + históricas. + + "GPL and additional rights" Variante histórica para expressar que o fonte + do módulo possui licenciamento duplo sob uma + variante da GPL v2 e a licença MIT. Por favor, + não use em códigos novos. + + "Dual MIT/GPL" A maneira correta de expressar que o módulo + possui licenciamento duplo sob uma escolha de + variante GPL v2 ou licença MIT. + + "Dual BSD/GPL" O módulo possui licenciamento duplo sob uma + escolha de variante GPL v2 ou licença BSD. A + variante exata da licença BSD só pode ser + determinada por meio das informações de + licença nos arquivos fonte correspondentes. + + "Dual MPL/GPL" O módulo possui licenciamento duplo sob uma + escolha de variante GPL v2 ou Mozilla Public + License (MPL). A variante exata da licença + MPL só pode ser determinada por meio das + informações de licença nos arquivos fonte + correspondentes. + + "Proprietary" O módulo está sob uma licença proprietária. + "Proprietary" deve ser entendido apenas como + "A licença não é compatível com GPLv2". Esta + string é exclusiva para módulos de terceiros + não compatíveis com GPL2 e não pode ser usada + para módulos que tenham seu código-fonte na + árvore do kernel. Módulos marcados dessa forma + contaminam (tainting) o kernel com a flag 'P' + quando carregados, e o carregador de módulos + recusa-se a vincular tais módulos a símbolos + exportados com EXPORT_SYMBOL_GPL(). + ============================= ============================================= \ No newline at end of file From c8ebfd4436aa8a1cf5f13f5ade2e06ddf8bbbda5 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sun, 3 May 2026 19:02:22 +0300 Subject: [PATCH 319/655] docs: locking: Fix stale dquot.c path The quota code was moved from fs/dquot.c to fs/quota/dquot.c in commit 884d179dff3a ("quota: Move quota files into separate directory"). Update the reference. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Reviewed-by: Jan Kara Signed-off-by: Jonathan Corbet Message-ID: <20260503160221.1594319-2-costa.shul@redhat.com> --- Documentation/filesystems/locking.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index 8421ea21bd35..277e49314d32 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -584,7 +584,7 @@ write_info: yes dqonoff_sem FS recursion means calling ->quota_read() and ->quota_write() from superblock operations. -More details about quota locking can be found in fs/dquot.c. +More details about quota locking can be found in fs/quota/dquot.c. vm_operations_struct ==================== From 696ce7ca20f5269ccef828663c4272b72be88ac3 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Fri, 1 May 2026 07:38:46 +0300 Subject: [PATCH 320/655] docs: housekeeping: Fix struct member access in code example No such array housekeeping_cpumasks Fix to housekeeping.cpumasks. Signed-off-by: Costa Shulyupin Reviewed-by: Frederic Weisbecker Signed-off-by: Jonathan Corbet Message-ID: <20260501043855.980567-1-costa.shul@redhat.com> --- Documentation/core-api/housekeeping.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/core-api/housekeeping.rst b/Documentation/core-api/housekeeping.rst index 92c6e53cea75..ccb0a88b9cb3 100644 --- a/Documentation/core-api/housekeeping.rst +++ b/Documentation/core-api/housekeeping.rst @@ -99,7 +99,7 @@ the same RCU read side critical section. A typical layout example would look like this on the update side (``housekeeping_update()``):: - rcu_assign_pointer(housekeeping_cpumasks[type], trial); + rcu_assign_pointer(housekeeping.cpumasks[type], trial); synchronize_rcu(); flush_workqueue(example_workqueue); From f5899ff9c48d8f4dcfb1d622605d6ea2e0cf7eb9 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Fri, 17 Apr 2026 11:25:40 +0800 Subject: [PATCH 321/655] docs: Update nosmt support for arm64 commit eed4583bcf9a6 ("arm64: Kconfig: Enable HOTPLUG_SMT") enable HOTPLUG_SMT for SMT control for arm64, but the documentation was not updated accordingly to reflect that ARM64 now supports control SMT via boot parameter and sysfs knobs: 1. Boot parameters: nosmt: Disable SMT, can be enabled via sysfs knobs. nosmt=force: Disable SMT, cannot be enabled via sysfs knobs. 2. Runtime sysfs controls: Write "on", "off", "forceoff" or the number of SMT threads (1, 2, ...) to /sys/devices/system/cpu/smt/control. Signed-off-by: Jinjie Ruan Signed-off-by: Jonathan Corbet Message-ID: <20260417032540.3720627-1-ruanjinjie@huawei.com> --- Documentation/admin-guide/kernel-parameters.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index b1e2e50d5c8d..8c22943e51c0 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4638,7 +4638,7 @@ Kernel parameters nosmt [KNL,MIPS,PPC,EARLY] Disable symmetric multithreading (SMT). Equivalent to smt=1. - [KNL,LOONGARCH,X86,PPC,S390] Disable symmetric multithreading (SMT). + [KNL,LOONGARCH,X86,ARM64,PPC,S390] Disable symmetric multithreading (SMT). nosmt=force: Force disable SMT, cannot be undone via the sysfs control file. From 46d9c16115cf046ce564f0230126cae785f73826 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Thu, 7 May 2026 02:32:32 +0000 Subject: [PATCH 322/655] scripts/kernel-doc: Detect mismatched inline member documentation tags Add validation in check_sections() to verify that inline member documentation tags (/** @member: description */) match actual struct/union member names. Previously, kernel-doc only validated section headers against the parameter list, but inline doc tags stored in parameterdescs were never cross-checked, allowing stale or mistyped member names to go undetected. The new check iterates over parameterdescs keys and warns about any that don't appear in the parameter list, catching issues like renamed struct members where the documentation tag was not updated to match. This catches real issues such as: - xe_bo_types.h: @atomic_access (missing struct prefix, should be @attr.atomic_access) - xe_device_types.h: @usm.asid (member is actually asid_to_vm) While at it, fix two long-standing issues with named variadic parameters (macros like ``#define foo(fmt, args...)``) that the new check exposed: 1. A description provided via the ``@args...:`` doc form was stored in parameterdescs under the unstripped key ``args...``, while push_parameter() stripped the trailing ``...`` and only added ``args`` to parameterlist. As a result the user-supplied description was orphaned, parameterdescs[``args``] was auto- populated with the generic "variable arguments" text, and the user's actual description was silently discarded by the output stage. Migrate the description from the unstripped to the stripped key inside push_parameter() so the user's text reaches the output and the new check does not flag the orphaned key. 2. push_parameter() always auto-populated parameterdescs[param] with "variable arguments" for variadic parameters, which bypassed the existing "parameter not described" warning at line 549. As a consequence, a named variadic with no matching ``@:`` doc tag (or a mistyped one such as ``@args:`` for a parameter named ``arg``) went undetected. Emit the standard "not described" warning for named variadics before applying the auto-fill, so missing or mistyped variadic docs are reported just like missing docs for any other parameter. The bare ``@...:`` form is unaffected because it has no natural name for the user to document. This second hunk surfaces one real pre-existing documentation gap in include/linux/hashtable.h: hash_for_each_possible_rcu()'s ``cond...`` parameter has no matching ``@cond:`` doc entry. No false positives were observed across include/linux, kernel/, or drivers/gpu/drm. v2: Skip variadic parameters whose documented key ends with ``...`` and whose stripped name is in parameterlist, to avoid false-positive "Excess function parameter 'args...'" warnings on macros like ``#define foo(fmt, args...)`` documented with ``@args...:``. v3: The v2 special case in check_sections() only suppressed the warning while still letting the user's description be silently dropped from the generated output. Replace it with a fix in push_parameter() that migrates the description from ``args...`` to ``args`` when the name is stripped, so the user's text is preserved end-to-end and the new excess-parameter check naturally finds nothing to flag. v4: Also emit the standard "parameter not described" warning for named variadics that have no matching ``@:`` doc tag. Previously push_parameter()'s unconditional auto-fill bypassed that warning, so a missing or mistyped variadic doc went undetected. (Randy) Assisted-by: Claude:claude-opus-4.6 Signed-off-by: Shuicheng Lin Tested-by: Randy Dunlap Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260507023232.4108680-1-shuicheng.lin@intel.com> --- tools/lib/python/kdoc/kdoc_parser.py | 54 +++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/tools/lib/python/kdoc/kdoc_parser.py b/tools/lib/python/kdoc/kdoc_parser.py index c3f966da533e..2dedda215c22 100644 --- a/tools/lib/python/kdoc/kdoc_parser.py +++ b/tools/lib/python/kdoc/kdoc_parser.py @@ -380,9 +380,36 @@ class KernelDoc: # if dtype == '': if param.endswith("..."): - if len(param) > 3: # there is a name provided, use that + named_variadic = len(param) > 3 + if named_variadic: # there is a name provided, use that + # + # If the user documented the parameter using the + # ``@name...:`` form, the description is stored in + # parameterdescs under the unstripped key. Migrate + # it to the stripped key so the user's text is not + # silently dropped during output, and so the new + # excess-parameter check in check_sections() does + # not flag the unstripped key as orphaned. + # + orig = self.entry.parameterdescs.pop(param, None) param = param[:-3] + if orig is not None and \ + not self.entry.parameterdescs.get(param): + self.entry.parameterdescs[param] = orig if not self.entry.parameterdescs.get(param): + # + # For a named variadic (e.g. ``args...``), emit the + # standard "not described" warning before auto-filling + # so a missing or mistyped ``@:`` doc tag does + # not go undetected. The bare ``...`` form has no + # natural name for the user to document and so always + # gets the auto-generated text. + # + if named_variadic and decl_type == 'function': + self.emit_msg(ln, + f"function parameter '{param}' " + f"not described in " + f"'{declaration_name}'") self.entry.parameterdescs[param] = "variable arguments" elif (not param) or param == "void": @@ -546,6 +573,31 @@ class KernelDoc: self.emit_msg(ln, f"Excess {dname} '{section}' description in '{decl_name}'") + # + # Check that documented parameter names (from doc comments, including + # inline ``/** @member: */`` tags) actually match real members in + # the declaration. This catches mismatched or stale kernel-doc + # member tags that don't correspond to any actual struct/union + # member or function parameter. + # + for param_name, desc in self.entry.parameterdescs.items(): + # Skip auto-generated entries from push_parameter() + if desc == self.undescribed: + continue + if desc in ("no arguments", "anonymous\n", "variable arguments"): + continue + if param_name.startswith("{unnamed_"): + continue + if param_name in self.entry.parameterlist: + continue + + if decl_type == 'function': + dname = f"{decl_type} parameter" + else: + dname = f"{decl_type} member" + self.emit_msg(ln, + f"Excess {dname} '{param_name}' description in '{decl_name}'") + def check_return_section(self, ln, declaration_name, return_type): """ If the function doesn't return void, warns about the lack of a From 61579def4e3df35ee727f185ac4a9c8231793ca1 Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Thu, 7 May 2026 06:47:31 -0700 Subject: [PATCH 323/655] Documentation: core-api/cpu_hotplug: Remove stale cpu0_hotplug docs Commit e59e74dc48a3 ("x86/topology: Remove CPU0 hotplug option") removed the 'cpu0_hotplug' option, but its documentation remained in cpu_hotplug.rst. Remove the stale entry. Reported-by: Dave Hansen Signed-off-by: Chao Gao Message-ID: <20260507134732.254617-1-chao.gao@intel.com> Signed-off-by: Jonathan Corbet --- Documentation/core-api/cpu_hotplug.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/core-api/cpu_hotplug.rst b/Documentation/core-api/cpu_hotplug.rst index 9b4afca9fd09..6de26d1c6a9a 100644 --- a/Documentation/core-api/cpu_hotplug.rst +++ b/Documentation/core-api/cpu_hotplug.rst @@ -45,11 +45,6 @@ Command Line Switches This option is limited to the X86 and S390 architecture. -``cpu0_hotplug`` - Allow to shutdown CPU0. - - This option is limited to the X86 architecture. - CPU maps ======== From d848b1b099111c3b905a690e7e1a2600302e3b94 Mon Sep 17 00:00:00 2001 From: Cheng-Han Wu Date: Sun, 3 May 2026 18:14:26 +0800 Subject: [PATCH 324/655] docs: admin-guide: fix typos in workload tracing guide Fix several typos in the workload tracing guide: - sys_opennat() -> sys_openat() - annotate the to view -> annotate the output to view - sys_getegid -> sys_getegid() Signed-off-by: Cheng-Han Wu Reviewed-by: Shuah Khan Signed-off-by: Jonathan Corbet Message-ID: <20260503101429.254394-2-hank20010209@gmail.com> --- Documentation/admin-guide/workload-tracing.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/workload-tracing.rst b/Documentation/admin-guide/workload-tracing.rst index 35963491b9f1..22cb05025ffc 100644 --- a/Documentation/admin-guide/workload-tracing.rst +++ b/Documentation/admin-guide/workload-tracing.rst @@ -278,8 +278,8 @@ associated with a process. This command records the profiling data in the perf.data file in the same directory. Using the following commands you can record the events associated with the -netdev stressor, view the generated report perf.data and annotate the to -view the statistics of each instruction of the program:: +netdev stressor, view the generated report perf.data and annotate the output +to view the statistics of each instruction of the program:: perf record stress-ng --netdev 1 -t 60 --metrics command. perf report @@ -349,13 +349,13 @@ times each system call is invoked, and the corresponding Linux subsystem. +-------------------+-----------+-----------------+-------------------------+ | geteuid | 1 | Process Mgmt. | sys_geteuid() | +-------------------+-----------+-----------------+-------------------------+ -| getegid | 1 | Process Mgmt. | sys_getegid | +| getegid | 1 | Process Mgmt. | sys_getegid() | +-------------------+-----------+-----------------+-------------------------+ | close | 49951 | Filesystem | sys_close() | +-------------------+-----------+-----------------+-------------------------+ | pipe | 604 | Filesystem | sys_pipe() | +-------------------+-----------+-----------------+-------------------------+ -| openat | 48560 | Filesystem | sys_opennat() | +| openat | 48560 | Filesystem | sys_openat() | +-------------------+-----------+-----------------+-------------------------+ | fstat | 8338 | Filesystem | sys_fstat() | +-------------------+-----------+-----------------+-------------------------+ From 6e13c0aac620ec418f1a47f6a3bb9230a6677e3f Mon Sep 17 00:00:00 2001 From: Cheng-Han Wu Date: Sun, 3 May 2026 18:14:27 +0800 Subject: [PATCH 325/655] docs: admin-guide: fix stress-ng command examples The workload tracing guide includes stress-ng command examples with a stray "command." word at the end. This makes the examples invalid if they are copied and run directly. Remove the stray word from the stress-ng example. Also use "--" in the perf record example to clearly separate perf record options from the workload command being recorded. Signed-off-by: Cheng-Han Wu Reviewed-by: Shuah Khan Signed-off-by: Jonathan Corbet Message-ID: <20260503101429.254394-3-hank20010209@gmail.com> --- Documentation/admin-guide/workload-tracing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/workload-tracing.rst b/Documentation/admin-guide/workload-tracing.rst index 22cb05025ffc..43a3c8098654 100644 --- a/Documentation/admin-guide/workload-tracing.rst +++ b/Documentation/admin-guide/workload-tracing.rst @@ -271,7 +271,7 @@ exercised: The following command runs the stressor:: - stress-ng --netdev 1 -t 60 --metrics command. + stress-ng --netdev 1 -t 60 --metrics We can use the perf record command to record the events and information associated with a process. This command records the profiling data in the @@ -281,7 +281,7 @@ Using the following commands you can record the events associated with the netdev stressor, view the generated report perf.data and annotate the output to view the statistics of each instruction of the program:: - perf record stress-ng --netdev 1 -t 60 --metrics command. + perf record -- stress-ng --netdev 1 -t 60 --metrics perf report perf annotate From 7fb658ede0404e8dac52bb196bc0457c5db03f19 Mon Sep 17 00:00:00 2001 From: Cheng-Han Wu Date: Sun, 3 May 2026 18:14:28 +0800 Subject: [PATCH 326/655] docs: admin-guide: clarify perf bench all behavior The workload tracing guide lists a fixed set of benchmarks for "perf bench all". This list is stale and can become outdated when perf adds, removes, or renames benchmark collections or individual benchmarks. Describe "perf bench all" as running all available benchmarks in the perf bench framework instead. Also document how to list the collections and benchmarks available on a given system. Signed-off-by: Cheng-Han Wu Reviewed-by: Shuah Khan Signed-off-by: Jonathan Corbet Message-ID: <20260503101429.254394-4-hank20010209@gmail.com> --- .../admin-guide/workload-tracing.rst | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/workload-tracing.rst b/Documentation/admin-guide/workload-tracing.rst index 43a3c8098654..c49c2a00a8b8 100644 --- a/Documentation/admin-guide/workload-tracing.rst +++ b/Documentation/admin-guide/workload-tracing.rst @@ -243,13 +243,21 @@ which can help mitigate performance regressions. It also acts as a common benchmarking framework, enabling developers to easily create test cases, integrate transparently, and use performance-rich tooling. -"perf bench all" command runs the following benchmarks: +"perf bench all" runs all available benchmarks in the perf bench +framework. The exact set of benchmarks depends on the perf version and on +the features enabled when perf was built. - * sched/messaging - * sched/pipe - * syscall/basic - * mem/memcpy - * mem/memset +To list the benchmark collections available on the current system, run:: + + perf bench + +To list benchmarks in a collection, run:: + + perf bench + +For example, to list the benchmarks in the mem collection, run:: + + perf bench mem What is stress-ng and how do we use it? ======================================= From e27108800bb8a8be08300ce14d532f7225e4c50f Mon Sep 17 00:00:00 2001 From: Cheng-Han Wu Date: Sun, 3 May 2026 18:14:29 +0800 Subject: [PATCH 327/655] docs: admin-guide: add IGNORE_DIRS example for cscope The workload tracing guide shows how to build a cscope database by running cscope command directly. The kernel build system also provides a cscope target, which supports IGNORE_DIRS for excluding directories from the generated database. Mention make cscope and show how to exclude Documentation/ as an example. Signed-off-by: Cheng-Han Wu Reviewed-by: Shuah Khan Signed-off-by: Jonathan Corbet Message-ID: <20260503101429.254394-5-hank20010209@gmail.com> --- Documentation/admin-guide/workload-tracing.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/admin-guide/workload-tracing.rst b/Documentation/admin-guide/workload-tracing.rst index c49c2a00a8b8..314e5f03474e 100644 --- a/Documentation/admin-guide/workload-tracing.rst +++ b/Documentation/admin-guide/workload-tracing.rst @@ -202,6 +202,15 @@ database. To get out of this mode press ctrl+d. -p option is used to specify the number of file path components to display. -p10 is optimal for browsing kernel sources. +Alternatively, the kernel build system can generate the cscope database:: + + make cscope + +To exclude directories from the generated database, pass IGNORE_DIRS to +the cscope target. For example, to exclude Documentation/, run:: + + make IGNORE_DIRS="Documentation" cscope + What is perf and how do we use it? ================================== From d3873c5f4d6e86852dee427832105b36fb06aef8 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Thu, 7 May 2026 22:06:36 +0800 Subject: [PATCH 328/655] spi: rspi: Simplify reset control handling Use devm_reset_control_get_optional_exclusive_deasserted() to combine get + deassert + cleanup in a single call, removing the redundant rspi_reset_control_assert() helper. Signed-off-by: Felix Gu Link: https://patch.msgid.link/20260507-rspi-v1-1-8cfa47cd56aa@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 951e9a8af547..a0c77e02bc90 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1222,11 +1222,6 @@ static const struct of_device_id rspi_of_match[] __maybe_unused = { MODULE_DEVICE_TABLE(of, rspi_of_match); #ifdef CONFIG_OF -static void rspi_reset_control_assert(void *data) -{ - reset_control_assert(data); -} - static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr) { struct reset_control *rstc; @@ -1242,22 +1237,10 @@ static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr) ctlr->num_chipselect = num_cs; - rstc = devm_reset_control_get_optional_exclusive(dev, NULL); + rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL); if (IS_ERR(rstc)) return dev_err_probe(dev, PTR_ERR(rstc), - "failed to get reset ctrl\n"); - - error = reset_control_deassert(rstc); - if (error) { - dev_err(dev, "failed to deassert reset %d\n", error); - return error; - } - - error = devm_add_action_or_reset(dev, rspi_reset_control_assert, rstc); - if (error) { - dev_err(dev, "failed to register assert devm action, %d\n", error); - return error; - } + "failed to get reset ctrl and deassert reset\n"); return 0; } From 05d871c5194bef01b525ca9289efb736bbfd6ece Mon Sep 17 00:00:00 2001 From: Sander Vanheule Date: Fri, 15 May 2026 23:23:50 +0200 Subject: [PATCH 329/655] watchdog: realtek-otto: prevent PHASE2 underflows For small pretimeout values, ((timeout - pretimeout) / tick) might be rounded up to the same value as (timeout / tick). As a result, the number of PHASE2 ticks may be zero, causing an underflow when subtracting 1 to configure the hardware. While this results in a longer-than-expected time to system reset, the duration of PHASE1 and minimum ping interval for the watchdog would still be correct. As the watchdog core ensures pretimeout is strictly less than timeout, ceil(timeout / tick) is strictly greater than floor(pretimeout / tick) and the number of PHASE1 ticks cannot be 0. So instead of rounding up the number of PHASE1 ticks, we can round down the number of PHASE2 ticks, maintaining the current behavior while avoiding underflows. The original helper function is now inlined, as it doesn't save any duplication anymore. Signed-off-by: Sander Vanheule Link: https://lore.kernel.org/r/20260515212351.752054-2-sander@svanheule.net Signed-off-by: Guenter Roeck --- drivers/watchdog/realtek_otto_wdt.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/watchdog/realtek_otto_wdt.c b/drivers/watchdog/realtek_otto_wdt.c index 2c30ddd574c5..1495e8a8cbb5 100644 --- a/drivers/watchdog/realtek_otto_wdt.c +++ b/drivers/watchdog/realtek_otto_wdt.c @@ -114,12 +114,6 @@ static int otto_wdt_tick_ms(struct otto_wdt_ctrl *ctrl, int prescale) * the value stored in those fields. This means each phase will run for at least * one tick, so small values need to be clamped to correctly reflect the timeout. */ -static inline unsigned int div_round_ticks(unsigned int val, unsigned int tick_duration, - unsigned int min_ticks) -{ - return max(min_ticks, DIV_ROUND_UP(val, tick_duration)); -} - static int otto_wdt_determine_timeouts(struct watchdog_device *wdev, unsigned int timeout, unsigned int pretimeout) { @@ -140,9 +134,9 @@ static int otto_wdt_determine_timeouts(struct watchdog_device *wdev, unsigned in return -EINVAL; tick_ms = otto_wdt_tick_ms(ctrl, prescale); - total_ticks = div_round_ticks(timeout_ms, tick_ms, 2); - phase1_ticks = div_round_ticks(timeout_ms - pretimeout_ms, tick_ms, 1); - phase2_ticks = total_ticks - phase1_ticks; + total_ticks = max(2, DIV_ROUND_UP(timeout_ms, tick_ms)); + phase2_ticks = max(1, pretimeout_ms / tick_ms); + phase1_ticks = total_ticks - phase2_ticks; prescale_next++; } while (phase1_ticks > OTTO_WDT_PHASE_TICKS_MAX From 1147eb0dc29bd33aa3499f9d02777d4165587575 Mon Sep 17 00:00:00 2001 From: Sander Vanheule Date: Fri, 15 May 2026 23:23:51 +0200 Subject: [PATCH 330/655] watchdog: realtek-otto: enable clock before using I/O As the watchdog is normally on the same bus as the UART peripheral, the bootloader will have ensured the bus' clock is up and running before the watchdog driver is probed. Nevertheless, let's do things the right way and enable the watchdog's clock before performing I/O accesses. Signed-off-by: Sander Vanheule Link: https://lore.kernel.org/r/20260515212351.752054-3-sander@svanheule.net Signed-off-by: Guenter Roeck --- drivers/watchdog/realtek_otto_wdt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/realtek_otto_wdt.c b/drivers/watchdog/realtek_otto_wdt.c index 1495e8a8cbb5..01b3ef89bacf 100644 --- a/drivers/watchdog/realtek_otto_wdt.c +++ b/drivers/watchdog/realtek_otto_wdt.c @@ -296,15 +296,15 @@ static int otto_wdt_probe(struct platform_device *pdev) if (IS_ERR(ctrl->base)) return PTR_ERR(ctrl->base); + ret = otto_wdt_probe_clk(ctrl); + if (ret) + return ret; + /* Clear any old interrupts and reset initial state */ iowrite32(OTTO_WDT_INTR_PHASE_1 | OTTO_WDT_INTR_PHASE_2, ctrl->base + OTTO_WDT_REG_INTR); iowrite32(OTTO_WDT_CTRL_DEFAULT, ctrl->base + OTTO_WDT_REG_CTRL); - ret = otto_wdt_probe_clk(ctrl); - if (ret) - return ret; - ctrl->irq_phase1 = platform_get_irq_byname(pdev, "phase1"); if (ctrl->irq_phase1 < 0) return ctrl->irq_phase1; From a7a24f0eaa7163f6988badee601492deb9e51551 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:03:57 +0200 Subject: [PATCH 331/655] spi: altera-platform: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-2-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-altera-platform.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c index fc81de2610ef..3ee5d3480bb4 100644 --- a/drivers/spi/spi-altera-platform.c +++ b/drivers/spi/spi-altera-platform.c @@ -39,12 +39,12 @@ static int altera_spi_probe(struct platform_device *pdev) enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN; struct altera_spi *hw; struct spi_controller *host; - int err = -ENODEV; + int err; u16 i; - host = spi_alloc_host(&pdev->dev, sizeof(struct altera_spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct altera_spi)); if (!host) - return err; + return -ENOMEM; /* setup the host state. */ host->bus_num = -1; @@ -54,8 +54,7 @@ static int altera_spi_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Invalid number of chipselect: %u\n", pdata->num_chipselect); - err = -EINVAL; - goto exit; + return -EINVAL; } host->num_chipselect = pdata->num_chipselect; @@ -80,7 +79,7 @@ static int altera_spi_probe(struct platform_device *pdev) hw->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!hw->regmap) { dev_err(&pdev->dev, "get regmap failed\n"); - goto exit; + return -ENODEV; } regoff = platform_get_resource(pdev, IORESOURCE_REG, 0); @@ -90,17 +89,14 @@ static int altera_spi_probe(struct platform_device *pdev) void __iomem *res; res = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(res)) { - err = PTR_ERR(res); - goto exit; - } + if (IS_ERR(res)) + return PTR_ERR(res); hw->regmap = devm_regmap_init_mmio(&pdev->dev, res, &spi_altera_config); if (IS_ERR(hw->regmap)) { dev_err(&pdev->dev, "regmap mmio init failed\n"); - err = PTR_ERR(hw->regmap); - goto exit; + return PTR_ERR(hw->regmap); } } @@ -112,12 +108,12 @@ static int altera_spi_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0, pdev->name, host); if (err) - goto exit; + return err; } err = devm_spi_register_controller(&pdev->dev, host); if (err) - goto exit; + return err; if (pdata) { for (i = 0; i < pdata->num_devices; i++) { @@ -131,9 +127,6 @@ static int altera_spi_probe(struct platform_device *pdev) dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq); return 0; -exit: - spi_controller_put(host); - return err; } #ifdef CONFIG_OF From 5b4a0450fe2f7912f34590721eb191010bf98dd3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:03:58 +0200 Subject: [PATCH 332/655] spi: armada-3700: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-3-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 44 +++++++++++------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 78248729d3e9..ca2faa265ca0 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -818,17 +818,13 @@ static int a3700_spi_probe(struct platform_device *pdev) u32 num_cs = 0; int irq, ret = 0; - host = spi_alloc_host(dev, sizeof(*spi)); - if (!host) { - dev_err(dev, "host allocation failed\n"); - ret = -ENOMEM; - goto out; - } + host = devm_spi_alloc_host(dev, sizeof(*spi)); + if (!host) + return -ENOMEM; if (of_property_read_u32(dev->of_node, "num-cs", &num_cs)) { dev_err(dev, "could not find num-cs\n"); - ret = -ENXIO; - goto error; + return -ENXIO; } host->bus_num = pdev->id; @@ -849,25 +845,20 @@ static int a3700_spi_probe(struct platform_device *pdev) spi->host = host; spi->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(spi->base)) { - ret = PTR_ERR(spi->base); - goto error; - } + if (IS_ERR(spi->base)) + return PTR_ERR(spi->base); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = -ENXIO; - goto error; - } + if (irq < 0) + return -ENXIO; + spi->irq = irq; init_completion(&spi->done); spi->clk = devm_clk_get_prepared(dev, NULL); - if (IS_ERR(spi->clk)) { - dev_err(dev, "could not find clk: %ld\n", PTR_ERR(spi->clk)); - goto error; - } + if (IS_ERR(spi->clk)) + return dev_err_probe(dev, PTR_ERR(spi->clk), "could not find clk\n"); host->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ, clk_get_rate(spi->clk)); @@ -878,23 +869,16 @@ static int a3700_spi_probe(struct platform_device *pdev) ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0, dev_name(dev), host); - if (ret) { - dev_err(dev, "could not request IRQ: %d\n", ret); - goto error; - } + if (ret) + return dev_err_probe(dev, ret, "could not request IRQ\n"); ret = devm_spi_register_controller(dev, host); if (ret) { dev_err(dev, "Failed to register host\n"); - goto error; + return ret; } return 0; - -error: - spi_controller_put(host); -out: - return ret; } static struct platform_driver a3700_spi_driver = { From ee9575d2b3db1f3fde4563b6e52832dacc49d9c9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:03:59 +0200 Subject: [PATCH 333/655] spi: clps711x: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-4-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index d6458e59d41b..382c3c81c4b9 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -99,7 +99,7 @@ static int spi_clps711x_probe(struct platform_device *pdev) if (irq < 0) return irq; - host = spi_alloc_host(&pdev->dev, sizeof(*hw)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*hw)); if (!host) return -ENOMEM; @@ -113,22 +113,16 @@ static int spi_clps711x_probe(struct platform_device *pdev) hw = spi_controller_get_devdata(host); hw->spi_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(hw->spi_clk)) { - ret = PTR_ERR(hw->spi_clk); - goto err_out; - } + if (IS_ERR(hw->spi_clk)) + return PTR_ERR(hw->spi_clk); hw->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(hw->syscon)) { - ret = PTR_ERR(hw->syscon); - goto err_out; - } + if (IS_ERR(hw->syscon)) + return PTR_ERR(hw->syscon); hw->syncio = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hw->syncio)) { - ret = PTR_ERR(hw->syncio); - goto err_out; - } + if (IS_ERR(hw->syncio)) + return PTR_ERR(hw->syncio); /* Disable extended mode due hardware problems */ regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0); @@ -139,16 +133,9 @@ static int spi_clps711x_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0, dev_name(&pdev->dev), host); if (ret) - goto err_out; + return ret; - ret = devm_spi_register_controller(&pdev->dev, host); - if (!ret) - return 0; - -err_out: - spi_controller_put(host); - - return ret; + return devm_spi_register_controller(&pdev->dev, host); } static const struct of_device_id clps711x_spi_dt_ids[] = { From 864c368199cf30cadf6d9b5dbab82a8504d9650a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:00 +0200 Subject: [PATCH 334/655] spi: falcon: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-5-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-falcon.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index cb15faabd88f..e00e808eafee 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -392,9 +392,8 @@ static int falcon_sflash_probe(struct platform_device *pdev) { struct falcon_sflash *priv; struct spi_controller *host; - int ret; - host = spi_alloc_host(&pdev->dev, sizeof(*priv)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*priv)); if (!host) return -ENOMEM; @@ -406,10 +405,7 @@ static int falcon_sflash_probe(struct platform_device *pdev) host->setup = falcon_sflash_setup; host->transfer_one_message = falcon_sflash_xfer_one; - ret = devm_spi_register_controller(&pdev->dev, host); - if (ret) - spi_controller_put(host); - return ret; + return devm_spi_register_controller(&pdev->dev, host); } static const struct of_device_id falcon_sflash_match[] = { From c087eb4603d90e992ff26483682ba62c8c3f5628 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:01 +0200 Subject: [PATCH 335/655] spi: fsi: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-6-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-fsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index f6a75f0184c4..451cb4cfdb9c 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -554,7 +554,7 @@ static int fsi_spi_probe(struct fsi_device *fsi) if (of_property_read_u32(np, "reg", &base)) continue; - ctlr = spi_alloc_host(dev, sizeof(*ctx)); + ctlr = devm_spi_alloc_host(dev, sizeof(*ctx)); if (!ctlr) break; @@ -571,9 +571,9 @@ static int fsi_spi_probe(struct fsi_device *fsi) rc = devm_spi_register_controller(dev, ctlr); if (rc) - spi_controller_put(ctlr); - else - num_controllers_registered++; + continue; + + num_controllers_registered++; } if (!num_controllers_registered) From 572a9fb1a6098170b669681e8444e8516a95b8c3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:02 +0200 Subject: [PATCH 336/655] spi: hisi-sfc-v3xx: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-7-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-hisi-sfc-v3xx.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index b2af2eed197f..eeeb86381862 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -436,7 +436,7 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev) u32 version, glb_config; int ret; - ctlr = spi_alloc_host(&pdev->dev, sizeof(*host)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*host)); if (!ctlr) return -ENOMEM; @@ -451,16 +451,12 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); host->regbase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(host->regbase)) { - ret = PTR_ERR(host->regbase); - goto err_put_host; - } + if (IS_ERR(host->regbase)) + return PTR_ERR(host->regbase); host->irq = platform_get_irq_optional(pdev, 0); - if (host->irq == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_put_host; - } + if (host->irq == -EPROBE_DEFER) + return -EPROBE_DEFER; hisi_sfc_v3xx_disable_int(host); @@ -501,16 +497,12 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev) ret = devm_spi_register_controller(dev, ctlr); if (ret) - goto err_put_host; + return ret; dev_info(&pdev->dev, "hw version 0x%x, %s mode.\n", version, host->irq ? "irq" : "polling"); return 0; - -err_put_host: - spi_controller_put(ctlr); - return ret; } static const struct acpi_device_id hisi_sfc_v3xx_acpi_ids[] = { From 0a290bb1ff0b11998db2b36c8ebcca4913ccacb7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:03 +0200 Subject: [PATCH 337/655] spi: jcore: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-8-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-jcore.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c index e37ca22e04ba..a75cd61ec7a3 100644 --- a/drivers/spi/spi-jcore.c +++ b/drivers/spi/spi-jcore.c @@ -146,11 +146,10 @@ static int jcore_spi_probe(struct platform_device *pdev) struct resource *res; u32 clock_freq; struct clk *clk; - int err = -ENODEV; - host = spi_alloc_host(&pdev->dev, sizeof(struct jcore_spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct jcore_spi)); if (!host) - return err; + return -ENOMEM; /* Setup the host state. */ host->num_chipselect = 3; @@ -167,14 +166,14 @@ static int jcore_spi_probe(struct platform_device *pdev) /* Find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) - goto exit_busy; + return -EBUSY; if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name)) - goto exit_busy; + return -EBUSY; hw->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!hw->base) - goto exit_busy; + return -EBUSY; /* * The SPI clock rate controlled via a configurable clock divider @@ -200,17 +199,7 @@ static int jcore_spi_probe(struct platform_device *pdev) jcore_spi_baudrate(hw, 400000); /* Register our spi controller */ - err = devm_spi_register_controller(&pdev->dev, host); - if (err) - goto exit; - - return 0; - -exit_busy: - err = -EBUSY; -exit: - spi_controller_put(host); - return err; + return devm_spi_register_controller(&pdev->dev, host); } static const struct of_device_id jcore_spi_of_match[] = { From 06ba67d9d47929652f66b7c3eeda5293f48a4545 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:04 +0200 Subject: [PATCH 338/655] spi: lp8841-rtc: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-9-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-lp8841-rtc.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-lp8841-rtc.c b/drivers/spi/spi-lp8841-rtc.c index e466866d5e80..355d9df4d1be 100644 --- a/drivers/spi/spi-lp8841-rtc.c +++ b/drivers/spi/spi-lp8841-rtc.c @@ -185,7 +185,7 @@ spi_lp8841_rtc_probe(struct platform_device *pdev) struct spi_controller *host; struct spi_lp8841_rtc *data; - host = spi_alloc_host(&pdev->dev, sizeof(*data)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*data)); if (!host) return -ENOMEM; platform_set_drvdata(pdev, host); @@ -208,23 +208,17 @@ spi_lp8841_rtc_probe(struct platform_device *pdev) ret = PTR_ERR_OR_ZERO(data->iomem); if (ret) { dev_err(&pdev->dev, "failed to get IO address\n"); - goto err_put_host; + return ret; } /* register with the SPI framework */ ret = devm_spi_register_controller(&pdev->dev, host); if (ret) { dev_err(&pdev->dev, "cannot register spi host\n"); - goto err_put_host; + return ret; } - return ret; - - -err_put_host: - spi_controller_put(host); - - return ret; + return 0; } MODULE_ALIAS("platform:" DRIVER_NAME); From 4fee1d3a563d2fd6eee8434adde0af10cd7db2ae Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:05 +0200 Subject: [PATCH 339/655] spi: lp8841-rtc: drop unused ifdef Drop the probe CONFIG_OF ifdef which is unused since commit 3974a585be78 ("spi: Drop duplicate of_node assignment"). Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-10-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-lp8841-rtc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-lp8841-rtc.c b/drivers/spi/spi-lp8841-rtc.c index 355d9df4d1be..b2546a3a9eaa 100644 --- a/drivers/spi/spi-lp8841-rtc.c +++ b/drivers/spi/spi-lp8841-rtc.c @@ -199,8 +199,6 @@ spi_lp8841_rtc_probe(struct platform_device *pdev) host->set_cs = spi_lp8841_rtc_set_cs; host->transfer_one = spi_lp8841_rtc_transfer_one; host->bits_per_word_mask = SPI_BPW_MASK(8); -#ifdef CONFIG_OF -#endif data = spi_controller_get_devdata(host); From 1e447a5aa12443410da74b4bbf2ae922ca63ef4e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:06 +0200 Subject: [PATCH 340/655] spi: meson-spifc: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-11-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spifc.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index b818950a8cb7..d700fa315223 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -288,9 +288,9 @@ static int meson_spifc_probe(struct platform_device *pdev) struct meson_spifc *spifc; void __iomem *base; unsigned int rate; - int ret = 0; + int ret; - host = spi_alloc_host(&pdev->dev, sizeof(struct meson_spifc)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct meson_spifc)); if (!host) return -ENOMEM; @@ -300,23 +300,18 @@ static int meson_spifc_probe(struct platform_device *pdev) spifc->dev = &pdev->dev; base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto out_err; - } + if (IS_ERR(base)) + return PTR_ERR(base); spifc->regmap = devm_regmap_init_mmio(spifc->dev, base, &spifc_regmap_config); - if (IS_ERR(spifc->regmap)) { - ret = PTR_ERR(spifc->regmap); - goto out_err; - } + if (IS_ERR(spifc->regmap)) + return PTR_ERR(spifc->regmap); spifc->clk = devm_clk_get_enabled(spifc->dev, NULL); if (IS_ERR(spifc->clk)) { dev_err(spifc->dev, "missing clock\n"); - ret = PTR_ERR(spifc->clk); - goto out_err; + return PTR_ERR(spifc->clk); } rate = clk_get_rate(spifc->clk); @@ -342,8 +337,7 @@ static int meson_spifc_probe(struct platform_device *pdev) return 0; out_pm: pm_runtime_disable(spifc->dev); -out_err: - spi_controller_put(host); + return ret; } From 60db555fca747c8d860d9b683d281d903c4dab50 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:07 +0200 Subject: [PATCH 341/655] spi: mux: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-12-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-mux.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-mux.c b/drivers/spi/spi-mux.c index bd122de152c0..08fe1fa32dea 100644 --- a/drivers/spi/spi-mux.c +++ b/drivers/spi/spi-mux.c @@ -127,9 +127,8 @@ static int spi_mux_probe(struct spi_device *spi) { struct spi_controller *ctlr; struct spi_mux_priv *priv; - int ret; - ctlr = spi_alloc_host(&spi->dev, sizeof(*priv)); + ctlr = devm_spi_alloc_host(&spi->dev, sizeof(*priv)); if (!ctlr) return -ENOMEM; @@ -146,9 +145,8 @@ static int spi_mux_probe(struct spi_device *spi) priv->mux = devm_mux_control_get(&spi->dev, NULL); if (IS_ERR(priv->mux)) { - ret = dev_err_probe(&spi->dev, PTR_ERR(priv->mux), - "failed to get control-mux\n"); - goto err_put_ctlr; + return dev_err_probe(&spi->dev, PTR_ERR(priv->mux), + "failed to get control-mux\n"); } priv->current_cs = SPI_MUX_NO_CS; @@ -164,16 +162,7 @@ static int spi_mux_probe(struct spi_device *spi) ctlr->must_async = true; ctlr->defer_optimize_message = true; - ret = devm_spi_register_controller(&spi->dev, ctlr); - if (ret) - goto err_put_ctlr; - - return 0; - -err_put_ctlr: - spi_controller_put(ctlr); - - return ret; + return devm_spi_register_controller(&spi->dev, ctlr); } static const struct spi_device_id spi_mux_id[] = { From f3d1dc0bc65ae902a821bc2e03baaa107b319350 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 11 May 2026 17:04:08 +0200 Subject: [PATCH 342/655] spi: xlp: switch to managed controller allocation Switch to device managed controller allocation for consistency and to simplify error handling. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260511150408.796155-13-johan@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-xlp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c index be8bbe1cbba3..d014955e6d4b 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -398,7 +398,7 @@ static int xlp_spi_probe(struct platform_device *pdev) xspi->spi_clk = clk_get_rate(clk); - host = spi_alloc_host(&pdev->dev, 0); + host = devm_spi_alloc_host(&pdev->dev, 0); if (!host) { dev_err(&pdev->dev, "could not alloc host\n"); return -ENOMEM; @@ -418,7 +418,6 @@ static int xlp_spi_probe(struct platform_device *pdev) err = devm_spi_register_controller(&pdev->dev, host); if (err) { dev_err(&pdev->dev, "spi register host failed!\n"); - spi_controller_put(host); return err; } From c574bdb524095d24169e229b2e3b9318c72e733a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 18 May 2026 19:19:01 +0200 Subject: [PATCH 343/655] watchdog: ziirave_wdt: Use named initializers for struct i2c_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://lore.kernel.org/r/20260518171901.904094-2-u.kleine-koenig@baylibre.com Signed-off-by: Guenter Roeck --- drivers/watchdog/ziirave_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c index 5c6e3fa001d8..f3bb935c08c2 100644 --- a/drivers/watchdog/ziirave_wdt.c +++ b/drivers/watchdog/ziirave_wdt.c @@ -718,7 +718,7 @@ static void ziirave_wdt_remove(struct i2c_client *client) } static const struct i2c_device_id ziirave_wdt_id[] = { - { "rave-wdt" }, + { .name = "rave-wdt" }, { } }; MODULE_DEVICE_TABLE(i2c, ziirave_wdt_id); From bf62d130b1f2e34d91ba606a8c1bd3037d6c1450 Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Mon, 18 May 2026 22:30:51 +0530 Subject: [PATCH 344/655] spi: qcom-geni: trace: Add trace events for Qualcomm GENI SPI Add tracepoint support to the Qualcomm GENI SPI driver to provide runtime visibility into driver behavior without requiring invasive debug patches. The trace events cover clock and setup parameter configuration, transfer metadata, interrupt status to be making it easier to diagnose communication issues in the field.. Reviewed-by: Konrad Dybcio Signed-off-by: Praveen Talari Link: https://patch.msgid.link/20260518-add-tracepoints-for-qcom-geni-spi-v3-1-7928f6810a79@oss.qualcomm.com Signed-off-by: Mark Brown --- include/trace/events/qcom_geni_spi.h | 103 +++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 include/trace/events/qcom_geni_spi.h diff --git a/include/trace/events/qcom_geni_spi.h b/include/trace/events/qcom_geni_spi.h new file mode 100644 index 000000000000..6d027adf2e1d --- /dev/null +++ b/include/trace/events/qcom_geni_spi.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_geni_spi + +#if !defined(_TRACE_QCOM_GENI_SPI_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_QCOM_GENI_SPI_H + +#include + +TRACE_EVENT(geni_spi_setup_params, + TP_PROTO(struct device *dev, u8 cs, u32 mode, + u32 mode_changed, bool cs_changed), + TP_ARGS(dev, cs, mode, mode_changed, cs_changed), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(u8, cs) + __field(u32, mode) + __field(u32, mode_changed) + __field(bool, cs_changed) + ), + + TP_fast_assign(__assign_str(name); + __entry->cs = cs; + __entry->mode = mode; + __entry->mode_changed = mode_changed; + __entry->cs_changed = cs_changed; + ), + + TP_printk("%s: cs=%u mode=0x%08x mode_changed=0x%08x cs_changed=%d", + __get_str(name), __entry->cs, __entry->mode, + __entry->mode_changed, __entry->cs_changed) +); + +TRACE_EVENT(geni_spi_clk_cfg, + TP_PROTO(struct device *dev, unsigned long req_hz, + unsigned long sclk_hz, unsigned int clk_idx, + unsigned int clk_div, unsigned int bpw), + TP_ARGS(dev, req_hz, sclk_hz, clk_idx, clk_div, bpw), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(unsigned long, req_hz) + __field(unsigned long, sclk_hz) + __field(unsigned int, clk_idx) + __field(unsigned int, clk_div) + __field(unsigned int, bpw) + ), + + TP_fast_assign(__assign_str(name); + __entry->req_hz = req_hz; + __entry->sclk_hz = sclk_hz; + __entry->clk_idx = clk_idx; + __entry->clk_div = clk_div; + __entry->bpw = bpw; + ), + + TP_printk("%s: req_hz=%lu sclk_hz=%lu clk_idx=%u clk_div=%u bpw=%u", + __get_str(name), __entry->req_hz, __entry->sclk_hz, + __entry->clk_idx, __entry->clk_div, __entry->bpw) +); + +TRACE_EVENT(geni_spi_transfer, + TP_PROTO(struct device *dev, unsigned int len, u32 m_cmd), + TP_ARGS(dev, len, m_cmd), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(unsigned int, len) + __field(u32, m_cmd) + ), + + TP_fast_assign(__assign_str(name); + __entry->len = len; + __entry->m_cmd = m_cmd; + ), + + TP_printk("%s: len=%u m_cmd=0x%08x", + __get_str(name), __entry->len, __entry->m_cmd) +); + +TRACE_EVENT(geni_spi_irq, + TP_PROTO(struct device *dev, u32 m_irq, u32 dma_tx, u32 dma_rx), + TP_ARGS(dev, m_irq, dma_tx, dma_rx), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(u32, m_irq) + __field(u32, dma_tx) + __field(u32, dma_rx) + ), + + TP_fast_assign(__assign_str(name); + __entry->m_irq = m_irq; + __entry->dma_tx = dma_tx; + __entry->dma_rx = dma_rx; + ), + + TP_printk("%s: m_irq=0x%08x dma_tx=0x%08x dma_rx=0x%08x", + __get_str(name), __entry->m_irq, __entry->dma_tx, + __entry->dma_rx) +); + +#endif /* _TRACE_QCOM_GENI_SPI_H */ + +/* This part must be outside protection */ +#include From b5687af4af890cfd0a59f879ded40be92a19076e Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Mon, 18 May 2026 22:30:52 +0530 Subject: [PATCH 345/655] spi: qcom-geni: Add trace events for Qualcomm GENI SPI driver Add tracepoints to the Qualcomm GENI (Generic Interface) SPI driver. These trace events enable runtime debugging and performance analysis of SPI operations. The trace events capture SPI clock configuration, setup parameters, transfer details, interrupt status. Reviewed-by: Konrad Dybcio Signed-off-by: Praveen Talari Link: https://patch.msgid.link/20260518-add-tracepoints-for-qcom-geni-spi-v3-2-7928f6810a79@oss.qualcomm.com Signed-off-by: Mark Brown --- drivers/spi/spi-geni-qcom.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index d5fb0edc8e0c..a04cdc1e5ad4 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017-2018, The Linux foundation. All rights reserved. +#define CREATE_TRACE_POINTS +#include + #include #include #include @@ -332,6 +335,9 @@ static int geni_spi_set_clock_and_bw(struct spi_geni_master *mas, writel(clk_sel, se->base + SE_GENI_CLK_SEL); writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); + trace_geni_spi_clk_cfg(mas->dev, clk_hz, mas->cur_sclk_hz, idx, div, + mas->cur_bits_per_word); + /* Set BW quota for CPU as driver supports FIFO mode only. */ se->icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(mas->cur_speed_hz); ret = geni_icc_set_bw(se); @@ -366,6 +372,9 @@ static int setup_fifo_params(struct spi_device *spi_slv, if ((mode_changed & SPI_CS_HIGH) || (cs_changed && (spi_slv->mode & SPI_CS_HIGH))) writel((spi_slv->mode & SPI_CS_HIGH) ? BIT(chipselect) : 0, se->base + SE_SPI_DEMUX_OUTPUT_INV); + trace_geni_spi_setup_params(mas->dev, chipselect, spi_slv->mode, + mode_changed, cs_changed); + return 0; } @@ -861,6 +870,8 @@ static int setup_se_xfer(struct spi_transfer *xfer, spin_lock_irq(&mas->lock); geni_se_setup_m_cmd(se, m_cmd, m_params); + trace_geni_spi_transfer(mas->dev, len, m_cmd); + if (mas->cur_xfer_mode == GENI_SE_DMA) { if (m_cmd & SPI_RX_ONLY) geni_se_rx_init_dma(se, sg_dma_address(xfer->rx_sg.sgl), @@ -915,6 +926,8 @@ static irqreturn_t geni_spi_isr(int irq, void *data) if (!m_irq && !dma_tx_status && !dma_rx_status) return IRQ_NONE; + trace_geni_spi_irq(mas->dev, m_irq, dma_tx_status, dma_rx_status); + if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN | M_RX_FIFO_RD_ERR_EN | M_RX_FIFO_WR_ERR_EN | M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN)) From 0c5b5c40dc31089e8e59d53a32313baa50bc0809 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 18 May 2026 17:56:14 -0700 Subject: [PATCH 346/655] spi: cadence-xspi: Add COMPILE_TEST support The Cadence XSPI driver uses readq() and writeq(), which are not provided directly by all 32-bit architectures. Include the generic non-atomic 64-bit I/O accessor fallback for non-64-bit builds so the driver can build there. Drop the 64BIT dependency at the same time. The driver only needs MMIO and the SPI memory interface at build time, and the fallback accessors cover the 32-bit compile-test case. Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260519005614.628437-1-rosenp@gmail.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 3 ++- drivers/spi/spi-cadence-xspi.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8782514bb89b..957c3e065b83 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -321,7 +321,8 @@ config SPI_CADENCE_QUADSPI config SPI_CADENCE_XSPI tristate "Cadence XSPI controller" - depends on OF && HAS_IOMEM && 64BIT + depends on HAS_IOMEM || COMPILE_TEST + depends on OF depends on SPI_MEM help Enable support for the Cadence XSPI Flash controller. diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 32fa19ebf7a9..c45b29c043bf 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -22,6 +22,10 @@ #include #include +#ifndef CONFIG_64BIT +#include +#endif + #define CDNS_XSPI_MAGIC_NUM_VALUE 0x6522 #define CDNS_XSPI_MAX_BANKS 8 #define CDNS_XSPI_NAME "cadence-xspi" From cdc517688ffa2c30a64a20b558a9ecbf046c70f1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 May 2026 17:15:15 +0800 Subject: [PATCH 347/655] regulator: dt-bindings: mt6359: Drop regulator-name pattern restrictions The name of the regulator should match what the board design specifies for the power rail. There should be no limitations on what the name can be, and they definitely don't always follow the PMIC's own names. Drop the restrictions on regulator-name. Fixes: 8771456635d5 ("dt-bindings: regulator: Add document for MT6359 regulator") Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260514091520.2718987-3-wenst@chromium.org Signed-off-by: Mark Brown --- .../bindings/regulator/mt6359-regulator.yaml | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml index fe4ac9350ba0..ac925334ae83 100644 --- a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml @@ -18,84 +18,41 @@ patternProperties: "^buck_v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$" - unevaluatedProperties: false "^ldo_v(ibr|rf12|usb|camio|efuse|xo22)$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^v(ibr|rf12|usb|camio|efuse|xo22)$" - unevaluatedProperties: false "^ldo_v(rfck|emc|a12|a09|ufs|bbck)$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^v(rfck|emc|a12|a09|ufs|bbck)$" - unevaluatedProperties: false "^ldo_vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$" - unevaluatedProperties: false "^ldo_vsram_(proc2|others|md|proc1|others_sshub)$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^vsram_(proc2|others|md|proc1|others_sshub)$" - unevaluatedProperties: false "^ldo_v(fe|bif|io)28$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^v(fe|bif|io)28$" - unevaluatedProperties: false "^ldo_v(aud|io|aux|rf|m)18$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^v(aud|io|aux|rf|m)18$" - unevaluatedProperties: false "^ldo_vsim[12]$": type: object $ref: regulator.yaml# - - properties: - regulator-name: - pattern: "^vsim[12]$" - - required: - - regulator-name - unevaluatedProperties: false additionalProperties: false From beb4fe27998936c069c9b52b89ad65c4c697fc46 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 May 2026 17:15:16 +0800 Subject: [PATCH 348/655] regulator: dt-bindings: mt6359: Deprecate bogus vcn33_[12]_* split regulators vcn33_[12]_bt and vcn33_[12]_wifi refer to the same output. There are two enable bits in the registers so that BT and WiFi drivers can toggle them separately without any coordination. If either bit is set, then the regulator output is enabled. Deprecate the existing regulators, and add proper regulators matching the outputs: vcn33_1 and vcn33_2. Signed-off-by: Chen-Yu Tsai Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260514091520.2718987-4-wenst@chromium.org Signed-off-by: Mark Brown --- .../bindings/regulator/mt6359-regulator.yaml | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml index ac925334ae83..e3c20412c8a7 100644 --- a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml @@ -30,7 +30,7 @@ patternProperties: $ref: regulator.yaml# unevaluatedProperties: false - "^ldo_vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$": + "^ldo_vcn(18|13|33_[12])$": type: object $ref: regulator.yaml# unevaluatedProperties: false @@ -55,6 +55,15 @@ patternProperties: $ref: regulator.yaml# unevaluatedProperties: false + "^ldo_vcn33_[12]_(bt|wifi)$": + type: object + $ref: regulator.yaml# + description: + vcn33_[12]_(bt|wifi) are incorrect representations. + Use vcn33_[12] instead. + deprecated: true + unevaluatedProperties: false + additionalProperties: false examples: @@ -203,13 +212,8 @@ examples: regulator-min-microvolt = <900000>; regulator-max-microvolt = <1300000>; }; - mt6359_vcn33_1_bt_ldo_reg: ldo_vcn33_1_bt { - regulator-name = "vcn33_1_bt"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <3500000>; - }; - mt6359_vcn33_1_wifi_ldo_reg: ldo_vcn33_1_wifi { - regulator-name = "vcn33_1_wifi"; + mt6359_vcn33_1_bt_ldo_reg: ldo_vcn33_1 { + regulator-name = "vcn33_1"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <3500000>; }; @@ -270,13 +274,8 @@ examples: regulator-min-microvolt = <2500000>; regulator-max-microvolt = <3300000>; }; - mt6359_vcn33_2_bt_ldo_reg: ldo_vcn33_2_bt { - regulator-name = "vcn33_2_bt"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <3500000>; - }; - mt6359_vcn33_2_wifi_ldo_reg: ldo_vcn33_2_wifi { - regulator-name = "vcn33_2_wifi"; + mt6359_vcn33_2_bt_ldo_reg: ldo_vcn33_2 { + regulator-name = "vcn33_2"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <3500000>; }; From eb17a319f1c95b5a8abb3d1ff3e30068a38173a7 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 May 2026 17:15:17 +0800 Subject: [PATCH 349/655] regulator: mt6359: const-ify regulator descriptions The regulator descriptions and extended descriptions don't change at runtime. The only reason they are not const is that the regulator driver data is non-const. Const-ify the descriptions and all references to them. For the driver data, explicitly cast it to non-const void *. Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260514091520.2718987-5-wenst@chromium.org Signed-off-by: Mark Brown --- drivers/regulator/mt6359-regulator.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c index c8a788858824..bcf9a476a34e 100644 --- a/drivers/regulator/mt6359-regulator.c +++ b/drivers/regulator/mt6359-regulator.c @@ -251,7 +251,7 @@ static int mt6359_get_status(struct regulator_dev *rdev) { int ret; u32 regval; - struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); ret = regmap_read(rdev->regmap, info->status_reg, ®val); if (ret != 0) { @@ -267,7 +267,7 @@ static int mt6359_get_status(struct regulator_dev *rdev) static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev) { - struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); int ret, regval; ret = regmap_read(rdev->regmap, info->modeset_reg, ®val); @@ -299,7 +299,7 @@ static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev) static int mt6359_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { - struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); int ret = 0, val; int curr_mode; @@ -354,7 +354,7 @@ static int mt6359_regulator_set_mode(struct regulator_dev *rdev, static int mt6359p_vemc_set_voltage_sel(struct regulator_dev *rdev, u32 sel) { - struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); int ret; u32 val = 0; @@ -393,7 +393,7 @@ static int mt6359p_vemc_set_voltage_sel(struct regulator_dev *rdev, static int mt6359p_vemc_get_voltage_sel(struct regulator_dev *rdev) { - struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); int ret; u32 val = 0; @@ -469,7 +469,7 @@ static const struct regulator_ops mt6359p_vemc_ops = { }; /* The array is indexed by id(MT6359_ID_XXX) */ -static struct mt6359_regulator_info mt6359_regulators[] = { +static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500, MT6359_RG_BUCK_VS1_EN_ADDR, MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR, @@ -705,7 +705,7 @@ static struct mt6359_regulator_info mt6359_regulators[] = { MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT), }; -static struct mt6359_regulator_info mt6359p_regulators[] = { +static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500, MT6359_RG_BUCK_VS1_EN_ADDR, MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR, @@ -950,7 +950,7 @@ static int mt6359_regulator_probe(struct platform_device *pdev) struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = {}; struct regulator_dev *rdev; - struct mt6359_regulator_info *mt6359_info; + const struct mt6359_regulator_info *mt6359_info; int i, hw_ver, ret; ret = regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver); @@ -965,7 +965,8 @@ static int mt6359_regulator_probe(struct platform_device *pdev) config.dev = mt6397->dev; config.regmap = mt6397->regmap; for (i = 0; i < MT6359_MAX_REGULATOR; i++, mt6359_info++) { - config.driver_data = mt6359_info; + /* drop const here, but all uses in the driver are const */ + config.driver_data = (void *)mt6359_info; rdev = devm_regulator_register(&pdev->dev, &mt6359_info->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name); From 10be8fc1d534b4c23a9056ad20ff2bc0b314eeb2 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 May 2026 17:15:18 +0800 Subject: [PATCH 350/655] regulator: mt6359: Add regulator supply names The MT6359 regulator DT binding defines the supply names for the PMIC. Add support for them by adding .supply_name field settings for each regulator. The buck regulators each have their own supply. The name of the supply is related to the name of the buck regulator. The LDOs have shared supplies. Add the supply name to the declaration of each regulator. At the moment they are declared explicitly, but the buck regulator macro can be made to derive both the match string and supply name from the base name once the *_sshub regulators are figured out and removed. For context, the *_sshub regulators are not separate regulators, but separate settings for the same name regulators without the "_sshub" suffix. Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260514091520.2718987-6-wenst@chromium.org Signed-off-by: Mark Brown --- drivers/regulator/mt6359-regulator.c | 220 +++++++++++++++------------ 1 file changed, 125 insertions(+), 95 deletions(-) diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c index bcf9a476a34e..46cafe93b24e 100644 --- a/drivers/regulator/mt6359-regulator.c +++ b/drivers/regulator/mt6359-regulator.c @@ -38,7 +38,7 @@ struct mt6359_regulator_info { u32 lp_mode_mask; }; -#define MT6359_BUCK(match, _name, min, max, step, \ +#define MT6359_BUCK(match, _name, supply, min, max, step, \ _enable_reg, _status_reg, \ _vsel_reg, _vsel_mask, \ _lp_mode_reg, _lp_mode_shift, \ @@ -46,6 +46,7 @@ struct mt6359_regulator_info { [MT6359_ID_##_name] = { \ .desc = { \ .name = #_name, \ + .supply_name = supply, \ .of_match = of_match_ptr(match), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &mt6359_volt_linear_ops, \ @@ -69,11 +70,12 @@ struct mt6359_regulator_info { .modeset_mask = BIT(_modeset_shift), \ } -#define MT6359_LDO_LINEAR(match, _name, min, max, step, \ +#define MT6359_LDO_LINEAR(match, _name, supply, min, max, step, \ _enable_reg, _status_reg, _vsel_reg, _vsel_mask) \ [MT6359_ID_##_name] = { \ .desc = { \ .name = #_name, \ + .supply_name = supply, \ .of_match = of_match_ptr(match), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &mt6359_volt_linear_ops, \ @@ -92,12 +94,13 @@ struct mt6359_regulator_info { .qi = BIT(0), \ } -#define MT6359_LDO(match, _name, _volt_table, \ +#define MT6359_LDO(match, _name, supply, _volt_table, \ _enable_reg, _enable_mask, _status_reg, \ _vsel_reg, _vsel_mask, _en_delay) \ [MT6359_ID_##_name] = { \ .desc = { \ .name = #_name, \ + .supply_name = supply, \ .of_match = of_match_ptr(match), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &mt6359_volt_table_ops, \ @@ -116,11 +119,13 @@ struct mt6359_regulator_info { .qi = BIT(0), \ } -#define MT6359_REG_FIXED(match, _name, _enable_reg, \ - _status_reg, _fixed_volt) \ +#define MT6359_REG_FIXED(match, _name, supply, \ + _enable_reg, _status_reg, \ + _fixed_volt) \ [MT6359_ID_##_name] = { \ .desc = { \ .name = #_name, \ + .supply_name = supply, \ .of_match = of_match_ptr(match), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &mt6359_volt_fixed_ops, \ @@ -136,12 +141,14 @@ struct mt6359_regulator_info { .qi = BIT(0), \ } -#define MT6359P_LDO1(match, _name, _ops, _volt_table, \ - _enable_reg, _enable_mask, _status_reg, \ - _vsel_reg, _vsel_mask) \ +#define MT6359P_LDO1(match, _name, supply, _ops, \ + _volt_table, _enable_reg, \ + _enable_mask, _status_reg, \ + _vsel_reg, _vsel_mask) \ [MT6359_ID_##_name] = { \ .desc = { \ .name = #_name, \ + .supply_name = supply, \ .of_match = of_match_ptr(match), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &_ops, \ @@ -470,14 +477,14 @@ static const struct regulator_ops mt6359p_vemc_ops = { /* The array is indexed by id(MT6359_ID_XXX) */ static const struct mt6359_regulator_info mt6359_regulators[] = { - MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500, + MT6359_BUCK("buck_vs1", VS1, "vsys-vs1", 800000, 2200000, 12500, MT6359_RG_BUCK_VS1_EN_ADDR, MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR, MT6359_RG_BUCK_VS1_VOSEL_MASK << MT6359_RG_BUCK_VS1_VOSEL_SHIFT, MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT, MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT), - MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250, + MT6359_BUCK("buck_vgpu11", VGPU11, "vsys-vgpu11", 400000, 1193750, 6250, MT6359_RG_BUCK_VGPU11_EN_ADDR, MT6359_DA_VGPU11_EN_ADDR, MT6359_RG_BUCK_VGPU11_VOSEL_ADDR, MT6359_RG_BUCK_VGPU11_VOSEL_MASK << @@ -485,7 +492,7 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_RG_BUCK_VGPU11_LP_ADDR, MT6359_RG_BUCK_VGPU11_LP_SHIFT, MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT), - MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250, + MT6359_BUCK("buck_vmodem", VMODEM, "vsys-vmodem", 400000, 1100000, 6250, MT6359_RG_BUCK_VMODEM_EN_ADDR, MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_MASK << @@ -493,35 +500,35 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_RG_BUCK_VMODEM_LP_ADDR, MT6359_RG_BUCK_VMODEM_LP_SHIFT, MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT), - MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250, + MT6359_BUCK("buck_vpu", VPU, "vsys-vpu", 400000, 1193750, 6250, MT6359_RG_BUCK_VPU_EN_ADDR, MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR, MT6359_RG_BUCK_VPU_VOSEL_MASK << MT6359_RG_BUCK_VPU_VOSEL_SHIFT, MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT, MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT), - MT6359_BUCK("buck_vcore", VCORE, 400000, 1193750, 6250, + MT6359_BUCK("buck_vcore", VCORE, "vsys-vcore", 400000, 1193750, 6250, MT6359_RG_BUCK_VCORE_EN_ADDR, MT6359_DA_VCORE_EN_ADDR, MT6359_RG_BUCK_VCORE_VOSEL_ADDR, MT6359_RG_BUCK_VCORE_VOSEL_MASK << MT6359_RG_BUCK_VCORE_VOSEL_SHIFT, MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT, MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT), - MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500, + MT6359_BUCK("buck_vs2", VS2, "vsys-vs2", 800000, 1600000, 12500, MT6359_RG_BUCK_VS2_EN_ADDR, MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR, MT6359_RG_BUCK_VS2_VOSEL_MASK << MT6359_RG_BUCK_VS2_VOSEL_SHIFT, MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT, MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT), - MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + MT6359_BUCK("buck_vpa", VPA, "vsys-vpa", 500000, 3650000, 50000, MT6359_RG_BUCK_VPA_EN_ADDR, MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR, MT6359_RG_BUCK_VPA_VOSEL_MASK << MT6359_RG_BUCK_VPA_VOSEL_SHIFT, MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT, MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT), - MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250, + MT6359_BUCK("buck_vproc2", VPROC2, "vsys-vproc2", 400000, 1193750, 6250, MT6359_RG_BUCK_VPROC2_EN_ADDR, MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_MASK << @@ -529,7 +536,7 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_RG_BUCK_VPROC2_LP_ADDR, MT6359_RG_BUCK_VPROC2_LP_SHIFT, MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT), - MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250, + MT6359_BUCK("buck_vproc1", VPROC1, "vsys-vproc1", 400000, 1193750, 6250, MT6359_RG_BUCK_VPROC1_EN_ADDR, MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_MASK << @@ -537,7 +544,7 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_RG_BUCK_VPROC1_LP_ADDR, MT6359_RG_BUCK_VPROC1_LP_SHIFT, MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT), - MT6359_BUCK("buck_vcore_sshub", VCORE_SSHUB, 400000, 1193750, 6250, + MT6359_BUCK("buck_vcore_sshub", VCORE_SSHUB, "vsys-vcore", 400000, 1193750, 6250, MT6359_RG_BUCK_VCORE_SSHUB_EN_ADDR, MT6359_DA_VCORE_EN_ADDR, MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_ADDR, @@ -545,158 +552,159 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_SHIFT, MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT, MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT), - MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359_RG_LDO_VAUD18_EN_ADDR, + MT6359_REG_FIXED("ldo_vaud18", VAUD18, "vs1-ldo1", MT6359_RG_LDO_VAUD18_EN_ADDR, MT6359_DA_VAUD18_B_EN_ADDR, 1800000), - MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages, + MT6359_LDO("ldo_vsim1", VSIM1, "vsys-ldo2", vsim1_voltages, MT6359_RG_LDO_VSIM1_EN_ADDR, MT6359_RG_LDO_VSIM1_EN_SHIFT, MT6359_DA_VSIM1_B_EN_ADDR, MT6359_RG_VSIM1_VOSEL_ADDR, MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT, 480), - MT6359_LDO("ldo_vibr", VIBR, vibr_voltages, + MT6359_LDO("ldo_vibr", VIBR, "vsys-ldo1", vibr_voltages, MT6359_RG_LDO_VIBR_EN_ADDR, MT6359_RG_LDO_VIBR_EN_SHIFT, MT6359_DA_VIBR_B_EN_ADDR, MT6359_RG_VIBR_VOSEL_ADDR, MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages, + MT6359_LDO("ldo_vrf12", VRF12, "vs2-ldo2", vrf12_voltages, MT6359_RG_LDO_VRF12_EN_ADDR, MT6359_RG_LDO_VRF12_EN_SHIFT, MT6359_DA_VRF12_B_EN_ADDR, MT6359_RG_VRF12_VOSEL_ADDR, MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT, 120), - MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359_RG_LDO_VUSB_EN_0_ADDR, + MT6359_REG_FIXED("ldo_vusb", VUSB, "vsys-ldo2", MT6359_RG_LDO_VUSB_EN_0_ADDR, MT6359_DA_VUSB_B_EN_ADDR, 3000000), - MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250, + MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, "vs2-ldo1", 500000, 1293750, 6250, MT6359_RG_LDO_VSRAM_PROC2_EN_ADDR, MT6359_DA_VSRAM_PROC2_B_EN_ADDR, MT6359_RG_LDO_VSRAM_PROC2_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK << MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT), - MT6359_LDO("ldo_vio18", VIO18, volt18_voltages, + MT6359_LDO("ldo_vio18", VIO18, "vs1-ldo2", volt18_voltages, MT6359_RG_LDO_VIO18_EN_ADDR, MT6359_RG_LDO_VIO18_EN_SHIFT, MT6359_DA_VIO18_B_EN_ADDR, MT6359_RG_VIO18_VOSEL_ADDR, MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT, 960), - MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages, + MT6359_LDO("ldo_vcamio", VCAMIO, "vs1-ldo1", volt18_voltages, MT6359_RG_LDO_VCAMIO_EN_ADDR, MT6359_RG_LDO_VCAMIO_EN_SHIFT, MT6359_DA_VCAMIO_B_EN_ADDR, MT6359_RG_VCAMIO_VOSEL_ADDR, MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT, 1290), - MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359_RG_LDO_VCN18_EN_ADDR, + MT6359_REG_FIXED("ldo_vcn18", VCN18, "vs1-ldo2", MT6359_RG_LDO_VCN18_EN_ADDR, MT6359_DA_VCN18_B_EN_ADDR, 1800000), - MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359_RG_LDO_VFE28_EN_ADDR, + MT6359_REG_FIXED("ldo_vfe28", VFE28, "vsys-ldo1", MT6359_RG_LDO_VFE28_EN_ADDR, MT6359_DA_VFE28_B_EN_ADDR, 2800000), - MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages, + MT6359_LDO("ldo_vcn13", VCN13, "vs2-ldo2", vcn13_voltages, MT6359_RG_LDO_VCN13_EN_ADDR, MT6359_RG_LDO_VCN13_EN_SHIFT, MT6359_DA_VCN13_B_EN_ADDR, MT6359_RG_VCN13_VOSEL_ADDR, MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages, + MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages, MT6359_RG_LDO_VCN33_1_EN_0_ADDR, MT6359_RG_LDO_VCN33_1_EN_0_SHIFT, MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR, MT6359_RG_VCN33_1_VOSEL_MASK << MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages, + MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages, MT6359_RG_LDO_VCN33_1_EN_1_ADDR, MT6359_RG_LDO_VCN33_1_EN_1_SHIFT, MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR, MT6359_RG_VCN33_1_VOSEL_MASK << MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), - MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359_RG_LDO_VAUX18_EN_ADDR, + MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359_RG_LDO_VAUX18_EN_ADDR, MT6359_DA_VAUX18_B_EN_ADDR, 1800000), - MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, + MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750, 6250, MT6359_RG_LDO_VSRAM_OTHERS_EN_ADDR, MT6359_DA_VSRAM_OTHERS_B_EN_ADDR, MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK << MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT), - MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, + MT6359_LDO("ldo_vefuse", VEFUSE, "vs1-ldo2", vefuse_voltages, MT6359_RG_LDO_VEFUSE_EN_ADDR, MT6359_RG_LDO_VEFUSE_EN_SHIFT, MT6359_DA_VEFUSE_B_EN_ADDR, MT6359_RG_VEFUSE_VOSEL_ADDR, MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages, + MT6359_LDO("ldo_vxo22", VXO22, "vsys-ldo2", vxo22_voltages, MT6359_RG_LDO_VXO22_EN_ADDR, MT6359_RG_LDO_VXO22_EN_SHIFT, MT6359_DA_VXO22_B_EN_ADDR, MT6359_RG_VXO22_VOSEL_ADDR, MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT, 120), - MT6359_LDO("ldo_vrfck", VRFCK, vrfck_voltages, + MT6359_LDO("ldo_vrfck", VRFCK, "vsys-ldo2", vrfck_voltages, MT6359_RG_LDO_VRFCK_EN_ADDR, MT6359_RG_LDO_VRFCK_EN_SHIFT, MT6359_DA_VRFCK_B_EN_ADDR, MT6359_RG_VRFCK_VOSEL_ADDR, MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT, 480), - MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359_RG_LDO_VBIF28_EN_ADDR, + MT6359_REG_FIXED("ldo_vbif28", VBIF28, "vsys-ldo2", MT6359_RG_LDO_VBIF28_EN_ADDR, MT6359_DA_VBIF28_B_EN_ADDR, 2800000), - MT6359_LDO("ldo_vio28", VIO28, vio28_voltages, + MT6359_LDO("ldo_vio28", VIO28, "vsys-ldo2", vio28_voltages, MT6359_RG_LDO_VIO28_EN_ADDR, MT6359_RG_LDO_VIO28_EN_SHIFT, MT6359_DA_VIO28_B_EN_ADDR, MT6359_RG_VIO28_VOSEL_ADDR, MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vemc", VEMC, vemc_voltages, + MT6359_LDO("ldo_vemc", VEMC, "vsys-ldo2", vemc_voltages, MT6359_RG_LDO_VEMC_EN_ADDR, MT6359_RG_LDO_VEMC_EN_SHIFT, MT6359_DA_VEMC_B_EN_ADDR, MT6359_RG_VEMC_VOSEL_ADDR, MT6359_RG_VEMC_VOSEL_MASK << MT6359_RG_VEMC_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages, + MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages, MT6359_RG_LDO_VCN33_2_EN_0_ADDR, MT6359_RG_LDO_VCN33_2_EN_0_SHIFT, MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR, MT6359_RG_VCN33_2_VOSEL_MASK << MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages, + MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages, MT6359_RG_LDO_VCN33_2_EN_1_ADDR, MT6359_RG_LDO_VCN33_2_EN_1_SHIFT, MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR, MT6359_RG_VCN33_2_VOSEL_MASK << MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_va12", VA12, va12_voltages, + MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages, MT6359_RG_LDO_VA12_EN_ADDR, MT6359_RG_LDO_VA12_EN_SHIFT, MT6359_DA_VA12_B_EN_ADDR, MT6359_RG_VA12_VOSEL_ADDR, MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_va09", VA09, va09_voltages, + MT6359_LDO("ldo_va09", VA09, "vs2-ldo2", va09_voltages, MT6359_RG_LDO_VA09_EN_ADDR, MT6359_RG_LDO_VA09_EN_SHIFT, MT6359_DA_VA09_B_EN_ADDR, MT6359_RG_VA09_VOSEL_ADDR, MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages, + MT6359_LDO("ldo_vrf18", VRF18, "vs1-ldo2", vrf18_voltages, MT6359_RG_LDO_VRF18_EN_ADDR, MT6359_RG_LDO_VRF18_EN_SHIFT, MT6359_DA_VRF18_B_EN_ADDR, MT6359_RG_VRF18_VOSEL_ADDR, MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT, 120), - MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1100000, 6250, + MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, "vs2-ldo1", 500000, 1100000, 6250, MT6359_RG_LDO_VSRAM_MD_EN_ADDR, MT6359_DA_VSRAM_MD_B_EN_ADDR, MT6359_RG_LDO_VSRAM_MD_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK << MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT), - MT6359_LDO("ldo_vufs", VUFS, volt18_voltages, + MT6359_LDO("ldo_vufs", VUFS, "vs1-ldo1", volt18_voltages, MT6359_RG_LDO_VUFS_EN_ADDR, MT6359_RG_LDO_VUFS_EN_SHIFT, MT6359_DA_VUFS_B_EN_ADDR, MT6359_RG_VUFS_VOSEL_ADDR, MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT, 1920), - MT6359_LDO("ldo_vm18", VM18, volt18_voltages, + MT6359_LDO("ldo_vm18", VM18, "vs1-ldo1", volt18_voltages, MT6359_RG_LDO_VM18_EN_ADDR, MT6359_RG_LDO_VM18_EN_SHIFT, MT6359_DA_VM18_B_EN_ADDR, MT6359_RG_VM18_VOSEL_ADDR, MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT, 1920), - MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages, + /* vbbck is fed from vio18 internally. */ + MT6359_LDO("ldo_vbbck", VBBCK, "VIO18", vbbck_voltages, MT6359_RG_LDO_VBBCK_EN_ADDR, MT6359_RG_LDO_VBBCK_EN_SHIFT, MT6359_DA_VBBCK_B_EN_ADDR, MT6359_RG_VBBCK_VOSEL_ADDR, MT6359_RG_VBBCK_VOSEL_MASK << MT6359_RG_VBBCK_VOSEL_SHIFT, 240), - MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250, + MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, "vs2-ldo1", 500000, 1293750, 6250, MT6359_RG_LDO_VSRAM_PROC1_EN_ADDR, MT6359_DA_VSRAM_PROC1_B_EN_ADDR, MT6359_RG_LDO_VSRAM_PROC1_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK << MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT), - MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages, + MT6359_LDO("ldo_vsim2", VSIM2, "vsys-ldo2", vsim2_voltages, MT6359_RG_LDO_VSIM2_EN_ADDR, MT6359_RG_LDO_VSIM2_EN_SHIFT, MT6359_DA_VSIM2_B_EN_ADDR, MT6359_RG_VSIM2_VOSEL_ADDR, MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT, 480), - MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, + MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, "vs2-ldo1", 500000, 1293750, 6250, MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR, MT6359_DA_VSRAM_OTHERS_B_EN_ADDR, @@ -706,14 +714,14 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { }; static const struct mt6359_regulator_info mt6359p_regulators[] = { - MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500, + MT6359_BUCK("buck_vs1", VS1, "vsys-vs1", 800000, 2200000, 12500, MT6359_RG_BUCK_VS1_EN_ADDR, MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR, MT6359_RG_BUCK_VS1_VOSEL_MASK << MT6359_RG_BUCK_VS1_VOSEL_SHIFT, MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT, MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT), - MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250, + MT6359_BUCK("buck_vgpu11", VGPU11, "vsys-vgpu11", 400000, 1193750, 6250, MT6359_RG_BUCK_VGPU11_EN_ADDR, MT6359_DA_VGPU11_EN_ADDR, MT6359P_RG_BUCK_VGPU11_VOSEL_ADDR, MT6359_RG_BUCK_VGPU11_VOSEL_MASK << @@ -721,7 +729,7 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359_RG_BUCK_VGPU11_LP_ADDR, MT6359_RG_BUCK_VGPU11_LP_SHIFT, MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT), - MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250, + MT6359_BUCK("buck_vmodem", VMODEM, "vsys-vmodem", 400000, 1100000, 6250, MT6359_RG_BUCK_VMODEM_EN_ADDR, MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_MASK << @@ -729,35 +737,35 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359_RG_BUCK_VMODEM_LP_ADDR, MT6359_RG_BUCK_VMODEM_LP_SHIFT, MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT), - MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250, + MT6359_BUCK("buck_vpu", VPU, "vsys-vpu", 400000, 1193750, 6250, MT6359_RG_BUCK_VPU_EN_ADDR, MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR, MT6359_RG_BUCK_VPU_VOSEL_MASK << MT6359_RG_BUCK_VPU_VOSEL_SHIFT, MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT, MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT), - MT6359_BUCK("buck_vcore", VCORE, 506250, 1300000, 6250, + MT6359_BUCK("buck_vcore", VCORE, "vsys-vcore", 506250, 1300000, 6250, MT6359_RG_BUCK_VCORE_EN_ADDR, MT6359_DA_VCORE_EN_ADDR, MT6359P_RG_BUCK_VCORE_VOSEL_ADDR, MT6359_RG_BUCK_VCORE_VOSEL_MASK << MT6359_RG_BUCK_VCORE_VOSEL_SHIFT, MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT, MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT), - MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500, + MT6359_BUCK("buck_vs2", VS2, "vsys-vs2", 800000, 1600000, 12500, MT6359_RG_BUCK_VS2_EN_ADDR, MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR, MT6359_RG_BUCK_VS2_VOSEL_MASK << MT6359_RG_BUCK_VS2_VOSEL_SHIFT, MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT, MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT), - MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + MT6359_BUCK("buck_vpa", VPA, "vsys-vpa", 500000, 3650000, 50000, MT6359_RG_BUCK_VPA_EN_ADDR, MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR, MT6359_RG_BUCK_VPA_VOSEL_MASK << MT6359_RG_BUCK_VPA_VOSEL_SHIFT, MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT, MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT), - MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250, + MT6359_BUCK("buck_vproc2", VPROC2, "vsys-vproc2", 400000, 1193750, 6250, MT6359_RG_BUCK_VPROC2_EN_ADDR, MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_MASK << @@ -765,7 +773,7 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359_RG_BUCK_VPROC2_LP_ADDR, MT6359_RG_BUCK_VPROC2_LP_SHIFT, MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT), - MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250, + MT6359_BUCK("buck_vproc1", VPROC1, "vsys-vproc1", 400000, 1193750, 6250, MT6359_RG_BUCK_VPROC1_EN_ADDR, MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_MASK << @@ -773,7 +781,7 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359_RG_BUCK_VPROC1_LP_ADDR, MT6359_RG_BUCK_VPROC1_LP_SHIFT, MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT), - MT6359_BUCK("buck_vgpu11_sshub", VGPU11_SSHUB, 400000, 1193750, 6250, + MT6359_BUCK("buck_vgpu11_sshub", VGPU11_SSHUB, "vsys-vgpu11", 400000, 1193750, 6250, MT6359P_RG_BUCK_VGPU11_SSHUB_EN_ADDR, MT6359_DA_VGPU11_EN_ADDR, MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_ADDR, @@ -782,161 +790,161 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359_RG_BUCK_VGPU11_LP_ADDR, MT6359_RG_BUCK_VGPU11_LP_SHIFT, MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT), - MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359P_RG_LDO_VAUD18_EN_ADDR, + MT6359_REG_FIXED("ldo_vaud18", VAUD18, "vs1-ldo1", MT6359P_RG_LDO_VAUD18_EN_ADDR, MT6359P_DA_VAUD18_B_EN_ADDR, 1800000), - MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages, + MT6359_LDO("ldo_vsim1", VSIM1, "vsys-ldo2", vsim1_voltages, MT6359P_RG_LDO_VSIM1_EN_ADDR, MT6359P_RG_LDO_VSIM1_EN_SHIFT, MT6359P_DA_VSIM1_B_EN_ADDR, MT6359P_RG_VSIM1_VOSEL_ADDR, MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT, 480), - MT6359_LDO("ldo_vibr", VIBR, vibr_voltages, + MT6359_LDO("ldo_vibr", VIBR, "vsys-ldo1", vibr_voltages, MT6359P_RG_LDO_VIBR_EN_ADDR, MT6359P_RG_LDO_VIBR_EN_SHIFT, MT6359P_DA_VIBR_B_EN_ADDR, MT6359P_RG_VIBR_VOSEL_ADDR, MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages, + MT6359_LDO("ldo_vrf12", VRF12, "vs2-ldo2", vrf12_voltages, MT6359P_RG_LDO_VRF12_EN_ADDR, MT6359P_RG_LDO_VRF12_EN_SHIFT, MT6359P_DA_VRF12_B_EN_ADDR, MT6359P_RG_VRF12_VOSEL_ADDR, MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT, 480), - MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359P_RG_LDO_VUSB_EN_0_ADDR, + MT6359_REG_FIXED("ldo_vusb", VUSB, "vsys-ldo2", MT6359P_RG_LDO_VUSB_EN_0_ADDR, MT6359P_DA_VUSB_B_EN_ADDR, 3000000), - MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250, + MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, "vs2-ldo1", 500000, 1293750, 6250, MT6359P_RG_LDO_VSRAM_PROC2_EN_ADDR, MT6359P_DA_VSRAM_PROC2_B_EN_ADDR, MT6359P_RG_LDO_VSRAM_PROC2_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK << MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT), - MT6359_LDO("ldo_vio18", VIO18, volt18_voltages, + MT6359_LDO("ldo_vio18", VIO18, "vs1-ldo2", volt18_voltages, MT6359P_RG_LDO_VIO18_EN_ADDR, MT6359P_RG_LDO_VIO18_EN_SHIFT, MT6359P_DA_VIO18_B_EN_ADDR, MT6359P_RG_VIO18_VOSEL_ADDR, MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT, 960), - MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages, + MT6359_LDO("ldo_vcamio", VCAMIO, "vs1-ldo1", volt18_voltages, MT6359P_RG_LDO_VCAMIO_EN_ADDR, MT6359P_RG_LDO_VCAMIO_EN_SHIFT, MT6359P_DA_VCAMIO_B_EN_ADDR, MT6359P_RG_VCAMIO_VOSEL_ADDR, MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT, 1290), - MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359P_RG_LDO_VCN18_EN_ADDR, + MT6359_REG_FIXED("ldo_vcn18", VCN18, "vs1-ldo2", MT6359P_RG_LDO_VCN18_EN_ADDR, MT6359P_DA_VCN18_B_EN_ADDR, 1800000), - MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359P_RG_LDO_VFE28_EN_ADDR, + MT6359_REG_FIXED("ldo_vfe28", VFE28, "vsys-ldo1", MT6359P_RG_LDO_VFE28_EN_ADDR, MT6359P_DA_VFE28_B_EN_ADDR, 2800000), - MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages, + MT6359_LDO("ldo_vcn13", VCN13, "vs2-ldo2", vcn13_voltages, MT6359P_RG_LDO_VCN13_EN_ADDR, MT6359P_RG_LDO_VCN13_EN_SHIFT, MT6359P_DA_VCN13_B_EN_ADDR, MT6359P_RG_VCN13_VOSEL_ADDR, MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages, + MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages, MT6359P_RG_LDO_VCN33_1_EN_0_ADDR, MT6359_RG_LDO_VCN33_1_EN_0_SHIFT, MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR, MT6359_RG_VCN33_1_VOSEL_MASK << MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages, + MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages, MT6359P_RG_LDO_VCN33_1_EN_1_ADDR, MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT, MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR, MT6359_RG_VCN33_1_VOSEL_MASK << MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), - MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359P_RG_LDO_VAUX18_EN_ADDR, + MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359P_RG_LDO_VAUX18_EN_ADDR, MT6359P_DA_VAUX18_B_EN_ADDR, 1800000), - MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, + MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750, 6250, MT6359P_RG_LDO_VSRAM_OTHERS_EN_ADDR, MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR, MT6359P_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK << MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT), - MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, + MT6359_LDO("ldo_vefuse", VEFUSE, "vs1-ldo2", vefuse_voltages, MT6359P_RG_LDO_VEFUSE_EN_ADDR, MT6359P_RG_LDO_VEFUSE_EN_SHIFT, MT6359P_DA_VEFUSE_B_EN_ADDR, MT6359P_RG_VEFUSE_VOSEL_ADDR, MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages, + MT6359_LDO("ldo_vxo22", VXO22, "vsys-ldo2", vxo22_voltages, MT6359P_RG_LDO_VXO22_EN_ADDR, MT6359P_RG_LDO_VXO22_EN_SHIFT, MT6359P_DA_VXO22_B_EN_ADDR, MT6359P_RG_VXO22_VOSEL_ADDR, MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT, 480), - MT6359_LDO("ldo_vrfck_1", VRFCK, vrfck_voltages_1, + MT6359_LDO("ldo_vrfck_1", VRFCK, "vsys-ldo2", vrfck_voltages_1, MT6359P_RG_LDO_VRFCK_EN_ADDR, MT6359P_RG_LDO_VRFCK_EN_SHIFT, MT6359P_DA_VRFCK_B_EN_ADDR, MT6359P_RG_VRFCK_VOSEL_ADDR, MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT, 480), - MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359P_RG_LDO_VBIF28_EN_ADDR, + MT6359_REG_FIXED("ldo_vbif28", VBIF28, "vsys-ldo2", MT6359P_RG_LDO_VBIF28_EN_ADDR, MT6359P_DA_VBIF28_B_EN_ADDR, 2800000), - MT6359_LDO("ldo_vio28", VIO28, vio28_voltages, + MT6359_LDO("ldo_vio28", VIO28, "vsys-ldo2", vio28_voltages, MT6359P_RG_LDO_VIO28_EN_ADDR, MT6359P_RG_LDO_VIO28_EN_SHIFT, MT6359P_DA_VIO28_B_EN_ADDR, MT6359P_RG_VIO28_VOSEL_ADDR, MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT, 1920), - MT6359P_LDO1("ldo_vemc_1", VEMC, mt6359p_vemc_ops, vemc_voltages_1, + MT6359P_LDO1("ldo_vemc_1", VEMC, "vsys-ldo2", mt6359p_vemc_ops, vemc_voltages_1, MT6359P_RG_LDO_VEMC_EN_ADDR, MT6359P_RG_LDO_VEMC_EN_SHIFT, MT6359P_DA_VEMC_B_EN_ADDR, MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR, MT6359P_RG_LDO_VEMC_VOSEL_0_MASK << MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT), - MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages, + MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages, MT6359P_RG_LDO_VCN33_2_EN_0_ADDR, MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT, MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR, MT6359_RG_VCN33_2_VOSEL_MASK << MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages, + MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages, MT6359P_RG_LDO_VCN33_2_EN_1_ADDR, MT6359_RG_LDO_VCN33_2_EN_1_SHIFT, MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR, MT6359_RG_VCN33_2_VOSEL_MASK << MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_va12", VA12, va12_voltages, + MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages, MT6359P_RG_LDO_VA12_EN_ADDR, MT6359P_RG_LDO_VA12_EN_SHIFT, MT6359P_DA_VA12_B_EN_ADDR, MT6359P_RG_VA12_VOSEL_ADDR, MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT, 960), - MT6359_LDO("ldo_va09", VA09, va09_voltages, + MT6359_LDO("ldo_va09", VA09, "vs2-ldo2", va09_voltages, MT6359P_RG_LDO_VA09_EN_ADDR, MT6359P_RG_LDO_VA09_EN_SHIFT, MT6359P_DA_VA09_B_EN_ADDR, MT6359P_RG_VA09_VOSEL_ADDR, MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT, 960), - MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages, + MT6359_LDO("ldo_vrf18", VRF18, "vs1-ldo2", vrf18_voltages, MT6359P_RG_LDO_VRF18_EN_ADDR, MT6359P_RG_LDO_VRF18_EN_SHIFT, MT6359P_DA_VRF18_B_EN_ADDR, MT6359P_RG_VRF18_VOSEL_ADDR, MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT, 240), - MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1293750, 6250, + MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, "vs2-ldo1", 500000, 1293750, 6250, MT6359P_RG_LDO_VSRAM_MD_EN_ADDR, MT6359P_DA_VSRAM_MD_B_EN_ADDR, MT6359P_RG_LDO_VSRAM_MD_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK << MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT), - MT6359_LDO("ldo_vufs", VUFS, volt18_voltages, + MT6359_LDO("ldo_vufs", VUFS, "vs1-ldo1", volt18_voltages, MT6359P_RG_LDO_VUFS_EN_ADDR, MT6359P_RG_LDO_VUFS_EN_SHIFT, MT6359P_DA_VUFS_B_EN_ADDR, MT6359P_RG_VUFS_VOSEL_ADDR, MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT, 1920), - MT6359_LDO("ldo_vm18", VM18, volt18_voltages, + MT6359_LDO("ldo_vm18", VM18, "vs1-ldo1", volt18_voltages, MT6359P_RG_LDO_VM18_EN_ADDR, MT6359P_RG_LDO_VM18_EN_SHIFT, MT6359P_DA_VM18_B_EN_ADDR, MT6359P_RG_VM18_VOSEL_ADDR, MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT, 1920), - MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages, + MT6359_LDO("ldo_vbbck", VBBCK, "LDO_VIO18", vbbck_voltages, MT6359P_RG_LDO_VBBCK_EN_ADDR, MT6359P_RG_LDO_VBBCK_EN_SHIFT, MT6359P_DA_VBBCK_B_EN_ADDR, MT6359P_RG_VBBCK_VOSEL_ADDR, MT6359P_RG_VBBCK_VOSEL_MASK << MT6359P_RG_VBBCK_VOSEL_SHIFT, 480), - MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250, + MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, "vs2-ldo1", 500000, 1293750, 6250, MT6359P_RG_LDO_VSRAM_PROC1_EN_ADDR, MT6359P_DA_VSRAM_PROC1_B_EN_ADDR, MT6359P_RG_LDO_VSRAM_PROC1_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK << MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT), - MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages, + MT6359_LDO("ldo_vsim2", VSIM2, "vsys-ldo2", vsim2_voltages, MT6359P_RG_LDO_VSIM2_EN_ADDR, MT6359P_RG_LDO_VSIM2_EN_SHIFT, MT6359P_DA_VSIM2_B_EN_ADDR, MT6359P_RG_VSIM2_VOSEL_ADDR, MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT, 480), - MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, + MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, "vs2-ldo1", 500000, 1293750, 6250, MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR, MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR, @@ -951,6 +959,7 @@ static int mt6359_regulator_probe(struct platform_device *pdev) struct regulator_config config = {}; struct regulator_dev *rdev; const struct mt6359_regulator_info *mt6359_info; + const char *vio18_name; int i, hw_ver, ret; ret = regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver); @@ -962,16 +971,37 @@ static int mt6359_regulator_probe(struct platform_device *pdev) else mt6359_info = mt6359_regulators; + vio18_name = mt6359_info[MT6359_ID_VIO18].desc.name; + config.dev = mt6397->dev; config.regmap = mt6397->regmap; for (i = 0; i < MT6359_MAX_REGULATOR; i++, mt6359_info++) { + const struct regulator_desc *desc = &mt6359_info->desc; + struct regulator_desc *_desc; + /* drop const here, but all uses in the driver are const */ config.driver_data = (void *)mt6359_info; - rdev = devm_regulator_register(&pdev->dev, &mt6359_info->desc, &config); + + /* Use vio18's actual name as supply_name for vbbck */ + if (i == MT6359_ID_VBBCK && strcmp(desc->supply_name, vio18_name) != 0) { + _desc = devm_kzalloc(&pdev->dev, sizeof(*_desc), GFP_KERNEL); + if (!_desc) + return -ENOMEM; + + memcpy(_desc, desc, sizeof(*_desc)); + _desc->supply_name = vio18_name; + desc = _desc; + } + + rdev = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name); return PTR_ERR(rdev); } + + /* Save vio18 name for vbbck */ + if (i == MT6359_ID_VIO18) + vio18_name = rdev_get_name(rdev); } return 0; From fb6a6297acfad9810dea91a67185a90ba7a7bfbd Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 May 2026 17:15:19 +0800 Subject: [PATCH 351/655] regulator: mt6359: Add proper ldo_vcn33_[12] regulators The ldo_vcn33_[12]_wifi and ldo_vcn33_[12]_bt are just two regulator outputs instead of four. The wifi and bt parts refer to separate enable bits that are OR-ed together to affect the actual regulator output. The separate bits allow the wifi and bt stacks to enable their power without coordination between them. These have been deprecated in favor of proper nodes matching the output. Add proper ldo_vcn33_[12] regulators to replace the existing ones. The enable status is synced to just one of the two enable bits, and the other is forced off. This makes the handling in other bits simpler. The existing *_(bt|wifi) regulators are converted to no-op regulators that are fed from their new respective ldo_vcn33_[12] regulator. This allows existing device trees to continue to work. Signed-off-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260514091520.2718987-7-wenst@chromium.org Signed-off-by: Mark Brown --- drivers/regulator/mt6359-regulator.c | 184 +++++++++++++++++---- include/linux/regulator/mt6359-regulator.h | 10 +- 2 files changed, 159 insertions(+), 35 deletions(-) diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c index 46cafe93b24e..af0e0339fbdd 100644 --- a/drivers/regulator/mt6359-regulator.c +++ b/drivers/regulator/mt6359-regulator.c @@ -166,6 +166,20 @@ struct mt6359_regulator_info { .qi = BIT(0), \ } +#define MT6359_LDO_NOOP(match, _name, supply) \ +[MT6359_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .supply_name = supply, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &mt6359_noop_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6359_ID_##_name, \ + .owner = THIS_MODULE, \ + }, \ +} + static const unsigned int vsim1_voltages[] = { 0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000, }; @@ -475,6 +489,9 @@ static const struct regulator_ops mt6359p_vemc_ops = { .get_status = mt6359_get_status, }; +/* Used for backward-compatible placeholder regulators */ +static const struct regulator_ops mt6359_noop_ops = {}; + /* The array is indexed by id(MT6359_ID_XXX) */ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_BUCK("buck_vs1", VS1, "vsys-vs1", 800000, 2200000, 12500, @@ -596,18 +613,12 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_DA_VCN13_B_EN_ADDR, MT6359_RG_VCN13_VOSEL_ADDR, MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages, + MT6359_LDO("ldo_vcn33_1", VCN33_1, "vsys-ldo1", vcn33_voltages, MT6359_RG_LDO_VCN33_1_EN_0_ADDR, MT6359_RG_LDO_VCN33_1_EN_0_SHIFT, MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR, MT6359_RG_VCN33_1_VOSEL_MASK << MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages, - MT6359_RG_LDO_VCN33_1_EN_1_ADDR, - MT6359_RG_LDO_VCN33_1_EN_1_SHIFT, - MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR, - MT6359_RG_VCN33_1_VOSEL_MASK << - MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359_RG_LDO_VAUX18_EN_ADDR, MT6359_DA_VAUX18_B_EN_ADDR, 1800000), MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750, @@ -644,18 +655,12 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_DA_VEMC_B_EN_ADDR, MT6359_RG_VEMC_VOSEL_ADDR, MT6359_RG_VEMC_VOSEL_MASK << MT6359_RG_VEMC_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages, + MT6359_LDO("ldo_vcn33_2", VCN33_2, "vsys-ldo1", vcn33_voltages, MT6359_RG_LDO_VCN33_2_EN_0_ADDR, MT6359_RG_LDO_VCN33_2_EN_0_SHIFT, MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR, MT6359_RG_VCN33_2_VOSEL_MASK << MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages, - MT6359_RG_LDO_VCN33_2_EN_1_ADDR, - MT6359_RG_LDO_VCN33_2_EN_1_SHIFT, - MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR, - MT6359_RG_VCN33_2_VOSEL_MASK << - MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages, MT6359_RG_LDO_VA12_EN_ADDR, MT6359_RG_LDO_VA12_EN_SHIFT, MT6359_DA_VA12_B_EN_ADDR, MT6359_RG_VA12_VOSEL_ADDR, @@ -711,6 +716,11 @@ static const struct mt6359_regulator_info mt6359_regulators[] = { MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK << MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT), + /* Placeholders for DT backward compatibility */ + MT6359_LDO_NOOP("ldo_vcn33_1_bt", VCN33_1_BT, "LDO_VCN33_1"), + MT6359_LDO_NOOP("ldo_vcn33_1_wifi", VCN33_1_WIFI, "LDO_VCN33_1"), + MT6359_LDO_NOOP("ldo_vcn33_2_bt", VCN33_2_BT, "LDO_VCN33_2"), + MT6359_LDO_NOOP("ldo_vcn33_2_wifi", VCN33_2_WIFI, "LDO_VCN33_2"), }; static const struct mt6359_regulator_info mt6359p_regulators[] = { @@ -835,18 +845,12 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359P_DA_VCN13_B_EN_ADDR, MT6359P_RG_VCN13_VOSEL_ADDR, MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages, + MT6359_LDO("ldo_vcn33_1", VCN33_1, "vsys-ldo1", vcn33_voltages, MT6359P_RG_LDO_VCN33_1_EN_0_ADDR, MT6359_RG_LDO_VCN33_1_EN_0_SHIFT, MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR, MT6359_RG_VCN33_1_VOSEL_MASK << MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages, - MT6359P_RG_LDO_VCN33_1_EN_1_ADDR, - MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT, - MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR, - MT6359_RG_VCN33_1_VOSEL_MASK << - MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359P_RG_LDO_VAUX18_EN_ADDR, MT6359P_DA_VAUX18_B_EN_ADDR, 1800000), MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750, @@ -885,18 +889,12 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR, MT6359P_RG_LDO_VEMC_VOSEL_0_MASK << MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT), - MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages, + MT6359_LDO("ldo_vcn33_2", VCN33_2, "vsys-ldo1", vcn33_voltages, MT6359P_RG_LDO_VCN33_2_EN_0_ADDR, MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT, MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR, MT6359_RG_VCN33_2_VOSEL_MASK << MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), - MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages, - MT6359P_RG_LDO_VCN33_2_EN_1_ADDR, - MT6359_RG_LDO_VCN33_2_EN_1_SHIFT, - MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR, - MT6359_RG_VCN33_2_VOSEL_MASK << - MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages, MT6359P_RG_LDO_VA12_EN_ADDR, MT6359P_RG_LDO_VA12_EN_SHIFT, MT6359P_DA_VA12_B_EN_ADDR, MT6359P_RG_VA12_VOSEL_ADDR, @@ -951,27 +949,119 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = { MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR, MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK << MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT), + /* Placeholders for DT backward compatibility */ + MT6359_LDO_NOOP("ldo_vcn33_1_bt", VCN33_1_BT, "LDO_VCN33_1"), + MT6359_LDO_NOOP("ldo_vcn33_1_wifi", VCN33_1_WIFI, "LDO_VCN33_1"), + MT6359_LDO_NOOP("ldo_vcn33_2_bt", VCN33_2_BT, "LDO_VCN33_2"), + MT6359_LDO_NOOP("ldo_vcn33_2_wifi", VCN33_2_WIFI, "LDO_VCN33_2"), }; +struct mt6359_vcn33_regs { + u32 wifi_en_reg; + u32 wifi_en_mask; + u32 bt_en_reg; + u32 bt_en_mask; +}; + +static const struct mt6359_vcn33_regs vcn33_regs[][2] = { + { /* MT6359 */ + { + .wifi_en_reg = MT6359_RG_LDO_VCN33_1_EN_1_ADDR, + .wifi_en_mask = BIT(MT6359_RG_LDO_VCN33_1_EN_1_SHIFT), + .bt_en_reg = MT6359_RG_LDO_VCN33_1_EN_0_ADDR, + .bt_en_mask = BIT(MT6359_RG_LDO_VCN33_1_EN_0_SHIFT), + }, { + .wifi_en_reg = MT6359_RG_LDO_VCN33_2_EN_1_ADDR, + .wifi_en_mask = BIT(MT6359_RG_LDO_VCN33_2_EN_1_SHIFT), + .bt_en_reg = MT6359_RG_LDO_VCN33_2_EN_0_ADDR, + .bt_en_mask = BIT(MT6359_RG_LDO_VCN33_2_EN_0_SHIFT), + } + }, { /* MT6359P */ + { + .wifi_en_reg = MT6359P_RG_LDO_VCN33_1_EN_1_ADDR, + .wifi_en_mask = BIT(MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT), + .bt_en_reg = MT6359P_RG_LDO_VCN33_1_EN_0_ADDR, + .bt_en_mask = BIT(MT6359_RG_LDO_VCN33_1_EN_0_SHIFT), + }, { + .wifi_en_reg = MT6359P_RG_LDO_VCN33_2_EN_1_ADDR, + .wifi_en_mask = BIT(MT6359_RG_LDO_VCN33_2_EN_1_SHIFT), + .bt_en_reg = MT6359P_RG_LDO_VCN33_2_EN_0_ADDR, + .bt_en_mask = BIT(MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT), + } + } +}; + +static int mt6359_sync_vcn33_setting(struct device *dev, unsigned int idx) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(dev->parent); + unsigned int val; + int ret; + + /* + * VCN33_[12]_WIFI and VCN33_[12]_BT are two separate enable bits for + * the same regulator. They share the same voltage setting and output + * pin. Instead of having two potentially conflicting regulators, just + * have one regulator. Sync the two enable bits and only use one in + * the regulator device. + */ + for (unsigned int i = 0; i < ARRAY_SIZE(vcn33_regs[0]); i++) { + u32 bt_en_mask = vcn33_regs[idx][i].bt_en_mask; + u32 wifi_en_mask = vcn33_regs[idx][i].wifi_en_mask; + + ret = regmap_read(mt6397->regmap, vcn33_regs[idx][i].wifi_en_reg, &val); + if (ret) + return dev_err_probe(dev, ret, "Failed to read VCN33_%u_WIFI setting\n", + i + 1); + + if (!(val & wifi_en_mask)) + continue; + + /* Sync VCN33_[12]_WIFI enable status to VCN33_[12]_BT */ + ret = regmap_update_bits(mt6397->regmap, vcn33_regs[idx][i].bt_en_reg, + bt_en_mask, bt_en_mask); + if (ret) + return dev_err_probe(dev, ret, + "Failed to sync VCN33_%u_WIFI setting to VCN33_%u_BT\n", + i + 1, i + 1); + + /* Disable VCN33_[12]_WIFI */ + ret = regmap_update_bits(mt6397->regmap, vcn33_regs[idx][i].wifi_en_reg, + wifi_en_mask, 0); + if (ret) + return dev_err_probe(dev, ret, "Failed to disable VCN33_%u_WIFI\n", i + 1); + } + + return 0; +} + static int mt6359_regulator_probe(struct platform_device *pdev) { struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = {}; struct regulator_dev *rdev; const struct mt6359_regulator_info *mt6359_info; - const char *vio18_name; + const char *vio18_name, *vcn33_1_name, *vcn33_2_name; int i, hw_ver, ret; ret = regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver); if (ret) return ret; - if (hw_ver >= MT6359P_CHIP_VER) + if (hw_ver >= MT6359P_CHIP_VER) { mt6359_info = mt6359p_regulators; - else + ret = mt6359_sync_vcn33_setting(&pdev->dev, 1); + if (ret) + return ret; + } else { mt6359_info = mt6359_regulators; + ret = mt6359_sync_vcn33_setting(&pdev->dev, 0); + if (ret) + return ret; + } vio18_name = mt6359_info[MT6359_ID_VIO18].desc.name; + vcn33_1_name = mt6359_info[MT6359_ID_VCN33_1].desc.name; + vcn33_2_name = mt6359_info[MT6359_ID_VCN33_2].desc.name; config.dev = mt6397->dev; config.regmap = mt6397->regmap; @@ -993,6 +1083,30 @@ static int mt6359_regulator_probe(struct platform_device *pdev) desc = _desc; } + /* Use vcn33_1's actual name as supply_name for vcn33_1_(bt|wifi) */ + if ((i == MT6359_ID_VCN33_1_BT || i == MT6359_ID_VCN33_1_WIFI) && + strcmp(desc->supply_name, vcn33_1_name) != 0) { + _desc = devm_kzalloc(&pdev->dev, sizeof(*_desc), GFP_KERNEL); + if (!_desc) + return -ENOMEM; + + memcpy(_desc, desc, sizeof(*_desc)); + _desc->supply_name = vcn33_1_name; + desc = _desc; + } + + /* Use vcn33_2's actual name as supply_name for vcn33_2_(bt|wifi) */ + if ((i == MT6359_ID_VCN33_2_BT || i == MT6359_ID_VCN33_2_WIFI) && + strcmp(desc->supply_name, vcn33_2_name) != 0) { + _desc = devm_kzalloc(&pdev->dev, sizeof(*_desc), GFP_KERNEL); + if (!_desc) + return -ENOMEM; + + memcpy(_desc, desc, sizeof(*_desc)); + _desc->supply_name = vcn33_2_name; + desc = _desc; + } + rdev = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name); @@ -1002,6 +1116,14 @@ static int mt6359_regulator_probe(struct platform_device *pdev) /* Save vio18 name for vbbck */ if (i == MT6359_ID_VIO18) vio18_name = rdev_get_name(rdev); + + /* Save vcn33_1 name for vbbck */ + if (i == MT6359_ID_VCN33_1) + vcn33_1_name = rdev_get_name(rdev); + + /* Save vcn33_2 name for vbbck */ + if (i == MT6359_ID_VCN33_2) + vcn33_2_name = rdev_get_name(rdev); } return 0; diff --git a/include/linux/regulator/mt6359-regulator.h b/include/linux/regulator/mt6359-regulator.h index 6d6e5a58f482..ce2cd0fc9d95 100644 --- a/include/linux/regulator/mt6359-regulator.h +++ b/include/linux/regulator/mt6359-regulator.h @@ -29,8 +29,7 @@ enum { MT6359_ID_VCN18, MT6359_ID_VFE28, MT6359_ID_VCN13, - MT6359_ID_VCN33_1_BT, - MT6359_ID_VCN33_1_WIFI, + MT6359_ID_VCN33_1, MT6359_ID_VAUX18, MT6359_ID_VSRAM_OTHERS, MT6359_ID_VEFUSE, @@ -39,8 +38,7 @@ enum { MT6359_ID_VBIF28, MT6359_ID_VIO28, MT6359_ID_VEMC, - MT6359_ID_VCN33_2_BT, - MT6359_ID_VCN33_2_WIFI, + MT6359_ID_VCN33_2, MT6359_ID_VA12, MT6359_ID_VA09, MT6359_ID_VRF18, @@ -51,6 +49,10 @@ enum { MT6359_ID_VSRAM_PROC1, MT6359_ID_VSIM2, MT6359_ID_VSRAM_OTHERS_SSHUB, + MT6359_ID_VCN33_1_BT, + MT6359_ID_VCN33_1_WIFI, + MT6359_ID_VCN33_2_BT, + MT6359_ID_VCN33_2_WIFI, MT6359_ID_RG_MAX, }; From 37a91b995952a556a6eb90c31736ee773b86999c Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sat, 2 May 2026 21:56:34 -0700 Subject: [PATCH 352/655] fbdev: remove Hercules monochrome ISA graphics adapter driver The hgafb driver supports graphics adapters compatible with the Hercules adapter from 1984. These were ISA cards or onboard devices that supported monochrome 720x348 graphics. This driver was created in 1999 by Ferenc Bakonyi. In the entire Git history (since Linux 2.6.12-rc2), there has only been one commit in 2010 which indicated that the driver was in use, commit 529ed806d454 ("video: Fix the HGA framebuffer driver"). The commit message states: Only tested with fbcon, since most fbdev-based software appears to only support 12bpp and up. It does not appear that this driver has worked for at least the entire 2.6.x series, perhaps since 2002. Given the age and limited capabilities of the hardware and the lack of users, remove this driver and move the former maintainer to CREDITS. Signed-off-by: Ethan Nelson-Moore Acked-by: Thomas Zimmermann Signed-off-by: Helge Deller --- CREDITS | 3 + MAINTAINERS | 7 - drivers/video/fbdev/Kconfig | 13 - drivers/video/fbdev/Makefile | 1 - drivers/video/fbdev/hgafb.c | 685 ----------------------------------- 5 files changed, 3 insertions(+), 706 deletions(-) delete mode 100644 drivers/video/fbdev/hgafb.c diff --git a/CREDITS b/CREDITS index 17962bdd6dbd..59d5de3eeb5b 100644 --- a/CREDITS +++ b/CREDITS @@ -197,6 +197,9 @@ S: Hauptstrasse 19 S: 79837 St. Blasien S: Germany +N: Ferenc Bakonyi +D: Hercules graphics adapter framebuffer driver + N: Krishna Balasubramanian E: balasub@cis.ohio-state.edu D: Wrote SYS V IPC (part of standard kernel since 0.99.10) diff --git a/MAINTAINERS b/MAINTAINERS index c2c6d79275c6..261671ba6f73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11382,13 +11382,6 @@ F: Documentation/filesystems/hfsplus.rst F: fs/hfsplus/ F: include/linux/hfs_common.h -HGA FRAMEBUFFER DRIVER -M: Ferenc Bakonyi -L: linux-nvidia@lists.surfsouth.com -S: Maintained -W: http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml -F: drivers/video/fbdev/hgafb.c - HIBERNATION (aka Software Suspend, aka swsusp) M: "Rafael J. Wysocki" R: Pavel Machek diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 1c73d560f196..085d3a202148 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -453,19 +453,6 @@ config FB_N411 This enables support for the Apollo display controller in its Hecuba form using the n411 devkit. -config FB_HGA - tristate "Hercules mono graphics support" - depends on FB && X86 - select FB_IOMEM_FOPS - help - Say Y here if you have a Hercules mono graphics card. - - To compile this driver as a module, choose M here: the - module will be called hgafb. - - As this card technology is at least 25 years old, - most people will answer N here. - config FB_GBE bool "SGI Graphics Backend frame buffer support" depends on (FB = y) && HAS_IOMEM diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 36a18d958ba0..0b17c878154d 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -59,7 +59,6 @@ obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ obj-$(CONFIG_FB_MAC) += macfb.o obj-$(CONFIG_FB_HECUBA) += hecubafb.o obj-$(CONFIG_FB_N411) += n411.o -obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_XVR500) += sunxvr500.o obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o obj-$(CONFIG_FB_XVR1000) += sunxvr1000.o diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c deleted file mode 100644 index d32fd1c5217c..000000000000 --- a/drivers/video/fbdev/hgafb.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * linux/drivers/video/hgafb.c -- Hercules graphics adaptor frame buffer device - * - * Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu) - * Based on skeletonfb.c by Geert Uytterhoeven and - * mdacon.c by Andrew Apted - * - * History: - * - * - Revision 0.1.8 (23 Oct 2002): Ported to new framebuffer api. - * - * - Revision 0.1.7 (23 Jan 2001): fix crash resulting from MDA only cards - * being detected as Hercules. (Paul G.) - * - Revision 0.1.6 (17 Aug 2000): new style structs - * documentation - * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc - * minor fixes - * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for - * HGA-only systems - * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure - * screen is cleared after rmmod - * virtual resolutions - * module parameter 'nologo={0|1}' - * the most important: boot logo :) - * - Revision 0.1.0 (6 Dec 1999): faster scrolling and minor fixes - * - First release (25 Nov 1999) - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args) -#else -#define DPRINTK(args...) -#endif - -#if 0 -#define CHKINFO(ret) if (info != &fb_info) { printk(KERN_DEBUG __FILE__": This should never happen, line:%d \n", __LINE__); return ret; } -#else -#define CHKINFO(ret) -#endif - -/* Description of the hardware layout */ - -static void __iomem *hga_vram; /* Base of video memory */ -static unsigned long hga_vram_len; /* Size of video memory */ - -#define HGA_ROWADDR(row) ((row%4)*8192 + (row>>2)*90) -#define HGA_TXT 0 -#define HGA_GFX 1 - -static inline u8 __iomem * rowaddr(struct fb_info *info, u_int row) -{ - return info->screen_base + HGA_ROWADDR(row); -} - -static int hga_mode = -1; /* 0 = txt, 1 = gfx mode */ - -static enum { TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } hga_type; -static char *hga_type_name; - -#define HGA_INDEX_PORT 0x3b4 /* Register select port */ -#define HGA_VALUE_PORT 0x3b5 /* Register value port */ -#define HGA_MODE_PORT 0x3b8 /* Mode control port */ -#define HGA_STATUS_PORT 0x3ba /* Status and Config port */ -#define HGA_GFX_PORT 0x3bf /* Graphics control port */ - -/* HGA register values */ - -#define HGA_CURSOR_BLINKING 0x00 -#define HGA_CURSOR_OFF 0x20 -#define HGA_CURSOR_SLOWBLINK 0x60 - -#define HGA_MODE_GRAPHICS 0x02 -#define HGA_MODE_VIDEO_EN 0x08 -#define HGA_MODE_BLINK_EN 0x20 -#define HGA_MODE_GFX_PAGE1 0x80 - -#define HGA_STATUS_HSYNC 0x01 -#define HGA_STATUS_VSYNC 0x80 -#define HGA_STATUS_VIDEO 0x08 - -#define HGA_CONFIG_COL132 0x08 -#define HGA_GFX_MODE_EN 0x01 -#define HGA_GFX_PAGE_EN 0x02 - -/* Global locks */ - -static DEFINE_SPINLOCK(hga_reg_lock); - -/* Framebuffer driver structures */ - -static const struct fb_var_screeninfo hga_default_var = { - .xres = 720, - .yres = 348, - .xres_virtual = 720, - .yres_virtual = 348, - .bits_per_pixel = 1, - .red = {0, 1, 0}, - .green = {0, 1, 0}, - .blue = {0, 1, 0}, - .transp = {0, 0, 0}, - .height = -1, - .width = -1, -}; - -static struct fb_fix_screeninfo hga_fix = { - .id = "HGA", - .type = FB_TYPE_PACKED_PIXELS, /* (not sure) */ - .visual = FB_VISUAL_MONO10, - .xpanstep = 8, - .ypanstep = 8, - .line_length = 90, - .accel = FB_ACCEL_NONE -}; - -/* Don't assume that tty1 will be the initial current console. */ -static int release_io_port = 0; -static int release_io_ports = 0; -static bool nologo = 0; - -/* ------------------------------------------------------------------------- - * - * Low level hardware functions - * - * ------------------------------------------------------------------------- */ - -static void write_hga_b(unsigned int val, unsigned char reg) -{ - outb_p(reg, HGA_INDEX_PORT); - outb_p(val, HGA_VALUE_PORT); -} - -static void write_hga_w(unsigned int val, unsigned char reg) -{ - outb_p(reg, HGA_INDEX_PORT); outb_p(val >> 8, HGA_VALUE_PORT); - outb_p(reg+1, HGA_INDEX_PORT); outb_p(val & 0xff, HGA_VALUE_PORT); -} - -static int test_hga_b(unsigned char val, unsigned char reg) -{ - outb_p(reg, HGA_INDEX_PORT); - outb (val, HGA_VALUE_PORT); - udelay(20); val = (inb_p(HGA_VALUE_PORT) == val); - return val; -} - -static void hga_clear_screen(void) -{ - unsigned char fillchar = 0xbf; /* magic */ - unsigned long flags; - - spin_lock_irqsave(&hga_reg_lock, flags); - if (hga_mode == HGA_TXT) - fillchar = ' '; - else if (hga_mode == HGA_GFX) - fillchar = 0x00; - spin_unlock_irqrestore(&hga_reg_lock, flags); - if (fillchar != 0xbf) - memset_io(hga_vram, fillchar, hga_vram_len); -} - -static void hga_txt_mode(void) -{ - unsigned long flags; - - spin_lock_irqsave(&hga_reg_lock, flags); - outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_BLINK_EN, HGA_MODE_PORT); - outb_p(0x00, HGA_GFX_PORT); - outb_p(0x00, HGA_STATUS_PORT); - - write_hga_b(0x61, 0x00); /* horizontal total */ - write_hga_b(0x50, 0x01); /* horizontal displayed */ - write_hga_b(0x52, 0x02); /* horizontal sync pos */ - write_hga_b(0x0f, 0x03); /* horizontal sync width */ - - write_hga_b(0x19, 0x04); /* vertical total */ - write_hga_b(0x06, 0x05); /* vertical total adjust */ - write_hga_b(0x19, 0x06); /* vertical displayed */ - write_hga_b(0x19, 0x07); /* vertical sync pos */ - - write_hga_b(0x02, 0x08); /* interlace mode */ - write_hga_b(0x0d, 0x09); /* maximum scanline */ - write_hga_b(0x0c, 0x0a); /* cursor start */ - write_hga_b(0x0d, 0x0b); /* cursor end */ - - write_hga_w(0x0000, 0x0c); /* start address */ - write_hga_w(0x0000, 0x0e); /* cursor location */ - - hga_mode = HGA_TXT; - spin_unlock_irqrestore(&hga_reg_lock, flags); -} - -static void hga_gfx_mode(void) -{ - unsigned long flags; - - spin_lock_irqsave(&hga_reg_lock, flags); - outb_p(0x00, HGA_STATUS_PORT); - outb_p(HGA_GFX_MODE_EN, HGA_GFX_PORT); - outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT); - - write_hga_b(0x35, 0x00); /* horizontal total */ - write_hga_b(0x2d, 0x01); /* horizontal displayed */ - write_hga_b(0x2e, 0x02); /* horizontal sync pos */ - write_hga_b(0x07, 0x03); /* horizontal sync width */ - - write_hga_b(0x5b, 0x04); /* vertical total */ - write_hga_b(0x02, 0x05); /* vertical total adjust */ - write_hga_b(0x57, 0x06); /* vertical displayed */ - write_hga_b(0x57, 0x07); /* vertical sync pos */ - - write_hga_b(0x02, 0x08); /* interlace mode */ - write_hga_b(0x03, 0x09); /* maximum scanline */ - write_hga_b(0x00, 0x0a); /* cursor start */ - write_hga_b(0x00, 0x0b); /* cursor end */ - - write_hga_w(0x0000, 0x0c); /* start address */ - write_hga_w(0x0000, 0x0e); /* cursor location */ - - hga_mode = HGA_GFX; - spin_unlock_irqrestore(&hga_reg_lock, flags); -} - -static void hga_show_logo(struct fb_info *info) -{ -/* - void __iomem *dest = hga_vram; - char *logo = linux_logo_bw; - int x, y; - - for (y = 134; y < 134 + 80 ; y++) * this needs some cleanup * - for (x = 0; x < 10 ; x++) - writeb(~*(logo++),(dest + HGA_ROWADDR(y) + x + 40)); -*/ -} - -static void hga_pan(unsigned int xoffset, unsigned int yoffset) -{ - unsigned int base; - unsigned long flags; - - base = (yoffset / 8) * 90 + xoffset; - spin_lock_irqsave(&hga_reg_lock, flags); - write_hga_w(base, 0x0c); /* start address */ - spin_unlock_irqrestore(&hga_reg_lock, flags); - DPRINTK("hga_pan: base:%d\n", base); -} - -static void hga_blank(int blank_mode) -{ - unsigned long flags; - - spin_lock_irqsave(&hga_reg_lock, flags); - if (blank_mode) { - outb_p(0x00, HGA_MODE_PORT); /* disable video */ - } else { - outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT); - } - spin_unlock_irqrestore(&hga_reg_lock, flags); -} - -static int hga_card_detect(struct platform_device *pdev) -{ - int count = 0; - void __iomem *p, *q; - unsigned short p_save, q_save; - - hga_vram_len = 0x08000; - - if (!devm_request_mem_region(&pdev->dev, 0xb0000, hga_vram_len, "hgafb")) { - dev_err(&pdev->dev, "cannot reserve video memory at 0xb0000\n"); - return -EBUSY; - } - - hga_vram = ioremap(0xb0000, hga_vram_len); - if (!hga_vram) - return -ENOMEM; - - if (request_region(0x3b0, 12, "hgafb")) - release_io_ports = 1; - if (request_region(0x3bf, 1, "hgafb")) - release_io_port = 1; - - /* do a memory check */ - - p = hga_vram; - q = hga_vram + 0x01000; - - p_save = readw(p); q_save = readw(q); - - writew(0xaa55, p); if (readw(p) == 0xaa55) count++; - writew(0x55aa, p); if (readw(p) == 0x55aa) count++; - writew(p_save, p); - - if (count != 2) - goto error; - - /* Ok, there is definitely a card registering at the correct - * memory location, so now we do an I/O port test. - */ - - if (!test_hga_b(0x66, 0x0f)) /* cursor low register */ - goto error; - - if (!test_hga_b(0x99, 0x0f)) /* cursor low register */ - goto error; - - /* See if the card is a Hercules, by checking whether the vsync - * bit of the status register is changing. This test lasts for - * approximately 1/10th of a second. - */ - - p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC; - - for (count=0; count < 50000 && p_save == q_save; count++) { - q_save = inb(HGA_STATUS_PORT) & HGA_STATUS_VSYNC; - udelay(2); - } - - if (p_save == q_save) - goto error; - - switch (inb_p(HGA_STATUS_PORT) & 0x70) { - case 0x10: - hga_type = TYPE_HERCPLUS; - hga_type_name = "HerculesPlus"; - break; - case 0x50: - hga_type = TYPE_HERCCOLOR; - hga_type_name = "HerculesColor"; - break; - default: - hga_type = TYPE_HERC; - hga_type_name = "Hercules"; - break; - } - return 0; -error: - if (release_io_ports) - release_region(0x3b0, 12); - if (release_io_port) - release_region(0x3bf, 1); - - iounmap(hga_vram); - - pr_err("hgafb: HGA card not detected.\n"); - - return -EINVAL; -} - -/** - * hgafb_open - open the framebuffer device - * @info: pointer to fb_info object containing info for current hga board - * @init: open by console system or userland. - * - * Returns: %0 - */ - -static int hgafb_open(struct fb_info *info, int init) -{ - hga_gfx_mode(); - hga_clear_screen(); - if (!nologo) hga_show_logo(info); - return 0; -} - -/** - * hgafb_release - open the framebuffer device - * @info: pointer to fb_info object containing info for current hga board - * @init: open by console system or userland. - * - * Returns: %0 - */ - -static int hgafb_release(struct fb_info *info, int init) -{ - hga_txt_mode(); - hga_clear_screen(); - return 0; -} - -/** - * hgafb_setcolreg - set color registers - * @regno:register index to set - * @red:red value, unused - * @green:green value, unused - * @blue:blue value, unused - * @transp:transparency value, unused - * @info:unused - * - * This callback function is used to set the color registers of a HGA - * board. Since we have only two fixed colors only @regno is checked. - * A zero is returned on success and 1 for failure. - * - * Returns: %0 - */ - -static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (regno > 1) - return 1; - return 0; -} - -/** - * hgafb_pan_display - pan or wrap the display - * @var:contains new xoffset, yoffset and vmode values - * @info:pointer to fb_info object containing info for current hga board - * - * This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP - * flag in @var. If input parameters are correct it calls hga_pan() to - * program the hardware. @info->var is updated to the new values. - * - * Returns: %0 on success or %-EINVAL for failure. - */ - -static int hgafb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset >= info->var.yres_virtual || - var->xoffset) - return -EINVAL; - } else { - if (var->xoffset + info->var.xres > info->var.xres_virtual - || var->yoffset + info->var.yres > info->var.yres_virtual - || var->yoffset % 8) - return -EINVAL; - } - - hga_pan(var->xoffset, var->yoffset); - return 0; -} - -/** - * hgafb_blank - (un)blank the screen - * @blank_mode:blanking method to use - * @info:unused - * - * Blank the screen if blank_mode != 0, else unblank. - * Implements VESA suspend and powerdown modes on hardware that supports - * disabling hsync/vsync: - * @blank_mode == 2 means suspend vsync, - * @blank_mode == 3 means suspend hsync, - * @blank_mode == 4 means powerdown. - * - * Returns: %0 - */ - -static int hgafb_blank(int blank_mode, struct fb_info *info) -{ - hga_blank(blank_mode); - return 0; -} - -/* - * Accel functions - */ -static void hgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - u_int rows, y; - u8 __iomem *dest; - - y = rect->dy; - - for (rows = rect->height; rows--; y++) { - dest = rowaddr(info, y) + (rect->dx >> 3); - switch (rect->rop) { - case ROP_COPY: - memset_io(dest, rect->color, (rect->width >> 3)); - break; - case ROP_XOR: - fb_writeb(~(fb_readb(dest)), dest); - break; - } - } -} - -static void hgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) -{ - u_int rows, y1, y2; - u8 __iomem *src; - u8 __iomem *dest; - - if (area->dy <= area->sy) { - y1 = area->sy; - y2 = area->dy; - - for (rows = area->height; rows--; ) { - src = rowaddr(info, y1) + (area->sx >> 3); - dest = rowaddr(info, y2) + (area->dx >> 3); - memmove(dest, src, (area->width >> 3)); - y1++; - y2++; - } - } else { - y1 = area->sy + area->height - 1; - y2 = area->dy + area->height - 1; - - for (rows = area->height; rows--;) { - src = rowaddr(info, y1) + (area->sx >> 3); - dest = rowaddr(info, y2) + (area->dx >> 3); - memmove(dest, src, (area->width >> 3)); - y1--; - y2--; - } - } -} - -static void hgafb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - u8 __iomem *dest; - u8 *cdat = (u8 *) image->data; - u_int rows, y = image->dy; - u_int x; - u8 d; - - for (rows = image->height; rows--; y++) { - for (x = 0; x < image->width; x+= 8) { - d = *cdat++; - dest = rowaddr(info, y) + ((image->dx + x)>> 3); - fb_writeb(d, dest); - } - } -} - -static const struct fb_ops hgafb_ops = { - .owner = THIS_MODULE, - .fb_open = hgafb_open, - .fb_release = hgafb_release, - __FB_DEFAULT_IOMEM_OPS_RDWR, - .fb_setcolreg = hgafb_setcolreg, - .fb_pan_display = hgafb_pan_display, - .fb_blank = hgafb_blank, - .fb_fillrect = hgafb_fillrect, - .fb_copyarea = hgafb_copyarea, - .fb_imageblit = hgafb_imageblit, - __FB_DEFAULT_IOMEM_OPS_MMAP, -}; - -/* ------------------------------------------------------------------------- * - * - * Functions in fb_info - * - * ------------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------------- */ - - /* - * Initialization - */ - -static int hgafb_probe(struct platform_device *pdev) -{ - struct fb_info *info; - int ret; - - ret = hga_card_detect(pdev); - if (ret) - return ret; - - printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n", - hga_type_name, hga_vram_len/1024); - - info = framebuffer_alloc(0, &pdev->dev); - if (!info) { - iounmap(hga_vram); - return -ENOMEM; - } - - hga_fix.smem_start = (unsigned long)hga_vram; - hga_fix.smem_len = hga_vram_len; - - info->flags = FBINFO_HWACCEL_YPAN; - info->var = hga_default_var; - info->fix = hga_fix; - info->monspecs.hfmin = 0; - info->monspecs.hfmax = 0; - info->monspecs.vfmin = 10000; - info->monspecs.vfmax = 10000; - info->monspecs.dpms = 0; - info->fbops = &hgafb_ops; - info->screen_base = hga_vram; - - if (register_framebuffer(info) < 0) { - framebuffer_release(info); - iounmap(hga_vram); - return -EINVAL; - } - - fb_info(info, "%s frame buffer device\n", info->fix.id); - platform_set_drvdata(pdev, info); - return 0; -} - -static void hgafb_remove(struct platform_device *pdev) -{ - struct fb_info *info = platform_get_drvdata(pdev); - - hga_txt_mode(); - hga_clear_screen(); - - if (info) { - unregister_framebuffer(info); - framebuffer_release(info); - } - - iounmap(hga_vram); - - if (release_io_ports) - release_region(0x3b0, 12); - - if (release_io_port) - release_region(0x3bf, 1); -} - -static struct platform_driver hgafb_driver = { - .probe = hgafb_probe, - .remove = hgafb_remove, - .driver = { - .name = "hgafb", - }, -}; - -static struct platform_device *hgafb_device; - -static int __init hgafb_init(void) -{ - int ret; - - if (fb_get_options("hgafb", NULL)) - return -ENODEV; - - ret = platform_driver_register(&hgafb_driver); - - if (!ret) { - hgafb_device = platform_device_register_simple("hgafb", 0, NULL, 0); - - if (IS_ERR(hgafb_device)) { - platform_driver_unregister(&hgafb_driver); - ret = PTR_ERR(hgafb_device); - } - } - - return ret; -} - -static void __exit hgafb_exit(void) -{ - platform_device_unregister(hgafb_device); - platform_driver_unregister(&hgafb_driver); -} - -/* ------------------------------------------------------------------------- - * - * Modularization - * - * ------------------------------------------------------------------------- */ - -MODULE_AUTHOR("Ferenc Bakonyi "); -MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor"); -MODULE_LICENSE("GPL"); - -module_param(nologo, bool, 0); -MODULE_PARM_DESC(nologo, "Disables startup logo if != 0 (default=0)"); -module_init(hgafb_init); -module_exit(hgafb_exit); From e38b27199e0f5b530fd2b033e3b63241a0b16596 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Tue, 19 May 2026 20:31:36 -0700 Subject: [PATCH 353/655] console: mdacon: remove this obsolete driver The mdacon driver supports using ISA MDA or Hercules-compatible display adapters as a secondary text console. This was commonly used in the 1990s and earlier for debugging software which took over the primary display. It is highly unlikely anyone is doing so nowadays because serial consoles and much better methods of debugging exist. The driver is not enabled by any defconfig, nor any of the dozens of distro configs collected at [1]. It has been relegated to VTs 13-16 since commit 0b9cf3aa6b1e ("mdacon messing up default vc's - set default to vc13-16 again") in Linux 2.6.27 (and before Linux 2.5.53 - see the link in the message of the above commit). The change in 2.6.27 was done because it was incorrectly detecting non-MDA adapters as MDA and taking over all VTs, rendering them unusable. Furthermore, vgacon supports using MDA/Hercules-compatible adapters as the primary text console, so any systems with only one of these adapters were already using vgacon and will not experience any loss in functionality from the removal of this driver. Given all of these factors, the mdacon driver is likely entirely unused. Remove it. [1] https://github.com/nyrahul/linux-kernel-configs/tree/f0bee86a135a0406ea427855f52702dd00d770f9 Signed-off-by: Ethan Nelson-Moore Signed-off-by: Helge Deller --- .../admin-guide/kernel-parameters.txt | 5 - arch/alpha/kernel/io.c | 2 +- arch/powerpc/include/asm/vga.h | 4 +- drivers/tty/vt/vt.c | 3 - drivers/video/console/Kconfig | 15 - drivers/video/console/Makefile | 1 - drivers/video/console/mdacon.c | 566 ------------------ include/linux/console.h | 2 - include/linux/vt_buffer.h | 2 +- 9 files changed, 4 insertions(+), 596 deletions(-) delete mode 100644 drivers/video/console/mdacon.c diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 4d0f545fb3ec..e873b27cdd30 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -36,7 +36,6 @@ M68k M68k architecture is enabled. These options have more detailed description inside of Documentation/arch/m68k/kernel-options.rst. - MDA MDA console support is enabled. MIPS MIPS architecture is enabled. MOUSE Appropriate mouse support is enabled. MSI Message Signaled Interrupts (PCI). @@ -3816,10 +3815,6 @@ Kernel parameters md= [HW] RAID subsystems devices and level See Documentation/admin-guide/md.rst. - mdacon= [MDA] - Format: , - Specifies range of consoles to be captured by the MDA. - mds= [X86,INTEL,EARLY] Control mitigation for the Micro-architectural Data Sampling (MDS) vulnerability. diff --git a/arch/alpha/kernel/io.c b/arch/alpha/kernel/io.c index c28035d6d1e6..2bad1b4fb240 100644 --- a/arch/alpha/kernel/io.c +++ b/arch/alpha/kernel/io.c @@ -647,7 +647,7 @@ void _memset_c_io(volatile void __iomem *to, unsigned long c, long count) EXPORT_SYMBOL(_memset_c_io); -#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE) +#if IS_ENABLED(CONFIG_VGA_CONSOLE) #include diff --git a/arch/powerpc/include/asm/vga.h b/arch/powerpc/include/asm/vga.h index f2dc40e1c52a..e45063b02b45 100644 --- a/arch/powerpc/include/asm/vga.h +++ b/arch/powerpc/include/asm/vga.h @@ -14,7 +14,7 @@ #include -#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE) +#ifdef CONFIG_VGA_CONSOLE #define VT_BUF_HAVE_RW /* @@ -40,7 +40,7 @@ static inline void scr_memsetw(u16 *s, u16 v, unsigned int n) memset16(s, cpu_to_le16(v), n / 2); } -#endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */ +#endif /* !CONFIG_VGA_CONSOLE */ #ifdef __powerpc64__ #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s)) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e99636ab9db5..3ca5e3dc5ac0 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3978,9 +3978,6 @@ int __init vty_init(const struct file_operations *console_fops) panic("Couldn't register console driver\n"); kbd_init(); console_map_init(); -#ifdef CONFIG_MDA_CONSOLE - mda_console_init(); -#endif return 0; } diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 12f54480f57f..9f81af3506da 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -23,21 +23,6 @@ config VGA_CONSOLE Say Y. -config MDA_CONSOLE - depends on VGA_CONSOLE && ISA - tristate "MDA text console (dual-headed)" - help - Say Y here if you have an old MDA or monochrome Hercules graphics - adapter in your system acting as a second head ( = video card). You - will then be able to use two monitors with your Linux system. Do not - say Y here if your MDA card is the primary card in your system; the - normal VGA driver will handle it. - - To compile this driver as a module, choose M here: the - module will be called mdacon. - - If unsure, say N. - config SGI_NEWPORT_CONSOLE tristate "SGI Newport Console support" depends on SGI_IP22 && HAS_IOMEM diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index fd79016a0d95..f1000605210c 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -7,4 +7,3 @@ obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o obj-$(CONFIG_STI_CONSOLE) += sticon.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o -obj-$(CONFIG_MDA_CONSOLE) += mdacon.o diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c deleted file mode 100644 index d52cd99cd18b..000000000000 --- a/drivers/video/console/mdacon.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * linux/drivers/video/mdacon.c -- Low level MDA based console driver - * - * (c) 1998 Andrew Apted - * - * including portions (c) 1995-1998 Patrick Caulfield. - * - * slight improvements (c) 2000 Edward Betts - * - * This file is based on the VGA console driver (vgacon.c): - * - * Created 28 Sep 1997 by Geert Uytterhoeven - * - * Rewritten by Martin Mares , July 1998 - * - * and on the old console.c, vga.c and vesa_blank.c drivers: - * - * Copyright (C) 1991, 1992 Linus Torvalds - * 1995 Jay Estabrook - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * Changelog: - * Paul G. (03/2001) Fix mdacon= boot prompt to use __setup(). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static DEFINE_SPINLOCK(mda_lock); - -/* description of the hardware layout */ - -static u16 *mda_vram_base; /* Base of video memory */ -static unsigned long mda_vram_len; /* Size of video memory */ -static unsigned int mda_num_columns; /* Number of text columns */ -static unsigned int mda_num_lines; /* Number of text lines */ - -static unsigned int mda_index_port; /* Register select port */ -static unsigned int mda_value_port; /* Register value port */ -static unsigned int mda_mode_port; /* Mode control port */ -static unsigned int mda_status_port; /* Status and Config port */ -static unsigned int mda_gfx_port; /* Graphics control port */ - -/* current hardware state */ - -static int mda_cursor_loc=-1; -static int mda_cursor_size_from=-1; -static int mda_cursor_size_to=-1; - -static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type; -static char *mda_type_name; - -/* console information */ - -static int mda_first_vc = 13; -static int mda_last_vc = 16; - -static struct vc_data *mda_display_fg = NULL; - -module_param(mda_first_vc, int, 0); -MODULE_PARM_DESC(mda_first_vc, "First virtual console. Default: 13"); -module_param(mda_last_vc, int, 0); -MODULE_PARM_DESC(mda_last_vc, "Last virtual console. Default: 16"); - -/* MDA register values - */ - -#define MDA_CURSOR_BLINKING 0x00 -#define MDA_CURSOR_OFF 0x20 -#define MDA_CURSOR_SLOWBLINK 0x60 - -#define MDA_MODE_GRAPHICS 0x02 -#define MDA_MODE_VIDEO_EN 0x08 -#define MDA_MODE_BLINK_EN 0x20 -#define MDA_MODE_GFX_PAGE1 0x80 - -#define MDA_STATUS_HSYNC 0x01 -#define MDA_STATUS_VSYNC 0x80 -#define MDA_STATUS_VIDEO 0x08 - -#define MDA_CONFIG_COL132 0x08 -#define MDA_GFX_MODE_EN 0x01 -#define MDA_GFX_PAGE_EN 0x02 - - -/* - * MDA could easily be classified as "pre-dinosaur hardware". - */ - -static void write_mda_b(unsigned int val, unsigned char reg) -{ - unsigned long flags; - - spin_lock_irqsave(&mda_lock, flags); - - outb_p(reg, mda_index_port); - outb_p(val, mda_value_port); - - spin_unlock_irqrestore(&mda_lock, flags); -} - -static void write_mda_w(unsigned int val, unsigned char reg) -{ - unsigned long flags; - - spin_lock_irqsave(&mda_lock, flags); - - outb_p(reg, mda_index_port); outb_p(val >> 8, mda_value_port); - outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port); - - spin_unlock_irqrestore(&mda_lock, flags); -} - -#ifdef TEST_MDA_B -static int test_mda_b(unsigned char val, unsigned char reg) -{ - unsigned long flags; - - spin_lock_irqsave(&mda_lock, flags); - - outb_p(reg, mda_index_port); - outb (val, mda_value_port); - - udelay(20); val = (inb_p(mda_value_port) == val); - - spin_unlock_irqrestore(&mda_lock, flags); - return val; -} -#endif - -static inline void mda_set_cursor(unsigned int location) -{ - if (mda_cursor_loc == location) - return; - - write_mda_w(location >> 1, 0x0e); - - mda_cursor_loc = location; -} - -static inline void mda_set_cursor_size(int from, int to) -{ - if (mda_cursor_size_from==from && mda_cursor_size_to==to) - return; - - if (from > to) { - write_mda_b(MDA_CURSOR_OFF, 0x0a); /* disable cursor */ - } else { - write_mda_b(from, 0x0a); /* cursor start */ - write_mda_b(to, 0x0b); /* cursor end */ - } - - mda_cursor_size_from = from; - mda_cursor_size_to = to; -} - - -#ifndef MODULE -static int __init mdacon_setup(char *str) -{ - /* command line format: mdacon=, */ - - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] < 2) - return 0; - - if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || - ints[2] < 1 || ints[2] > MAX_NR_CONSOLES) - return 0; - - mda_first_vc = ints[1]; - mda_last_vc = ints[2]; - return 1; -} - -__setup("mdacon=", mdacon_setup); -#endif - -static int mda_detect(void) -{ - int count=0; - u16 *p, p_save; - u16 *q, q_save; - - /* do a memory check */ - - p = mda_vram_base; - q = mda_vram_base + 0x01000 / 2; - - p_save = scr_readw(p); - q_save = scr_readw(q); - - scr_writew(0xAA55, p); - if (scr_readw(p) == 0xAA55) - count++; - - scr_writew(0x55AA, p); - if (scr_readw(p) == 0x55AA) - count++; - - scr_writew(p_save, p); - - if (count != 2) { - return 0; - } - - /* check if we have 4K or 8K */ - - scr_writew(0xA55A, q); - scr_writew(0x0000, p); - if (scr_readw(q) == 0xA55A) - count++; - - scr_writew(0x5AA5, q); - scr_writew(0x0000, p); - if (scr_readw(q) == 0x5AA5) - count++; - - scr_writew(p_save, p); - scr_writew(q_save, q); - - if (count == 4) { - mda_vram_len = 0x02000; - } - - /* Ok, there is definitely a card registering at the correct - * memory location, so now we do an I/O port test. - */ - -#ifdef TEST_MDA_B - /* Edward: These two mess `tests' mess up my cursor on bootup */ - - /* cursor low register */ - if (!test_mda_b(0x66, 0x0f)) - return 0; - - /* cursor low register */ - if (!test_mda_b(0x99, 0x0f)) - return 0; -#endif - - /* See if the card is a Hercules, by checking whether the vsync - * bit of the status register is changing. This test lasts for - * approximately 1/10th of a second. - */ - - p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC; - - for (count = 0; count < 50000 && p_save == q_save; count++) { - q_save = inb(mda_status_port) & MDA_STATUS_VSYNC; - udelay(2); - } - - if (p_save != q_save) { - switch (inb_p(mda_status_port) & 0x70) { - case 0x10: - mda_type = TYPE_HERCPLUS; - mda_type_name = "HerculesPlus"; - break; - case 0x50: - mda_type = TYPE_HERCCOLOR; - mda_type_name = "HerculesColor"; - break; - default: - mda_type = TYPE_HERC; - mda_type_name = "Hercules"; - break; - } - } - - return 1; -} - -static void mda_initialize(void) -{ - write_mda_b(97, 0x00); /* horizontal total */ - write_mda_b(80, 0x01); /* horizontal displayed */ - write_mda_b(82, 0x02); /* horizontal sync pos */ - write_mda_b(15, 0x03); /* horizontal sync width */ - - write_mda_b(25, 0x04); /* vertical total */ - write_mda_b(6, 0x05); /* vertical total adjust */ - write_mda_b(25, 0x06); /* vertical displayed */ - write_mda_b(25, 0x07); /* vertical sync pos */ - - write_mda_b(2, 0x08); /* interlace mode */ - write_mda_b(13, 0x09); /* maximum scanline */ - write_mda_b(12, 0x0a); /* cursor start */ - write_mda_b(13, 0x0b); /* cursor end */ - - write_mda_w(0x0000, 0x0c); /* start address */ - write_mda_w(0x0000, 0x0e); /* cursor location */ - - outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port); - outb_p(0x00, mda_status_port); - outb_p(0x00, mda_gfx_port); -} - -static const char *mdacon_startup(void) -{ - mda_num_columns = 80; - mda_num_lines = 25; - - mda_vram_len = 0x01000; - mda_vram_base = (u16 *)VGA_MAP_MEM(0xb0000, mda_vram_len); - - mda_index_port = 0x3b4; - mda_value_port = 0x3b5; - mda_mode_port = 0x3b8; - mda_status_port = 0x3ba; - mda_gfx_port = 0x3bf; - - mda_type = TYPE_MDA; - mda_type_name = "MDA"; - - if (! mda_detect()) { - printk("mdacon: MDA card not detected.\n"); - return NULL; - } - - if (mda_type != TYPE_MDA) { - mda_initialize(); - } - - /* cursor looks ugly during boot-up, so turn it off */ - mda_set_cursor(mda_vram_len - 1); - - printk("mdacon: %s with %ldK of memory detected.\n", - mda_type_name, mda_vram_len/1024); - - return "MDA-2"; -} - -static void mdacon_init(struct vc_data *c, bool init) -{ - c->vc_complement_mask = 0x0800; /* reverse video */ - c->vc_display_fg = &mda_display_fg; - - if (init) { - c->vc_cols = mda_num_columns; - c->vc_rows = mda_num_lines; - } else - vc_resize(c, mda_num_columns, mda_num_lines); - - /* make the first MDA console visible */ - - if (mda_display_fg == NULL) - mda_display_fg = c; -} - -static void mdacon_deinit(struct vc_data *c) -{ - /* con_set_default_unimap(c->vc_num); */ - - if (mda_display_fg == c) - mda_display_fg = NULL; -} - -static inline u16 mda_convert_attr(u16 ch) -{ - u16 attr = 0x0700; - - /* Underline and reverse-video are mutually exclusive on MDA. - * Since reverse-video is used for cursors and selected areas, - * it takes precedence. - */ - - if (ch & 0x0800) attr = 0x7000; /* reverse */ - else if (ch & 0x0400) attr = 0x0100; /* underline */ - - return ((ch & 0x0200) << 2) | /* intensity */ - (ch & 0x8000) | /* blink */ - (ch & 0x00ff) | attr; -} - -static u8 mdacon_build_attr(struct vc_data *c, u8 color, - enum vc_intensity intensity, - bool blink, bool underline, bool reverse, - bool italic) -{ - /* The attribute is just a bit vector: - * - * Bit 0..1 : intensity (0..2) - * Bit 2 : underline - * Bit 3 : reverse - * Bit 7 : blink - */ - - return (intensity & VCI_MASK) | - (underline << 2) | - (reverse << 3) | - (italic << 4) | - (blink << 7); -} - -static void mdacon_invert_region(struct vc_data *c, u16 *p, int count) -{ - for (; count > 0; count--) { - scr_writew(scr_readw(p) ^ 0x0800, p); - p++; - } -} - -static inline u16 *mda_addr(unsigned int x, unsigned int y) -{ - return mda_vram_base + y * mda_num_columns + x; -} - -static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count, - unsigned int y, unsigned int x) -{ - u16 *dest = mda_addr(x, y); - - for (; count > 0; count--) { - scr_writew(mda_convert_attr(scr_readw(s++)), dest++); - } -} - -static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x, - unsigned int width) -{ - u16 *dest = mda_addr(x, y); - u16 eattr = mda_convert_attr(c->vc_video_erase_char); - - scr_memsetw(dest, eattr, width * 2); -} - -static bool mdacon_switch(struct vc_data *c) -{ - return true; /* redrawing needed */ -} - -static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank, - bool mode_switch) -{ - if (mda_type == TYPE_MDA) { - if (blank) - scr_memsetw(mda_vram_base, - mda_convert_attr(c->vc_video_erase_char), - c->vc_screenbuf_size); - /* Tell console.c that it has to restore the screen itself */ - return true; - } else { - if (blank) - outb_p(0x00, mda_mode_port); /* disable video */ - else - outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, - mda_mode_port); - return false; - } -} - -static void mdacon_cursor(struct vc_data *c, bool enable) -{ - if (!enable) { - mda_set_cursor(mda_vram_len - 1); - return; - } - - mda_set_cursor(c->state.y * mda_num_columns * 2 + c->state.x * 2); - - switch (CUR_SIZE(c->vc_cursor_type)) { - - case CUR_LOWER_THIRD: mda_set_cursor_size(10, 13); break; - case CUR_LOWER_HALF: mda_set_cursor_size(7, 13); break; - case CUR_TWO_THIRDS: mda_set_cursor_size(4, 13); break; - case CUR_BLOCK: mda_set_cursor_size(1, 13); break; - case CUR_NONE: mda_set_cursor_size(14, 13); break; - default: mda_set_cursor_size(12, 13); break; - } -} - -static bool mdacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, - enum con_scroll dir, unsigned int lines) -{ - u16 eattr = mda_convert_attr(c->vc_video_erase_char); - - if (!lines) - return false; - - if (lines > c->vc_rows) /* maximum realistic size */ - lines = c->vc_rows; - - switch (dir) { - - case SM_UP: - scr_memmovew(mda_addr(0, t), mda_addr(0, t + lines), - (b-t-lines)*mda_num_columns*2); - scr_memsetw(mda_addr(0, b - lines), eattr, - lines*mda_num_columns*2); - break; - - case SM_DOWN: - scr_memmovew(mda_addr(0, t + lines), mda_addr(0, t), - (b-t-lines)*mda_num_columns*2); - scr_memsetw(mda_addr(0, t), eattr, lines*mda_num_columns*2); - break; - } - - return false; -} - - -/* - * The console `switch' structure for the MDA based console - */ - -static const struct consw mda_con = { - .owner = THIS_MODULE, - .con_startup = mdacon_startup, - .con_init = mdacon_init, - .con_deinit = mdacon_deinit, - .con_clear = mdacon_clear, - .con_putcs = mdacon_putcs, - .con_cursor = mdacon_cursor, - .con_scroll = mdacon_scroll, - .con_switch = mdacon_switch, - .con_blank = mdacon_blank, - .con_build_attr = mdacon_build_attr, - .con_invert_region = mdacon_invert_region, -}; - -int __init mda_console_init(void) -{ - int err; - - if (mda_first_vc > mda_last_vc) - return 1; - console_lock(); - err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0); - console_unlock(); - return err; -} - -static void __exit mda_console_exit(void) -{ - give_up_console(&mda_con); -} - -module_init(mda_console_init); -module_exit(mda_console_exit); - -MODULE_DESCRIPTION("MDA based console driver"); -MODULE_LICENSE("GPL"); - diff --git a/include/linux/console.h b/include/linux/console.h index 5520e4477ad7..d624200cfc17 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -718,8 +718,6 @@ extern bool console_suspend_enabled; extern void console_suspend_all(void); extern void console_resume_all(void); -int mda_console_init(void); - void vcs_make_sysfs(int index); void vcs_remove_sysfs(int index); diff --git a/include/linux/vt_buffer.h b/include/linux/vt_buffer.h index b6eeb8cb6070..6c15c6a15f74 100644 --- a/include/linux/vt_buffer.h +++ b/include/linux/vt_buffer.h @@ -16,7 +16,7 @@ #include -#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE) +#if IS_ENABLED(CONFIG_VGA_CONSOLE) #include #endif From 34808ac8ddafc3e2c2a59e84eaab0a410e7a0fdc Mon Sep 17 00:00:00 2001 From: Nishanth Sampath Kumar Date: Wed, 20 May 2026 08:11:09 -0700 Subject: [PATCH 354/655] regmap-i2c: fix sparse warning in regmap_smbus_word_write_reg16 i2c_smbus_write_word_data() expects a plain u16, but cpu_to_le16() returns __le16 (a sparse-restricted endian type), causing: drivers/base/regmap/regmap-i2c.c:340: sparse: incorrect type in argument 3 (different base types) expected unsigned short [usertype] value got restricted __le16 [usertype] SMBus already defines byte ordering internally, so cpu_to_le16() is wrong here. Replace it with a plain (u16) cast. Fixes: bad4bd28abf4 ("regmap-i2c: add SMBus byte/word reg16 bus for adapters lacking I2C_FUNC_I2C") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605161621.mY5zFh4D-lkp@intel.com/ Signed-off-by: Nishanth Sampath Kumar Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 31e30dfced19..51a04961faf7 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -337,7 +337,7 @@ static int regmap_smbus_word_write_reg16(void *context, const void *data, val = ((u8 *)data)[2]; return i2c_smbus_write_word_data(i2c, addr_hi, - cpu_to_le16(((u16)val << 8) | addr_lo)); + ((u16)val << 8) | addr_lo); } static const struct regmap_bus regmap_smbus_byte_word_reg16 = { From 019947c495850461242fdcc0780258805595036c Mon Sep 17 00:00:00 2001 From: Thomas Lin Date: Thu, 21 May 2026 10:34:50 +0800 Subject: [PATCH 355/655] spi: dw-mmio: Add ACPI ID LECA0002 for LECARC SoCs This ID requires a custom initialization function dw_spi_hssi_no_dma_init() that sets dws->dws.ip to DW_HSSI_ID. Signed-off-by: Thomas Lin Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20260521-lecarc-acpi-ids-v1-2-ae0ae90b2817@lecomputing.com Signed-off-by: Mark Brown --- drivers/acpi/acpi_apd.c | 7 +++++++ drivers/spi/spi-dw-mmio.c | 7 ++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index bed0791c17fc..4d5a51d30adc 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -181,6 +181,12 @@ static const struct apd_device_desc hip08_spi_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 250000000, }; + +static const struct apd_device_desc leca_spi_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 400000000, +}; + #endif /* CONFIG_ARM64 */ #endif @@ -251,6 +257,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { { "HISI02A2", APD_ADDR(hip08_i2c_desc) }, { "HISI02A3", APD_ADDR(hip08_lite_i2c_desc) }, { "HISI0173", APD_ADDR(hip08_spi_desc) }, + { "LECA0002", APD_ADDR(leca_spi_desc) }, { "NXP0001", APD_ADDR(nxp_i2c_desc) }, #endif { } diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 1bfdf24c3227..4fc864d38cff 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -226,8 +226,8 @@ static int dw_spi_hssi_init(struct platform_device *pdev, return 0; } -static int dw_spi_intel_init(struct platform_device *pdev, - struct dw_spi_mmio *dwsmmio) +static int dw_spi_hssi_no_dma_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) { dwsmmio->dws.ip = DW_HSSI_ID; @@ -438,7 +438,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = { { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init}, { .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init}, { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init}, - { .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init}, + { .compatible = "intel,keembay-ssi", .data = dw_spi_hssi_no_dma_init}, { .compatible = "intel,mountevans-imc-ssi", .data = dw_spi_mountevans_imc_init, @@ -453,6 +453,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id dw_spi_mmio_acpi_match[] = { {"HISI0173", (kernel_ulong_t)dw_spi_pssi_init}, + {"LECA0002", (kernel_ulong_t)dw_spi_hssi_no_dma_init}, {}, }; MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match); From 16ba3b0c66ef1d16bce2e99d787d7d12281bb2de Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 21 May 2026 09:38:16 +0200 Subject: [PATCH 356/655] spi: fix controller registration API inconsistency The SPI controller API is asymmetric in that a controller is allocated and registered in two step, while it is freed as part of deregistration. [1] This is especially unfortunate as any driver data is freed along with the controller, something which has lead to use-after-free bugs during deregistration when drivers tear down resources after deregistering the controller (or tear down resources that may still be in use before deregistering the controller in an attempt to work around the API). To reduce the risk of such bugs being introduced a device managed allocation interface was added, but this arguably made things even less consistent as now whether the controller gets freed as part of deregistration depends on how it was allocated. [2][3] With most drivers converted to use managed allocation in preparation for fixing the API, the remaining 16 drivers can be converted in one tree-wide change. Ten of those drivers use the bitbang interface and can be converted by simply removing the extra reference already taken by spi_bitbang_start() (and updating the two bitbang drivers that use managed allocation). [4] Fix the API inconsistency by no longer dropping a reference when deregistering non-devres allocated controllers. [1] 68b892f1fdc4 ("spi: document odd controller reference handling") [2] 5e844cc37a5c ("spi: Introduce device-managed SPI controller allocation") [3] 3f174274d224 ("spi: fix misleading controller deregistration kernel-doc") [4] 702a4879ec33 ("spi: bitbang: Let spi_bitbang_start() take a reference to master") Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260521073816.766596-1-johan@kernel.org Signed-off-by: Mark Brown --- drivers/media/usb/msi2500/msi2500.c | 9 ++++---- drivers/spi/spi-bitbang.c | 11 +-------- drivers/spi/spi-dw-core.c | 2 ++ drivers/spi/spi-fsl-dspi.c | 2 ++ drivers/spi/spi-mpc52xx.c | 2 +- drivers/spi/spi-topcliff-pch.c | 2 -- drivers/spi/spi-xilinx.c | 2 -- drivers/spi/spi-xtensa-xtfpga.c | 1 - drivers/spi/spi.c | 35 +++++------------------------ drivers/staging/greybus/spilib.c | 8 +++---- include/linux/spi/spi.h | 4 ---- 11 files changed, 19 insertions(+), 59 deletions(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 1ff98956b680..5c512d61dc1b 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -575,6 +575,7 @@ static void msi2500_disconnect(struct usb_interface *intf) v4l2_device_disconnect(&dev->v4l2_dev); video_unregister_device(&dev->vdev); spi_unregister_controller(dev->ctlr); + spi_controller_put(dev->ctlr); mutex_unlock(&dev->v4l2_lock); mutex_unlock(&dev->vb_queue_lock); @@ -1230,10 +1231,8 @@ static int msi2500_probe(struct usb_interface *intf, ctlr->transfer_one_message = msi2500_transfer_one_message; spi_controller_set_devdata(ctlr, dev); ret = spi_register_controller(ctlr); - if (ret) { - spi_controller_put(ctlr); - goto err_unregister_v4l2_dev; - } + if (ret) + goto err_put_controller; /* load v4l2 subdevice */ sd = v4l2_spi_new_subdev(&dev->v4l2_dev, ctlr, &board_info); @@ -1276,6 +1275,8 @@ err_free_controls: v4l2_ctrl_handler_free(&dev->hdl); err_unregister_controller: spi_unregister_controller(dev->ctlr); +err_put_controller: + spi_controller_put(dev->ctlr); err_unregister_v4l2_dev: v4l2_device_unregister(&dev->v4l2_dev); err_free_mem: diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 9f03ac217319..fb288ed56d94 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -420,11 +420,6 @@ EXPORT_SYMBOL_GPL(spi_bitbang_init); * This routine registers the spi_controller, which will process requests in a * dedicated task, keeping IRQs unblocked most of the time. To stop * processing those requests, call spi_bitbang_stop(). - * - * On success, this routine will take a reference to the controller. The caller - * is responsible for calling spi_bitbang_stop() to decrement the reference and - * spi_controller_put() as counterpart of spi_alloc_host() to prevent a memory - * leak. */ int spi_bitbang_start(struct spi_bitbang *bitbang) { @@ -438,11 +433,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) /* driver may get busy before register() returns, especially * if someone registered boardinfo for devices */ - ret = spi_register_controller(spi_controller_get(ctlr)); - if (ret) - spi_controller_put(ctlr); - - return ret; + return spi_register_controller(ctlr); } EXPORT_SYMBOL_GPL(spi_bitbang_start); diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index b47637888c5c..9a85a3ce5652 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -1032,6 +1032,8 @@ void dw_spi_remove_controller(struct dw_spi *dws) dw_spi_shutdown_chip(dws); free_irq(dws->irq, dws->ctlr); + + spi_controller_put(dws->ctlr); } EXPORT_SYMBOL_NS_GPL(dw_spi_remove_controller, "SPI_DW_CORE"); diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 9f2a7b8163b1..019d05cdefe6 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1715,6 +1715,8 @@ static void dspi_remove(struct platform_device *pdev) dspi_release_dma(dspi); if (dspi->irq) free_irq(dspi->irq, dspi); + + spi_controller_put(dspi->ctlr); } static void dspi_shutdown(struct platform_device *pdev) diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 04c2270cd2cf..70d8e17e8c43 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -520,7 +520,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) static void mpc52xx_spi_remove(struct platform_device *op) { - struct spi_controller *host = spi_controller_get(platform_get_drvdata(op)); + struct spi_controller *host = platform_get_drvdata(op); struct mpc52xx_spi *ms = spi_controller_get_devdata(host); int i; diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 02ced638d8b4..c5409ca7faef 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1406,8 +1406,6 @@ static void pch_spi_pd_remove(struct platform_device *plat_dev) dev_dbg(&plat_dev->dev, "%s:[ch%d] irq=%d\n", __func__, plat_dev->id, board_dat->pdev->irq); - spi_controller_get(data->host); - spi_unregister_controller(data->host); /* check for any pending messages; no action is taken if the queue diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 9f065d4e27d1..3aeef70caa96 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -515,8 +515,6 @@ static void xilinx_spi_remove(struct platform_device *pdev) xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); /* Disable the global IPIF interrupt */ xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); - - spi_controller_put(xspi->bitbang.ctlr); } /* work with hotplug and coldplug */ diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index 71f0f176cfd9..d47a1e548fce 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -122,7 +122,6 @@ static void xtfpga_spi_remove(struct platform_device *pdev) struct xtfpga_spi *xspi = spi_controller_get_devdata(host); spi_bitbang_stop(&xspi->bitbang); - spi_controller_put(host); } MODULE_ALIAS("platform:" XTFPGA_SPI_NAME); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5f57de24b9f7..0576bd00d3ef 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3226,9 +3226,9 @@ extern struct class spi_target_class; /* dummy */ * This must be called from context that can sleep. * * The caller is responsible for assigning the bus number and initializing the - * controller's methods before calling spi_register_controller(); and (after - * errors adding the device) calling spi_controller_put() to prevent a memory - * leak. + * controller's methods before calling spi_register_controller(); and calling + * spi_controller_put() to prevent a memory leak when done with the + * controller. * * Return: the SPI controller structure on success, else NULL. */ @@ -3312,8 +3312,6 @@ struct spi_controller *__devm_spi_alloc_controller(struct device *dev, if (ret) return NULL; - ctlr->devm_allocated = true; - return ctlr; } EXPORT_SYMBOL_GPL(__devm_spi_alloc_controller); @@ -3579,8 +3577,7 @@ static void devm_spi_unregister_controller(void *ctlr) * Context: can sleep * * Register a SPI device as with spi_register_controller() which will - * automatically be unregistered (and freed unless it has been allocated using - * devm_spi_alloc_host/target()). + * automatically be unregistered. * * Return: zero on success, else a negative error code. */ @@ -3593,19 +3590,7 @@ int devm_spi_register_controller(struct device *dev, if (ret) return ret; - /* - * Prevent controller from being freed by spi_unregister_controller() - * if devm_add_action_or_reset() fails for a non-devres allocated - * controller. - */ - spi_controller_get(ctlr); - - ret = devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr); - - if (ret == 0 || ctlr->devm_allocated) - spi_controller_put(ctlr); - - return ret; + return devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr); } EXPORT_SYMBOL_GPL(devm_spi_register_controller); @@ -3624,9 +3609,6 @@ static int __unregister(struct device *dev, void *null) * only ones directly touching chip registers. * * This must be called from context that can sleep. - * - * Note that this function also drops a reference to the controller unless it - * has been allocated using devm_spi_alloc_host/target(). */ void spi_unregister_controller(struct spi_controller *ctlr) { @@ -3661,13 +3643,6 @@ void spi_unregister_controller(struct spi_controller *ctlr) if (IS_ENABLED(CONFIG_SPI_DYNAMIC)) mutex_unlock(&ctlr->add_lock); - - /* - * Release the last reference on the controller if its driver - * has not yet been converted to devm_spi_alloc_host/target(). - */ - if (!ctlr->devm_allocated) - put_device(&ctlr->dev); } EXPORT_SYMBOL_GPL(spi_unregister_controller); diff --git a/drivers/staging/greybus/spilib.c b/drivers/staging/greybus/spilib.c index 24e9c909fa02..e4d1ae8308aa 100644 --- a/drivers/staging/greybus/spilib.c +++ b/drivers/staging/greybus/spilib.c @@ -547,13 +547,10 @@ int gb_spilib_master_init(struct gb_connection *connection, struct device *dev, return 0; -exit_spi_put: - spi_controller_put(ctlr); - - return ret; - exit_spi_unregister: spi_unregister_controller(ctlr); +exit_spi_put: + spi_controller_put(ctlr); return ret; } @@ -564,6 +561,7 @@ void gb_spilib_master_exit(struct gb_connection *connection) struct spi_controller *ctlr = gb_connection_get_data(connection); spi_unregister_controller(ctlr); + spi_controller_put(ctlr); } EXPORT_SYMBOL_GPL(gb_spilib_master_exit); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 79513f5941cc..f6ed93eff00b 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -424,7 +424,6 @@ extern struct spi_device *devm_spi_new_ancillary_device(struct spi_device *spi, * @flags: other constraints relevant to this driver * @slave: indicates that this is an SPI slave controller * @target: indicates that this is an SPI target controller - * @devm_allocated: whether the allocation of this struct is devres-managed * @max_transfer_size: function that returns the max transfer size for * a &spi_device; may be %NULL, so the default %SIZE_MAX will be used. * @max_message_size: function that returns the max message size for @@ -629,9 +628,6 @@ struct spi_controller { */ #define SPI_CONTROLLER_MULTI_CS BIT(7) - /* Flag indicating if the allocation of this struct is devres-managed */ - bool devm_allocated; - union { /* Flag indicating this is an SPI slave controller */ bool slave; From 90330ae4e0d891ecb4879d03cbdd6bdca062c7a0 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 20 May 2026 10:13:42 +0100 Subject: [PATCH 357/655] spi: Drop redundant 'cs' variable declaration in __spi_add_device() Remove the redundant local variable 'cs' definition declared within the chipselect GPIO configuration block. Signed-off-by: Lad Prabhakar Link: https://patch.msgid.link/20260520091342.68029-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 0576bd00d3ef..fe7e3b3b98fc 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -732,8 +732,6 @@ static int __spi_add_device(struct spi_device *spi, struct spi_device *parent) } if (ctlr->cs_gpiods) { - u8 cs; - for (idx = 0; idx < spi->num_chipselect; idx++) { cs = spi_get_chipselect(spi, idx); spi_set_csgpiod(spi, idx, ctlr->cs_gpiods[cs]); From 5c3091e23f8fc2bdb6d85ca23b6097f05f3f0467 Mon Sep 17 00:00:00 2001 From: Chin-Ting Kuo Date: Fri, 22 May 2026 15:16:20 +0800 Subject: [PATCH 358/655] spi: aspeed: Fix missing __iomem annotation in output transfer path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dst parameter of aspeed_spi_user_transfer_tx() is an MMIO address obtained from chip->ahb_base, but it was typed as void * instead of void __iomem *. This caused a sparse warning report. Fix the parameter type to void __iomem * and drop the now-unnecessary cast at the call site. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605180441.uD3toFRJ-lkp@intel.com/ Signed-off-by: Chin-Ting Kuo Reviewed-by: Cédric Le Goater Link: https://patch.msgid.link/20260522071621.102507-2-chin-ting_kuo@aspeedtech.com Signed-off-by: Mark Brown --- drivers/spi/spi-aspeed-smc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index c21323e07d3c..808659a1f460 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -891,7 +891,7 @@ static int aspeed_spi_user_unprepare_msg(struct spi_controller *ctlr, static void aspeed_spi_user_transfer_tx(struct aspeed_spi *aspi, struct spi_device *spi, const u8 *tx_buf, u8 *rx_buf, - void *dst, u32 len) + void __iomem *dst, u32 len) { const struct aspeed_spi_data *data = aspi->data; bool full_duplex_transfer = data->full_duplex && tx_buf == rx_buf; @@ -936,7 +936,7 @@ static int aspeed_spi_user_transfer(struct spi_controller *ctlr, aspeed_spi_set_io_mode(chip, CTRL_IO_QUAD_DATA); aspeed_spi_user_transfer_tx(aspi, spi, tx_buf, rx_buf, - (void *)ahb_base, xfer->len); + ahb_base, xfer->len); } if (rx_buf && rx_buf != tx_buf) { From 94f5efbaa7518cfa0f9c684be85d66bd005cfbe3 Mon Sep 17 00:00:00 2001 From: Chin-Ting Kuo Date: Fri, 22 May 2026 15:16:21 +0800 Subject: [PATCH 359/655] spi: aspeed: Replace VLA parameter with flat pointer in calibration helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aspeed_spi_ast2600_optimized_timing() declared its buffer argument as a variable-length array parameter (u8 buf[rows][cols]), which causes a sparse warning. Replace the VLA parameter with a plain u8 * and compute the 2-D index manually. The corresponding call site is also updated. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605180441.uD3toFRJ-lkp@intel.com/ Signed-off-by: Chin-Ting Kuo Reviewed-by: Cédric Le Goater Link: https://patch.msgid.link/20260522071621.102507-3-chin-ting_kuo@aspeedtech.com Signed-off-by: Mark Brown --- drivers/spi/spi-aspeed-smc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index 808659a1f460..027caa2eeb5c 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -1467,8 +1467,7 @@ end_calib: * must contains the highest number of consecutive "pass" * results and not span across multiple rows. */ -static u32 aspeed_spi_ast2600_optimized_timing(u32 rows, u32 cols, - u8 buf[rows][cols]) +static u32 aspeed_spi_ast2600_optimized_timing(u32 rows, u32 cols, u8 *buf) { int r = 0, c = 0; int max = 0; @@ -1478,7 +1477,7 @@ static u32 aspeed_spi_ast2600_optimized_timing(u32 rows, u32 cols, for (j = 0; j < cols;) { int k = j; - while (k < cols && buf[i][k]) + while (k < cols && buf[(i * cols) + k]) k++; if (k - j > max) { @@ -1541,7 +1540,7 @@ static int aspeed_spi_ast2600_calibrate(struct aspeed_spi_chip *chip, u32 hdiv, } } - calib_point = aspeed_spi_ast2600_optimized_timing(6, 17, calib_res); + calib_point = aspeed_spi_ast2600_optimized_timing(6, 17, &calib_res[0][0]); /* No good setting for this frequency */ if (calib_point == 0) return -1; From 84bfaa6ceed629cbaeaccf03c4b287c719663284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 18 May 2026 19:05:41 +0200 Subject: [PATCH 360/655] spi: Use named initializers for arrays of i2c_device_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. The mentioned robustness is relevant for a planned change to struct i2c_device_id that replaces .driver_data by an anonymous union. While touching these arrays, drop a comma after the list terminator. This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/20260518170542.807843-2-u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/spi/spi-sc18is602.c | 6 +++--- drivers/spi/spi-xcomm.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 78c558e7228e..ae534ebd5e87 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -295,9 +295,9 @@ static int sc18is602_probe(struct i2c_client *client) } static const struct i2c_device_id sc18is602_id[] = { - { "sc18is602", sc18is602 }, - { "sc18is602b", sc18is602b }, - { "sc18is603", sc18is603 }, + { .name = "sc18is602", .driver_data = sc18is602 }, + { .name = "sc18is602b", .driver_data = sc18is602b }, + { .name = "sc18is603", .driver_data = sc18is603 }, { } }; MODULE_DEVICE_TABLE(i2c, sc18is602_id); diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 130a3d716dd4..e40ec6ebe4e5 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -269,8 +269,8 @@ static int spi_xcomm_probe(struct i2c_client *i2c) } static const struct i2c_device_id spi_xcomm_ids[] = { - { "spi-xcomm" }, - { }, + { .name = "spi-xcomm" }, + { } }; MODULE_DEVICE_TABLE(i2c, spi_xcomm_ids); From 7452b3a025484abb147d109237599c5c4231c639 Mon Sep 17 00:00:00 2001 From: lizhi Date: Mon, 11 May 2026 08:49:27 +0800 Subject: [PATCH 361/655] crypto: hisilicon/sec2 - lower priority for hisilicon crypto implementations Lower the priority of HiSilicon's crypto implementations to allow more suitable alternatives to be selected. For example, certain kernel use-cases do not benefit from HiSilicon's symmetric crypto algorithms. This change ensures that more appropriate options are chosen first while retaining HiSilicon's implementations as alternatives. Signed-off-by: lizhi Signed-off-by: Chenghai Huang Reviewed-by: Longfang Liu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index 2471a4dd0b50..77e0e03cbcab 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -20,7 +20,7 @@ #include "sec.h" #include "sec_crypto.h" -#define SEC_PRIORITY 4001 +#define SEC_PRIORITY 80 #define SEC_XTS_MIN_KEY_SIZE (2 * AES_MIN_KEY_SIZE) #define SEC_XTS_MID_KEY_SIZE (3 * AES_MIN_KEY_SIZE) #define SEC_XTS_MAX_KEY_SIZE (2 * AES_MAX_KEY_SIZE) From d237230728c567297f2f98b425d63156ab2ed17f Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Mon, 11 May 2026 11:04:08 +0100 Subject: [PATCH 362/655] crypto: qat - remove unused character device and IOCTLs The QAT driver exposes a character device (qat_adf_ctl) with IOCTLs for device configuration, start, stop, status query and enumeration. These IOCTLs are not part of any public uAPI header and have no known in-tree or out-of-tree users. Device lifecycle is already managed via sysfs. The ioctl interface also increases the attack surface and is the subject of a number of bug reports. Remove the character device, the IOCTL definitions, and the related data structures (adf_dev_status_info, adf_user_cfg_key_val, adf_user_cfg_section, adf_user_cfg_ctl_data). Drop the now-unused adf_cfg_user.h header and strip adf_ctl_drv.c down to the minimal module_init/module_exit hooks for workqueue, AER, and crypto/compression algorithm registration. Clean up leftover dead code that was only reachable from the removed IOCTL paths: adf_cfg_del_all(), adf_devmgr_verify_id(), adf_devmgr_get_num_dev(), adf_devmgr_get_dev_by_id(), adf_get_vf_real_id() and the unused ADF_CFG macros. Additionally, drop the entry associated to QAT IOCTLs in ioctl-number.rst. Cc: stable@vger.kernel.org Fixes: d8cba25d2c68 ("crypto: qat - Intel(R) QAT driver framework") Reported-by: Zhi Wang Reported-by: Bin Yu Reported-by: MingYu Wang Closes: https://lore.kernel.org/all/61d6d499.ab89.19b9b7f3186.Coremail.wangzhi_xd@stu.xidian.edu.cn/ Link: https://lore.kernel.org/all/20260508034841.256794-1-w15303746062@163.com/ Link: https://lore.kernel.org/all/20260508023542.256299-1-w15303746062@163.com/ Link: https://lore.kernel.org/all/20260504025120.98242-1-w15303746062@163.com/ Signed-off-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Signed-off-by: Herbert Xu --- .../userspace-api/ioctl/ioctl-number.rst | 1 - drivers/crypto/intel/qat/qat_common/adf_cfg.c | 10 - drivers/crypto/intel/qat/qat_common/adf_cfg.h | 1 - .../intel/qat/qat_common/adf_cfg_common.h | 32 -- .../intel/qat/qat_common/adf_cfg_user.h | 38 -- .../intel/qat/qat_common/adf_common_drv.h | 3 - .../crypto/intel/qat/qat_common/adf_ctl_drv.c | 404 +----------------- .../crypto/intel/qat/qat_common/adf_dev_mgr.c | 70 --- 8 files changed, 1 insertion(+), 558 deletions(-) delete mode 100644 drivers/crypto/intel/qat/qat_common/adf_cfg_user.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 331223761fff..29a08bc059dd 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -229,7 +229,6 @@ Code Seq# Include File Comments 'a' all linux/atm*.h, linux/sonet.h ATM on linux -'a' 00-0F drivers/crypto/qat/qat_common/adf_cfg_common.h conflict! qat driver 'b' 00-FF conflict! bit3 vme host bridge 'b' 00-0F linux/dma-buf.h conflict! diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg.c b/drivers/crypto/intel/qat/qat_common/adf_cfg.c index c202209f17d5..ea5d72d5090c 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg.c +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg.c @@ -103,16 +103,6 @@ static void adf_cfg_section_del_all(struct list_head *head); static void adf_cfg_section_del_all_except(struct list_head *head, const char *section_name); -void adf_cfg_del_all(struct adf_accel_dev *accel_dev) -{ - struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg; - - down_write(&dev_cfg_data->lock); - adf_cfg_section_del_all(&dev_cfg_data->sec_list); - up_write(&dev_cfg_data->lock); - clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); -} - void adf_cfg_del_all_except(struct adf_accel_dev *accel_dev, const char *section_name) { diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg.h b/drivers/crypto/intel/qat/qat_common/adf_cfg.h index 2afa6f0d15c5..108032b39242 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg.h +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg.h @@ -34,7 +34,6 @@ void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev); void adf_cfg_dev_dbgfs_add(struct adf_accel_dev *accel_dev); void adf_cfg_dev_dbgfs_rm(struct adf_accel_dev *accel_dev); int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name); -void adf_cfg_del_all(struct adf_accel_dev *accel_dev); void adf_cfg_del_all_except(struct adf_accel_dev *accel_dev, const char *section_name); int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev, diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h index 81e9e9d7eccd..d63f4dcccbb5 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h @@ -4,18 +4,11 @@ #define ADF_CFG_COMMON_H_ #include -#include #define ADF_CFG_MAX_STR_LEN 64 #define ADF_CFG_MAX_KEY_LEN_IN_BYTES ADF_CFG_MAX_STR_LEN #define ADF_CFG_MAX_VAL_LEN_IN_BYTES ADF_CFG_MAX_STR_LEN #define ADF_CFG_MAX_SECTION_LEN_IN_BYTES ADF_CFG_MAX_STR_LEN -#define ADF_CFG_BASE_DEC 10 -#define ADF_CFG_BASE_HEX 16 -#define ADF_CFG_ALL_DEVICES 0xFE -#define ADF_CFG_NO_DEVICE 0xFF -#define ADF_CFG_AFFINITY_WHATEVER 0xFF -#define MAX_DEVICE_NAME_SIZE 32 #define ADF_MAX_DEVICES (32 * 32) #define ADF_DEVS_ARRAY_SIZE BITS_TO_LONGS(ADF_MAX_DEVICES) @@ -51,29 +44,4 @@ enum adf_device_type { DEV_420XX, DEV_6XXX, }; - -struct adf_dev_status_info { - enum adf_device_type type; - __u32 accel_id; - __u32 instance_id; - __u8 num_ae; - __u8 num_accel; - __u8 num_logical_accel; - __u8 banks_per_accel; - __u8 state; - __u8 bus; - __u8 dev; - __u8 fun; - char name[MAX_DEVICE_NAME_SIZE]; -}; - -#define ADF_CTL_IOC_MAGIC 'a' -#define IOCTL_CONFIG_SYS_RESOURCE_PARAMETERS _IOW(ADF_CTL_IOC_MAGIC, 0, \ - struct adf_user_cfg_ctl_data) -#define IOCTL_STOP_ACCEL_DEV _IOW(ADF_CTL_IOC_MAGIC, 1, \ - struct adf_user_cfg_ctl_data) -#define IOCTL_START_ACCEL_DEV _IOW(ADF_CTL_IOC_MAGIC, 2, \ - struct adf_user_cfg_ctl_data) -#define IOCTL_STATUS_ACCEL_DEV _IOW(ADF_CTL_IOC_MAGIC, 3, __u32) -#define IOCTL_GET_NUM_DEVICES _IOW(ADF_CTL_IOC_MAGIC, 4, __s32) #endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_user.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_user.h deleted file mode 100644 index 421f4fb8b4dd..000000000000 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_user.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ -/* Copyright(c) 2014 - 2020 Intel Corporation */ -#ifndef ADF_CFG_USER_H_ -#define ADF_CFG_USER_H_ - -#include "adf_cfg_common.h" -#include "adf_cfg_strings.h" - -struct adf_user_cfg_key_val { - char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; - char val[ADF_CFG_MAX_VAL_LEN_IN_BYTES]; - union { - struct adf_user_cfg_key_val *next; - __u64 padding3; - }; - enum adf_cfg_val_type type; -} __packed; - -struct adf_user_cfg_section { - char name[ADF_CFG_MAX_SECTION_LEN_IN_BYTES]; - union { - struct adf_user_cfg_key_val *params; - __u64 padding1; - }; - union { - struct adf_user_cfg_section *next; - __u64 padding3; - }; -} __packed; - -struct adf_user_cfg_ctl_data { - union { - struct adf_user_cfg_section *config_section; - __u64 padding; - }; - __u8 device_id; -} __packed; -#endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index fb0fd46a79b0..e8dd76751dfb 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -68,10 +68,7 @@ int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev, void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, struct adf_accel_dev *pf); struct list_head *adf_devmgr_get_head(void); -struct adf_accel_dev *adf_devmgr_get_dev_by_id(u32 id); struct adf_accel_dev *adf_devmgr_pci_to_accel_dev(struct pci_dev *pci_dev); -int adf_devmgr_verify_id(u32 id); -void adf_devmgr_get_num_dev(u32 *num); int adf_devmgr_in_reset(struct adf_accel_dev *accel_dev); int adf_dev_started(struct adf_accel_dev *accel_dev); int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c index c2e6f0cb7480..f01f2946de6e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c @@ -2,410 +2,13 @@ /* Copyright(c) 2014 - 2020 Intel Corporation */ #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include "adf_accel_devices.h" #include "adf_common_drv.h" -#include "adf_cfg.h" -#include "adf_cfg_common.h" -#include "adf_cfg_user.h" - -#define ADF_CFG_MAX_SECTION 512 -#define ADF_CFG_MAX_KEY_VAL 256 - -#define DEVICE_NAME "qat_adf_ctl" - -static DEFINE_MUTEX(adf_ctl_lock); -static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); - -static const struct file_operations adf_ctl_ops = { - .owner = THIS_MODULE, - .unlocked_ioctl = adf_ctl_ioctl, - .compat_ioctl = compat_ptr_ioctl, -}; - -static const struct class adf_ctl_class = { - .name = DEVICE_NAME, -}; - -struct adf_ctl_drv_info { - unsigned int major; - struct cdev drv_cdev; -}; - -static struct adf_ctl_drv_info adf_ctl_drv; - -static void adf_chr_drv_destroy(void) -{ - device_destroy(&adf_ctl_class, MKDEV(adf_ctl_drv.major, 0)); - cdev_del(&adf_ctl_drv.drv_cdev); - class_unregister(&adf_ctl_class); - unregister_chrdev_region(MKDEV(adf_ctl_drv.major, 0), 1); -} - -static int adf_chr_drv_create(void) -{ - dev_t dev_id; - struct device *drv_device; - int ret; - - if (alloc_chrdev_region(&dev_id, 0, 1, DEVICE_NAME)) { - pr_err("QAT: unable to allocate chrdev region\n"); - return -EFAULT; - } - - ret = class_register(&adf_ctl_class); - if (ret) - goto err_chrdev_unreg; - - adf_ctl_drv.major = MAJOR(dev_id); - cdev_init(&adf_ctl_drv.drv_cdev, &adf_ctl_ops); - if (cdev_add(&adf_ctl_drv.drv_cdev, dev_id, 1)) { - pr_err("QAT: cdev add failed\n"); - goto err_class_destr; - } - - drv_device = device_create(&adf_ctl_class, NULL, - MKDEV(adf_ctl_drv.major, 0), - NULL, DEVICE_NAME); - if (IS_ERR(drv_device)) { - pr_err("QAT: failed to create device\n"); - goto err_cdev_del; - } - return 0; -err_cdev_del: - cdev_del(&adf_ctl_drv.drv_cdev); -err_class_destr: - class_unregister(&adf_ctl_class); -err_chrdev_unreg: - unregister_chrdev_region(dev_id, 1); - return -EFAULT; -} - -static struct adf_user_cfg_ctl_data *adf_ctl_alloc_resources(unsigned long arg) -{ - struct adf_user_cfg_ctl_data *cfg_data; - - cfg_data = memdup_user((void __user *)arg, sizeof(*cfg_data)); - if (IS_ERR(cfg_data)) - pr_err("QAT: failed to copy from user cfg_data.\n"); - return cfg_data; -} - -static int adf_add_key_value_data(struct adf_accel_dev *accel_dev, - const char *section, - const struct adf_user_cfg_key_val *key_val) -{ - if (key_val->type == ADF_HEX) { - long *ptr = (long *)key_val->val; - long val = *ptr; - - if (adf_cfg_add_key_value_param(accel_dev, section, - key_val->key, (void *)val, - key_val->type)) { - dev_err(&GET_DEV(accel_dev), - "failed to add hex keyvalue.\n"); - return -EFAULT; - } - } else { - if (adf_cfg_add_key_value_param(accel_dev, section, - key_val->key, key_val->val, - key_val->type)) { - dev_err(&GET_DEV(accel_dev), - "failed to add keyvalue.\n"); - return -EFAULT; - } - } - return 0; -} - -static int adf_copy_key_value_data(struct adf_accel_dev *accel_dev, - struct adf_user_cfg_ctl_data *ctl_data) -{ - struct adf_user_cfg_key_val key_val; - struct adf_user_cfg_key_val *params_head; - struct adf_user_cfg_section section, *section_head; - int i, j; - - section_head = ctl_data->config_section; - - for (i = 0; section_head && i < ADF_CFG_MAX_SECTION; i++) { - if (copy_from_user(§ion, (void __user *)section_head, - sizeof(*section_head))) { - dev_err(&GET_DEV(accel_dev), - "failed to copy section info\n"); - goto out_err; - } - - if (adf_cfg_section_add(accel_dev, section.name)) { - dev_err(&GET_DEV(accel_dev), - "failed to add section.\n"); - goto out_err; - } - - params_head = section.params; - - for (j = 0; params_head && j < ADF_CFG_MAX_KEY_VAL; j++) { - if (copy_from_user(&key_val, (void __user *)params_head, - sizeof(key_val))) { - dev_err(&GET_DEV(accel_dev), - "Failed to copy keyvalue.\n"); - goto out_err; - } - if (adf_add_key_value_data(accel_dev, section.name, - &key_val)) { - goto out_err; - } - params_head = key_val.next; - } - section_head = section.next; - } - return 0; -out_err: - adf_cfg_del_all(accel_dev); - return -EFAULT; -} - -static int adf_ctl_ioctl_dev_config(struct file *fp, unsigned int cmd, - unsigned long arg) -{ - struct adf_user_cfg_ctl_data *ctl_data; - struct adf_accel_dev *accel_dev; - int ret = 0; - - ctl_data = adf_ctl_alloc_resources(arg); - if (IS_ERR(ctl_data)) - return PTR_ERR(ctl_data); - - accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); - if (!accel_dev) { - ret = -EFAULT; - goto out; - } - - if (adf_dev_started(accel_dev)) { - ret = -EFAULT; - goto out; - } - - if (adf_copy_key_value_data(accel_dev, ctl_data)) { - ret = -EFAULT; - goto out; - } - set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); -out: - kfree(ctl_data); - return ret; -} - -static int adf_ctl_is_device_in_use(int id) -{ - struct adf_accel_dev *dev; - - list_for_each_entry(dev, adf_devmgr_get_head(), list) { - if (id == dev->accel_id || id == ADF_CFG_ALL_DEVICES) { - if (adf_devmgr_in_reset(dev) || adf_dev_in_use(dev)) { - dev_info(&GET_DEV(dev), - "device qat_dev%d is busy\n", - dev->accel_id); - return -EBUSY; - } - } - } - return 0; -} - -static void adf_ctl_stop_devices(u32 id) -{ - struct adf_accel_dev *accel_dev; - - list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) { - if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) { - if (!adf_dev_started(accel_dev)) - continue; - - /* First stop all VFs */ - if (!accel_dev->is_vf) - continue; - - adf_dev_down(accel_dev); - } - } - - list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) { - if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) { - if (!adf_dev_started(accel_dev)) - continue; - - adf_dev_down(accel_dev); - } - } -} - -static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd, - unsigned long arg) -{ - int ret; - struct adf_user_cfg_ctl_data *ctl_data; - - ctl_data = adf_ctl_alloc_resources(arg); - if (IS_ERR(ctl_data)) - return PTR_ERR(ctl_data); - - if (adf_devmgr_verify_id(ctl_data->device_id)) { - pr_err("QAT: Device %d not found\n", ctl_data->device_id); - ret = -ENODEV; - goto out; - } - - ret = adf_ctl_is_device_in_use(ctl_data->device_id); - if (ret) - goto out; - - if (ctl_data->device_id == ADF_CFG_ALL_DEVICES) - pr_info("QAT: Stopping all acceleration devices.\n"); - else - pr_info("QAT: Stopping acceleration device qat_dev%d.\n", - ctl_data->device_id); - - adf_ctl_stop_devices(ctl_data->device_id); - -out: - kfree(ctl_data); - return ret; -} - -static int adf_ctl_ioctl_dev_start(struct file *fp, unsigned int cmd, - unsigned long arg) -{ - int ret; - struct adf_user_cfg_ctl_data *ctl_data; - struct adf_accel_dev *accel_dev; - - ctl_data = adf_ctl_alloc_resources(arg); - if (IS_ERR(ctl_data)) - return PTR_ERR(ctl_data); - - ret = -ENODEV; - accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); - if (!accel_dev) - goto out; - - dev_info(&GET_DEV(accel_dev), - "Starting acceleration device qat_dev%d.\n", - ctl_data->device_id); - - ret = adf_dev_up(accel_dev, false); - - if (ret) { - dev_err(&GET_DEV(accel_dev), "Failed to start qat_dev%d\n", - ctl_data->device_id); - adf_dev_down(accel_dev); - } -out: - kfree(ctl_data); - return ret; -} - -static int adf_ctl_ioctl_get_num_devices(struct file *fp, unsigned int cmd, - unsigned long arg) -{ - u32 num_devices = 0; - - adf_devmgr_get_num_dev(&num_devices); - if (copy_to_user((void __user *)arg, &num_devices, sizeof(num_devices))) - return -EFAULT; - - return 0; -} - -static int adf_ctl_ioctl_get_status(struct file *fp, unsigned int cmd, - unsigned long arg) -{ - struct adf_hw_device_data *hw_data; - struct adf_dev_status_info dev_info; - struct adf_accel_dev *accel_dev; - - if (copy_from_user(&dev_info, (void __user *)arg, - sizeof(struct adf_dev_status_info))) { - pr_err("QAT: failed to copy from user.\n"); - return -EFAULT; - } - - accel_dev = adf_devmgr_get_dev_by_id(dev_info.accel_id); - if (!accel_dev) - return -ENODEV; - - hw_data = accel_dev->hw_device; - dev_info.state = adf_dev_started(accel_dev) ? DEV_UP : DEV_DOWN; - dev_info.num_ae = hw_data->get_num_aes(hw_data); - dev_info.num_accel = hw_data->get_num_accels(hw_data); - dev_info.num_logical_accel = hw_data->num_logical_accel; - dev_info.banks_per_accel = hw_data->num_banks - / hw_data->num_logical_accel; - strscpy(dev_info.name, hw_data->dev_class->name, sizeof(dev_info.name)); - dev_info.instance_id = hw_data->instance_id; - dev_info.type = hw_data->dev_class->type; - dev_info.bus = accel_to_pci_dev(accel_dev)->bus->number; - dev_info.dev = PCI_SLOT(accel_to_pci_dev(accel_dev)->devfn); - dev_info.fun = PCI_FUNC(accel_to_pci_dev(accel_dev)->devfn); - - if (copy_to_user((void __user *)arg, &dev_info, - sizeof(struct adf_dev_status_info))) { - dev_err(&GET_DEV(accel_dev), "failed to copy status.\n"); - return -EFAULT; - } - return 0; -} - -static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -{ - int ret; - - if (mutex_lock_interruptible(&adf_ctl_lock)) - return -EFAULT; - - switch (cmd) { - case IOCTL_CONFIG_SYS_RESOURCE_PARAMETERS: - ret = adf_ctl_ioctl_dev_config(fp, cmd, arg); - break; - - case IOCTL_STOP_ACCEL_DEV: - ret = adf_ctl_ioctl_dev_stop(fp, cmd, arg); - break; - - case IOCTL_START_ACCEL_DEV: - ret = adf_ctl_ioctl_dev_start(fp, cmd, arg); - break; - - case IOCTL_GET_NUM_DEVICES: - ret = adf_ctl_ioctl_get_num_devices(fp, cmd, arg); - break; - - case IOCTL_STATUS_ACCEL_DEV: - ret = adf_ctl_ioctl_get_status(fp, cmd, arg); - break; - default: - pr_err_ratelimited("QAT: Invalid ioctl %d\n", cmd); - ret = -EFAULT; - break; - } - mutex_unlock(&adf_ctl_lock); - return ret; -} static int __init adf_register_ctl_device_driver(void) { - if (adf_chr_drv_create()) - goto err_chr_dev; - if (adf_init_misc_wq()) goto err_misc_wq; @@ -437,15 +40,11 @@ err_pf_wq: err_aer: adf_exit_misc_wq(); err_misc_wq: - adf_chr_drv_destroy(); -err_chr_dev: - mutex_destroy(&adf_ctl_lock); return -EFAULT; } static void __exit adf_unregister_ctl_device_driver(void) { - adf_chr_drv_destroy(); adf_exit_misc_wq(); adf_exit_aer(); adf_exit_vf_wq(); @@ -453,7 +52,6 @@ static void __exit adf_unregister_ctl_device_driver(void) qat_crypto_unregister(); qat_compression_unregister(); adf_clean_vf_map(false); - mutex_destroy(&adf_ctl_lock); } module_init(adf_register_ctl_device_driver); diff --git a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c index e050de16ab5d..161863841a52 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c @@ -45,19 +45,6 @@ static struct vf_id_map *adf_find_vf(u32 bdf) return NULL; } -static int adf_get_vf_real_id(u32 fake) -{ - struct list_head *itr; - - list_for_each(itr, &vfs_table) { - struct vf_id_map *ptr = - list_entry(itr, struct vf_id_map, list); - if (ptr->fake_id == fake) - return ptr->id; - } - return -1; -} - /** * adf_clean_vf_map() - Cleans VF id mappings * @vf: flag indicating whether mappings is cleaned @@ -304,63 +291,6 @@ struct adf_accel_dev *adf_devmgr_pci_to_accel_dev(struct pci_dev *pci_dev) } EXPORT_SYMBOL_GPL(adf_devmgr_pci_to_accel_dev); -struct adf_accel_dev *adf_devmgr_get_dev_by_id(u32 id) -{ - struct list_head *itr; - int real_id; - - mutex_lock(&table_lock); - real_id = adf_get_vf_real_id(id); - if (real_id < 0) - goto unlock; - - id = real_id; - - list_for_each(itr, &accel_table) { - struct adf_accel_dev *ptr = - list_entry(itr, struct adf_accel_dev, list); - if (ptr->accel_id == id) { - mutex_unlock(&table_lock); - return ptr; - } - } -unlock: - mutex_unlock(&table_lock); - return NULL; -} - -int adf_devmgr_verify_id(u32 id) -{ - if (id == ADF_CFG_ALL_DEVICES) - return 0; - - if (adf_devmgr_get_dev_by_id(id)) - return 0; - - return -ENODEV; -} - -static int adf_get_num_dettached_vfs(void) -{ - struct list_head *itr; - int vfs = 0; - - mutex_lock(&table_lock); - list_for_each(itr, &vfs_table) { - struct vf_id_map *ptr = - list_entry(itr, struct vf_id_map, list); - if (ptr->bdf != ~0 && !ptr->attached) - vfs++; - } - mutex_unlock(&table_lock); - return vfs; -} - -void adf_devmgr_get_num_dev(u32 *num) -{ - *num = num_devices - adf_get_num_dettached_vfs(); -} - /** * adf_dev_in_use() - Check whether accel_dev is currently in use * @accel_dev: Pointer to acceleration device. From 9206f1b3f8cf76d0dcacd3eab5813244e9fc9964 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Mon, 11 May 2026 11:04:09 +0100 Subject: [PATCH 363/655] crypto: qat - rename adf_ctl_drv.c to adf_module.c Now that the character device and IOCTL interface have been removed, adf_ctl_drv.c only contains module_init/module_exit hooks. Rename it to adf_module.c to better reflect its purpose and rename the init/exit functions accordingly. Signed-off-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/Makefile | 2 +- .../intel/qat/qat_common/{adf_ctl_drv.c => adf_module.c} | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename drivers/crypto/intel/qat/qat_common/{adf_ctl_drv.c => adf_module.c} (84%) diff --git a/drivers/crypto/intel/qat/qat_common/Makefile b/drivers/crypto/intel/qat/qat_common/Makefile index 9478111c8437..2b1649001518 100644 --- a/drivers/crypto/intel/qat/qat_common/Makefile +++ b/drivers/crypto/intel/qat/qat_common/Makefile @@ -9,7 +9,6 @@ intel_qat-y := adf_accel_engine.o \ adf_cfg.o \ adf_cfg_services.o \ adf_clock.o \ - adf_ctl_drv.o \ adf_dc.o \ adf_dev_mgr.o \ adf_gen2_config.o \ @@ -26,6 +25,7 @@ intel_qat-y := adf_accel_engine.o \ adf_hw_arbiter.o \ adf_init.o \ adf_isr.o \ + adf_module.o \ adf_mstate_mgr.o \ adf_rl_admin.o \ adf_rl.o \ diff --git a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/intel/qat/qat_common/adf_module.c similarity index 84% rename from drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c rename to drivers/crypto/intel/qat/qat_common/adf_module.c index f01f2946de6e..fccaa71eeedc 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/intel/qat/qat_common/adf_module.c @@ -7,7 +7,7 @@ #include "adf_common_drv.h" -static int __init adf_register_ctl_device_driver(void) +static int __init adf_register_module(void) { if (adf_init_misc_wq()) goto err_misc_wq; @@ -43,7 +43,7 @@ err_misc_wq: return -EFAULT; } -static void __exit adf_unregister_ctl_device_driver(void) +static void __exit adf_unregister_module(void) { adf_exit_misc_wq(); adf_exit_aer(); @@ -54,8 +54,8 @@ static void __exit adf_unregister_ctl_device_driver(void) adf_clean_vf_map(false); } -module_init(adf_register_ctl_device_driver); -module_exit(adf_unregister_ctl_device_driver); +module_init(adf_register_module); +module_exit(adf_unregister_module); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); From 209466c5fe352b81b9fa9d135bbffbac18350fb2 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 12 May 2026 15:34:15 +0200 Subject: [PATCH 364/655] crypto: cesa - use max to simplify mv_cesa_probe Use max() to simplify mv_cesa_probe() and improve its readability. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/marvell/cesa/cesa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c index 687ed730174d..75d8ba23d9a2 100644 --- a/drivers/crypto/marvell/cesa/cesa.c +++ b/drivers/crypto/marvell/cesa/cesa.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -442,10 +443,8 @@ static int mv_cesa_probe(struct platform_device *pdev) sram_size = CESA_SA_DEFAULT_SRAM_SIZE; of_property_read_u32(cesa->dev->of_node, "marvell,crypto-sram-size", &sram_size); - if (sram_size < CESA_SA_MIN_SRAM_SIZE) - sram_size = CESA_SA_MIN_SRAM_SIZE; - cesa->sram_size = sram_size; + cesa->sram_size = max(sram_size, CESA_SA_MIN_SRAM_SIZE); spin_lock_init(&cesa->lock); From e1ad89211938dcf0d5fffbbab6a178ce54b9ae38 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 12 May 2026 16:51:24 +0200 Subject: [PATCH 365/655] crypto: atmel - use min3 to simplify atmel_sha_append_sg Replace two consecutive min() calls with min3() to simplify the code. And since count is unsigned and cannot be less than zero, adjust the if check and update the comment accordingly. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 002b62902553..7e7c83a3d8cd 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -305,12 +305,12 @@ static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx) size_t count; while ((ctx->bufcnt < ctx->buflen) && ctx->total) { - count = min(ctx->sg->length - ctx->offset, ctx->total); - count = min(count, ctx->buflen - ctx->bufcnt); + count = min3(ctx->sg->length - ctx->offset, ctx->total, + ctx->buflen - ctx->bufcnt); - if (count <= 0) { + if (count == 0) { /* - * Check if count <= 0 because the buffer is full or + * Check if count == 0 because the buffer is full or * because the sg length is 0. In the latest case, * check if there is another sg in the list, a 0 length * sg doesn't necessarily mean the end of the sg list. From 310bcf581dc57506160ef138ad6276e965b550cd Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 13 May 2026 09:57:45 +0100 Subject: [PATCH 366/655] crypto: qat - remove MODULE_VERSION In-tree drivers do not need MODULE_VERSION as the kernel release identifies the version of their code. The static version "0.6.0", which the QAT drivers currently report, can be misleading as it might suggest the drivers are outdated. Remove MODULE_VERSION() from all QAT driver modules and the related ADF_DRV_VERSION, ADF_MAJOR_VERSION, ADF_MINOR_VERSION and ADF_BUILD_VERSION macros from adf_common_drv.h. Signed-off-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Reviewed-by: Andy Shevchenko Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_420xx/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_4xxx/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c62x/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_common/adf_common_drv.h | 7 ------- drivers/crypto/intel/qat/qat_common/adf_module.c | 1 - drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c | 1 - 10 files changed, 16 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c index cfa00daeb4fb..566adc0a2d11 100644 --- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c @@ -210,6 +210,5 @@ MODULE_AUTHOR("Intel"); MODULE_FIRMWARE(ADF_420XX_FW); MODULE_FIRMWARE(ADF_420XX_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_SOFTDEP("pre: crypto-intel_qat"); MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c index c9be5dcddb27..daca73651c14 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c @@ -214,6 +214,5 @@ MODULE_FIRMWARE(ADF_402XX_FW); MODULE_FIRMWARE(ADF_4XXX_MMP); MODULE_FIRMWARE(ADF_402XX_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_SOFTDEP("pre: crypto-intel_qat"); MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c index bceb5dd8b148..7a59bca3242f 100644 --- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c @@ -256,5 +256,4 @@ MODULE_AUTHOR("Intel"); MODULE_FIRMWARE(ADF_C3XXX_FW); MODULE_FIRMWARE(ADF_C3XXX_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c index c622793e94a8..0881575f7670 100644 --- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c @@ -225,5 +225,4 @@ module_exit(adfdrv_release); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c index 23ccb72b6ea2..4972e52dd944 100644 --- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c @@ -256,5 +256,4 @@ MODULE_AUTHOR("Intel"); MODULE_FIRMWARE(ADF_C62X_FW); MODULE_FIRMWARE(ADF_C62X_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c index 4840d44bbd5b..d3f728b9f2f2 100644 --- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c @@ -225,5 +225,4 @@ module_exit(adfdrv_release); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index e8dd76751dfb..a05d149423b0 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -9,13 +9,6 @@ #include "icp_qat_fw_loader_handle.h" #include "icp_qat_hal.h" -#define ADF_MAJOR_VERSION 0 -#define ADF_MINOR_VERSION 6 -#define ADF_BUILD_VERSION 0 -#define ADF_DRV_VERSION __stringify(ADF_MAJOR_VERSION) "." \ - __stringify(ADF_MINOR_VERSION) "." \ - __stringify(ADF_BUILD_VERSION) - #define ADF_STATUS_RESTARTING 0 #define ADF_STATUS_STARTING 1 #define ADF_STATUS_CONFIGURED 2 diff --git a/drivers/crypto/intel/qat/qat_common/adf_module.c b/drivers/crypto/intel/qat/qat_common/adf_module.c index fccaa71eeedc..30069feec3c1 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_module.c +++ b/drivers/crypto/intel/qat/qat_common/adf_module.c @@ -60,5 +60,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_ALIAS_CRYPTO("intel_qat"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c index b59e0cc49e52..8a863d7d86d7 100644 --- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c @@ -256,5 +256,4 @@ MODULE_AUTHOR("Intel"); MODULE_FIRMWARE(ADF_DH895XCC_FW); MODULE_FIRMWARE(ADF_DH895XCC_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c index 7cd528ee31e7..f8a6e10a1de7 100644 --- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c @@ -225,5 +225,4 @@ module_exit(adfdrv_release); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); -MODULE_VERSION(ADF_DRV_VERSION); MODULE_IMPORT_NS("CRYPTO_QAT"); From 27b536a2ec8e2f85a0380c2d13c9ecbc7aaab406 Mon Sep 17 00:00:00 2001 From: Anastasia Tishchenko Date: Wed, 13 May 2026 13:57:40 +0300 Subject: [PATCH 367/655] crypto: ecc - Fix carry overflow in vli multiplication The carry flag calculation fails when r01.m_high is saturated (0xFFFFFFFFFFFFFFFF) and addition of lower bits overflows. The condition (r01.m_high < product.m_high) doesn't handle the case where r01.m_high == product.m_high and an additional carry exists from lower-bit overflow. When commit 3c4b23901a0c ("crypto: ecdh - Add ECDH software support") introduced crypto/ecc.c, it split the muladd() function in the micro-ecc library into separate mul_64_64() and add_128_128() helpers. It seems the check got lost in translation. Add proper handling for this boundary by accounting for the carry from the lower addition. Fixes: 3c4b23901a0c ("crypto: ecdh - Add ECDH software support") Signed-off-by: Anastasia Tishchenko Cc: stable@vger.kernel.org # v4.8+ Reviewed-by: Lukas Wunner Signed-off-by: Herbert Xu --- crypto/ecc.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/crypto/ecc.c b/crypto/ecc.c index 43b0def3a225..6eb4d97a5f0d 100644 --- a/crypto/ecc.c +++ b/crypto/ecc.c @@ -393,14 +393,26 @@ static uint128_t mul_64_64(u64 left, u64 right) return result; } -static uint128_t add_128_128(uint128_t a, uint128_t b) +/* Calculate addition with overflow checking. Returns true on wrap-around, + * false otherwise. + */ +static bool check_add_128_128_overflow(uint128_t *result, uint128_t a, + uint128_t b) { - uint128_t result; + bool carry; - result.m_low = a.m_low + b.m_low; - result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low); + result->m_low = a.m_low + b.m_low; + carry = (result->m_low < a.m_low); - return result; + result->m_high = a.m_high + b.m_high + carry; + + /* Using constant-time bitwise arithmetic to prevent timing + * side-channels. + */ + carry = (result->m_high < a.m_high) | + ((result->m_high == a.m_high) & carry); + + return carry; } static void vli_mult(u64 *result, const u64 *left, const u64 *right, @@ -425,9 +437,7 @@ static void vli_mult(u64 *result, const u64 *left, const u64 *right, uint128_t product; product = mul_64_64(left[i], right[k - i]); - - r01 = add_128_128(r01, product); - r2 += (r01.m_high < product.m_high); + r2 += check_add_128_128_overflow(&r01, r01, product); } result[k] = r01.m_low; @@ -450,7 +460,7 @@ static void vli_umult(u64 *result, const u64 *left, u32 right, uint128_t product; product = mul_64_64(left[k], right); - r01 = add_128_128(r01, product); + check_add_128_128_overflow(&r01, r01, product); /* no carry */ result[k] = r01.m_low; r01.m_low = r01.m_high; @@ -487,8 +497,7 @@ static void vli_square(u64 *result, const u64 *left, unsigned int ndigits) product.m_low <<= 1; } - r01 = add_128_128(r01, product); - r2 += (r01.m_high < product.m_high); + r2 += check_add_128_128_overflow(&r01, r01, product); } result[k] = r01.m_low; From 277281c10c63791067d24d421f7c43a15faa9096 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 13 May 2026 15:47:32 +0100 Subject: [PATCH 368/655] crypto: qat - fix VF2PF work teardown race in adf_disable_sriov() The VF2PF interrupt handler queues PF-side response work that stores a raw pointer to per-VF state (struct adf_accel_vf_info). Currently, adf_disable_sriov() destroys per-VF mutexes and frees vf_info without stopping new VF2PF work or waiting for in-flight workers to complete. A concurrently scheduled or already queued worker can then dereference freed memory. This manifests as a use-after-free when KASAN is enabled: BUG: KASAN: null-ptr-deref in mutex_lock+0x76/0xe0 Write of size 8 at addr 0000000000000260 by task kworker/24:2/... Workqueue: qat_pf2vf_resp_wq adf_iov_send_resp [intel_qat] Call Trace: kasan_report+0x119/0x140 mutex_lock+0x76/0xe0 adf_gen4_pfvf_send+0xd4/0x1f0 [intel_qat] adf_recv_and_handle_vf2pf_msg+0x290/0x360 [intel_qat] adf_iov_send_resp+0x8c/0xe0 [intel_qat] process_one_work+0x6ac/0xfd0 worker_thread+0x4dd/0xd30 kthread+0x326/0x410 ret_from_fork+0x33b/0x670 Add a PF-local flag, vf2pf_disabled, that gates work queueing, worker processing, and interrupt re-enabling during teardown. Set this flag atomically with the hardware interrupt mask inside adf_disable_all_vf2pf_interrupts(). After masking, synchronize the AE cluster MSI-X interrupt and flush the PF response workqueue before tearing down per-VF locks and state so all in-flight work completes before vf_info is destroyed. Introduce adf_enable_all_vf2pf_interrupts() to clear the flag and unmask all VF2PF interrupts under the same lock when SR-IOV is re-enabled. This ensures the software flag and hardware state transition atomically on both the enable and disable paths. Cc: stable@vger.kernel.org Fixes: ed8ccaef52fa ("crypto: qat - Add support for SRIOV") Signed-off-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Signed-off-by: Herbert Xu --- .../intel/qat/qat_common/adf_accel_devices.h | 2 + .../intel/qat/qat_common/adf_common_drv.h | 2 + drivers/crypto/intel/qat/qat_common/adf_isr.c | 39 +++++++++++++++++++ .../crypto/intel/qat/qat_common/adf_sriov.c | 20 +++++++++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h index 03a4e9690208..d9b2a1cf474e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h @@ -480,6 +480,8 @@ struct adf_accel_dev { struct { /* protects VF2PF interrupts access */ spinlock_t vf2pf_ints_lock; + /* prevents VF2PF handling from racing with VF state teardown */ + bool vf2pf_disabled; /* vf_info is non-zero when SR-IOV is init'ed */ struct adf_accel_vf_info *vf_info; } pf; diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index a05d149423b0..b9188ea9aa72 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -110,6 +110,7 @@ void qat_comp_alg_callback(void *resp); int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev); void adf_isr_resource_free(struct adf_accel_dev *accel_dev); +void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev); int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev); void adf_vf_isr_resource_free(struct adf_accel_dev *accel_dev); @@ -183,6 +184,7 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs); void adf_disable_sriov(struct adf_accel_dev *accel_dev); void adf_reenable_sriov(struct adf_accel_dev *accel_dev); void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); +void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs); void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev); bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev); bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr); diff --git a/drivers/crypto/intel/qat/qat_common/adf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_isr.c index 4639d7fd93e6..159e91a50106 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_isr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c @@ -62,6 +62,23 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) unsigned long flags; spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); + if (!READ_ONCE(accel_dev->pf.vf2pf_disabled)) + GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask); + spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); +} + +void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs) +{ + void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev); + unsigned long flags; + u32 vf_mask; + + vf_mask = BIT_ULL(num_vfs) - 1; + if (!vf_mask) + return; + + spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); + WRITE_ONCE(accel_dev->pf.vf2pf_disabled, false); GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask); spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); } @@ -72,6 +89,7 @@ void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev) unsigned long flags; spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); + WRITE_ONCE(accel_dev->pf.vf2pf_disabled, true); GET_PFVF_OPS(accel_dev)->disable_all_vf2pf_interrupts(pmisc_addr); spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); } @@ -174,6 +192,27 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr) return IRQ_NONE; } +void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + u32 num_entries = pci_dev_info->msix_entries.num_entries; + struct adf_irq *irqs = pci_dev_info->msix_entries.irqs; + u32 irq_idx; + int irq; + + if (!test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status) || !irqs) + return; + + irq_idx = num_entries > 1 ? hw_data->num_banks : 0; + if (irq_idx >= num_entries || !irqs[irq_idx].enabled) + return; + + irq = pci_irq_vector(pci_dev_info->pci_dev, hw_data->num_banks); + if (irq > 0) + synchronize_irq(irq); +} + static void adf_free_irqs(struct adf_accel_dev *accel_dev) { struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev; diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c index 8bf0fe1fcb4d..96939572109e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c @@ -26,6 +26,9 @@ static void adf_iov_send_resp(struct work_struct *work) u32 vf_nr = vf_info->vf_nr; bool ret; + if (READ_ONCE(accel_dev->pf.vf2pf_disabled)) + goto out; + mutex_lock(&vf_info->pfvf_mig_lock); ret = adf_recv_and_handle_vf2pf_msg(accel_dev, vf_nr); if (ret) @@ -33,13 +36,18 @@ static void adf_iov_send_resp(struct work_struct *work) adf_enable_vf2pf_interrupts(accel_dev, 1 << vf_nr); mutex_unlock(&vf_info->pfvf_mig_lock); +out: kfree(pf2vf_resp); } void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info) { + struct adf_accel_dev *accel_dev = vf_info->accel_dev; struct adf_pf2vf_resp *pf2vf_resp; + if (READ_ONCE(accel_dev->pf.vf2pf_disabled)) + return; + pf2vf_resp = kzalloc_obj(*pf2vf_resp, GFP_ATOMIC); if (!pf2vf_resp) return; @@ -49,6 +57,12 @@ void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info) queue_work(pf2vf_resp_wq, &pf2vf_resp->pf2vf_resp_work); } +static void adf_flush_pf2vf_resp_wq(void) +{ + if (pf2vf_resp_wq) + flush_workqueue(pf2vf_resp_wq); +} + static int adf_enable_sriov(struct adf_accel_dev *accel_dev) { struct pci_dev *pdev = accel_to_pci_dev(accel_dev); @@ -75,7 +89,7 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev) hw_data->configure_iov_threads(accel_dev, true); /* Enable VF to PF interrupts for all VFs */ - adf_enable_vf2pf_interrupts(accel_dev, BIT_ULL(totalvfs) - 1); + adf_enable_all_vf2pf_interrupts(accel_dev, totalvfs); /* * Due to the hardware design, when SR-IOV and the ring arbiter @@ -248,8 +262,10 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev) adf_pf2vf_wait_for_restarting_complete(accel_dev); pci_disable_sriov(accel_to_pci_dev(accel_dev)); - /* Disable VF to PF interrupts */ + /* Block VF2PF work and disable VF to PF interrupts */ adf_disable_all_vf2pf_interrupts(accel_dev); + adf_isr_sync_ae_cluster(accel_dev); + adf_flush_pf2vf_resp_wq(); /* Clear Valid bits in AE Thread to PCIe Function Mapping */ if (hw_data->configure_iov_threads) From 57518500053987672050dc2f7bf8a774d5d52fd9 Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 13 May 2026 17:16:54 +0200 Subject: [PATCH 369/655] crypto: qat - keep VFs enabled during reset When a reset is triggered via sysfs, the PCI core invokes the reset_prepare() callback while holding pci_dev_lock(), which includes the PCI configuration space access semaphore. If reset_prepare() calls adf_dev_down(), the call chain adf_dev_stop() -> adf_disable_sriov() -> pci_disable_sriov() attempts to acquire the same semaphore, resulting in a deadlock. Avoid this by skipping pci_disable_sriov() when ADF_STATUS_RESTARTING is set. During reset the PCI topology is preserved, so VF devices remain valid and enumerated across the reset. VF notification and the quiesce handshake via adf_pf2vf_notify_restarting() are still performed unconditionally so that VFs stop submitting work before the PF shuts down. Correspondingly, skip pci_enable_sriov() in adf_enable_sriov() when VFs are already present, since their PCI devices were preserved from before the restart. This is in preparation for adding reset_prepare() and reset_done() callbacks in adf_aer.c. Cc: stable@vger.kernel.org Signed-off-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Reviewed-by: Damian Muszynski Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_sriov.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c index 96939572109e..f2011300a929 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c @@ -91,6 +91,10 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev) /* Enable VF to PF interrupts for all VFs */ adf_enable_all_vf2pf_interrupts(accel_dev, totalvfs); + /* Do not enable SR-IOV if already enabled */ + if (pci_num_vf(pdev)) + return 0; + /* * Due to the hardware design, when SR-IOV and the ring arbiter * are enabled all the VFs supported in hardware must be enabled in @@ -260,7 +264,13 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev) adf_pf2vf_notify_restarting(accel_dev); adf_pf2vf_wait_for_restarting_complete(accel_dev); - pci_disable_sriov(accel_to_pci_dev(accel_dev)); + /* + * When the device is restarting, preserve VF PCI devices across + * the reset by skipping pci_disable_sriov(). VFs are notified to + * quiesce regardless so the PF can safely shut down. + */ + if (!test_bit(ADF_STATUS_RESTARTING, &accel_dev->status)) + pci_disable_sriov(accel_to_pci_dev(accel_dev)); /* Block VF2PF work and disable VF to PF interrupts */ adf_disable_all_vf2pf_interrupts(accel_dev); From 6931835f2fdd0cb9b1c7791748d7e67d0749056a Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 13 May 2026 17:16:55 +0200 Subject: [PATCH 370/655] crypto: qat - notify fatal error before AER reset preparation Send fatal error notifications to subsystems and VFs as soon as AER error detection starts, before entering the reset preparation shutdown sequence. This reduces notification latency and ensures peers are informed immediately on fatal detection, rather than after restart-state setup and arbitration teardown. Cc: stable@vger.kernel.org Signed-off-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Reviewed-by: Damian Muszynski Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index ed01fb9ad74e..9c6bfb9fef80 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -33,13 +33,13 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_DISCONNECT; } + adf_error_notifier(accel_dev); + adf_pf2vf_notify_fatal_error(accel_dev); set_bit(ADF_STATUS_RESTARTING, &accel_dev->status); if (accel_dev->hw_device->exit_arb) { dev_dbg(&pdev->dev, "Disabling arbitration\n"); accel_dev->hw_device->exit_arb(accel_dev); } - adf_error_notifier(accel_dev); - adf_pf2vf_notify_fatal_error(accel_dev); adf_dev_restarting_notify(accel_dev); pci_clear_master(pdev); adf_dev_down(accel_dev); From e5712ff82947dd02d118cee119ed36cec671d814 Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 13 May 2026 17:16:56 +0200 Subject: [PATCH 371/655] crypto: qat - centralize bus master enable QAT driver currently toggles PCI bus mastering in multiple places (probe paths, and reset callbacks). This makes BME state depend on call ordering and on what PCI command bits were captured in saved PCI config state. Make BME control explicit and deterministic: - remove pci_set_master() from device-specific probe paths - add adf_set_bme() and call it from adf_dev_init() so BME is enabled at one point before device bring-up - drop redundant pci_set_master() and pci_clear_master from adf_aer.c and rely on the unified init path for BME enablement This is in preparation for adding reset_prepare() and reset_done() hooks. In the PCI reset callback flow, the PCI core saves and restores device configuration state around reset_prepare() and reset_done(). This change is needed to ensure that we are able to properly shutdown or reinitialize the device post sysfs triggered resets. Cc: stable@vger.kernel.org Signed-off-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_420xx/adf_drv.c | 2 -- drivers/crypto/intel/qat/qat_4xxx/adf_drv.c | 2 -- drivers/crypto/intel/qat/qat_6xxx/adf_drv.c | 2 -- drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c62x/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_common/adf_aer.c | 10 +++++++--- drivers/crypto/intel/qat/qat_common/adf_common_drv.h | 1 + drivers/crypto/intel/qat/qat_common/adf_init.c | 2 ++ drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c | 1 - 12 files changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c index 566adc0a2d11..265bd52778c5 100644 --- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c @@ -146,8 +146,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } - pci_set_master(pdev); - if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state.\n"); ret = -ENOMEM; diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c index daca73651c14..681c4dd8f3d2 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c @@ -148,8 +148,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } - pci_set_master(pdev); - if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state.\n"); ret = -ENOMEM; diff --git a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c index c52462a48c34..ab62b91ecb51 100644 --- a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c @@ -189,8 +189,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } - pci_set_master(pdev); - /* * The PCI config space is saved at this point and will be restored * after a Function Level Reset (FLR) as the FLR does not completely diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c index 7a59bca3242f..ded52744b4fc 100644 --- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c @@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_err_free_reg; } } - pci_set_master(pdev); if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state\n"); diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c index 0881575f7670..e7600d284ed3 100644 --- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c @@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_err_free_reg; } } - pci_set_master(pdev); /* Completion for VF2PF request/response message exchange */ init_completion(&accel_dev->vf.msg_received); diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c index 4972e52dd944..2ebff5855b01 100644 --- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c @@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_err_free_reg; } } - pci_set_master(pdev); if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state\n"); diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c index d3f728b9f2f2..91e148bb4870 100644 --- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c @@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_err_free_reg; } } - pci_set_master(pdev); /* Completion for VF2PF request/response message exchange */ init_completion(&accel_dev->vf.msg_received); diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 9c6bfb9fef80..365637e40439 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -41,7 +41,6 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, accel_dev->hw_device->exit_arb(accel_dev); } adf_dev_restarting_notify(accel_dev); - pci_clear_master(pdev); adf_dev_down(accel_dev); return PCI_ERS_RESULT_NEED_RESET; @@ -106,6 +105,13 @@ void adf_dev_restore(struct adf_accel_dev *accel_dev) } } +void adf_set_bme(struct adf_accel_dev *accel_dev) +{ + struct pci_dev *pdev = accel_to_pci_dev(accel_dev); + + pci_set_master(pdev); +} + static void adf_device_sriov_worker(struct work_struct *work) { struct adf_sriov_dev_data *sriov_data = @@ -198,8 +204,6 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; } - if (!pdev->is_busmaster) - pci_set_master(pdev); pci_restore_state(pdev); res = adf_dev_up(accel_dev, false); if (res && res != -EALREADY) diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index b9188ea9aa72..762a0b5e774a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -77,6 +77,7 @@ extern const struct pci_error_handlers adf_err_handler; void adf_reset_sbr(struct adf_accel_dev *accel_dev); void adf_reset_flr(struct adf_accel_dev *accel_dev); void adf_dev_restore(struct adf_accel_dev *accel_dev); +void adf_set_bme(struct adf_accel_dev *accel_dev); int adf_init_aer(void); void adf_exit_aer(void); int adf_init_arb(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c index f8088388cf12..f9f5696ed476 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_init.c +++ b/drivers/crypto/intel/qat/qat_common/adf_init.c @@ -74,6 +74,8 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev) return -EFAULT; } + adf_set_bme(accel_dev); + if (!test_bit(ADF_STATUS_CONFIGURED, &accel_dev->status) && !accel_dev->is_vf) { dev_err(&GET_DEV(accel_dev), "Device not configured\n"); diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c index 8a863d7d86d7..97ad53eef38f 100644 --- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c @@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_err_free_reg; } } - pci_set_master(pdev); if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state\n"); diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c index f8a6e10a1de7..a5edda8bad32 100644 --- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c @@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_err_free_reg; } } - pci_set_master(pdev); /* Completion for VF2PF request/response message exchange */ init_completion(&accel_dev->vf.msg_received); From 9676657117b79f88c22875680c36d7da84b75eca Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 13 May 2026 17:16:57 +0200 Subject: [PATCH 372/655] crypto: qat - skip restart for down devices Skip the shutdown and restart flow when adf_slot_reset() is entered for a device that is already down. In that case, leave ADF_STATUS_RESTARTING clear and let adf_slot_reset() restore PCI function state without calling adf_dev_up(), re-enabling SR-IOV, or sending restarted notifications. This is in preparation for adding reset_prepare() and reset_done() callbacks in adf_aer.c. Cc: stable@vger.kernel.org Signed-off-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 365637e40439..7255cac5aaa6 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -33,6 +33,9 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_DISCONNECT; } + if (!adf_dev_started(accel_dev)) + return PCI_ERS_RESULT_CAN_RECOVER; + adf_error_notifier(accel_dev); adf_pf2vf_notify_fatal_error(accel_dev); set_bit(ADF_STATUS_RESTARTING, &accel_dev->status); @@ -204,6 +207,9 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; } + if (!adf_devmgr_in_reset(accel_dev)) + goto reset_complete; + pci_restore_state(pdev); res = adf_dev_up(accel_dev, false); if (res && res != -EALREADY) @@ -213,6 +219,8 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev) adf_pf2vf_notify_restarted(accel_dev); adf_dev_restarted_notify(accel_dev); clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); + +reset_complete: return PCI_ERS_RESULT_RECOVERED; } From 56707afb92fee371c0f2e04332c9aa03cdb89793 Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 13 May 2026 17:16:58 +0200 Subject: [PATCH 373/655] crypto: qat - factor out AER reset helpers Move the shutdown and recovery sequences out of adf_error_detected() and adf_slot_reset() into reset_prepare() and reset_done() helpers. This makes the AER recovery path easier to follow and prepares the common reset flow for reuse by additional PCI reset callbacks without duplicating the logic. No functional change intended. Cc: stable@vger.kernel.org Signed-off-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Reviewed-by: Damian Muszynski Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 88 ++++++++++++------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 7255cac5aaa6..d29f70eb84b8 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -17,6 +17,58 @@ struct adf_fatal_error_data { static struct workqueue_struct *device_reset_wq; static struct workqueue_struct *device_sriov_wq; +static pci_ers_result_t reset_prepare(struct pci_dev *pdev) +{ + struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); + + if (!accel_dev) { + dev_err(&pdev->dev, "Can't find acceleration device\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + if (!adf_dev_started(accel_dev)) + return PCI_ERS_RESULT_CAN_RECOVER; + + set_bit(ADF_STATUS_RESTARTING, &accel_dev->status); + if (accel_dev->hw_device->exit_arb) { + dev_dbg(&pdev->dev, "Disabling arbitration\n"); + accel_dev->hw_device->exit_arb(accel_dev); + } + adf_dev_restarting_notify(accel_dev); + adf_dev_down(accel_dev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t reset_done(struct pci_dev *pdev) +{ + struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); + int res; + + if (!accel_dev) { + dev_err(&pdev->dev, "Can't find acceleration device\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + if (!adf_devmgr_in_reset(accel_dev)) + goto reset_complete; + + pci_restore_state(pdev); + res = adf_dev_up(accel_dev, false); + if (res && res != -EALREADY) + return PCI_ERS_RESULT_DISCONNECT; + + adf_reenable_sriov(accel_dev); + adf_pf2vf_notify_restarted(accel_dev); + adf_dev_restarted_notify(accel_dev); + clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); + +reset_complete: + dev_info(&pdev->dev, "Device reset completed successfully\n"); + + return PCI_ERS_RESULT_RECOVERED; +} + static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { @@ -33,20 +85,10 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_DISCONNECT; } - if (!adf_dev_started(accel_dev)) - return PCI_ERS_RESULT_CAN_RECOVER; - adf_error_notifier(accel_dev); adf_pf2vf_notify_fatal_error(accel_dev); - set_bit(ADF_STATUS_RESTARTING, &accel_dev->status); - if (accel_dev->hw_device->exit_arb) { - dev_dbg(&pdev->dev, "Disabling arbitration\n"); - accel_dev->hw_device->exit_arb(accel_dev); - } - adf_dev_restarting_notify(accel_dev); - adf_dev_down(accel_dev); - return PCI_ERS_RESULT_NEED_RESET; + return reset_prepare(pdev); } /* reset dev data */ @@ -199,29 +241,7 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev, static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev) { - struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); - int res = 0; - - if (!accel_dev) { - pr_err("QAT: Can't find acceleration device\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - - if (!adf_devmgr_in_reset(accel_dev)) - goto reset_complete; - - pci_restore_state(pdev); - res = adf_dev_up(accel_dev, false); - if (res && res != -EALREADY) - return PCI_ERS_RESULT_DISCONNECT; - - adf_reenable_sriov(accel_dev); - adf_pf2vf_notify_restarted(accel_dev); - adf_dev_restarted_notify(accel_dev); - clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); - -reset_complete: - return PCI_ERS_RESULT_RECOVERED; + return reset_done(pdev); } static void adf_resume(struct pci_dev *pdev) From 4627ef7019bc532f992c0723e881811ce12f0a02 Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 13 May 2026 17:16:59 +0200 Subject: [PATCH 374/655] crypto: qat - handle sysfs-triggered reset callbacks A reset requested through /sys/bus/pci/devices/.../reset invokes the driver reset_prepare() and reset_done() callbacks. The QAT driver does not implement those callbacks today, so the reset proceeds without quiescing the device or bringing it back up afterward, which leaves the device unusable. Hook reset_prepare() and reset_done() into adf_err_handler so the common shutdown and recovery flow also runs for reset. Skip device quiesce if the device is already in a down state. Cc: stable@vger.kernel.org Signed-off-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Reviewed-by: Damian Muszynski Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index d29f70eb84b8..af028488e660 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -250,10 +250,22 @@ static void adf_resume(struct pci_dev *pdev) dev_info(&pdev->dev, "Device is up and running\n"); } +static void adf_reset_prepare(struct pci_dev *pdev) +{ + reset_prepare(pdev); +} + +static void adf_reset_done(struct pci_dev *pdev) +{ + reset_done(pdev); +} + const struct pci_error_handlers adf_err_handler = { .error_detected = adf_error_detected, .slot_reset = adf_slot_reset, .resume = adf_resume, + .reset_prepare = adf_reset_prepare, + .reset_done = adf_reset_done, }; EXPORT_SYMBOL_GPL(adf_err_handler); From 86ad8069366642fec18c1bc53c24cad3da720ce5 Mon Sep 17 00:00:00 2001 From: Fiona Trahe Date: Wed, 13 May 2026 16:33:08 +0100 Subject: [PATCH 375/655] Documentation: qat_rl: make rate limiting wording clearer The term "capability" typically refers to an ability to perform an action, whereas "capacity" denotes a measurable amount of resources. Since the sysfs-driver-qat_rl document describes remaining resources available to perform work, "capacity" is the more accurate term. Replace "capability" with "capacity" in the document. Signed-off-by: Fiona Trahe Reviewed-by: Ahsan Atta Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- Documentation/ABI/testing/sysfs-driver-qat_rl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-driver-qat_rl b/Documentation/ABI/testing/sysfs-driver-qat_rl index d534f89b4971..422333a0eb69 100644 --- a/Documentation/ABI/testing/sysfs-driver-qat_rl +++ b/Documentation/ABI/testing/sysfs-driver-qat_rl @@ -209,7 +209,7 @@ Date: January 2024 KernelVersion: 6.7 Contact: qat-linux@intel.com Description: - (RW) This file will return the remaining capability for a + (RW) This file will return the remaining capacity for a particular service/sla. This is the remaining value that a new SLA can be set to or a current SLA can be increased with. From 3b626ba431c4501512ad07549310685e07fe4706 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 14 May 2026 08:55:58 +0200 Subject: [PATCH 376/655] X.509: Fix validation of ASN.1 certificate header x509_load_certificate_list() seeks to enforce that a certificate starts with 0x30 0x82 (ASN.1 SEQUENCE tag followed by a length of more than 256 and less than 65535 bytes). But it only enforces that *either* of those two byte values are present, instead of checking for the *conjunction* of the two values. Fix it. Fixes: 631cc66eb9ea ("MODSIGN: Provide module signing public keys to the kernel") Reported-by: Sashiko Closes: https://lore.kernel.org/r/20260508033917.B5873C2BCB0@smtp.kernel.org/ Signed-off-by: Lukas Wunner Cc: stable@vger.kernel.org # v3.7+ Reviewed-by: Ignat Korchagin Reviewed-by: Alistair Francis Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/x509_loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/asymmetric_keys/x509_loader.c b/crypto/asymmetric_keys/x509_loader.c index a41741326998..0d516c77cc26 100644 --- a/crypto/asymmetric_keys/x509_loader.c +++ b/crypto/asymmetric_keys/x509_loader.c @@ -20,7 +20,7 @@ int x509_load_certificate_list(const u8 cert_list[], */ if (end - p < 4) goto dodgy_cert; - if (p[0] != 0x30 && + if (p[0] != 0x30 || p[1] != 0x82) goto dodgy_cert; plen = (p[2] << 8) | p[3]; From fc2d791a43d3880496d1c729b8bd74d2c19cb4e7 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 14 May 2026 18:55:10 +0200 Subject: [PATCH 377/655] crypto: riscv/aes - replace min_t with min in riscv64_aes_ctr_crypt Use the simpler min() macro since the values are unsigned and compatible. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- arch/riscv/crypto/aes-riscv64-glue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/crypto/aes-riscv64-glue.c b/arch/riscv/crypto/aes-riscv64-glue.c index 8bbf7f348c23..bbd920c9e29d 100644 --- a/arch/riscv/crypto/aes-riscv64-glue.c +++ b/arch/riscv/crypto/aes-riscv64-glue.c @@ -19,6 +19,7 @@ #include #include #include +#include #include asmlinkage void aes_ecb_encrypt_zvkned(const struct crypto_aes_ctx *key, @@ -266,8 +267,7 @@ static int riscv64_aes_ctr_crypt(struct skcipher_request *req) * operation into two at the point where the overflow * will occur. After the first part, add the carry bit. */ - p1_nbytes = min_t(unsigned int, nbytes, - (nblocks - ctr32) * AES_BLOCK_SIZE); + p1_nbytes = min(nbytes, (nblocks - ctr32) * AES_BLOCK_SIZE); aes_ctr32_crypt_zvkned_zvkb(ctx, walk.src.virt.addr, walk.dst.virt.addr, p1_nbytes, req->iv); From f8c9c57d750346abd213ffed2ae3cacb0268e9f1 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 15 May 2026 11:34:52 +0900 Subject: [PATCH 378/655] crypto: tegra - Don't touch bo refcount in host1x bo pin/unpin Since commit "gpu: host1x: Allow entries in BO caches to be freed", host1x_bo_pin() and host1x_bo_unpin() handle the bo's refcount themselves. .pin/.unpin callbacks should not adjust it. Signed-off-by: Mikko Perttunen Signed-off-by: Herbert Xu --- drivers/crypto/tegra/tegra-se-main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/crypto/tegra/tegra-se-main.c b/drivers/crypto/tegra/tegra-se-main.c index eb71113ed146..d7541a9c0a92 100644 --- a/drivers/crypto/tegra/tegra-se-main.c +++ b/drivers/crypto/tegra/tegra-se-main.c @@ -52,7 +52,7 @@ tegra_se_cmdbuf_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_dire return ERR_PTR(-ENOMEM); kref_init(&map->ref); - map->bo = host1x_bo_get(bo); + map->bo = bo; map->direction = direction; map->dev = dev; @@ -93,7 +93,6 @@ static void tegra_se_cmdbuf_unpin(struct host1x_bo_mapping *map) dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); sg_free_table(map->sgt); kfree(map->sgt); - host1x_bo_put(map->bo); kfree(map); } From 43079e21ff53c6a77e669cec5b5b673b45f46e87 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Fri, 15 May 2026 22:02:14 +0300 Subject: [PATCH 379/655] include: Remove unused crypto-ux500.h The UX500 crypto drivers were removed in commit 453de3eb08c4 ("crypto: ux500/cryp - delete driver") and commit dd7b7972cb89 ("crypto: ux500/hash - delete driver"). No file includes this header. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Reviewed-by: Linus Walleij Signed-off-by: Herbert Xu --- include/linux/platform_data/crypto-ux500.h | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 include/linux/platform_data/crypto-ux500.h diff --git a/include/linux/platform_data/crypto-ux500.h b/include/linux/platform_data/crypto-ux500.h deleted file mode 100644 index 5d43350e32cc..000000000000 --- a/include/linux/platform_data/crypto-ux500.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * Author: Joakim Bech for ST-Ericsson - */ -#ifndef _CRYPTO_UX500_H -#define _CRYPTO_UX500_H -#include -#include - -struct hash_platform_data { - void *mem_to_engine; - bool (*dma_filter)(struct dma_chan *chan, void *filter_param); -}; - -struct cryp_platform_data { - struct stedma40_chan_cfg mem_to_engine; - struct stedma40_chan_cfg engine_to_mem; -}; - -#endif From 01c8d5662dd2f11a705edc55be3583b05288a26b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 15 May 2026 22:29:48 +0200 Subject: [PATCH 380/655] crypto: atmel-i2c - drop redundant void * callback cast in enqueue The callback already has the correct type - remove the redundant cast. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c index 0e275dbdc8c5..ff19857894d0 100644 --- a/drivers/crypto/atmel-i2c.c +++ b/drivers/crypto/atmel-i2c.c @@ -294,7 +294,7 @@ void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, void *areq, int status), void *areq) { - work_data->cbk = (void *)cbk; + work_data->cbk = cbk; work_data->areq = areq; INIT_WORK(&work_data->work, atmel_i2c_work_handler); From 09e6b79b8ce388993aec9ac91b1cb2c181c27bd9 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Sat, 16 May 2026 14:26:51 +0200 Subject: [PATCH 381/655] crypto: eip93 - fix reset ring register definition This patch fixes a descriptor ring reset. This causes a hang in the driver's unload/load sequence. Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") Suggested-by: Benjamin Larsson Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Herbert Xu --- drivers/crypto/inside-secure/eip93/eip93-regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/inside-secure/eip93/eip93-regs.h b/drivers/crypto/inside-secure/eip93/eip93-regs.h index 96285ca6fbbe..96d28c6651bd 100644 --- a/drivers/crypto/inside-secure/eip93/eip93-regs.h +++ b/drivers/crypto/inside-secure/eip93/eip93-regs.h @@ -103,7 +103,7 @@ #define EIP93_PE_TARGET_COMMAND_NO_RDR_MODE FIELD_PREP(EIP93_PE_CONFIG_PE_MODE, 0x2) #define EIP93_PE_TARGET_COMMAND_WITH_RDR_MODE FIELD_PREP(EIP93_PE_CONFIG_PE_MODE, 0x1) #define EIP93_PE_DIRECT_HOST_MODE FIELD_PREP(EIP93_PE_CONFIG_PE_MODE, 0x0) -#define EIP93_PE_CONFIG_RST_RING BIT(2) +#define EIP93_PE_CONFIG_RST_RING BIT(1) #define EIP93_PE_CONFIG_RST_PE BIT(0) #define EIP93_REG_PE_STATUS 0x104 #define EIP93_REG_PE_BUF_THRESH 0x10c From 2b7b16c905b08a4cd28cbb2809ee38a78bfe0489 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sat, 16 May 2026 20:23:36 +0200 Subject: [PATCH 382/655] crypto: drivers - remove of_match_ptr from OF match tables Drop of_match_ptr() because OF matching is stubbed out when CONFIG_OF=n. Indent bcm_spu_pdriver.driver and its members while at it. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/bcm/cipher.c | 6 +++--- drivers/crypto/qcom-rng.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 2bce15dc0aa8..240b40ae9cd6 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -4698,9 +4698,9 @@ static void bcm_spu_remove(struct platform_device *pdev) static struct platform_driver bcm_spu_pdriver = { .driver = { - .name = "brcm-spu-crypto", - .of_match_table = of_match_ptr(bcm_spu_dt_ids), - }, + .name = "brcm-spu-crypto", + .of_match_table = bcm_spu_dt_ids, + }, .probe = bcm_spu_probe, .remove = bcm_spu_remove, }; diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c index 0685ba122e8a..150e5802e351 100644 --- a/drivers/crypto/qcom-rng.c +++ b/drivers/crypto/qcom-rng.c @@ -265,7 +265,7 @@ static struct platform_driver qcom_rng_driver = { .remove = qcom_rng_remove, .driver = { .name = KBUILD_MODNAME, - .of_match_table = of_match_ptr(qcom_rng_of_match), + .of_match_table = qcom_rng_of_match, .acpi_match_table = ACPI_PTR(qcom_rng_acpi_match), } }; From 08b0f3a77561550d2358c73ceba59e1c5fa5721a Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 May 2026 01:42:12 +0200 Subject: [PATCH 383/655] crypto: atmel-sha - use memcpy_and_pad to simplify hmac_setup Use memcpy_and_pad() instead of memcpy() followed by memset() to simplify atmel_sha_hmac_setup(). Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 7e7c83a3d8cd..8e3b8efa8109 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1724,8 +1724,7 @@ static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd, return atmel_sha_hmac_prehash_key(dd, key, keylen); /* Prepare ipad. */ - memcpy((u8 *)hmac->ipad, key, keylen); - memset((u8 *)hmac->ipad + keylen, 0, bs - keylen); + memcpy_and_pad(hmac->ipad, bs, key, keylen, 0); return atmel_sha_hmac_compute_ipad_hash(dd); } From 42e4579846d58ec790c4cde4094a1b5f80b13703 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sat, 16 May 2026 20:14:26 -0700 Subject: [PATCH 384/655] LoongArch: Remove unused arch/loongarch/crypto directory All LoongArch crypto code was moved to arch/loongarch/lib in commit 72f51a4f4b07 ("loongarch/crc32: expose CRC32 functions through lib"). However, arch/loongarch/crypto still contains stub Kconfig and Makefile files. Remove these unnecessary files. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Herbert Xu --- arch/loongarch/Makefile | 2 -- arch/loongarch/crypto/Kconfig | 5 ----- arch/loongarch/crypto/Makefile | 4 ---- crypto/Kconfig | 3 --- 4 files changed, 14 deletions(-) delete mode 100644 arch/loongarch/crypto/Kconfig delete mode 100644 arch/loongarch/crypto/Makefile diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index 47516aeea9d2..897f85d53a55 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -195,8 +195,6 @@ endif libs-y += arch/loongarch/lib/ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a -drivers-y += arch/loongarch/crypto/ - # suspend and hibernation support drivers-$(CONFIG_PM) += arch/loongarch/power/ diff --git a/arch/loongarch/crypto/Kconfig b/arch/loongarch/crypto/Kconfig deleted file mode 100644 index a0270b3e5b30..000000000000 --- a/arch/loongarch/crypto/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -menu "Accelerated Cryptographic Algorithms for CPU (loongarch)" - -endmenu diff --git a/arch/loongarch/crypto/Makefile b/arch/loongarch/crypto/Makefile deleted file mode 100644 index ba83755dde2b..000000000000 --- a/arch/loongarch/crypto/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for LoongArch crypto files.. -# diff --git a/crypto/Kconfig b/crypto/Kconfig index 00b7ce4227ae..40b7601f00f1 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1366,9 +1366,6 @@ endif if ARM64 source "arch/arm64/crypto/Kconfig" endif -if LOONGARCH -source "arch/loongarch/crypto/Kconfig" -endif if MIPS source "arch/mips/crypto/Kconfig" endif From 2f07f4192687a4fd7352c30bb01160f02f10e9d6 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sat, 16 May 2026 20:20:56 -0700 Subject: [PATCH 385/655] MIPS: Remove unused arch/mips/crypto directory The last MIPS crypto code was moved to lib/crypto/mips in commit c9e5ac0ab9d1 ("lib/crypto: mips/md5: Migrate optimized code into library"). However, arch/mips/crypto still contains stub Kconfig, Makefile, and .gitignore files. Remove these unnecessary files. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Herbert Xu --- arch/mips/Makefile | 2 -- arch/mips/crypto/.gitignore | 2 -- arch/mips/crypto/Kconfig | 5 ----- arch/mips/crypto/Makefile | 5 ----- crypto/Kconfig | 3 --- 5 files changed, 17 deletions(-) delete mode 100644 arch/mips/crypto/.gitignore delete mode 100644 arch/mips/crypto/Kconfig delete mode 100644 arch/mips/crypto/Makefile diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 6705fa5d9211..cff1a9a43b89 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -350,8 +350,6 @@ OBJCOPYFLAGS += --remove-section=.reginfo libs-y += arch/mips/lib/ libs-$(CONFIG_MIPS_FP_SUPPORT) += arch/mips/math-emu/ -drivers-y += arch/mips/crypto/ - # suspend and hibernation support drivers-$(CONFIG_PM) += arch/mips/power/ diff --git a/arch/mips/crypto/.gitignore b/arch/mips/crypto/.gitignore deleted file mode 100644 index 0d47d4f21c6d..000000000000 --- a/arch/mips/crypto/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -poly1305-core.S diff --git a/arch/mips/crypto/Kconfig b/arch/mips/crypto/Kconfig deleted file mode 100644 index 6a5bd5074867..000000000000 --- a/arch/mips/crypto/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -menu "Accelerated Cryptographic Algorithms for CPU (mips)" - -endmenu diff --git a/arch/mips/crypto/Makefile b/arch/mips/crypto/Makefile deleted file mode 100644 index 5adb631a69c1..000000000000 --- a/arch/mips/crypto/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for MIPS crypto files.. -# - diff --git a/crypto/Kconfig b/crypto/Kconfig index 40b7601f00f1..b5c5a1e04435 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1366,9 +1366,6 @@ endif if ARM64 source "arch/arm64/crypto/Kconfig" endif -if MIPS -source "arch/mips/crypto/Kconfig" -endif if PPC source "arch/powerpc/crypto/Kconfig" endif From 083c9ab12c402efe9ed55c942ede92eb35f8bf2a Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 May 2026 12:34:14 +0200 Subject: [PATCH 386/655] crypto: omap-des - add COMPILE_TEST and fix CONFIG_OF=n build CRYPTO_DEV_OMAP_DES only depends on ARCH_OMAP2PLUS, which is ARM-only and selects OF via ARM's USE_OF, making any non-OF code unreachable. Add COMPILE_TEST so the driver can be built with CONFIG_OF=n, making the non-OF code reachable. Fix the resulting non-OF build failures: - omap_des_irq() was defined inside a CONFIG_OF block, but is referenced unconditionally from omap_des_probe(). Move the CONFIG_OF guard so it only covers omap_des_get_of(). - The non-OF omap_des_get_of() stub took a struct device *, while omap_des_probe() passes a struct platform_device *. Make the stub prototype match the OF implementation and the caller. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 4 ++-- drivers/crypto/omap-des.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index d23b58b81ca3..3449b3c9c6ad 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -316,7 +316,7 @@ config HW_RANDOM_PPC4XX config CRYPTO_DEV_OMAP tristate "Support for OMAP crypto HW accelerators" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || COMPILE_TEST help OMAP processors have various crypto HW accelerators. Select this if you want to use the OMAP modules for any of the crypto algorithms. @@ -352,7 +352,7 @@ config CRYPTO_DEV_OMAP_AES config CRYPTO_DEV_OMAP_DES tristate "Support for OMAP DES/3DES hw engine" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || COMPILE_TEST select CRYPTO_LIB_DES select CRYPTO_SKCIPHER select CRYPTO_ENGINE diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 16d5c617d5ee..f6f3b22e4ee5 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -800,7 +800,6 @@ static struct omap_des_algs_info omap_des_algs_info_ecb_cbc[] = { }, }; -#ifdef CONFIG_OF static const struct omap_des_pdata omap_des_pdata_omap4 = { .algs_info = omap_des_algs_info_ecb_cbc, .algs_info_size = ARRAY_SIZE(omap_des_algs_info_ecb_cbc), @@ -909,6 +908,7 @@ static const struct of_device_id omap_des_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_des_of_match); +#ifdef CONFIG_OF static int omap_des_get_of(struct omap_des_dev *dd, struct platform_device *pdev) { @@ -923,7 +923,7 @@ static int omap_des_get_of(struct omap_des_dev *dd, } #else static int omap_des_get_of(struct omap_des_dev *dd, - struct device *dev) + struct platform_device *pdev) { return -EINVAL; } From 0a06b86d4b748188878a132c637029eae4d9ac8d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 May 2026 12:36:52 +0200 Subject: [PATCH 387/655] crypto: omap-des - drop of_match_ptr from OF match table Drop of_match_ptr() because OF matching is stubbed out when CONFIG_OF=n. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/omap-des.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index f6f3b22e4ee5..dfaf831dd8ec 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -1117,7 +1117,7 @@ static struct platform_driver omap_des_driver = { .driver = { .name = "omap-des", .pm = &omap_des_pm_ops, - .of_match_table = of_match_ptr(omap_des_of_match), + .of_match_table = omap_des_of_match, }, }; From d58b4a09d7f06750a706b70d068f5a678dad8233 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 May 2026 14:37:07 +0200 Subject: [PATCH 388/655] crypto: atmel-sha204a - remove sysfs group before hwrng atmel_sha204a_probe() registers the hwrng before creating the sysfs group. Mirror this order in atmel_sha204a_remove() by removing the sysfs group before unregistering the hwrng. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha204a.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index 6e6ac4770416..37538b0fd7c2 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -199,11 +199,10 @@ static void atmel_sha204a_remove(struct i2c_client *client) { struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &atmel_sha204a_groups); devm_hwrng_unregister(&client->dev, &i2c_priv->hwrng); atmel_i2c_flush_queue(); - sysfs_remove_group(&client->dev.kobj, &atmel_sha204a_groups); - kfree((void *)i2c_priv->hwrng.priv); } From 49e05bb00f2e8168695f7af4d694c39e1423e8a2 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 May 2026 18:27:40 +0200 Subject: [PATCH 389/655] crypto: atmel-sha204a - fail on hwrng registration error in probe path Commit 13909a0c8897 ("crypto: atmel-sha204a - provide the otp content") overwrote the hwrng registration return value when creating the sysfs group, which allowed atmel_sha204a_probe() to succeed even if devm_hwrng_register() failed. Return immediately when devm_hwrng_register() fails, and report both hwrng and sysfs registration errors with dev_err(). Adjust the sysfs error log message for consistency. Fixes: 13909a0c8897 ("crypto: atmel-sha204a - provide the otp content") Cc: stable@vger.kernel.org Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha204a.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index 37538b0fd7c2..12eb85b57380 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -183,12 +183,14 @@ static int atmel_sha204a_probe(struct i2c_client *client) i2c_priv->hwrng.quality = *quality; ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng); - if (ret) - dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); + if (ret) { + dev_err(&client->dev, "failed to register RNG (%d)\n", ret); + return ret; + } ret = sysfs_create_group(&client->dev.kobj, &atmel_sha204a_groups); if (ret) { - dev_err(&client->dev, "failed to register sysfs entry\n"); + dev_err(&client->dev, "failed to create sysfs group (%d)\n", ret); return ret; } From 32faf8b9de3e0dc61a50a9c85634d8ac1c02ee33 Mon Sep 17 00:00:00 2001 From: Wensheng Wang Date: Tue, 14 Apr 2026 17:29:20 +0800 Subject: [PATCH 390/655] dt-bindings: hwmon: Add MPS mp2985 Add support for MPS mp2985 controller. Acked-by: Krzysztof Kozlowski Signed-off-by: Wensheng Wang Link: https://lore.kernel.org/r/20260414092921.1067735-1-wenswang@yeah.net Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 23fd4513933a..44ee92f1a09f 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -336,6 +336,8 @@ properties: - mps,mp29612 # Monolithic Power Systems Inc. multi-phase controller mp29816 - mps,mp29816 + # Monolithic Power Systems Inc. multi-phase controller mp2985 + - mps,mp2985 # Monolithic Power Systems Inc. multi-phase controller mp2993 - mps,mp2993 # Monolithic Power Systems Inc. hot-swap protection device From e656735fe32c59cc323c41e7922e77ac7bcd9f68 Mon Sep 17 00:00:00 2001 From: Wensheng Wang Date: Tue, 14 Apr 2026 17:29:21 +0800 Subject: [PATCH 391/655] hwmon: add MP2985 driver Add support for MPS mp2985 controller. This driver exposes telemetry and limit value readings and writtings. Signed-off-by: Wensheng Wang Link: https://lore.kernel.org/r/20260414092921.1067735-2-wenswang@yeah.net Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/mp2985.rst | 147 ++++++++++++ MAINTAINERS | 7 + drivers/hwmon/pmbus/Kconfig | 9 + drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/mp2985.c | 402 +++++++++++++++++++++++++++++++++ 6 files changed, 567 insertions(+) create mode 100644 Documentation/hwmon/mp2985.rst create mode 100644 drivers/hwmon/pmbus/mp2985.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 8b655e5d6b68..96612a16f93a 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -185,6 +185,7 @@ Hardware Monitoring Kernel Drivers mp2925 mp29502 mp2975 + mp2985 mp2993 mp5023 mp5920 diff --git a/Documentation/hwmon/mp2985.rst b/Documentation/hwmon/mp2985.rst new file mode 100644 index 000000000000..87a39c8a300c --- /dev/null +++ b/Documentation/hwmon/mp2985.rst @@ -0,0 +1,147 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver mp2985 +==================== + +Supported chips: + + * MPS mp2985 + + Prefix: 'mp2985' + +Author: + + Wensheng Wang + +Description +----------- + +This driver implements support for Monolithic Power Systems, Inc. (MPS) +MP2985 Dual Loop Digital Multi-phase Controller. + +Device compliant with: + +- PMBus rev 1.3 interface. + +The driver exports the following attributes via the 'sysfs' files +for input voltage: + +**in1_input** + +**in1_label** + +**in1_crit** + +**in1_crit_alarm** + +**in1_lcrit** + +**in1_lcrit_alarm** + +**in1_max** + +**in1_max_alarm** + +**in1_min** + +**in1_min_alarm** + +The driver provides the following attributes for output voltage: + +**in2_input** + +**in2_label** + +**in2_crit** + +**in2_crit_alarm** + +**in2_lcrit** + +**in2_lcrit_alarm** + +**in3_input** + +**in3_label** + +**in3_crit** + +**in3_crit_alarm** + +**in3_lcrit** + +**in3_lcrit_alarm** + +The driver provides the following attributes for input current: + +**curr1_input** + +**curr1_label** + +The driver provides the following attributes for output current: + +**curr2_input** + +**curr2_label** + +**curr2_crit** + +**curr2_crit_alarm** + +**curr2_max** + +**curr2_max_alarm** + +**curr3_input** + +**curr3_label** + +**curr3_crit** + +**curr3_crit_alarm** + +**curr3_max** + +**curr3_max_alarm** + +The driver provides the following attributes for input power: + +**power1_input** + +**power1_label** + +**power2_input** + +**power2_label** + +The driver provides the following attributes for output power: + +**power3_input** + +**power3_label** + +**power4_input** + +**power4_label** + +The driver provides the following attributes for temperature: + +**temp1_input** + +**temp1_crit** + +**temp1_crit_alarm** + +**temp1_max** + +**temp1_max_alarm** + +**temp2_input** + +**temp2_crit** + +**temp2_crit_alarm** + +**temp2_max** + +**temp2_max_alarm** diff --git a/MAINTAINERS b/MAINTAINERS index b539be153f6a..9c2ebcfe7b05 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18085,6 +18085,13 @@ S: Maintained F: Documentation/hwmon/mp29502.rst F: drivers/hwmon/pmbus/mp29502.c +MPS MP2985 DRIVER +M: Wensheng Wang +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/mp2985.rst +F: drivers/hwmon/pmbus/mp2985.c + MPS MP2993 DRIVER M: Noah Wang L: linux-hwmon@vger.kernel.org diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 8f4bff375ecb..8a2c3ea50c8d 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -456,6 +456,15 @@ config SENSORS_MP2975 This driver can also be built as a module. If so, the module will be called mp2975. +config SENSORS_MP2985 + tristate "MPS MP2985" + help + If you say yes here you get hardware monitoring support for MPS + MP2985 Dual Loop Digital Multi-Phase Controller. + + This driver can also be built as a module. If so, the module will + be called mp2985. + config SENSORS_MP2993 tristate "MPS MP2993" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 7129b62bc00f..6022614722bd 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_MP2891) += mp2891.o obj-$(CONFIG_SENSORS_MP2925) += mp2925.o obj-$(CONFIG_SENSORS_MP29502) += mp29502.o obj-$(CONFIG_SENSORS_MP2975) += mp2975.o +obj-$(CONFIG_SENSORS_MP2985) += mp2985.o obj-$(CONFIG_SENSORS_MP2993) += mp2993.o obj-$(CONFIG_SENSORS_MP5023) += mp5023.o obj-$(CONFIG_SENSORS_MP5920) += mp5920.o diff --git a/drivers/hwmon/pmbus/mp2985.c b/drivers/hwmon/pmbus/mp2985.c new file mode 100644 index 000000000000..b0a4796ca8ce --- /dev/null +++ b/drivers/hwmon/pmbus/mp2985.c @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP2985) + * + * Copyright (C) 2026 MPS + */ + +#include +#include +#include +#include +#include "pmbus.h" + +/* + * Vender specific register READ_PIN_EST(0x93), READ_IIN_EST(0x8E), + * MFR_VR_MULTI_CONFIG_R1(0x0D) and MFR_VR_MULTI_CONFIG_R2(0x1D). + * The READ_PIN_EST is used to read pin telemetry, the READ_IIN_EST + * is used to read iin telemetry and the MFR_VR_MULTI_CONFIG_R1, + * MFR_VR_MULTI_CONFIG_R2 are used to obtain vid scale. + */ +#define READ_PIN_EST 0x93 +#define READ_IIN_EST 0x8E +#define MFR_VR_MULTI_CONFIG_R1 0x0D +#define MFR_VR_MULTI_CONFIG_R2 0x1D + +#define MP2985_VOUT_DIV 64 +#define MP2985_VOUT_OVUV_UINT 125 +#define MP2985_VOUT_OVUV_DIV 64 + +#define MP2985_PAGE_NUM 2 + +#define MP2985_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | \ + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | \ + PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | \ + PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_HAVE_STATUS_TEMP | \ + PMBUS_HAVE_STATUS_INPUT) + +#define MP2985_RAIL2_FUNC (PMBUS_HAVE_PIN | PMBUS_HAVE_VOUT | \ + PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | \ + PMBUS_HAVE_TEMP | PMBUS_HAVE_IIN | \ + PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_HAVE_STATUS_TEMP | \ + PMBUS_HAVE_STATUS_INPUT) + +struct mp2985_data { + struct pmbus_driver_info info; + int vout_scale[MP2985_PAGE_NUM]; + int vid_offset[MP2985_PAGE_NUM]; +}; + +#define to_mp2985_data(x) container_of(x, struct mp2985_data, info) + +static u16 mp2985_linear_exp_transfer(u16 word, u16 expect_exponent) +{ + s16 exponent, mantissa, target_exponent; + + exponent = ((s16)word) >> 11; + mantissa = ((s16)((word & 0x7ff) << 5)) >> 5; + target_exponent = (s16)((expect_exponent & 0x1f) << 11) >> 11; + + /* + * The MP2985 does not support negtive limit value, if a negtive + * limit value is written, the limit value will become to 0. And + * the maximum positive limit value is limitted to 0x3FF. + */ + if (mantissa < 0) { + mantissa = 0; + } else { + if (exponent > target_exponent) { + mantissa = (1023 >> (exponent - target_exponent)) >= mantissa ? + mantissa << (exponent - target_exponent) : + 0x3FF; + } else { + mantissa = clamp_val(mantissa >> (target_exponent - exponent), + 0, 0x3FF); + } + } + + return mantissa | ((expect_exponent << 11) & 0xf800); +} + +static int mp2985_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_VOUT_MODE: + /* + * The MP2985 does not follow standard PMBus protocol completely, + * and the calculation of vout in this driver is based on direct + * format. As a result, the format of vout is enforced to direct. + */ + ret = PB_VOUT_MODE_DIRECT; + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int mp2985_read_word_data(struct i2c_client *client, int page, int phase, + int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp2985_data *data = to_mp2985_data(info); + int ret; + + switch (reg) { + case PMBUS_READ_VOUT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + /* + * The MP2985 supports three vout mode, direct, linear11 and vid mode. + * In vid mode, the MP2985 vout telemetry has 49 vid step offset, but + * PMBUS_VOUT_OV_FAULT_LIMIT and PMBUS_VOUT_UV_FAULT_LIMIT do not take + * this into consideration, their resolution are 1.953125mV/LSB, as a + * result, format[PSC_VOLTAGE_OUT] can not be set to vid mode directly. + * Adding extra vid_offset variable for vout telemetry. + */ + ret = clamp_val(DIV_ROUND_CLOSEST(((ret & GENMASK(11, 0)) + + data->vid_offset[page]) * + data->vout_scale[page], MP2985_VOUT_DIV), + 0, 0x7FFF); + break; + case PMBUS_READ_IIN: + /* + * The MP2985 has standard PMBUS_READ_IIN register(0x89), but this is + * not used to read the input current of per rail. The input current + * is read through the vender redefined register READ_IIN_EST(0x8E). + */ + ret = pmbus_read_word_data(client, page, phase, READ_IIN_EST); + break; + case PMBUS_READ_PIN: + /* + * The MP2985 has standard PMBUS_READ_PIN register(0x97), but this + * is not used to read the input power of per rail. The input power + * of per rail is read through the vender redefined register + * READ_PIN_EST(0x93). + */ + ret = pmbus_read_word_data(client, page, phase, READ_PIN_EST); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * MP2985_VOUT_OVUV_UINT, + MP2985_VOUT_OVUV_DIV); + break; + case PMBUS_STATUS_WORD: + case PMBUS_READ_VIN: + case PMBUS_READ_IOUT: + case PMBUS_READ_POUT: + case PMBUS_READ_TEMPERATURE_1: + case PMBUS_VIN_OV_FAULT_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_OT_WARN_LIMIT: + /* + * These register is not explicitly handled by the driver, + * as a result, return -ENODATA directly. + */ + ret = -ENODATA; + break; + default: + /* + * The MP2985 do not support other telemetry and limit value + * reading, so, return -EINVAL directly. + */ + ret = -EINVAL; + break; + } + + return ret; +} + +static int mp2985_write_word_data(struct i2c_client *client, int page, int reg, + u16 word) +{ + int ret; + + switch (reg) { + case PMBUS_VIN_OV_FAULT_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + /* + * The PMBUS_VIN_OV_FAULT_LIMIT, PMBUS_VIN_OV_WARN_LIMIT, + * PMBUS_VIN_UV_WARN_LIMIT and PMBUS_VIN_UV_FAULT_LIMIT + * of MP2985 is linear11 format, and the exponent is a + * constant value(5'b11101), so the exponent of word + * parameter should be converted to 5'b11101(0x1D). + */ + ret = pmbus_write_word_data(client, page, reg, + mp2985_linear_exp_transfer(word, 0x1D)); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + /* + * The bit0-bit11 is the limit value, and bit12-bit15 + * should not be changed. + */ + ret = pmbus_read_word_data(client, page, 0xff, reg); + if (ret < 0) + return ret; + + ret = pmbus_write_word_data(client, page, reg, + (ret & ~GENMASK(11, 0)) | + clamp_val(DIV_ROUND_CLOSEST(word * MP2985_VOUT_OVUV_DIV, + MP2985_VOUT_OVUV_UINT), 0, 0xFFF)); + break; + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_OT_WARN_LIMIT: + /* + * The PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT of + * MP2985 is linear11 format, and the exponent is a + * constant value(5'b00000), so the exponent of word + * parameter should be converted to 5'b00000. + */ + ret = pmbus_write_word_data(client, page, reg, + mp2985_linear_exp_transfer(word, 0x00)); + break; + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + /* + * The PMBUS_IOUT_OC_FAULT_LIMIT and PMBUS_IOUT_OC_WARN_LIMIT + * of MP2985 is linear11 format, and the exponent can not be + * changed. + */ + ret = pmbus_read_word_data(client, page, 0xff, reg); + if (ret < 0) + return ret; + + ret = pmbus_write_word_data(client, page, reg, + mp2985_linear_exp_transfer(word, + FIELD_GET(GENMASK(15, 11), + ret))); + break; + default: + /* + * The MP2985 do not support other limit value configuration, + * so, return -EINVAL directly. + */ + ret = -EINVAL; + break; + } + + return ret; +} + +static int +mp2985_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info, + int page) +{ + struct mp2985_data *data = to_mp2985_data(info); + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + /* + * The MP2985 supports three vout mode. If PMBUS_VOUT_MODE + * bit5 is 1, it is vid mode. If PMBUS PMBUS_VOUT_MODE bit4 + * is 1, it is linear11 mode, the vout scale is 1.953125mv/LSB. + * If PMBUS PMBUS_VOUT_MODE bit6 is 1, it is direct mode, the + * vout scale is 1mv/LSB. In vid mode, the MP2985 vout telemetry + * has 49 vid step offset. + */ + if (FIELD_GET(BIT(5), ret)) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_word_data(client, page == 0 ? + MFR_VR_MULTI_CONFIG_R1 : + MFR_VR_MULTI_CONFIG_R2); + if (ret < 0) + return ret; + + if (page == 0) { + if (FIELD_GET(BIT(4), ret)) + data->vout_scale[page] = 320; + else + data->vout_scale[page] = 640; + } else { + if (FIELD_GET(BIT(3), ret)) + data->vout_scale[page] = 320; + else + data->vout_scale[page] = 640; + } + + data->vid_offset[page] = 49; + + /* + * For vid mode, the MP2985 should be changed to page 2 + * to obtain vout scale value, this may confuse the PMBus + * core. To avoid this, switch back to the previous page + * again. + */ + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); + if (ret < 0) + return ret; + } else if (FIELD_GET(BIT(4), ret)) { + data->vout_scale[page] = 125; + data->vid_offset[page] = 0; + } else { + data->vout_scale[page] = 64; + data->vid_offset[page] = 0; + } + + return 0; +} + +static int mp2985_identify(struct i2c_client *client, struct pmbus_driver_info *info) +{ + int ret; + + ret = mp2985_identify_vout_scale(client, info, 0); + if (ret < 0) + return ret; + + return mp2985_identify_vout_scale(client, info, 1); +} + +static struct pmbus_driver_info mp2985_info = { + .pages = MP2985_PAGE_NUM, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + + .m[PSC_VOLTAGE_OUT] = 1, + .R[PSC_VOLTAGE_OUT] = 3, + .b[PSC_VOLTAGE_OUT] = 0, + + .func[0] = MP2985_RAIL1_FUNC, + .func[1] = MP2985_RAIL2_FUNC, + .read_word_data = mp2985_read_word_data, + .read_byte_data = mp2985_read_byte_data, + .write_word_data = mp2985_write_word_data, + .identify = mp2985_identify, +}; + +static int mp2985_probe(struct i2c_client *client) +{ + struct mp2985_data *data; + + data = devm_kzalloc(&client->dev, sizeof(struct mp2985_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + memcpy(&data->info, &mp2985_info, sizeof(mp2985_info)); + + return pmbus_do_probe(client, &data->info); +} + +static const struct i2c_device_id mp2985_id[] = { + {"mp2985", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mp2985_id); + +static const struct of_device_id __maybe_unused mp2985_of_match[] = { + {.compatible = "mps,mp2985"}, + {} +}; +MODULE_DEVICE_TABLE(of, mp2985_of_match); + +static struct i2c_driver mp2985_driver = { + .driver = { + .name = "mp2985", + .of_match_table = mp2985_of_match, + }, + .probe = mp2985_probe, + .id_table = mp2985_id, +}; + +module_i2c_driver(mp2985_driver); + +MODULE_AUTHOR("Wensheng Wang "); +MODULE_DESCRIPTION("PMBus driver for MPS MP2985 device"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); From a7c5aab8105d04d0784deabaa544f2fe581cd661 Mon Sep 17 00:00:00 2001 From: Flaviu Nistor Date: Fri, 17 Apr 2026 08:45:11 +0300 Subject: [PATCH 392/655] docs: hwmon: (lm75) Add section for sysfs interface Similar to other HWMON sensors add a section in the documentation describing the sysfs attributes, their permissions and a short description. Signed-off-by: Flaviu Nistor Link: https://lore.kernel.org/r/20260417054511.5432-1-flaviu.nistor@gmail.com [groeck: Removed trailing ":" from attribute names; fixed minor typo] Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm75.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/hwmon/lm75.rst b/Documentation/hwmon/lm75.rst index 4269da04508e..ca46754e028b 100644 --- a/Documentation/hwmon/lm75.rst +++ b/Documentation/hwmon/lm75.rst @@ -181,3 +181,19 @@ is supported by this driver, other specific enhancements are not. The LM77 is not supported, contrary to what we pretended for a long time. Both chips are simply not compatible, value encoding differs. + +sysfs-Interface +--------------- + +The following list includes the sysfs attributes that the driver provides, their +permissions and a short description: + +=============================== ======= =========================================== +Name Perm Description +=============================== ======= =========================================== +temp1_input RO Temperature input +temp1_label RO Descriptive name for the sensor +temp1_max RW Maximum temperature +temp1_max_hyst RW Maximum hysteresis temperature +update_interval RW Update conversions interval in milliseconds +=============================== ======= =========================================== From 42ef8bb116dae7610b0af65d7d819cd9239ad121 Mon Sep 17 00:00:00 2001 From: Flaviu Nistor Date: Fri, 17 Apr 2026 08:57:00 +0300 Subject: [PATCH 393/655] hwmon: (lm75) Add explicit default cases in lm75_is_visible() Add explicit default labels to switch statements in lm75_is_visible(). This makes the control flow explicit and improves readability, but also keeps consistency to other usage of the switch statement in the driver. Signed-off-by: Flaviu Nistor Link: https://lore.kernel.org/r/20260417055700.5739-1-flaviu.nistor@gmail.com [groeck: Reformatted description for line length] Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index c283443e363b..a47ce32df983 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -539,6 +539,8 @@ static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, if (config_data->params->num_sample_times > 1) return 0644; return 0444; + default: + break; } break; case hwmon_temp: @@ -555,6 +557,8 @@ static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, if (config_data->params->alarm) return 0444; break; + default: + break; } break; default: From 8480ea35d715995a7261da045b8f3d9340c79f21 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 22 May 2026 15:09:12 +0200 Subject: [PATCH 394/655] regulator: dt-bindings: document the SGM3804 Dual Output regulator Document the SG Micro SGM3804 Single Inductor Dual Output Buck/Boost Converter used to power LCD panels a provide positive and negative power rails with configurable voltage and active discharge function for each output. Reviewed-by: Rob Herring (Arm) Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260522-topic-sm8650-ayaneo-pocket-s2-sgm3804-v5-1-bd6b1c300ecc@linaro.org Signed-off-by: Mark Brown --- .../bindings/regulator/sgmicro,sgm3804.yaml | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/sgmicro,sgm3804.yaml diff --git a/Documentation/devicetree/bindings/regulator/sgmicro,sgm3804.yaml b/Documentation/devicetree/bindings/regulator/sgmicro,sgm3804.yaml new file mode 100644 index 000000000000..3716eaf81aa9 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/sgmicro,sgm3804.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/sgmicro,sgm3804.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SG Micro SGM3804 Single Inductor Dual Output Buck/Boost Converter + +maintainers: + - Neil Armstrong + +description: + The SGM3804 is a dual voltage regulator, designed to support positive/negative + supply for driving LCD panels. It support software-configurable output + switching. The output voltages can be programmed via an I2C compatible interface. + +properties: + compatible: + const: sgmicro,sgm3804 + + reg: + maxItems: 1 + + vin-supply: true + +patternProperties: + "^(pos|neg)$": + type: object + $ref: regulator.yaml# + + properties: + enable-gpios: true + + unevaluatedProperties: false + + required: + - enable-gpios + +required: + - compatible + - reg + - pos + - neg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@3e { + compatible = "sgmicro,sgm3804"; + reg = <0x3e>; + + vin-supply = <&vin_reg>; + + pos { + regulator-name = "outpos"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + }; + + neg { + regulator-name = "outneg"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + }; + }; + }; +... + From 0c47e1a8cf5d0052745553a0aeb2c8c4ab1b5453 Mon Sep 17 00:00:00 2001 From: KancyJoe Date: Fri, 22 May 2026 15:09:13 +0200 Subject: [PATCH 395/655] regulator: add SGM3804 Dual Output driver Add support for the SG Micro SGM3804 Single Inductor Dual Output Buck/Boost Converter used to power LCD panels a provide positive and negative power rails with configurable voltage and active discharge function for each output. The SGM3804 is powered by the enable GPIO pins inputs and only supports I2C write messages. In order to add flexibility and simplify the driver, the regmap cache is enabled and populated with default values since we can't write registers when the 2 GPIOs are down. Signed-off-by: KancyJoe Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260522-topic-sm8650-ayaneo-pocket-s2-sgm3804-v5-2-bd6b1c300ecc@linaro.org Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 + drivers/regulator/Makefile | 1 + drivers/regulator/sgm3804-regulator.c | 314 ++++++++++++++++++++++++++ 3 files changed, 323 insertions(+) create mode 100644 drivers/regulator/sgm3804-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 78076ac6eac4..9fcdeabb2be1 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1490,6 +1490,14 @@ config REGULATOR_SC2731 This driver provides support for the voltage regulators on the SC2731 PMIC. +config REGULATOR_SGM3804 + tristate "SGMicro SGM3804 voltage regulator" + depends on I2C && OF + depends on GPIOLIB + select REGMAP_I2C + help + This driver supports SGMicro SGM3804 dual-output voltage regulator. + config REGULATOR_SKY81452 tristate "Skyworks Solutions SKY81452 voltage regulator" depends on MFD_SKY81452 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 35639f3115fd..98ecbbc3c6b7 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -172,6 +172,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o +obj-$(CONFIG_REGULATOR_SGM3804) += sgm3804-regulator.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o obj-$(CONFIG_REGULATOR_SPACEMIT_P1) += spacemit-p1.o diff --git a/drivers/regulator/sgm3804-regulator.c b/drivers/regulator/sgm3804-regulator.c new file mode 100644 index 000000000000..c3406cfb73d0 --- /dev/null +++ b/drivers/regulator/sgm3804-regulator.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// SGMicro SGM3804 regulator Driver +// +// Copyright (C) 2025 Kancy Joe +// Copyright (C) 2026 Linaro Limited +// Author: Neil Armstrong + +#include +#include +#include +#include +#include +#include +#include + +#define SGM3804_POS_RAIL_VOLTAGE_REG 0x0 +#define SGM3804_NEG_RAIL_VOLTAGE_REG 0x1 +#define SGM3804_RAIL_DISCHARGE_REG 0x3 + +#define RAIL_VOLTAGE_MASK GENMASK(5, 0) + +#define POS_RAIL_DISCHARGE_EN BIT(1) +#define NEG_RAIL_DISCHARGE_EN BIT(0) + +#define RAIL_VOLTAGE_INVALID RAIL_VOLTAGE_MASK +#define RAIL_DISCHARGE_REG_DEFAULT (POS_RAIL_DISCHARGE_EN | NEG_RAIL_DISCHARGE_EN) + +#define SGM3804_VOLTAGES_MAX_SELECTOR 0x2f + +enum { + SGM3804_POS_RAIL = 0, + SGM3804_NEG_RAIL, + SGM3804_RAIL_COUNT, +}; + +/* + * The registers are only writable when the gpio is enabled, so + * we need to use the cache for read operations and set the regmap + * as cache_only when both GPIOs are down. + */ +struct sgm3804_data { + struct regmap *regmap; + /* Protects the regcache state update */ + struct mutex lock; + struct gpio_desc *gpios[SGM3804_RAIL_COUNT]; +}; + +static const struct linear_range sgm3804_voltages[] = { + REGULATOR_LINEAR_RANGE(2400000, 0x20, 0x2f, 100000), + REGULATOR_LINEAR_RANGE(4000000, 0x00, 0x17, 100000), +}; + +/* + * The cache is populated with those hardware default values + * so the regmap_update_bits operation will use the cached + * value to build a new register value and write it when GPIOs + * are enabled. + */ +static const struct reg_default sgm3804_reg_defaults[] = { + { SGM3804_POS_RAIL_VOLTAGE_REG, RAIL_VOLTAGE_INVALID }, + { SGM3804_NEG_RAIL_VOLTAGE_REG, RAIL_VOLTAGE_INVALID }, + { SGM3804_RAIL_DISCHARGE_REG, RAIL_DISCHARGE_REG_DEFAULT }, +}; + +/* Registers are only writable */ +static bool sgm3804_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SGM3804_POS_RAIL_VOLTAGE_REG: + case SGM3804_NEG_RAIL_VOLTAGE_REG: + case SGM3804_RAIL_DISCHARGE_REG: + return true; + default: + return false; + } +} + +/* + * Since all registers are only writeable, regmap will only read from the cache data. + */ +static bool sgm3804_readable_reg(struct device *dev, unsigned int reg) +{ + return false; +} + +static const struct regmap_config sgm3804_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x03, + .writeable_reg = sgm3804_writeable_reg, + .readable_reg = sgm3804_readable_reg, + .cache_type = REGCACHE_MAPLE, + .reg_defaults = sgm3804_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(sgm3804_reg_defaults), +}; + +static int sgm3804_sync_regcache_state(struct sgm3804_data *ctx) +{ + guard(mutex)(&ctx->lock); + + /* If both GPIOs are down, IC is powered down and I2C writes will fail */ + if (!gpiod_get_value_cansleep(ctx->gpios[SGM3804_POS_RAIL]) && + !gpiod_get_value_cansleep(ctx->gpios[SGM3804_NEG_RAIL])) { + regcache_cache_only(ctx->regmap, true); + regcache_mark_dirty(ctx->regmap); + } else { + int ret; + + /* At least a GPIO is up, we can write registers */ + regcache_cache_only(ctx->regmap, false); + ret = regcache_sync(ctx->regmap); + if (ret) { + regcache_cache_only(ctx->regmap, true); + return ret; + } + } + + return 0; +} + +static int sgm3804_get_voltage_sel(struct regulator_dev *rdev) +{ + int ret; + + ret = regulator_get_voltage_sel_regmap(rdev); + if (ret < 0) + return ret; + + /* Force setting a voltage on probe */ + if (ret == RAIL_VOLTAGE_INVALID) + return -ENOTRECOVERABLE; + + return ret; +} + +static int sgm3804_enable(struct regulator_dev *rdev) +{ + struct sgm3804_data *ctx = rdev->reg_data; + int ret; + + ret = gpiod_set_value_cansleep(ctx->gpios[rdev_get_id(rdev)], 1); + if (ret) + return ret; + + ret = sgm3804_sync_regcache_state(ctx); + if (ret) + goto err; + + return 0; + +err: + gpiod_set_value_cansleep(ctx->gpios[rdev_get_id(rdev)], 0); + return ret; +} + +static int sgm3804_disable(struct regulator_dev *rdev) +{ + struct sgm3804_data *ctx = rdev->reg_data; + int ret; + + ret = gpiod_set_value_cansleep(ctx->gpios[rdev_get_id(rdev)], 0); + if (ret) + return ret; + + return sgm3804_sync_regcache_state(ctx); +} + +static int sgm3804_is_enabled(struct regulator_dev *rdev) +{ + struct sgm3804_data *ctx = rdev->reg_data; + + return gpiod_get_value_cansleep(ctx->gpios[rdev_get_id(rdev)]); +} + +static const struct regulator_ops sgm3804_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = sgm3804_get_voltage_sel, + .set_active_discharge = regulator_set_active_discharge_regmap, + .enable = sgm3804_enable, + .disable = sgm3804_disable, + .is_enabled = sgm3804_is_enabled, +}; + +static const struct regulator_desc sgm3804_regulator_desc[] = { + /* Positive Output */ + { + .name = "pos", + .of_match = "pos", + .supply_name = "vin", + .id = SGM3804_POS_RAIL, + .ops = &sgm3804_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = sgm3804_voltages, + .n_linear_ranges = ARRAY_SIZE(sgm3804_voltages), + .n_voltages = SGM3804_VOLTAGES_MAX_SELECTOR + 1, + .vsel_reg = SGM3804_POS_RAIL_VOLTAGE_REG, + .vsel_mask = RAIL_VOLTAGE_MASK, + .active_discharge_on = POS_RAIL_DISCHARGE_EN, + .active_discharge_mask = POS_RAIL_DISCHARGE_EN, + .active_discharge_reg = SGM3804_RAIL_DISCHARGE_REG, + .enable_time = 40000, + .owner = THIS_MODULE, + }, + /* Negative Output */ + { + .name = "neg", + .of_match = "neg", + .supply_name = "vin", + .id = SGM3804_NEG_RAIL, + .ops = &sgm3804_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = sgm3804_voltages, + .n_linear_ranges = ARRAY_SIZE(sgm3804_voltages), + .n_voltages = SGM3804_VOLTAGES_MAX_SELECTOR + 1, + .vsel_reg = SGM3804_NEG_RAIL_VOLTAGE_REG, + .vsel_mask = RAIL_VOLTAGE_MASK, + .active_discharge_on = NEG_RAIL_DISCHARGE_EN, + .active_discharge_mask = NEG_RAIL_DISCHARGE_EN, + .active_discharge_reg = SGM3804_RAIL_DISCHARGE_REG, + .enable_time = 40000, + .owner = THIS_MODULE, + }, +}; + +static int sgm3804_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct sgm3804_data *ctx; + int ret, i; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mutex_init(&ctx->lock); + + ctx->regmap = devm_regmap_init_i2c(i2c, &sgm3804_regmap_config); + if (IS_ERR(ctx->regmap)) + return dev_err_probe(dev, PTR_ERR(ctx->regmap), + "failed to init regmap\n"); + + /* Get enable GPIOs */ + for (i = 0; i < ARRAY_SIZE(sgm3804_regulator_desc); i++) { + const struct regulator_desc *reg = &sgm3804_regulator_desc[i]; + struct fwnode_handle *child; + + child = device_get_named_child_node(dev, reg->of_match); + if (!child) { + dev_err(dev, "missing child '%s'\n", reg->of_match); + return -EINVAL; + } + + ctx->gpios[i] = devm_fwnode_gpiod_get(dev, child, "enable", + GPIOD_ASIS, reg->name); + fwnode_handle_put(child); + if (IS_ERR(ctx->gpios[i])) + return dev_err_probe(dev, PTR_ERR(ctx->gpios[i]), + "failed to get '%s' enable GPIO\n", + reg->name); + } + + ret = sgm3804_sync_regcache_state(ctx); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(sgm3804_regulator_desc); i++) { + struct regulator_config config = { }; + struct regulator_dev *rdev; + + config.dev = dev; + config.regmap = ctx->regmap; + config.of_node = dev_of_node(dev); + config.driver_data = ctx; + rdev = devm_regulator_register(dev, &sgm3804_regulator_desc[i], + &config); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "failed to register regulator %d\n", i); + } + + return 0; +} + +static const struct i2c_device_id sgm3804_id[] = { + { "sgm3804" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sgm3804_id); + +static const struct of_device_id sgm3804_of_match[] = { + { .compatible = "sgmicro,sgm3804" }, + { } +}; +MODULE_DEVICE_TABLE(of, sgm3804_of_match); + +static struct i2c_driver sgm3804_regulator_driver = { + .driver = { + .name = "sgm3804", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = sgm3804_of_match, + }, + .probe = sgm3804_probe, + .id_table = sgm3804_id, +}; + +module_i2c_driver(sgm3804_regulator_driver); + +MODULE_DESCRIPTION("SGMicro SGM3804 regulator Driver"); +MODULE_AUTHOR("Kancy Joe "); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL"); From 82056957e5c42c4060a1d8b1576aad2dfe54e568 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 18 May 2026 17:43:52 -0700 Subject: [PATCH 396/655] spi: omap2-mcspi: Use of_device_get_match_data() Use of_device_get_match_data() to fetch platform match data directly instead of open-coding an of_match_device() lookup. This also lets the driver drop the of_device.h include. Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260519004352.627148-1-rosenp@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index d53f98aa0aac..9cc078acc13c 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -1481,7 +1480,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev) int status = 0, i; u32 regs_offset = 0; struct device_node *node = pdev->dev.of_node; - const struct of_device_id *match; if (of_property_read_bool(node, "spi-slave")) ctlr = devm_spi_alloc_target(&pdev->dev, sizeof(*mcspi)); @@ -1509,10 +1507,9 @@ static int omap2_mcspi_probe(struct platform_device *pdev) mcspi = spi_controller_get_devdata(ctlr); mcspi->ctlr = ctlr; - match = of_match_device(omap_mcspi_of_match, &pdev->dev); - if (match) { + pdata = of_device_get_match_data(&pdev->dev); + if (pdata) { u32 num_cs = 1; /* default number of chipselect */ - pdata = match->data; of_property_read_u32(node, "ti,spi-num-cs", &num_cs); ctlr->num_chipselect = num_cs; From 48c3876a6a6f78578ccd0fec71ef67fd6a3fd6f5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 20 May 2026 17:48:47 +0200 Subject: [PATCH 397/655] docs: submitting-patches: Clarify that "reviewer" is a person Common understanding of word "Reviewer" is: a person performing a review work [1]. Tools are not persons, thus cannot be reviewers in this term. Also tools cannot make statements and cannot take responsibility for the review. Our docs already clearly mark that "Reviewed-by" must come from a person: - "By offering my Reviewed-by: tag, I state that:" Usage of first person "I" and word "state" - "A Reviewed-by tag is *a statement of opinion* that the patch is an appropriate modification of the kernel without any remaining serious" Only a person can make a statement of opinion. - "Any interested reviewer (who has done the work) can offer a Reviewed-by" A person can offer a tag thus above does not grant the tool permission to offer a tag. However this might not be enough, so let's clarify that only a person with a known identity can state the "Reviewer's statement of oversight". Link: https://en.wiktionary.org/wiki/reviewer [1] Cc: Greg Kroah-Hartman Cc: Vlastimil Babka Cc: Andrew Morton Cc: David Hildenbrand Cc: Linus Torvalds Acked-by: Vlastimil Babka (SUSE) Acked-by: Randy Dunlap Reviewed-by: Mark Brown Acked-by: David Hildenbrand (Arm) Reviewed-by: Greg Kroah-Hartman Signed-off-by: Krzysztof Kozlowski Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <20260520154846.162170-2-krzysztof.kozlowski@oss.qualcomm.com> --- Documentation/process/submitting-patches.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index d7290e208e72..cc6a1f73d7f2 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -581,12 +581,12 @@ By offering my Reviewed-by: tag, I state that: A Reviewed-by tag is a statement of opinion that the patch is an appropriate modification of the kernel without any remaining serious -technical issues. Any interested reviewer (who has done the work) can -offer a Reviewed-by tag for a patch. This tag serves to give credit to -reviewers and to inform maintainers of the degree of review which has been -done on the patch. Reviewed-by: tags, when supplied by reviewers known to -understand the subject area and to perform thorough reviews, will normally -increase the likelihood of your patch getting into the kernel. +technical issues. Any interested reviewer (who has done the work and is a +person with known identity) can offer a Reviewed-by tag for a patch. This tag +serves to give credit to reviewers and to inform maintainers of the degree of +review which has been done on the patch. Reviewed-by: tags, when supplied by +reviewers known to understand the subject area and to perform thorough reviews, +will normally increase the likelihood of your patch getting into the kernel. Both Tested-by and Reviewed-by tags, once received on mailing list from tester or reviewer, should be added by author to the applicable patches when sending From a0a6aa2f64cc794331152f8e68977bc73d1ea4e5 Mon Sep 17 00:00:00 2001 From: Daniel Pereira Date: Tue, 19 May 2026 11:00:33 -0300 Subject: [PATCH 398/655] docs: pt_BR: Translate process/kernel-docs.rst into Portuguese Translate Documentation/process/kernel-docs.rst into Portuguese (pt_BR) and update the main index. The content was adapted following the RST formatting rules and the appropriate technical terminology for Brazilian Portuguese. Signed-off-by: Daniel Pereira Signed-off-by: Jonathan Corbet Message-ID: <20260519140035.1031694-1-danielmaraboo@gmail.com> --- Documentation/translations/pt_BR/index.rst | 1 + .../pt_BR/process/kernel-docs.rst | 373 ++++++++++++++++++ 2 files changed, 374 insertions(+) create mode 100644 Documentation/translations/pt_BR/process/kernel-docs.rst diff --git a/Documentation/translations/pt_BR/index.rst b/Documentation/translations/pt_BR/index.rst index 77c1a1cdc963..76936710b06e 100644 --- a/Documentation/translations/pt_BR/index.rst +++ b/Documentation/translations/pt_BR/index.rst @@ -67,6 +67,7 @@ kernel e sobre como ver seu trabalho integrado. :maxdepth: 1 Introdução + Index de documentos do Kernel Regras de licenciamento Como começar Requisitos mínimos diff --git a/Documentation/translations/pt_BR/process/kernel-docs.rst b/Documentation/translations/pt_BR/process/kernel-docs.rst new file mode 100644 index 000000000000..3c8d80ffa567 --- /dev/null +++ b/Documentation/translations/pt_BR/process/kernel-docs.rst @@ -0,0 +1,373 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Índice de Documentação Adicional do Kernel +========================================== + +A necessidade de um documento como este tornou-se evidente na lista de discussão +linux-kernel, uma vez que as mesmas perguntas, solicitando referências de +informações, apareciam repetidamente. + +Felizmente, à medida que cada vez mais pessoas chegam ao GNU/Linux, mais pessoas +se interessam pelo Kernel. No entanto, ler o código-fonte nem sempre é o +suficiente. É fácil entender o código, mas perder os conceitos, a filosofia +e as decisões de design por trás dele. + +Infelizmente, não há muitos documentos disponíveis para iniciantes começarem. +E, mesmo quando existem, não havia um local "bem conhecido" que os centralizasse. +Estas linhas tentam suprir essa falta. + +POR FAVOR, se você conhece algum artigo não listado aqui ou se escrever um novo +documento, inclua uma referência a ele aqui, seguindo o processo de envio de +patches do kernel. Quaisquer correções, ideias ou comentários também são +bem-vindos. + +Todos os documentos estão catalogados com os seguintes campos: o "Título" do +documento, o(s) "Autor(es)", a "URL" onde podem ser encontrados, algumas +"Palavras-chave" úteis para pesquisar tópicos específicos e uma breve +"Descrição" do documento. + +.. note:: + + Os documentos em cada seção deste documento estão ordenados por sua data de + publicação, do mais recente para o mais antigo. O(s) mantenedor(es) deve(m) + remover periodicamente recursos à medida que se tornem obsoletos ou + desatualizados; com exceção de livros fundamentais. + +Documentação na árvore do Kernel +-------------------------------- + +Os manuais Sphinx devem ser compilados com ``make {htmldocs | pdfdocs | epubdocs}``. + + * Nome: **linux/Documentation** + + :Autor: Muitos. + :Localização: Documentation/ + :Palavras-chave: arquivos de texto, Sphinx. + :Descrição: Documentação que acompanha o código-fonte do kernel, + dentro do diretório Documentation. Algumas páginas deste documento + (incluindo este próprio documento) foram movidas para lá e podem + estar mais atualizadas do que a versão web. + +Documentação on-line +-------------------- + + * Título: **Linux Kernel Mailing List Glossary** + + :Autor: diversos + :URL: https://kernelnewbies.org/KernelGlossary + :Data: versão contínua (rolling) + :Palavras-chave: glossário, termos, linux-kernel. + :Descrição: Da introdução: "Este glossário destina-se a ser uma breve + descrição de algumas das siglas e termos que você poderá ouvir durante + as discussões sobre o kernel Linux". + + * Título: **The Linux Kernel Module Programming Guide** + + :Autor: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, + Jim Huang. + :URL: https://sysprog21.github.io/lkmpg/ + :Data: 2021 + :Palavras-chave: módulos, livro GPL, /proc, ioctls, chamadas de sistema, + manipuladores de interrupção. + :Descrição: Um excelente livro sob licença GPL sobre o tópico de + programação de módulos. Repleto de exemplos. Atualmente, a nova versão + está sendo mantida ativamente em https://github.com/sysprog21/lkmpg. + +Livros Publicados +----------------- + + * Title: **The Linux Memory Manager** + + :Autor: Lorenzo Stoakes + :Editora: No Starch Press + :Data: Fevereiro 2025 + :Páginas: 1300 + :ISBN: 978-1718504462 + :Notas: Gerenciamento de memória. Rascunho completo disponível como acesso + antecipado para ré-venda, lançamento completo agendado para o + outono de 2025. Veja https://nostarch.com/linux-memory-manager + para mais informações. + + * Title: **Practical Linux System Administration: A Guide to Installation, Configuration, and Management, 1st Edition** + + :Autor: Kenneth Hess + :Editora: O'Reilly Media + :Data: Maio, 2023 + :Páginas: 246 + :ISBN: 978-1098109035 + :Notas: Administração de sistemas + + * Title: **Linux Kernel Debugging: Leverage proven tools and advanced techniques to effectively debug Linux kernels and kernel modules** + + :Autor: Kaiwan N Billimoria + :Editora: Packt Publishing Ltd + :Data: Agosto, 2022 + :Páginas: 638 + :ISBN: 978-1801075039 + :Notas: Livro sobre depuração (debugging) + + * Title: **Linux Kernel Programming: A Comprehensive Guide to Kernel Internals, Writing Kernel Modules, and Kernel Synchronization** + + :Autor: Kaiwan N Billimoria + :Editora: Packt Publishing Ltd + :Data: Março, 2021 (Segunda edição publicada em 2024) + :Páginas: 754 + :ISBN: 978-1789953435 (O ISBN da segunda edição é 978-1803232225) + + * Title: **Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization: Create user-kernel interfaces, work with peripheral I/O, and handle hardware interrupts** + + :Autor: Kaiwan N Billimoria + :Editora: Packt Publishing Ltd + :Data: Março, 2021 + :Páginas: 452 + :ISBN: 978-1801079518 + + * Title: **Linux System Programming: Talking Directly to the Kernel and C Library** + + :Autor: Robert Love + :Editora: O'Reilly Media + :Data: Junho, 2013 + :Páginas: 456 + :ISBN: 978-1449339531 + :Notas: Livro fundamental + + * Título: **Linux Kernel Development, 3rd Edition** + + :Autor: Robert Love + :Editora: Addison-Wesley + :Data: Julho de 2010 + :Páginas: 440 + :ISBN: 978-0672329463 + :Notas: Livro fundamental + + * Título: **Linux Device Drivers, 3rd Edition** + + :Autores: Jonathan Corbet, Alessandro Rubini e Greg Kroah-Hartman + :Editora: O'Reilly & Associates + :Data: 2005 + :Páginas: 636 + :ISBN: 0-596-00590-3 + :Notas: Livro fundamental. Mais informações em + http://www.oreilly.com/catalog/linuxdrive3/ + Formato PDF, URL: https://lwn.net/Kernel/LDD3/ + + * Título: **The Design of the UNIX Operating System** + + :Autor: Maurice J. Bach + :Editora: Prentice Hall + :Data: 1986 + :Páginas: 471 + :ISBN: 0-13-201757-1 + :Notas: Livro fundamental + +Diversos +-------- + + * Nome: **Cross-Referencing Linux** + + :URL: https://elixir.bootlin.com/ + :Palavras-chave: Navegação em código-fonte. + :Descrição: Outro navegador web para o código-fonte do kernel Linux. + Possui muitas referências cruzadas para variáveis e funções. Você pode + ver onde elas são definidas e onde são utilizadas. + + * Nome: **Linux Weekly News** + + :URL: https://lwn.net + :Palavras-chave: últimas notícias do kernel. + :Descrição: O título diz tudo. Há uma seção fixa sobre o kernel que + resume o trabalho dos desenvolvedores, correções de bugs, novos recursos + e versões produzidas durante a semana. + + * Nome: **The home page of Linux-MM** + + :Autor: A equipe Linux-MM. + :URL: https://linux-mm.org/ + :Palavras-chave: gerenciamento de memória, Linux-MM, mm patches, TODO, + docs, mailing list. + :Descrição: Site dedicado ao desenvolvimento do Gerenciamento de Memória + do Linux. Patches relacionados à memória, HOWTOs, links, desenvolvedores + mm... Não perca se você estiver interessado no desenvolvimento do + gerenciamento de memória! + + * Nome: **Kernel Newbies IRC Channel and Website** + + :URL: https://www.kernelnewbies.org + :Palavras-chave: IRC, novatos, canal, tirar dúvidas. + :Descrição: #kernelnewbies em irc.oftc.net. + O canal #kernelnewbies é uma rede de IRC dedicada ao hacker de kernel + "novato" (newbie). O público consiste principalmente de pessoas que estão + aprendendo sobre o kernel, trabalhando em projetos do kernel ou hackers + profissionais que desejam ajudar pessoas menos experientes. + O #kernelnewbies está na rede de IRC OFTC. + Tente acessar irc.oftc.net como seu servidor e então digite /join #kernelnewbies. + O site kernelnewbies também hospeda artigos, documentos, FAQs... + + * Nome: **linux-kernel mailing list archives and search engines** + + :URL: https://subspace.kernel.org + :URL: https://lore.kernel.org + :Palavras-chave: linux-kernel, arquivos, busca. + :Descrição: Alguns dos arquivadores da lista de discussão linux-kernel. + Se você conhece algum outro (ou um melhor), por favor, me avise. + + * Nome: **The Linux Foundation YouTube channel** + + :URL: https://www.youtube.com/user/thelinuxfoundation + :Palavras-chave: linux, vídeos, linux-foundation, youtube. + :Descrição: A Linux Foundation faz o upload de gravações de vídeo de seus + eventos colaborativos, conferências de Linux (incluindo a LinuxCon) e + outras pesquisas originais e conteúdos relacionados ao Linux e ao + desenvolvimento de software. + +Rust +---- + + * Título: **Rust for Linux** + + :Autor: diversos + :URL: https://rust-for-linux.com/ + :Data: versão contínua (rolling) + :Palavras-chave: glossário, termos, linux-kernel, rust. + :Descrição Do site: "Rust for Linux é o projeto que adiciona suporte à + linguagem Rust ao kernel Linux. Este site pretende ser um hub de links, + documentação e recursos relacionados ao projeto". + + * Título: **Learn Rust the Dangerous Way** + + :Autor: Cliff L. Biffle + :URL: https://cliffle.com/p/dangerust/ + :Data: Acessado em 11 de setembro de 2024 + :Palavras-chave: rust, blog. + :Descrição: Do site: "LRtDW é uma série de artigos que coloca os recursos + do Rust em contexto para programadores C de baixo nível que talvez não + tenham uma formação formal em Ciência da Computação, o tipo de pessoa + que trabalha com firmware, engines de jogos, kernels de SO e afins. + Basicamente, pessoas como eu.". O site ilustra conversões de linha por + linha de C para Rust. + + * Título: **The Rust Book** + + :Autor: Steve Klabnik e Carol Nichols, com contribuições da comunidade Rust + :URL: https://doc.rust-lang.org/book/ + :Data: Acessado em 11 de setembro de 2024 + :Palavras-chave: rust, livro. + :Descrição: Do site: "Este livro abraça totalmente o potencial do Rust para + capacitar seus usuários. É um texto amigável e acessível destinado a + ajudá-lo a elevar não apenas seu conhecimento de Rust, mas também seu + alcance e confiança como programador em geral. Então mergulhe de cabeça, + prepare-se para aprender e bem-vindo à comunidade Rust!". + + * Título: **Rust for the Polyglot Programmer** + + :Autor: Ian Jackson + :URL: https://www.chiark.greenend.org.uk/~ianmdlvl/rust-polyglot/index.html + :Data: Dezembro de 2022 + :Palavras-chave: rust, blog, tooling. + :Descrição: Do site: "Existem muitos guias e introduções ao Rust. Este é + algo diferente: destina-se ao programador experiente que já conhece + muitas outras linguagens de programação. Tento ser abrangente o suficiente + para servir de ponto de partida para qualquer área do Rust, mas evito + entrar em detalhes excessivos, exceto onde as coisas não são como você + poderia esperar. Além disso, este guia não é inteiramente isento de + opiniões, incluindo recomendações de bibliotecas (crates), ferramentas, etc.". + + * Título: **Fasterthanli.me** + + :Autor: Amos Wenger + :URL: https://fasterthanli.me/ + :Data: Acessado em 11 de setembro de 2024 + :Palavras-chave: rust, blog, notícias. + :Descrição: Do site: "Eu crio artigos e vídeos sobre como os computadores + funcionam. Meu conteúdo é de formato longo, didático e exploratório + e frequentemente uma desculpa para ensinar Rust!". + + * Título: **Comprehensive Rust** + + :Autor: Equipe Android do Google + :URL: https://google.github.io/comprehensive-rust/ + :Data: Acessado em 13 de setembro de 2024 + :Palavras-chave: rust, blog. + :Descrição: Do site: "O curso cobre todo o espectro do Rust, desde a + sintaxe básica até tópicos avançados como genéricos e tratamento de erros". + + * Título: **The Embedded Rust Book** + + :Autor: Múltiplos colaboradores, principalmente Jorge Aparicio + :URL: https://docs.rust-embedded.org/book/ + :Data: Acessado em 13 de setembro de 2024 + :Palavras-chave: rust, blog. + :Descrição: Do site: "Um livro introdutório sobre o uso da linguagem de + programação Rust em sistemas embarcados 'Bare Metal', como microcontroladores". + + * Título: **Experiment: Improving the Rust Book** + + :Autor: Cognitive Engineering Lab na Brown University + :URL: https://rust-book.cs.brown.edu/ + :Data: Acessado em 22 de setembro de 2024 + :Palavras-chave: rust, blog. + :Descrição: Do site: "O objetivo deste experimento é avaliar e melhorar o + conteúdo do Rust Book para ajudar as pessoas a aprenderem Rust de forma + mais eficaz". + + * Título: **New Rustacean** (podcast) + + :Autor: Chris Krycho + :URL: https://newrustacean.com/ + :Data: Acessado em 22 de setembro de 2024 + :Palavras-chave: rust, podcast. + :Descrição: Do site: "Este é um podcast sobre aprender a linguagem de + programação Rust do zero! Além desta página inicial elegante, todo o + conteúdo do site é construído com as próprias ferramentas de documentação + do Rust". + + * Título: **Opsem-team** (repositório) + + :Autor: Equipe de semântica operacional (Operational semantics team) + :URL: https://github.com/rust-lang/opsem-team/tree/main + :Data: Acessado em 22 de setembro de 2024 + :Palavras-chave: rust, repositório. + :Descrição: Do README: "A equipe opsem é a sucessora do grupo de trabalho + unsafe-code-guidelines e é responsável por responder a muitas das perguntas + difíceis sobre a semântica do Rust inseguro (unsafe Rust)". + + * Título: **You Can't Spell Trust Without Rust** + + :Autor: Alexis Beingessner + :URL: https://repository.library.carleton.ca/downloads/1j92g820w?locale=en + :Data: 2015 + :Palavras-chave: rust, mestrado, tese. + :Descrição: Esta tese foca no sistema de propriedade (ownership) do Rust, + que garante a segurança de memória ao controlar a manipulação de dados e + o tempo de vida, enquanto também destaca suas limitações e o compara a + sistemas semelhantes no Cyclone e C++. + + * Nome: **Apresentações de Rust no Linux Plumbers (LPC) 2024** + + :Título: Rust microconference + :URL: https://lpc.events/event/18/sessions/186/#20240918 + :Título: Rust for Linux + :URL: https://lpc.events/event/18/contributions/1912/ + :Título: Journey of a C kernel engineer starting a Rust driver project + :URL: https://lpc.events/event/18/contributions/1911/ + :Título: Crafting a Linux kernel scheduler that runs in user-space using Rust + :URL: https://lpc.events/event/18/contributions/1723/ + :Título: openHCL: A Linux and Rust based paravisor + :URL: https://lpc.events/event/18/contributions/1956/ + :Palavras-chave: rust, lpc, apresentações. + :Descrição: Uma série de palestras do LPC relacionadas ao Rust. + + * Nome: **The Rustacean Station Podcast** + + :URL: https://rustacean-station.org/ + :Palavras-chave: rust, podcasts. + :Descrição: Um projeto comunitário para a criação de conteúdo em podcast + sobre a linguagem de programação Rust. + +------- + +Este documento foi originalmente baseado em: + +https://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html + +e escrito por Juan-Mariano de Goyeneche. From 89f332c1ef348e260a885085cd7821d6d72db7ec Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 17 May 2026 18:41:41 +0300 Subject: [PATCH 399/655] docs: threat-model: add missing closing parenthesis Fixes: a03ef333fbd6 ("Documentation: security-bugs: explain what is and is not a security bug") Signed-off-by: Baruch Siach Acked-by: Willy Tarreau Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/process/threat-model.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/process/threat-model.rst b/Documentation/process/threat-model.rst index f177b8d3c1ca..9dd8011dde82 100644 --- a/Documentation/process/threat-model.rst +++ b/Documentation/process/threat-model.rst @@ -176,7 +176,7 @@ regular bug: * problems seen only under development simulators, emulators, or combinations that do not exist on real systems at the time of reporting (issues involving tens of millions of threads, tens of thousands of CPUs, - unrealistic CPU frequencies, RAM sizes or disk capacities, network speeds. + unrealistic CPU frequencies, RAM sizes or disk capacities, network speeds). * issues whose reproduction requires hardware modification or emulation, including fake USB devices that pretend to be another one. From 8a61b8a71e640225c00de982e722220fe85fe93e Mon Sep 17 00:00:00 2001 From: Sakurai Shun Date: Sun, 17 May 2026 13:32:53 +0900 Subject: [PATCH 400/655] docs: fix typo in leds-lp55xx.rst Replace "regsister" with "register" Signed-off-by: Sakurai Shun Signed-off-by: Jonathan Corbet Message-ID: <20260517043303.17111-1-ssh1326@icloud.com> --- Documentation/leds/leds-lp55xx.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/leds/leds-lp55xx.rst b/Documentation/leds/leds-lp55xx.rst index 632e41cec0b5..f60c7ec39816 100644 --- a/Documentation/leds/leds-lp55xx.rst +++ b/Documentation/leds/leds-lp55xx.rst @@ -18,7 +18,7 @@ The LP55xx common driver provides these features using exported functions. lp55xx_init_device() / lp55xx_deinit_device() lp55xx_register_leds() / lp55xx_unregister_leds() - lp55xx_regsister_sysfs() / lp55xx_unregister_sysfs() + lp55xx_register_sysfs() / lp55xx_unregister_sysfs() ( Driver Structure Data ) From f69322f8f8bde6513be5ce09883f825c67df284e Mon Sep 17 00:00:00 2001 From: Sakurai Shun Date: Sun, 17 May 2026 11:24:44 +0900 Subject: [PATCH 401/655] docs: fix typo in user_mode_linux_howto_v2.rst Replace "privilges" with "privileges" Signed-off-by: Sakurai Shun Signed-off-by: Jonathan Corbet Message-ID: <20260517022456.5895-1-ssh1326@icloud.com> --- Documentation/virt/uml/user_mode_linux_howto_v2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/virt/uml/user_mode_linux_howto_v2.rst b/Documentation/virt/uml/user_mode_linux_howto_v2.rst index c37e8e594d12..9224bea5ee9f 100644 --- a/Documentation/virt/uml/user_mode_linux_howto_v2.rst +++ b/Documentation/virt/uml/user_mode_linux_howto_v2.rst @@ -234,7 +234,7 @@ an ioctl to setup the tun interface and/or use raw sockets where needed. This can be achieved by granting the user a particular capability instead of running UML as root. In case of vector transport, a user can add the capability ``CAP_NET_ADMIN`` or ``CAP_NET_RAW`` to the uml binary. -Thenceforth, UML can be run with normal user privilges, along with +Thenceforth, UML can be run with normal user privileges, along with full networking. For example:: From 0b740ec538d6598a439645fa553ba1b5d4b7395d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 16 May 2026 19:33:33 +0200 Subject: [PATCH 402/655] docs: maintainers_include: restore compatibility with Python 3.6 glob root_dir parameter requires Python 3.10, which is more than our current Python minimal requirement. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: <930036c189414f3f7096c22269687489f8566dd9.1778952682.git.mchehab+huawei@kernel.org> --- Documentation/sphinx/maintainers_include.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index be8e566e0363..b8b7282ebe38 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -143,7 +143,7 @@ class MaintainersParser: if not m: return None - doc_list = glob(m.group(1), root_dir=self.base_dir) + doc_list = glob(os.path.join(self.base_dir, m.group(1))) else: doc_list = [text] From ff8b091864cfe535463ecafac00e229b5ca6738a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 16 May 2026 19:33:34 +0200 Subject: [PATCH 403/655] docs: maintainers_include: keep the last entry at the end The last maintainer's entry ("THE REST") is meant to be at the end. Ensure that. While here, use a case-insensitive sort to avoid placing "iSCSI" near the end. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet Message-ID: --- Documentation/sphinx/maintainers_include.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py index b8b7282ebe38..dc9f9e188ffa 100755 --- a/Documentation/sphinx/maintainers_include.py +++ b/Documentation/sphinx/maintainers_include.py @@ -284,7 +284,12 @@ class MaintainersInclude(Include): self.state.document['maintainers_included'] = True - for name, fields in sorted(maint_parser.maint_entries.items()): + # Keep the last entry ("THE REST") in the end + entries = list(maint_parser.maint_entries.keys()) + entries = sorted(entries[:-1], key=str.casefold) + [entries[-1]] + + for name in entries: + fields = maint_parser.maint_entries[name] output += f" * - {name}\n" tag = "-" for field, lines in fields.items(): From 04dba9d9b2e2f4ba03e591a2eea66529686bb25f Mon Sep 17 00:00:00 2001 From: Akiyoshi Kurita Date: Wed, 13 May 2026 22:11:11 +0900 Subject: [PATCH 404/655] docs/ja_JP: translate more of submitting-patches.rst (no-mime) Translate the "No MIME, no links, no compression, no attachments. Just plain text" and "Respond to review comments" sections in Documentation/translations/ja_JP/process/submitting-patches.rst. Keep the wording close to the English text and wrap lines to match the style used in the surrounding Japanese translation. Signed-off-by: Akiyoshi Kurita Acked-by: Akira Yokosawa Signed-off-by: Jonathan Corbet Message-ID: <20260513131111.432772-1-weibu@redadmin.org> --- .../ja_JP/process/submitting-patches.rst | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/Documentation/translations/ja_JP/process/submitting-patches.rst b/Documentation/translations/ja_JP/process/submitting-patches.rst index 928e38a8d34d..165cb3ed94ec 100644 --- a/Documentation/translations/ja_JP/process/submitting-patches.rst +++ b/Documentation/translations/ja_JP/process/submitting-patches.rst @@ -292,3 +292,66 @@ MAINTAINERS ファイルに記載されている MAN-PAGES メンテナに man-pages パッチ、少なくとも変更の通知を送って、情報が マニュアルページに反映されるようにしてください。ユーザー空間 API の 変更は、linux-api@vger.kernel.org にも Cc してください。 + +MIME・リンク・圧縮・添付なし、プレーンテキストのみ +---------------------------------------------------- + +Linus や他のカーネル開発者は、あなたが投稿する変更を読み、 +コメントできる必要があります。カーネル開発者が標準的な +メールツールを使ってあなたの変更を「引用」し、コードの特定の +箇所についてコメントできることが重要です。 + +このため、すべてのパッチはメール本文中に ``inline`` で投稿すべきです。 +これを行う最も簡単な方法は ``git send-email`` を使うことであり、 +強く推奨されます。``git send-email`` の対話型チュートリアルは +https://git-send-email.io で利用できます。 + +``git send-email`` を使わないことを選ぶ場合: + +.. warning:: + + パッチをコピー&ペーストする場合は、エディタの word-wrap によって + パッチが壊れないよう注意してください。 + +圧縮の有無にかかわらず、パッチを MIME 添付ファイルとして添付しては +いけません。多くの一般的なメールアプリケーションは、MIME 添付 +ファイルを常にプレーンテキストとして送信するとは限らず、あなたの +コードにコメントできなくなります。MIME 添付ファイルは Linus が +処理するのにも少し余分な時間がかかるため、MIME 添付された変更が +受け入れられる可能性を下げます。 + +例外: メーラがパッチを壊してしまう場合は、誰かから MIME を使って +再送するよう求められることがあります。 + +パッチを変更せずに送信するようメールクライアントを設定するための +ヒントについては、Documentation/process/email-clients.rst を参照してください。 + + +レビューコメントに返答する +-------------------------- + +あなたのパッチには、ほぼ確実に、パッチを改善する方法について +レビューアからコメントが付きます。それは、あなたのメールへの返信という +形で届きます。それらのコメントには必ず返答してください。レビューアを +無視することは、こちらも無視されるためのよい方法です。コメントに +答えるには、単にそのメールへ返信すれば構いません。コード変更に +つながらないレビューコメントや質問であっても、次のレビューアが状況を +よりよく理解できるように、ほぼ確実にコメントまたは changelog エントリに +反映すべきです。 + +どのような変更を行うのかをレビューアに必ず伝え、時間を割いてくれた +ことに感謝してください。コードレビューは疲れる、時間のかかる作業であり、 +レビューアが不機嫌になることもあります。そのような場合であっても、 +丁寧に返答し、指摘された問題に対応してください。次の版を送るときは、 +cover letter または個々のパッチに ``patch changelog`` を追加し、前回の +投稿との差分を説明してください。詳細は原文の該当節 +("The canonical patch format") を参照してください。 + +.. TODO: Convert to file-local cross-reference when the destination is + translated. + +あなたのパッチにコメントした人には、パッチの Cc リストに追加して、 +新しい版を知らせてください。 + +メールクライアントとメーリングリストでの作法についての推奨事項は、 +Documentation/process/email-clients.rst を参照してください。 From 1af866584f7e69e276a8cfce4cfa172557240ad4 Mon Sep 17 00:00:00 2001 From: Daniel Pereira Date: Fri, 15 May 2026 15:21:58 -0300 Subject: [PATCH 405/655] docs: pt_BR: update minimal software requirements in changes.rst Update the Brazilian Portuguese translation of changes.rst to align with the latest English version. Key changes include: - Updated minimum versions for Rust (1.85.0), bindgen (0.71.1), and pahole (1.22). - Fixed ReST syntax for internal references (:ref:) and external links. - Corrected formatting for tool names and config options using inline code backticks. - Synchronized technical descriptions for udev, kmod, and NFS-utils. v2: - Fix alignment in the minimal software requirements table that broke the build. - Fix Sphinx footnote syntax. Signed-off-by: Daniel Pereira Signed-off-by: Jonathan Corbet Message-ID: <20260515182200.654324-1-danielmaraboo@gmail.com> --- .../translations/pt_BR/process/changes.rst | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Documentation/translations/pt_BR/process/changes.rst b/Documentation/translations/pt_BR/process/changes.rst index 1964c1c93b34..a105581dcf64 100644 --- a/Documentation/translations/pt_BR/process/changes.rst +++ b/Documentation/translations/pt_BR/process/changes.rst @@ -20,7 +20,8 @@ Requisitos Mínimos Atuais Atualize para pelo menos estas revisões de software antes de pensar que encontrou um bug! Se não tiver certeza de qual versão está executando atualmente -, o comando sugerido deve lhe informar. +, o comando sugerido deve lhe informar. Para uma lista dos programas em seu +sistema, incluindo as versões, execute ./scripts/ver_linux. Novamente, tenha em mente que esta lista pressupõe que você já possui um kernel Linux em execução funcional. Além disso, nem todas as ferramentas são @@ -28,20 +29,21 @@ necessárias em todos os sistemas; obviamente, se você não possui nenhum hardw PC Card por exemplo, provavelmente não precisará se preocupar com o pcmciautils. ====================== =============== ======================================== - Programa Versão mínima Comando para verificar a versão +Programa Versão mínima Comando para verificar a versão ====================== =============== ======================================== GNU C 8.1 gcc --version Clang/LLVM (optional) 15.0.0 clang --version -Rust (optional) 1.78.0 rustc --version -bindgen (optional) 0.65.1 bindgen --version +Rust (optional) 1.85.0 rustc --version +bindgen (optional) 0.71.1 bindgen --version GNU make 4.0 make --version bash 4.2 bash --version binutils 2.30 ld -v flex 2.5.35 flex --version +gdb 7.2 gdb --version bison 2.0 bison --version -pahole 1.16 pahole --version +pahole 1.22 pahole --version util-linux 2.10o mount --version -kmod 13 depmod -V +kmod 13 kmod -V e2fsprogs 1.41.4 e2fsck -V jfsutils 1.1.3 fsck.jfs -V xfsprogs 2.6.0 xfs_db -V @@ -52,13 +54,13 @@ quota-tools 3.09 quota -V PPP 2.4.0 pppd --version nfs-utils 1.0.5 showmount --version procps 3.2.0 ps --version -udev 081 udevd --version +udev 081 udevadm --version grub 0.93 grub --version || grub-install --version mcelog 0.6 mcelog --version iptables 1.4.2 iptables -V openssl & libcrypto 1.0.0 openssl version bc 1.06.95 bc --version -Sphinx\ [#f1]_ 3.4.3 sphinx-build --version +Sphinx [#f1]_ 3.4.3 sphinx-build --version GNU tar 1.28 tar --version gtags (opcional) 6.6.5 gtags --version mkimage (opcional) 2017.01 mkimage --version @@ -81,11 +83,11 @@ Clang/LLVM (opcional) --------------------- A versão formal mais recente do clang e dos utilitários LLVM (de acordo com -releases.llvm.org _) é suportada para a compilação +`releases.llvm.org `_) é suportada para a compilação de kernels. Versões anteriores não têm funcionamento garantido, e poderemos remover do kernel soluções de contorno (workarounds) que eram utilizadas para -suportar versões mais antigas. Por favor, veja a documentação adicional em: -ref:Building Linux with Clang/LLVM . +suportar versões mais antigas. Por favor, veja a documentação adicional em +:ref:`Building Linux with Clang/LLVM `. Rust (opcional) --------------- @@ -124,7 +126,7 @@ pkg-config O sistema de compilação, a partir da versão 4.18, requer o pkg-config para verificar as ferramentas kconfig instaladas e para determinar as configurações -de flags para uso em make {g,x}config. Anteriormente, o pkg-config já era +de flags para uso em 'make {g,x}config'. Anteriormente, o pkg-config já era utilizado, mas não era verificado nem documentado. Flex @@ -145,7 +147,7 @@ pahole Desde o Linux 5.2, se CONFIG_DEBUG_INFO_BTF estiver selecionado, o sistema de compilação gera BTF (BPF Type Format) a partir do DWARF no vmlinux, e um pouco -depois para os módulos do kernel também. Isso requer o pahole v1.16 ou superior. +depois para os módulos do kernel também. Isso requer o pahole v1.22 ou superior. Ele pode ser encontrado nos pacotes ``dwarves`` ou ``pahole`` das distribuições, ou em https://fedorapeople.org/~acme/dwarves/. @@ -153,8 +155,8 @@ distribuições, ou em https://fedorapeople.org/~acme/dwarves/. Perl ---- -Você precisará do perl 5 e dos seguintes módulos: Getopt::Long, -Getopt::Std, File::Basename e File::Find para compilar o kernel. +Você precisará do perl 5 e dos seguintes módulos: ``Getopt::Long``, +``Getopt::Std``, ``File::Basename`` e ``File::Find`` para compilar o kernel. Python ------ @@ -191,14 +193,14 @@ gtags / GNU GLOBAL (optional) ----------------------------- A compilação do kernel requer o GNU GLOBAL versão 6.6.5 ou superior para gerar -arquivos de tags através de make gtags. Isso se deve ao uso da flag -C -(--directory) pelo gtags. +arquivos de tags através de make gtags. Isso se deve ao uso da flag ``-C +(--directory)`` pelo ``gtags``. mkimage ------- Esta ferramenta é utilizada ao gerar uma Flat Image Tree (FIT), comumente usada -em plataformas ARM. A ferramenta está disponível através do pacote u-boot-tools +em plataformas ARM. A ferramenta está disponível através do pacote ``u-boot-tools`` ou pode ser compilada a partir do código-fonte do U-Boot. Veja as instruções em https://docs.u-boot.org/en/latest/build/tools.html#building-tools-for-linux @@ -225,13 +227,13 @@ A documentação das funções do Linux está migrando para a documentação emb definições no código-fonte. Esses comentários podem ser combinados com arquivos ReST no diretório Documentation/ para criar uma documentação enriquecida, que pode então ser convertida para arquivos PostScript, HTML, LaTeX, ePUB e PDF. -Para converter do formato ReST para o formato de sua escolha,você precisará do +Para converter do formato ReST para o formato de sua escolha, você precisará do Sphinx. Util-linux ---------- -Novas versões do util-linux oferecem suporte no fdisk para discos maiores, +Novas versões do util-linux oferecem suporte no ``fdisk`` para discos maiores, suporte a novas opções para o mount, reconhecimento de mais tipos de partição e outras funcionalidades interessantes. Você provavelmente vai querer atualizar. @@ -240,23 +242,23 @@ Ksymoops Se o impensável acontecer e o seu kernel sofrer um oops, você pode precisar da ferramenta ksymoops para decodificá-lo, mas na maioria dos casos, não será -necessário. É geralmente preferível compilar o kernel com CONFIG_KALLSYMS para +necessário. É geralmente preferível compilar o kernel com ``CONFIG_KALLSYMS`` para que ele produza dumps legíveis que possam ser usados no estado em que se encontram (isso também gera uma saída melhor do que a do ksymoops). -Se por algum motivo o seu kernel não for compilado com CONFIG_KALLSYMS e você +Se por algum motivo o seu kernel não for compilado com ``CONFIG_KALLSYMS`` e você não tiver como recompilar e reproduzir o oops com essa opção, você ainda poderá decodificá-lo com o ksymoops. Mkinitrd -------- -Estas mudanças no layout da árvore de arquivos /lib/modules também exigem que o +Estas mudanças no layout da árvore de arquivos ``/lib/modules`` também exigem que o mkinitrd seja atualizado. E2fsprogs --------- -A versão mais recente do e2fsprogs corrige diversos bugs no fsck e no debugfs. +A versão mais recente do ``e2fsprogs`` corrige diversos bugs no fsck e no debugfs. Obviamente, é uma boa ideia atualizar. JFSutils @@ -270,8 +272,6 @@ utilitários estão disponíveis: - ``mkfs.jfs`` - cria uma partição formatada em JFS. -- Para o seu arquivo changes.rst, a tradução técnica adequada é: - Outros utilitários de sistema de arquivos também estão disponíveis neste pacote. Xfsprogs @@ -309,7 +309,7 @@ usando o udev, você poderá precisar de:: mknod /dev/cpu/microcode c 10 184 chmod 0644 /dev/cpu/microcode -Se você não estiver usando o udev, você poderá precisar executar os comandos +você poderá precisar executar os comandos acima como root antes de poder usar isso. Você provavelmente também desejará obter o utilitário de espaço de usuário ``microcode_ctl`` para utilizar em conjunto com este driver. @@ -318,7 +318,7 @@ udev ---- O udev é uma aplicação de espaço de usuário para popular o diretório /dev -dinamicamente, apenas com entradas para dispositivos de fat presentes no +dinamicamente, apenas com entradas para dispositivos de fato presentes no sistema. O udev substitui a funcionalidade básica do devfs, permitindo ao mesmo tempo a nomeação persistente de dispositivos. From d7391997ea9c93137bc855fd2b55392acbb7ef63 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Fri, 15 May 2026 21:01:57 +0300 Subject: [PATCH 406/655] docs: sysctl/net: Remove ax25, netrom, rose entries These networking subsystems were removed in commit dd8d4bc28ad7 ("net: remove ax25 and amateur radio (hamradio) subsystem"), but the sysctl directory table still listed them. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260515180200.1490926-1-costa.shul@redhat.com> --- Documentation/admin-guide/sysctl/net.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst index 0724a793798f..3db464e006a3 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -36,12 +36,11 @@ Table : Subdirectories in /proc/sys/net ========= =================== = ========== =================== 802 E802 protocol mptcp Multipath TCP appletalk Appletalk protocol netfilter Network Filter - ax25 AX25 netrom NET/ROM - bridge Bridging rose X.25 PLP layer - core General parameter tipc TIPC - ethernet Ethernet protocol unix Unix domain sockets - ipv4 IP version 4 vsock VSOCK sockets - ipv6 IP version 6 x25 X.25 protocol + bridge Bridging tipc TIPC + core General parameter unix Unix domain sockets + ethernet Ethernet protocol vsock VSOCK sockets + ipv4 IP version 4 x25 X.25 protocol + ipv6 IP version 6 ========= =================== = ========== =================== 1. /proc/sys/net/core - Network core options From ba742531260782a2646bc031f9a12cafebc22594 Mon Sep 17 00:00:00 2001 From: "Vlastimil Babka (SUSE)" Date: Fri, 22 May 2026 16:23:20 +0200 Subject: [PATCH 407/655] mm, slab: add an optimistic __slab_try_return_freelist() When we end up returning extraneous objects during refill to a slab where we just did a get_freelist_nofreeze(), it is likely no other CPU has freed objects to it meanwhile. We can then reattach the remainder of the freelist without having to walk the (potentially cache cold) freelist for finding its tail to connect slab->freelist to it. Add a __slab_try_return_freelist() function that does that. As suggested by Hao Li, it doesn't need to also return the slab to the partial list, because there's code in __refill_objects_node() that already does that for any slabs where we don't detach the freelist in the first place. So we just put the slab back to the pc.slabs list. It's no longer likely that the list will be empty now, so remove the unlikely() annotation. However, also change that code to add to the tail of the partial list instead of head to match what __slab_free() did and avoid a regression, that was reported for the earlier version by the kernel test robot [1]. This change will also affect slabs which were grabbed from the partial list and not refilled from even partially, but those should be much more rare than a partial refill. [1] https://lore.kernel.org/all/202605112204.9382cecf-lkp@intel.com/ Reviewed-by: Hao Li Tested-by: Hao Li Reviewed-by: Harry Yoo (Oracle) Link: https://patch.msgid.link/20260522-b4-refill-optimistic-return-v3-1-2ba78ec1c6ed@kernel.org Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 59 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index a7bd929bcb26..60a765b03b2d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -4326,7 +4326,8 @@ static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags) * Assumes this is performed only for caches without debugging so we * don't need to worry about adding the slab to the full list. */ -static inline void *get_freelist_nofreeze(struct kmem_cache *s, struct slab *slab) +static inline void *get_freelist_nofreeze(struct kmem_cache *s, struct slab *slab, + unsigned int *count) { struct freelist_counters old, new; @@ -4342,6 +4343,7 @@ static inline void *get_freelist_nofreeze(struct kmem_cache *s, struct slab *sla } while (!slab_update_freelist(s, slab, &old, &new, "get_freelist_nofreeze")); + *count = old.objects - old.inuse; return old.freelist; } @@ -5509,6 +5511,34 @@ static noinline void free_to_partial_list( } } +/* + * Try returning (remainder of) the freelist that we just detached from the + * slab. Optimistically assume the slab is still full, so we don't need to find + * the tail of the detached freelist. + * + * Fail if the slab isn't full anymore due to a concurrent free. + */ +static bool __slab_try_return_freelist(struct kmem_cache *s, struct slab *slab, + void *head, int cnt) +{ + struct freelist_counters old, new; + + old.freelist = slab->freelist; + old.counters = slab->counters; + + if (old.freelist) + return false; + + new.freelist = head; + new.counters = old.counters; + new.inuse -= cnt; + + if (!slab_update_freelist(s, slab, &old, &new, "__slab_try_return_freelist")) + return false; + + return true; +} + /* * Slow path handling. This may still be called frequently since objects * have a longer lifetime than the cpu slabs in most processing loads. @@ -7120,41 +7150,48 @@ __refill_objects_node(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int mi list_for_each_entry_safe(slab, slab2, &pc.slabs, slab_list) { + unsigned int count; + list_del(&slab->slab_list); - object = get_freelist_nofreeze(s, slab); + object = get_freelist_nofreeze(s, slab, &count); - while (object && refilled < max) { + while (count && refilled < max) { p[refilled] = object; object = get_freepointer(s, object); maybe_wipe_obj_freeptr(s, p[refilled]); refilled++; + count--; } /* * Freelist had more objects than we can accommodate, we need to - * free them back. We can treat it like a detached freelist, just - * need to find the tail object. + * free them back. First we try to be optimistic and assume the + * slab is still full since we just detached its freelist. + * Otherwise we must find the tail object. */ - if (unlikely(object)) { + if (unlikely(count)) { void *head = object; void *tail; - int cnt = 0; + + if (__slab_try_return_freelist(s, slab, head, count)) { + list_add(&slab->slab_list, &pc.slabs); + break; + } do { tail = object; - cnt++; object = get_freepointer(s, object); } while (object); - __slab_free(s, slab, head, tail, cnt, _RET_IP_); + __slab_free(s, slab, head, tail, count, _RET_IP_); } if (refilled >= max) break; } - if (unlikely(!list_empty(&pc.slabs))) { + if (!list_empty(&pc.slabs)) { spin_lock_irqsave(&n->list_lock, flags); list_for_each_entry_safe(slab, slab2, &pc.slabs, slab_list) { @@ -7163,7 +7200,7 @@ __refill_objects_node(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int mi continue; list_del(&slab->slab_list); - add_partial(n, slab, ADD_TO_HEAD); + add_partial(n, slab, ADD_TO_TAIL); } spin_unlock_irqrestore(&n->list_lock, flags); From 93a51a74d7de4c2e25829caadc49547117de333a Mon Sep 17 00:00:00 2001 From: "Vlastimil Babka (SUSE)" Date: Fri, 22 May 2026 16:23:21 +0200 Subject: [PATCH 408/655] mm, slab: simplify returning slab in __refill_objects_node() When we return slabs to the partial list because we didn't fully refill from them, we observe the min_partial limit when the returned slab is empty, and discard it when over the limit. But it's unlikely for the limit to be reached while we were refilling, and the worst outcome is to have temporarily more free slabs on the list than necessary. So just drop that code and simplify the function. Link: https://patch.msgid.link/20260522-b4-refill-optimistic-return-v3-2-2ba78ec1c6ed@kernel.org Reviewed-by: Hao Li Tested-by: Hao Li Reviewed-by: Harry Yoo (Oracle) Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 60a765b03b2d..ff667b22bc04 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -7196,21 +7196,11 @@ __refill_objects_node(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int mi list_for_each_entry_safe(slab, slab2, &pc.slabs, slab_list) { - if (unlikely(!slab->inuse && n->nr_partial >= s->min_partial)) - continue; - list_del(&slab->slab_list); add_partial(n, slab, ADD_TO_TAIL); } spin_unlock_irqrestore(&n->list_lock, flags); - - /* any slabs left are completely free and for discard */ - list_for_each_entry_safe(slab, slab2, &pc.slabs, slab_list) { - - list_del(&slab->slab_list); - discard_slab(s, slab); - } } return refilled; From c996bad23b9164cfbdd6881f51316622e2a32210 Mon Sep 17 00:00:00 2001 From: Wilson Zeng Date: Sun, 17 May 2026 00:40:33 +0800 Subject: [PATCH 409/655] mm/slub: fix typo in sheaves comment Fix a typo in the comment describing oversize sheaves handling: "area" should be "are". Signed-off-by: Wilson Zeng Acked-by: Harry Yoo (Oracle) Link: https://patch.msgid.link/20260516164033.1566208-1-cheng20011202@gmail.com Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index ff667b22bc04..fad0d2b6a33d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5024,7 +5024,7 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size) /* * we do not need to care about pfmemalloc here because oversize - * sheaves area always flushed and freed when returned + * sheaves are always flushed and freed when returned */ if (!__kmem_cache_alloc_bulk(s, gfp, size, &sheaf->objects[0])) { From b282e237ee4c3b0cbab762ef2e9a08a5d4a21b6d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 27 May 2026 21:37:44 +0200 Subject: [PATCH 410/655] regulator: remove used pcap regulator driver The platform was removed a few years ago, and the mfd driver is also gone now, so it is impossible to build or use it. Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20260527193837.3436148-1-arnd@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 7 - drivers/regulator/Makefile | 1 - drivers/regulator/pcap-regulator.c | 274 ----------------------------- 3 files changed, 282 deletions(-) delete mode 100644 drivers/regulator/pcap-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 9fcdeabb2be1..47d55fb141be 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1055,13 +1055,6 @@ config REGULATOR_PF9453 help Say y here to support the NXP PF9453 PMIC regulator driver. -config REGULATOR_PCAP - tristate "Motorola PCAP2 regulator driver" - depends on EZX_PCAP - help - This driver provides support for the voltage regulators of the - PCAP2 PMIC. - config REGULATOR_PF0900 tristate "NXP PF0900/PF0901/PF09XX regulator driver" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 98ecbbc3c6b7..134eee274dbf 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -142,7 +142,6 @@ obj-$(CONFIG_REGULATOR_PV88090) += pv88090-regulator.o obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o -obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_RAA215300) += raa215300.o obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY) += rpi-panel-attiny-regulator.o obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2) += rpi-panel-v2-regulator.o diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c deleted file mode 100644 index 441c9344aef7..000000000000 --- a/drivers/regulator/pcap-regulator.c +++ /dev/null @@ -1,274 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * PCAP2 Regulator Driver - * - * Copyright (c) 2009 Daniel Ribeiro - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static const unsigned int V1_table[] = { - 2775000, 1275000, 1600000, 1725000, 1825000, 1925000, 2075000, 2275000, -}; - -static const unsigned int V2_table[] = { - 2500000, 2775000, -}; - -static const unsigned int V3_table[] = { - 1075000, 1275000, 1550000, 1725000, 1876000, 1950000, 2075000, 2275000, -}; - -static const unsigned int V4_table[] = { - 1275000, 1550000, 1725000, 1875000, 1950000, 2075000, 2275000, 2775000, -}; - -static const unsigned int V5_table[] = { - 1875000, 2275000, 2475000, 2775000, -}; - -static const unsigned int V6_table[] = { - 2475000, 2775000, -}; - -static const unsigned int V7_table[] = { - 1875000, 2775000, -}; - -#define V8_table V4_table - -static const unsigned int V9_table[] = { - 1575000, 1875000, 2475000, 2775000, -}; - -static const unsigned int V10_table[] = { - 5000000, -}; - -static const unsigned int VAUX1_table[] = { - 1875000, 2475000, 2775000, 3000000, -}; - -#define VAUX2_table VAUX1_table - -static const unsigned int VAUX3_table[] = { - 1200000, 1200000, 1200000, 1200000, 1400000, 1600000, 1800000, 2000000, - 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 3600000, -}; - -static const unsigned int VAUX4_table[] = { - 1800000, 1800000, 3000000, 5000000, -}; - -static const unsigned int VSIM_table[] = { - 1875000, 3000000, -}; - -static const unsigned int VSIM2_table[] = { - 1875000, -}; - -static const unsigned int VVIB_table[] = { - 1300000, 1800000, 2000000, 3000000, -}; - -static const unsigned int SW1_table[] = { - 900000, 950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, - 1300000, 1350000, 1400000, 1450000, 1500000, 1600000, 1875000, 2250000, -}; - -#define SW2_table SW1_table - -struct pcap_regulator { - const u8 reg; - const u8 en; - const u8 index; - const u8 stby; - const u8 lowpwr; -}; - -#define NA 0xff - -#define VREG_INFO(_vreg, _reg, _en, _index, _stby, _lowpwr) \ - [_vreg] = { \ - .reg = _reg, \ - .en = _en, \ - .index = _index, \ - .stby = _stby, \ - .lowpwr = _lowpwr, \ - } - -static const struct pcap_regulator vreg_table[] = { - VREG_INFO(V1, PCAP_REG_VREG1, 1, 2, 18, 0), - VREG_INFO(V2, PCAP_REG_VREG1, 5, 6, 19, 22), - VREG_INFO(V3, PCAP_REG_VREG1, 7, 8, 20, 23), - VREG_INFO(V4, PCAP_REG_VREG1, 11, 12, 21, 24), - /* V5 STBY and LOWPWR are on PCAP_REG_VREG2 */ - VREG_INFO(V5, PCAP_REG_VREG1, 15, 16, 12, 19), - - VREG_INFO(V6, PCAP_REG_VREG2, 1, 2, 14, 20), - VREG_INFO(V7, PCAP_REG_VREG2, 3, 4, 15, 21), - VREG_INFO(V8, PCAP_REG_VREG2, 5, 6, 16, 22), - VREG_INFO(V9, PCAP_REG_VREG2, 9, 10, 17, 23), - VREG_INFO(V10, PCAP_REG_VREG2, 10, NA, 18, 24), - - VREG_INFO(VAUX1, PCAP_REG_AUXVREG, 1, 2, 22, 23), - /* VAUX2 ... VSIM2 STBY and LOWPWR are on PCAP_REG_LOWPWR */ - VREG_INFO(VAUX2, PCAP_REG_AUXVREG, 4, 5, 0, 1), - VREG_INFO(VAUX3, PCAP_REG_AUXVREG, 7, 8, 2, 3), - VREG_INFO(VAUX4, PCAP_REG_AUXVREG, 12, 13, 4, 5), - VREG_INFO(VSIM, PCAP_REG_AUXVREG, 17, 18, NA, 6), - VREG_INFO(VSIM2, PCAP_REG_AUXVREG, 16, NA, NA, 7), - VREG_INFO(VVIB, PCAP_REG_AUXVREG, 19, 20, NA, NA), - - VREG_INFO(SW1, PCAP_REG_SWCTRL, 1, 2, NA, NA), - VREG_INFO(SW2, PCAP_REG_SWCTRL, 6, 7, NA, NA), - /* SW3 STBY is on PCAP_REG_AUXVREG */ - VREG_INFO(SW3, PCAP_REG_SWCTRL, 11, 12, 24, NA), - - /* SWxS used to control SWx voltage on standby */ -/* VREG_INFO(SW1S, PCAP_REG_LOWPWR, NA, 12, NA, NA), - VREG_INFO(SW2S, PCAP_REG_LOWPWR, NA, 20, NA, NA), */ -}; - -static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev, - unsigned selector) -{ - const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; - void *pcap = rdev_get_drvdata(rdev); - - /* the regulator doesn't support voltage switching */ - if (rdev->desc->n_voltages == 1) - return -EINVAL; - - return ezx_pcap_set_bits(pcap, vreg->reg, - (rdev->desc->n_voltages - 1) << vreg->index, - selector << vreg->index); -} - -static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev) -{ - const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; - void *pcap = rdev_get_drvdata(rdev); - u32 tmp; - - if (rdev->desc->n_voltages == 1) - return 0; - - ezx_pcap_read(pcap, vreg->reg, &tmp); - tmp = ((tmp >> vreg->index) & (rdev->desc->n_voltages - 1)); - return tmp; -} - -static int pcap_regulator_enable(struct regulator_dev *rdev) -{ - const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; - void *pcap = rdev_get_drvdata(rdev); - - if (vreg->en == NA) - return -EINVAL; - - return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 1 << vreg->en); -} - -static int pcap_regulator_disable(struct regulator_dev *rdev) -{ - const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; - void *pcap = rdev_get_drvdata(rdev); - - if (vreg->en == NA) - return -EINVAL; - - return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 0); -} - -static int pcap_regulator_is_enabled(struct regulator_dev *rdev) -{ - const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; - void *pcap = rdev_get_drvdata(rdev); - u32 tmp; - - if (vreg->en == NA) - return -EINVAL; - - ezx_pcap_read(pcap, vreg->reg, &tmp); - return (tmp >> vreg->en) & 1; -} - -static const struct regulator_ops pcap_regulator_ops = { - .list_voltage = regulator_list_voltage_table, - .set_voltage_sel = pcap_regulator_set_voltage_sel, - .get_voltage_sel = pcap_regulator_get_voltage_sel, - .enable = pcap_regulator_enable, - .disable = pcap_regulator_disable, - .is_enabled = pcap_regulator_is_enabled, -}; - -#define VREG(_vreg) \ - [_vreg] = { \ - .name = #_vreg, \ - .id = _vreg, \ - .n_voltages = ARRAY_SIZE(_vreg##_table), \ - .volt_table = _vreg##_table, \ - .ops = &pcap_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - } - -static const struct regulator_desc pcap_regulators[] = { - VREG(V1), VREG(V2), VREG(V3), VREG(V4), VREG(V5), VREG(V6), VREG(V7), - VREG(V8), VREG(V9), VREG(V10), VREG(VAUX1), VREG(VAUX2), VREG(VAUX3), - VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2), -}; - -static int pcap_regulator_probe(struct platform_device *pdev) -{ - struct regulator_dev *rdev; - void *pcap = dev_get_drvdata(pdev->dev.parent); - struct regulator_config config = { }; - - config.dev = &pdev->dev; - config.init_data = dev_get_platdata(&pdev->dev); - config.driver_data = pcap; - - rdev = devm_regulator_register(&pdev->dev, &pcap_regulators[pdev->id], - &config); - if (IS_ERR(rdev)) - return PTR_ERR(rdev); - - platform_set_drvdata(pdev, rdev); - - return 0; -} - -static struct platform_driver pcap_regulator_driver = { - .driver = { - .name = "pcap-regulator", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - }, - .probe = pcap_regulator_probe, -}; - -static int __init pcap_regulator_init(void) -{ - return platform_driver_register(&pcap_regulator_driver); -} - -static void __exit pcap_regulator_exit(void) -{ - platform_driver_unregister(&pcap_regulator_driver); -} - -subsys_initcall(pcap_regulator_init); -module_exit(pcap_regulator_exit); - -MODULE_AUTHOR("Daniel Ribeiro "); -MODULE_DESCRIPTION("PCAP2 Regulator Driver"); -MODULE_LICENSE("GPL"); From e054cdee673181622bc12f2b5049134ecbc2eeb1 Mon Sep 17 00:00:00 2001 From: Zhushuai Yin Date: Mon, 18 May 2026 22:29:51 +0800 Subject: [PATCH 411/655] crypto: hisilicon/qm - allow VF devices to query hardware isolation status The problem that the VF device cannot obtain the isolation status and isolation threshold of the device is resolved. The accelerator driver can query the device isolation status and threshold via the VF device using the fault query sysfs interface under uacce. Note that only the PF device supports isolation policy configuration, while the VF device is limited to read-only query operations. Signed-off-by: Zhushuai Yin Signed-off-by: Zongyu Wu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 10 +- drivers/crypto/hisilicon/qm.c | 128 ++++++++++++++++++++-- drivers/crypto/hisilicon/sec2/sec_main.c | 10 +- drivers/crypto/hisilicon/zip/zip_main.c | 10 +- include/linux/hisi_acc_qm.h | 1 + 5 files changed, 129 insertions(+), 30 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 357ab5e5887e..a484381f522a 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -1631,12 +1631,10 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_qm_del_list; } - if (qm->uacce) { - ret = uacce_register(qm->uacce); - if (ret) { - pci_err(pdev, "failed to register uacce (%d)!\n", ret); - goto err_with_alg_register; - } + ret = hisi_qm_register_uacce(qm); + if (ret) { + pci_err(pdev, "failed to register uacce (%d)!\n", ret); + goto err_with_alg_register; } if (qm->fun_type == QM_HW_PF && vfs_num) { diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 3ca47e2a9719..9cf52873a891 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -246,6 +246,10 @@ #define QM_QOS_MAX_CIR_U 6 #define QM_AUTOSUSPEND_DELAY 3000 +/* qm isolation state mask */ +#define QM_ISOLATED_STATE BIT(31) +#define QM_ISOLATED_THRESHOLD_MASK GENMASK(15, 0) + /* abnormal status value for stopping queue */ #define QM_STOP_QUEUE_FAIL 1 #define QM_DUMP_SQC_FAIL 3 @@ -286,6 +290,20 @@ enum qm_alg_type { ALG_TYPE_1, }; +/* + * Message format for QM_VF_GET_ISOLATE and QM_PF_SET_ISOLATE commands + * + * These commands use a 32-bit command field (cmd) and 32-bit data field (data) + * + * Command behavior: + * - QM_VF_GET_ISOLATE: VF requests isolation status and threshold + * - QM_PF_SET_ISOLATE: PF sets isolation status and threshold + * + * Data field bit layout: + * - bit31 (MSB): Isolation status flag (1 = isolated, 0 = non-isolated) + * - bit15-0 (16 LSB): Isolation threshold value + * - bit30-16 (15 bits): Reserved + */ enum qm_ifc_cmd { QM_PF_FLR_PREPARE = 0x01, QM_PF_SRST_PREPARE, @@ -296,6 +314,8 @@ enum qm_ifc_cmd { QM_VF_START_FAIL, QM_PF_SET_QOS, QM_VF_GET_QOS, + QM_VF_GET_ISOLATE, + QM_PF_SET_ISOLATE, }; enum qm_basic_type { @@ -1734,7 +1754,7 @@ err_unlock: return ret; } -static int qm_ping_all_vfs(struct hisi_qm *qm, enum qm_ifc_cmd cmd) +static int qm_ping_all_vfs(struct hisi_qm *qm, enum qm_ifc_cmd cmd, u32 data) { struct device *dev = &qm->pdev->dev; u32 vfs_num = qm->vfs_num; @@ -1743,7 +1763,7 @@ static int qm_ping_all_vfs(struct hisi_qm *qm, enum qm_ifc_cmd cmd) int ret; u32 i; - ret = qm->ops->set_ifc_begin(qm, cmd, 0, QM_MB_PING_ALL_VFS); + ret = qm->ops->set_ifc_begin(qm, cmd, data, QM_MB_PING_ALL_VFS); if (ret) { dev_err(dev, "failed to send command(0x%x) to all vfs!\n", cmd); qm->ops->set_ifc_end(qm); @@ -2779,6 +2799,7 @@ static enum uacce_dev_state hisi_qm_get_isolate_state(struct uacce_device *uacce static int hisi_qm_isolate_threshold_write(struct uacce_device *uacce, u32 num) { struct hisi_qm *qm = uacce->priv; + int ret; /* Must be set by PF */ if (uacce->is_vf) @@ -2792,6 +2813,18 @@ static int hisi_qm_isolate_threshold_write(struct uacce_device *uacce, u32 num) /* After the policy is updated, need to reset the hardware err list */ qm_hw_err_destroy(qm); + + if (!qm->vfs_num) { + mutex_unlock(&qm->isolate_data.isolate_lock); + return 0; + } + + /* Notify all VFs to update the isolation threshold. */ + if (test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps)) { + ret = qm_ping_all_vfs(qm, QM_PF_SET_ISOLATE, qm->isolate_data.err_threshold); + if (ret) + dev_err(&qm->pdev->dev, "failed to send command to all VFs set isolate!\n"); + } mutex_unlock(&qm->isolate_data.isolate_lock); return 0; @@ -2802,7 +2835,7 @@ static u32 hisi_qm_isolate_threshold_read(struct uacce_device *uacce) struct hisi_qm *qm = uacce->priv; struct hisi_qm *pf_qm; - if (uacce->is_vf) { + if (uacce->is_vf && !test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps)) { pf_qm = pci_get_drvdata(pci_physfn(qm->pdev)); return pf_qm->isolate_data.err_threshold; } @@ -2889,7 +2922,10 @@ static int qm_alloc_uacce(struct hisi_qm *qm) return -EINVAL; } - uacce->is_vf = pdev->is_virtfn; + if (qm->fun_type == QM_HW_PF) + uacce->is_vf = false; + else + uacce->is_vf = true; uacce->priv = qm; if (qm->ver == QM_HW_V1) @@ -2918,6 +2954,25 @@ static int qm_alloc_uacce(struct hisi_qm *qm) return 0; } +int hisi_qm_register_uacce(struct hisi_qm *qm) +{ + int ret; + + if (!qm->uacce) + return 0; + + dev_info(&qm->pdev->dev, "qm register to uacce\n"); + + if (qm->fun_type == QM_HW_VF && test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps)) { + ret = qm_ping_pf(qm, QM_VF_GET_ISOLATE); + if (ret) + dev_err(&qm->pdev->dev, "failed to send cmd to PF to get isolate!\n"); + } + + return uacce_register(qm->uacce); +} +EXPORT_SYMBOL_GPL(hisi_qm_register_uacce); + /** * qm_frozen() - Try to froze QM to cut continuous queue request. If * there is user on the QM, return failure without doing anything. @@ -4484,7 +4539,7 @@ static int qm_try_stop_vfs(struct hisi_qm *qm, enum qm_ifc_cmd cmd, /* Kunpeng930 supports to notify VFs to stop before PF reset */ if (test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps)) { - ret = qm_ping_all_vfs(qm, cmd); + ret = qm_ping_all_vfs(qm, cmd, 0); if (ret) pci_err(pdev, "failed to send command to all VFs before PF reset!\n"); } else { @@ -4671,6 +4726,7 @@ restart_fail: static int qm_try_start_vfs(struct hisi_qm *qm, enum qm_ifc_cmd cmd) { struct pci_dev *pdev = qm->pdev; + u32 data; int ret; if (!qm->vfs_num) @@ -4684,7 +4740,11 @@ static int qm_try_start_vfs(struct hisi_qm *qm, enum qm_ifc_cmd cmd) /* Kunpeng930 supports to notify VFs to start after PF reset. */ if (test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps)) { - ret = qm_ping_all_vfs(qm, cmd); + data = qm->isolate_data.err_threshold; + if (qm->isolate_data.is_isolate) + data |= QM_ISOLATED_STATE; + /* Broadcasting isolate info via RAS to all VFs. */ + ret = qm_ping_all_vfs(qm, cmd, data); if (ret) pci_warn(pdev, "failed to send cmd to all VFs after PF reset!\n"); } else { @@ -5131,10 +5191,22 @@ static void qm_pf_reset_vf_done(struct hisi_qm *qm) qm_reset_bit_clear(qm); } -static int qm_wait_pf_reset_finish(struct hisi_qm *qm) +static void qm_vf_update_isolate_info(struct hisi_qm *qm, u32 data) +{ + /* Updating the local isolation status. */ + mutex_lock(&qm->isolate_data.isolate_lock); + if (data & QM_ISOLATED_STATE) + qm->isolate_data.is_isolate = true; + else + qm->isolate_data.is_isolate = false; + qm->isolate_data.err_threshold = data & QM_ISOLATED_THRESHOLD_MASK; + mutex_unlock(&qm->isolate_data.isolate_lock); +} + +static int qm_wait_pf_reset_finish(struct hisi_qm *qm, enum qm_stop_reason stop_reason) { struct device *dev = &qm->pdev->dev; - u32 val, cmd; + u32 val, cmd, data; int ret; /* Wait for reset to finish */ @@ -5151,7 +5223,7 @@ static int qm_wait_pf_reset_finish(struct hisi_qm *qm) * Whether message is got successfully, * VF needs to ack PF by clearing the interrupt. */ - ret = qm->ops->get_ifc(qm, &cmd, NULL, 0); + ret = qm->ops->get_ifc(qm, &cmd, &data, 0); qm_clear_cmd_interrupt(qm, 0); if (ret) { dev_err(dev, "failed to get command from PF in reset done!\n"); @@ -5160,10 +5232,14 @@ static int qm_wait_pf_reset_finish(struct hisi_qm *qm) if (cmd != QM_PF_RESET_DONE) { dev_err(dev, "the command(0x%x) is not reset done!\n", cmd); - ret = -EINVAL; + return -EINVAL; } - return ret; + /* The VF processes the device isolation information received from the RAS reset. */ + if (stop_reason == QM_SOFT_RESET) + qm_vf_update_isolate_info(qm, data); + + return 0; } static void qm_pf_reset_vf_process(struct hisi_qm *qm, @@ -5178,7 +5254,7 @@ static void qm_pf_reset_vf_process(struct hisi_qm *qm, qm_cmd_uninit(qm); qm_pf_reset_vf_prepare(qm, stop_reason); - ret = qm_wait_pf_reset_finish(qm); + ret = qm_wait_pf_reset_finish(qm, stop_reason); if (ret) goto err_get_status; @@ -5189,10 +5265,31 @@ static void qm_pf_reset_vf_process(struct hisi_qm *qm, return; err_get_status: + if (stop_reason == QM_SOFT_RESET) { + /* Update local isolation status on PF-VF reset failure. */ + mutex_lock(&qm->isolate_data.isolate_lock); + qm->isolate_data.is_isolate = true; + mutex_unlock(&qm->isolate_data.isolate_lock); + } qm_cmd_init(qm); qm_reset_bit_clear(qm); } +static void qm_vf_get_isolate_data(struct hisi_qm *qm, u32 fun_num) +{ + u32 data = qm->isolate_data.err_threshold; + struct device *dev = &qm->pdev->dev; + int ret; + + if (qm->isolate_data.is_isolate) + data |= QM_ISOLATED_STATE; + + ret = qm_ping_single_vf(qm, QM_PF_SET_ISOLATE, data, fun_num); + if (ret) + dev_err(dev, "failed to send command(0x%x) to VF(%u)!\n", + (unsigned int)QM_PF_SET_ISOLATE, fun_num); +} + static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num) { struct device *dev = &qm->pdev->dev; @@ -5224,6 +5321,13 @@ static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num) case QM_PF_SET_QOS: qm->mb_qos = data; break; + case QM_VF_GET_ISOLATE: + /* Read the isolation policy of the PF during VF initialization. */ + qm_vf_get_isolate_data(qm, fun_num); + break; + case QM_PF_SET_ISOLATE: + qm_vf_update_isolate_info(qm, data); + break; default: dev_err(dev, "unsupported command(0x%x) sent by function(%u)!\n", cmd, fun_num); break; diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 056bd8f4da5a..e8bea1e496f7 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -1449,12 +1449,10 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_qm_del_list; } - if (qm->uacce) { - ret = uacce_register(qm->uacce); - if (ret) { - pci_err(pdev, "failed to register uacce (%d)!\n", ret); - goto err_alg_unregister; - } + ret = hisi_qm_register_uacce(qm); + if (ret) { + pci_err(pdev, "failed to register uacce (%d)!\n", ret); + goto err_alg_unregister; } if (qm->fun_type == QM_HW_PF && vfs_num) { diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 44df9c859bd8..5135b3028cb2 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -1559,12 +1559,10 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_qm_del_list; } - if (qm->uacce) { - ret = uacce_register(qm->uacce); - if (ret) { - pci_err(pdev, "failed to register uacce (%d)!\n", ret); - goto err_qm_alg_unregister; - } + ret = hisi_qm_register_uacce(qm); + if (ret) { + pci_err(pdev, "failed to register uacce (%d)!\n", ret); + goto err_qm_alg_unregister; } if (qm->fun_type == QM_HW_PF && vfs_num > 0) { diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index a6268dc4f7cb..ddecdc2531a2 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -552,6 +552,7 @@ static inline void hisi_qm_del_list(struct hisi_qm *qm, struct hisi_qm_list *qm_ mutex_unlock(&qm_list->lock); } +int hisi_qm_register_uacce(struct hisi_qm *qm); int hisi_qm_q_num_set(const char *val, const struct kernel_param *kp, unsigned int device); int hisi_qm_init(struct hisi_qm *qm); From 789fc74a220b33bb21257c707467985aac536ecd Mon Sep 17 00:00:00 2001 From: Zhushuai Yin Date: Mon, 18 May 2026 22:29:52 +0800 Subject: [PATCH 412/655] crypto: hisilicon/qm - place the interrupt status interface after the PM usage counter To avoid accessing memory of a suspended device, and since the counter interface used by PM involves sleep operations, the counter interface cannot be placed in the interrupt top half. Therefore, the interface for acquiring the interrupt status in the RAS reset flow that resides in the interrupt context needs to be moved to the bottom half for processing. Signed-off-by: Zhushuai Yin Signed-off-by: Zongyu Wu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 34 ++++++++++++++++++---------------- include/linux/hisi_acc_qm.h | 1 - 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 9cf52873a891..71af462daf5b 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -1195,6 +1195,11 @@ static irqreturn_t qm_aeq_thread(int irq, void *data) atomic64_inc(&qm->debug.dfx.aeq_irq_cnt); + if (qm_pm_get_sync(qm)) { + dev_err(&qm->pdev->dev, "failed to get runtime PM for aeq handle\n"); + return IRQ_HANDLED; + } + while (QM_AEQE_PHASE(dw0) == qm->status.aeqc_phase) { type = (dw0 >> QM_AEQE_TYPE_SHIFT) & QM_AEQE_TYPE_MASK; qp_id = dw0 & QM_AEQE_CQN_MASK; @@ -1230,6 +1235,8 @@ static irqreturn_t qm_aeq_thread(int irq, void *data) qm_db(qm, 0, QM_DOORBELL_CMD_AEQ, qm->status.aeq_head, 0); + qm_pm_put_sync(qm); + return IRQ_HANDLED; } @@ -3043,9 +3050,9 @@ void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list) msleep(WAIT_PERIOD); } - while (test_bit(QM_RST_SCHED, &qm->misc_ctl) || - test_bit(QM_RESETTING, &qm->misc_ctl)) - msleep(WAIT_PERIOD); + /* Cancel possible RAS reset process during the uninstallation procedure. */ + if (qm->fun_type == QM_HW_PF) + cancel_work_sync(&qm->rst_work); if (test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps)) flush_work(&qm->cmd_process); @@ -4595,8 +4602,6 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm) if (ret) pci_err(pdev, "failed to stop by vfs in soft reset!\n"); - clear_bit(QM_RST_SCHED, &qm->misc_ctl); - return 0; } @@ -4914,7 +4919,6 @@ static int qm_controller_reset(struct hisi_qm *qm) if (ret) { hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET); hisi_qm_set_hw_reset(qm, QM_RESET_STOP_RX_OFFSET); - clear_bit(QM_RST_SCHED, &qm->misc_ctl); return ret; } @@ -5087,14 +5091,13 @@ static irqreturn_t qm_rsvd_irq(int irq, void *data) static irqreturn_t qm_abnormal_irq(int irq, void *data) { struct hisi_qm *qm = data; - enum acc_err_result ret; atomic64_inc(&qm->debug.dfx.abnormal_irq_cnt); - ret = qm_process_dev_error(qm); - if (ret == ACC_ERR_NEED_RESET && - !test_bit(QM_DRIVER_REMOVING, &qm->misc_ctl) && - !test_and_set_bit(QM_RST_SCHED, &qm->misc_ctl)) + + if (!test_bit(QM_DRIVER_REMOVING, &qm->misc_ctl)) schedule_work(&qm->rst_work); + else + pci_warn(qm->pdev, "Driver is down, need to reload driver!\n"); return IRQ_HANDLED; } @@ -5123,14 +5126,13 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work) ret = qm_pm_get_sync(qm); if (ret) { - clear_bit(QM_RST_SCHED, &qm->misc_ctl); + dev_err(&qm->pdev->dev, "failed to get runtime PM for controller\n"); return; } - /* reset pcie device controller */ - ret = qm_controller_reset(qm); - if (ret) - dev_err(&qm->pdev->dev, "controller reset failed (%d)\n", ret); + ret = qm_process_dev_error(qm); + if (ret == ACC_ERR_NEED_RESET) + (void)qm_controller_reset(qm); qm_pm_put_sync(qm); } diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index ddecdc2531a2..98ff6bcfdebe 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -158,7 +158,6 @@ enum qm_vf_state { enum qm_misc_ctl_bits { QM_DRIVER_REMOVING = 0x0, - QM_RST_SCHED, QM_RESETTING, QM_MODULE_PARAM, }; From 86cad7009fb4ac2c617077bc1c44a51c60d4ae2e Mon Sep 17 00:00:00 2001 From: Zhushuai Yin Date: Mon, 18 May 2026 22:29:53 +0800 Subject: [PATCH 413/655] crypto: hisilicon/qm - support function-level error reset When executing operations on crypto devices, hardware errors are inevitable. For certain errors, a full device reset is required to recover. However, in certain cases, only a specific function may fail, while other functions can still operate normally. A system-wide RAS reset in such cases would unnecessarily impact functioning components. This patch introduces function-level granularity handling, enabling targeted resets of only the error-reporting functions without affecting other operational functions. Signed-off-by: Zhushuai Yin Signed-off-by: Zongyu Wu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 90 +++++++++++++++++++++++++++++++---- include/linux/hisi_acc_qm.h | 1 + 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 71af462daf5b..2b3132595e42 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -246,6 +246,11 @@ #define QM_QOS_MAX_CIR_U 6 #define QM_AUTOSUSPEND_DELAY 3000 +/* qm function err mask */ +#define QM_FUNC_AXI_ERR_ST0 0x100280 +#define QM_RAS_FUNC_ERROR (BIT(0) | BIT(1)) +#define QM_FUNC_RAS_CLEAR_ALL GENMASK(63, 0) + /* qm isolation state mask */ #define QM_ISOLATED_STATE BIT(31) #define QM_ISOLATED_THRESHOLD_MASK GENMASK(15, 0) @@ -314,6 +319,7 @@ enum qm_ifc_cmd { QM_VF_START_FAIL, QM_PF_SET_QOS, QM_VF_GET_QOS, + QM_FUNCTION_RESET, QM_VF_GET_ISOLATE, QM_PF_SET_ISOLATE, }; @@ -493,6 +499,7 @@ static struct qm_typical_qos_table shaper_cbs_s[] = { static void qm_irqs_unregister(struct hisi_qm *qm); static int qm_reset_device(struct hisi_qm *qm); static void hisi_qm_stop_qp(struct hisi_qp *qp); +static int qm_restart(struct hisi_qm *qm); int hisi_qm_q_num_set(const char *val, const struct kernel_param *kp, unsigned int device) @@ -1171,18 +1178,20 @@ static void qm_reset_function(struct hisi_qm *qm) return; } + dev_info(dev, "function reset start...\n"); ret = hisi_qm_stop(qm, QM_DOWN); if (ret) { dev_err(dev, "failed to stop qm when reset function\n"); goto clear_bit; } - ret = hisi_qm_start(qm); + ret = qm_restart(qm); if (ret) dev_err(dev, "failed to start qm when reset function\n"); clear_bit: qm_reset_bit_clear(qm); + dev_info(dev, "function reset end...\n"); } static irqreturn_t qm_aeq_thread(int irq, void *data) @@ -1505,6 +1514,8 @@ static void qm_hw_error_cfg(struct hisi_qm *qm) qm->error_mask = qm_err->nfe | qm_err->ce | qm_err->fe; /* clear QM hw residual error source */ writel(qm->error_mask, qm->io_base + QM_ABNORMAL_INT_SOURCE); + if (qm->ver >= QM_HW_V5) + writeq(QM_FUNC_RAS_CLEAR_ALL, qm->io_base + QM_FUNC_AXI_ERR_ST0); /* configure error type */ writel(qm_err->ce, qm->io_base + QM_RAS_CE_ENABLE); @@ -1610,6 +1621,15 @@ static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm) qm->err_status.is_qm_ecc_mbit = true; qm_log_hw_error(qm, error_status); + /* Trigger func reset only when error is detected in bit 0 or bit 1. */ + if ((qm->ver >= QM_HW_V5) && + (error_status & QM_RAS_FUNC_ERROR) && + (error_status & qm_err->reset_mask) == 0) { + writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE); + writel(qm_err->nfe, qm->io_base + QM_RAS_NFE_ENABLE); + return ACC_ERR_NEED_FUNC_RESET; + } + if (error_status & qm_err->reset_mask) { /* Disable the same error reporting until device is recovered. */ writel(qm_err->nfe & (~error_status), qm->io_base + QM_RAS_NFE_ENABLE); @@ -4364,10 +4384,13 @@ static enum acc_err_result qm_process_dev_error(struct hisi_qm *qm) /* log device error */ dev_ret = qm_dev_err_handle(qm); + if (qm_ret == ACC_ERR_NEED_RESET || dev_ret == ACC_ERR_NEED_RESET) + return ACC_ERR_NEED_RESET; - return (qm_ret == ACC_ERR_NEED_RESET || - dev_ret == ACC_ERR_NEED_RESET) ? - ACC_ERR_NEED_RESET : ACC_ERR_RECOVERED; + if (qm_ret == ACC_ERR_NEED_FUNC_RESET) + return ACC_ERR_NEED_FUNC_RESET; + + return ACC_ERR_RECOVERED; } /** @@ -4392,7 +4415,7 @@ pci_ers_result_t hisi_qm_dev_err_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_DISCONNECT; ret = qm_process_dev_error(qm); - if (ret == ACC_ERR_NEED_RESET) + if (ret == ACC_ERR_NEED_RESET || ret == ACC_ERR_NEED_FUNC_RESET) return PCI_ERS_RESULT_NEED_RESET; return PCI_ERS_RESULT_RECOVERED; @@ -5119,9 +5142,53 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev) } EXPORT_SYMBOL_GPL(hisi_qm_dev_shutdown); +static u64 qm_get_function_mask(struct hisi_qm *qm) +{ + return readq(qm->io_base + QM_FUNC_AXI_ERR_ST0); +} + +static void qm_clear_function_mask(struct hisi_qm *qm, u64 func_mask) +{ + /* Register write 1 clear */ + writeq(func_mask, qm->io_base + QM_FUNC_AXI_ERR_ST0); +} + +static void qm_function_reset(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + u64 func_mask; + u32 fun_num; + int ret; + + func_mask = qm_get_function_mask(qm); + if (!func_mask) { + dev_info(dev, "no function need reset!\n"); + return; + } + + for (fun_num = 1; fun_num <= qm->vfs_num; fun_num++) { + if (func_mask & BIT(fun_num)) { + ret = qm_ping_single_vf(qm, QM_FUNCTION_RESET, 0, fun_num); + /* When function ping fail, user decides the VF reset method. */ + if (ret) + dev_err(dev, "failed to send command(0x%x) to VF(%u)!\n", + (unsigned int)QM_FUNCTION_RESET, fun_num); + } + } + + if (func_mask & BIT(0)) { + dev_info(dev, "function reset start...\n"); + qm_reset_function(qm); + dev_info(dev, "function reset end!\n"); + } + + qm_clear_function_mask(qm, func_mask); +} + static void hisi_qm_controller_reset(struct work_struct *rst_work) { struct hisi_qm *qm = container_of(rst_work, struct hisi_qm, rst_work); + enum acc_err_result err_result; int ret; ret = qm_pm_get_sync(qm); @@ -5130,9 +5197,11 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work) return; } - ret = qm_process_dev_error(qm); - if (ret == ACC_ERR_NEED_RESET) + err_result = qm_process_dev_error(qm); + if (err_result == ACC_ERR_NEED_RESET) (void)qm_controller_reset(qm); + else if (err_result == ACC_ERR_NEED_FUNC_RESET) + qm_function_reset(qm); qm_pm_put_sync(qm); } @@ -5179,7 +5248,7 @@ static void qm_pf_reset_vf_done(struct hisi_qm *qm) int ret; pci_restore_state(pdev); - ret = hisi_qm_start(qm); + ret = qm_restart(qm); if (ret) { dev_err(&pdev->dev, "failed to start QM, ret = %d.\n", ret); cmd = QM_VF_START_FAIL; @@ -5323,6 +5392,11 @@ static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num) case QM_PF_SET_QOS: qm->mb_qos = data; break; + case QM_FUNCTION_RESET: + dev_info(dev, "function reset start...\n"); + qm_reset_function(qm); + dev_info(dev, "function reset end!\n"); + break; case QM_VF_GET_ISOLATE: /* Read the isolation policy of the PF during VF initialization. */ qm_vf_get_isolate_data(qm, fun_num); diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index 98ff6bcfdebe..0a2da1029a3f 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -248,6 +248,7 @@ enum acc_err_result { ACC_ERR_NONE, ACC_ERR_NEED_RESET, ACC_ERR_RECOVERED, + ACC_ERR_NEED_FUNC_RESET, }; struct hisi_qm_err_mask { From e71dc5602b9a29027f6aedd5990d3e8c4f638c8c Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Mon, 18 May 2026 22:29:54 +0800 Subject: [PATCH 414/655] crypto: hisilicon/qm - disable error report before flr Before function level reset, driver first disable device error report and then waits for the device reset to complete. However, when the error is recovered, the error bits will be enabled again, resulting in invalid disable. It is modified to detect that there is no error before disable error report, and then do FLR. Fixes: 7ce396fa12a9 ("crypto: hisilicon - add FLR support") Signed-off-by: Weili Qian Signed-off-by: Zongyu Wu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 2b3132595e42..90b447b934c6 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -5004,8 +5004,6 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev) u32 delay = 0; int ret; - hisi_qm_dev_err_uninit(pf_qm); - /* * Check whether there is an ECC mbit error, If it occurs, need to * wait for soft reset to fix it. @@ -5022,6 +5020,8 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev) return; } + hisi_qm_dev_err_uninit(pf_qm); + /* PF obtains the information of VF by querying the register. */ if (qm->fun_type == QM_HW_PF) qm_cmd_uninit(qm); From b632bd38f2072982c7588629a1437e8ffa05c6e7 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Mon, 18 May 2026 22:29:55 +0800 Subject: [PATCH 415/655] crypto: hisilicon - mask all error type when removing driver Each bit in the error interrupt register corresponds to a specific error type. A bit value of 0 enables the interrupt, and a bit value of 1 disables the interrupt. Currently, when disabling interrupts, it incorrectly enables the interrupt types that were not enabled. Therefore, when disabling interrupts, all bits should be directly written to 1. Signed-off-by: Weili Qian Signed-off-by: Zongyu Wu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 9 +++---- drivers/crypto/hisilicon/qm.c | 30 ++++++----------------- drivers/crypto/hisilicon/sec2/sec_main.c | 3 ++- drivers/crypto/hisilicon/zip/zip_main.c | 10 +++----- 4 files changed, 18 insertions(+), 34 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index a484381f522a..b6903fce6071 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -55,6 +55,8 @@ #define HPRE_RAS_FE_ENB 0x301418 #define HPRE_OOO_SHUTDOWN_SEL 0x301a3c #define HPRE_HAC_RAS_FE_ENABLE 0 +#define HPRE_RAS_MASK_ALL GENMASK(31, 0) +#define HPRE_RAS_CLEAR_ALL GENMASK(31, 0) #define HPRE_CORE_ENB (HPRE_CLSTR_BASE + HPRE_CORE_EN_OFFSET) #define HPRE_CORE_INI_CFG (HPRE_CLSTR_BASE + HPRE_CORE_INI_CFG_OFFSET) @@ -820,11 +822,8 @@ static void hpre_master_ooo_ctrl(struct hisi_qm *qm, bool enable) static void hpre_hw_error_disable(struct hisi_qm *qm) { - struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; - u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; - /* disable hpre hw error interrupts */ - writel(err_mask, qm->io_base + HPRE_INT_MASK); + writel(HPRE_RAS_MASK_ALL, qm->io_base + HPRE_INT_MASK); /* disable HPRE block master OOO when nfe occurs on Kunpeng930 */ hpre_master_ooo_ctrl(qm, false); } @@ -835,7 +834,7 @@ static void hpre_hw_error_enable(struct hisi_qm *qm) u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; /* clear HPRE hw error source if having */ - writel(err_mask, qm->io_base + HPRE_HAC_SOURCE_INT); + writel(HPRE_RAS_CLEAR_ALL, qm->io_base + HPRE_HAC_SOURCE_INT); /* configure error type */ writel(dev_err->ce, qm->io_base + HPRE_RAS_CE_ENB); diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 90b447b934c6..bfee16503c38 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -128,7 +128,6 @@ #define QM_ABNORMAL_INT_SOURCE 0x100000 #define QM_ABNORMAL_INT_MASK 0x100004 -#define QM_ABNORMAL_INT_MASK_VALUE 0x7fff #define QM_ABNORMAL_INT_STATUS 0x100008 #define QM_ABNORMAL_INT_SET 0x10000c #define QM_ABNORMAL_INF00 0x100010 @@ -153,6 +152,8 @@ #define QM_DB_TIMEOUT BIT(10) #define QM_OF_FIFO_OF BIT(11) #define QM_RAS_AXI_ERROR (BIT(0) | BIT(1) | BIT(12)) +#define QM_RAS_MASK_ALL GENMASK(31, 0) +#define QM_RAS_CLEAR_ALL GENMASK(31, 0) #define QM_RESET_WAIT_TIMEOUT 400 #define QM_PEH_VENDOR_ID 0x1000d8 @@ -1504,7 +1505,7 @@ static int qm_get_vft_v2(struct hisi_qm *qm, u32 *base, u32 *number) static void qm_hw_error_init_v1(struct hisi_qm *qm) { - writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK); + writel(QM_RAS_MASK_ALL, qm->io_base + QM_ABNORMAL_INT_MASK); } static void qm_hw_error_cfg(struct hisi_qm *qm) @@ -1513,7 +1514,7 @@ static void qm_hw_error_cfg(struct hisi_qm *qm) qm->error_mask = qm_err->nfe | qm_err->ce | qm_err->fe; /* clear QM hw residual error source */ - writel(qm->error_mask, qm->io_base + QM_ABNORMAL_INT_SOURCE); + writel(QM_RAS_CLEAR_ALL, qm->io_base + QM_ABNORMAL_INT_SOURCE); if (qm->ver >= QM_HW_V5) writeq(QM_FUNC_RAS_CLEAR_ALL, qm->io_base + QM_FUNC_AXI_ERR_ST0); @@ -1526,43 +1527,28 @@ static void qm_hw_error_cfg(struct hisi_qm *qm) static void qm_hw_error_init_v2(struct hisi_qm *qm) { - u32 irq_unmask; - qm_hw_error_cfg(qm); - irq_unmask = ~qm->error_mask; - irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK); - writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK); + writel(~qm->error_mask, qm->io_base + QM_ABNORMAL_INT_MASK); } static void qm_hw_error_uninit_v2(struct hisi_qm *qm) { - u32 irq_mask = qm->error_mask; - - irq_mask |= readl(qm->io_base + QM_ABNORMAL_INT_MASK); - writel(irq_mask, qm->io_base + QM_ABNORMAL_INT_MASK); + writel(QM_RAS_MASK_ALL, qm->io_base + QM_ABNORMAL_INT_MASK); } static void qm_hw_error_init_v3(struct hisi_qm *qm) { - u32 irq_unmask; - qm_hw_error_cfg(qm); /* enable close master ooo when hardware error happened */ writel(qm->err_info.qm_err.shutdown_mask, qm->io_base + QM_OOO_SHUTDOWN_SEL); - - irq_unmask = ~qm->error_mask; - irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK); - writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK); + writel(~qm->error_mask, qm->io_base + QM_ABNORMAL_INT_MASK); } static void qm_hw_error_uninit_v3(struct hisi_qm *qm) { - u32 irq_mask = qm->error_mask; - - irq_mask |= readl(qm->io_base + QM_ABNORMAL_INT_MASK); - writel(irq_mask, qm->io_base + QM_ABNORMAL_INT_MASK); + writel(QM_RAS_MASK_ALL, qm->io_base + QM_ABNORMAL_INT_MASK); /* disable close master ooo when hardware error happened */ writel(0x0, qm->io_base + QM_OOO_SHUTDOWN_SEL); diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index e8bea1e496f7..752565200c16 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -48,6 +48,7 @@ #define SEC_OOO_SHUTDOWN_SEL 0x301014 #define SEC_RAS_DISABLE 0x0 #define SEC_AXI_ERROR_MASK (BIT(0) | BIT(1)) +#define SEC_RAS_CLEAR_ALL GENMASK(31, 0) #define SEC_MEM_START_INIT_REG 0x301100 #define SEC_MEM_INIT_DONE_REG 0x301104 @@ -752,7 +753,7 @@ static void sec_hw_error_enable(struct hisi_qm *qm) } /* clear SEC hw error source if having */ - writel(err_mask, qm->io_base + SEC_CORE_INT_SOURCE); + writel(SEC_RAS_CLEAR_ALL, qm->io_base + SEC_CORE_INT_SOURCE); /* enable RAS int */ writel(dev_err->ce, qm->io_base + SEC_RAS_CE_REG); diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 5135b3028cb2..706a73656977 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -64,7 +64,8 @@ #define HZIP_OOO_SHUTDOWN_SEL 0x30120C #define HZIP_SRAM_ECC_ERR_NUM_SHIFT 16 #define HZIP_SRAM_ECC_ERR_ADDR_SHIFT 24 -#define HZIP_CORE_INT_MASK_ALL GENMASK(12, 0) +#define HZIP_CORE_INT_MASK_ALL GENMASK(31, 0) +#define HZIP_CORE_RAS_CLEAR_ALL GENMASK(31, 0) #define HZIP_AXI_ERROR_MASK (BIT(2) | BIT(3)) #define HZIP_SQE_SIZE 128 #define HZIP_PF_DEF_Q_NUM 64 @@ -696,7 +697,7 @@ static void hisi_zip_hw_error_enable(struct hisi_qm *qm) } /* clear ZIP hw error source if having */ - writel(err_mask, qm->io_base + HZIP_CORE_INT_SOURCE); + writel(HZIP_CORE_RAS_CLEAR_ALL, qm->io_base + HZIP_CORE_INT_SOURCE); /* configure error type */ writel(dev_err->ce, qm->io_base + HZIP_CORE_INT_RAS_CE_ENB); @@ -713,11 +714,8 @@ static void hisi_zip_hw_error_enable(struct hisi_qm *qm) static void hisi_zip_hw_error_disable(struct hisi_qm *qm) { - struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; - u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; - /* disable ZIP hw error interrupts */ - writel(err_mask, qm->io_base + HZIP_CORE_INT_MASK_REG); + writel(HZIP_CORE_INT_MASK_ALL, qm->io_base + HZIP_CORE_INT_MASK_REG); hisi_zip_master_ooo_ctrl(qm, false); From cc3b6331ccb06ec481439cef464b38cfa35c2802 Mon Sep 17 00:00:00 2001 From: Zongyu Wu Date: Mon, 18 May 2026 22:29:56 +0800 Subject: [PATCH 416/655] crypto: hisilicon/qm - support doorbell enable control The driver notifies the hardware to handle task through doorbell. Currently, doorbell is enabled by default. To prevent the process from sending doorbells during hardware reset scenarios, which could cause the hardware to process doorbells and trigger new errors: For example, when the physical machine is resetting the device, doorbells are still being sent from the virtual machine. Therefore, the driver disables doorbell during hardware unavailability. After hardware initialization is completed, doorbell is enabled, and any task sent during the unavailability period will return errors. The hardware supports the PF to disable doorbells for all functions, while the VF can only disable its own doorbell function. When the PF is reset, it will disable doorbells for all functions. When VF is reset, it only disables its own doorbell and does not affect tasks on other functions. Signed-off-by: Zongyu Wu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 54 +++++++++++++++++++++++++++++++---- include/linux/hisi_acc_qm.h | 12 ++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index bfee16503c38..a951d2ef7833 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -247,6 +247,11 @@ #define QM_QOS_MAX_CIR_U 6 #define QM_AUTOSUSPEND_DELAY 3000 +#define QM_DB_DROP_ALL_FUNC_ENABLE GENMASK(63, 0) +#define QM_DB_DROP_ALL_FUNC_DISABLE 0 +#define QM_DEV_DB_DROP 0x0100250 +#define QM_FUN_DB_DROP 0x0038 + /* qm function err mask */ #define QM_FUNC_AXI_ERR_ST0 0x100280 #define QM_RAS_FUNC_ERROR (BIT(0) | BIT(1)) @@ -577,6 +582,29 @@ static int qm_wait_reset_finish(struct hisi_qm *qm) return 0; } +static void qm_fun_db_ctrl(struct hisi_qm *qm, bool enable) +{ + u32 val; + + if (qm->ver >= QM_HW_V5) { + val = readl(qm->io_base + QM_FUN_DB_DROP); + val = enable ? (val | BIT(0)) : (val & ~BIT(0)); + + writel(val, qm->io_base + QM_FUN_DB_DROP); + } +} + +static void qm_dev_db_ctrl(struct hisi_qm *qm, bool enable) +{ + u64 val; + + if (qm->ver >= QM_HW_V5 && qm->fun_type == QM_HW_PF) { + val = enable ? QM_DB_DROP_ALL_FUNC_ENABLE : QM_DB_DROP_ALL_FUNC_DISABLE; + + writeq(val, qm->io_base + QM_DEV_DB_DROP); + } +} + static int qm_reset_prepare_ready(struct hisi_qm *qm) { struct pci_dev *pdev = qm->pdev; @@ -3434,6 +3462,9 @@ static int __hisi_qm_start(struct hisi_qm *qm) if (ret) return ret; + /* Enables the doorbell function when the device is enabled. */ + qm_dev_db_ctrl(qm, false); + qm_fun_db_ctrl(qm, false); qm_init_prefetch(qm); qm_enable_eq_aeq_interrupts(qm); @@ -3541,7 +3572,7 @@ static void qm_invalid_queues(struct hisi_qm *qm) if (qm->status.stop_reason == QM_NORMAL) return; - if (qm->status.stop_reason == QM_DOWN) + if (qm->status.stop_reason == QM_DOWN || qm->status.stop_reason == QM_SHUTDOWN) hisi_qm_cache_wb(qm); for (i = 0; i < qm->qp_num; i++) { @@ -3585,6 +3616,8 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) if (qm->status.stop_reason != QM_NORMAL) { hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET); + if (qm->status.stop_reason != QM_SHUTDOWN) + qm_fun_db_ctrl(qm, true); /* * When performing soft reset, the hardware will no longer * do tasks, and the tasks in the device will be flushed @@ -4611,6 +4644,8 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm) if (ret) pci_err(pdev, "failed to stop by vfs in soft reset!\n"); + qm_dev_db_ctrl(qm, true); + return 0; } @@ -5019,16 +5054,25 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev) ret = hisi_qm_stop(qm, QM_DOWN); if (ret) { pci_err(pdev, "Failed to stop QM, ret = %d.\n", ret); - hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET); - hisi_qm_set_hw_reset(qm, QM_RESET_STOP_RX_OFFSET); - return; + goto err_prepare; } ret = qm_wait_vf_prepare_finish(qm); if (ret) pci_err(pdev, "failed to stop by vfs in FLR!\n"); + qm_dev_db_ctrl(qm, true); + pci_info(pdev, "FLR resetting...\n"); + + return; + +err_prepare: + pci_info(pdev, "FLR resetting prepare failed!\n"); + atomic_set(&qm->status.flags, QM_STOP); + hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET); + hisi_qm_set_hw_reset(qm, QM_RESET_STOP_RX_OFFSET); + qm_dev_db_ctrl(qm, true); } EXPORT_SYMBOL_GPL(hisi_qm_reset_prepare); @@ -5122,7 +5166,7 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev) struct hisi_qm *qm = pci_get_drvdata(pdev); int ret; - ret = hisi_qm_stop(qm, QM_DOWN); + ret = hisi_qm_stop(qm, QM_SHUTDOWN); if (ret) dev_err(&pdev->dev, "Fail to stop qm in shutdown!\n"); } diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index 0a2da1029a3f..f7570a409905 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -115,10 +115,22 @@ #define QM_ECC_MBIT BIT(2) +/** + * enum qm_stop_reason - Queue manager stop reasons + * @QM_NORMAL: Graceful stop. Used for device unbind, driver removal, + * or runtime power management (runtime_suspend). + * @QM_SOFT_RESET: Error recovery reset. Triggered by unrecoverable hardware + * errors (e.g., PCIe AER, timeout) to recover device state. + * @QM_DOWN: Function Level Reset. Used when the device needs to + * be reset at the function level without resetting the link. + * @QM_SHUTDOWN: System shutdown. Used during system poweroff, reboot, or + * kexec to ensure hardware is in a safe state. + */ enum qm_stop_reason { QM_NORMAL, QM_SOFT_RESET, QM_DOWN, + QM_SHUTDOWN, }; enum qm_state { From 8cfd577a5c9e37f3a05088aecf6112dce0f36b14 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Mon, 18 May 2026 23:22:56 +0200 Subject: [PATCH 417/655] crypto: inside-secure/eip93 - Drop superfluous blank line No need for a blank line. Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Herbert Xu --- drivers/crypto/inside-secure/eip93/eip93-main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c index 7dccfdeb7b11..320a37d1f7dc 100644 --- a/drivers/crypto/inside-secure/eip93/eip93-main.c +++ b/drivers/crypto/inside-secure/eip93/eip93-main.c @@ -439,7 +439,6 @@ static int eip93_crypto_probe(struct platform_device *pdev) return -ENOMEM; ret = eip93_desc_init(eip93); - if (ret) return ret; From 85a61bf9145d4097c740ffcf3aa832d930a8913b Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Mon, 18 May 2026 23:24:59 +0200 Subject: [PATCH 418/655] crypto: inside-secure/eip93 - Add check for devm_request_threaded_irq As the potential failure of the devm_request_threaded_irq(), it should be better to check the return value and return error if fails. Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Herbert Xu --- drivers/crypto/inside-secure/eip93/eip93-main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c index 320a37d1f7dc..1a8dabc4ada4 100644 --- a/drivers/crypto/inside-secure/eip93/eip93-main.c +++ b/drivers/crypto/inside-secure/eip93/eip93-main.c @@ -433,6 +433,8 @@ static int eip93_crypto_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(eip93->dev, eip93->irq, eip93_irq_handler, NULL, IRQF_ONESHOT, dev_name(eip93->dev), eip93); + if (ret) + return ret; eip93->ring = devm_kcalloc(eip93->dev, 1, sizeof(*eip93->ring), GFP_KERNEL); if (!eip93->ring) From 03215b8457784540acc741e6331e355b62c6c8ab Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 19 May 2026 12:22:18 +0800 Subject: [PATCH 419/655] crypto: tegra - Fix dma_free_coherent size error When freeing a coherent DMA buffer, the size must match the value that was used during the allocation. Unfortunately the size field in the tegra driver gets overwritten by this point so it no longer matches and creates a warning. Fix this by saving a copy of the size on the stack. Note that the ccm function actually mixes up the inbuf and outbuf sizes, but it doesn't matter because the two sizes are actually equal. Fixes: 1cb328da4e8f ("crypto: tegra - Do not use fixed size buffers") Reporeted-by: Patrick Talbert Signed-off-by: Herbert Xu Reviewed-by: Vladislav Dronov Signed-off-by: Herbert Xu --- drivers/crypto/tegra/tegra-se-aes.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c index 30c78afe3dea..5086e7f140c3 100644 --- a/drivers/crypto/tegra/tegra-se-aes.c +++ b/drivers/crypto/tegra/tegra-se-aes.c @@ -1201,6 +1201,7 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm); struct tegra_se *se = ctx->se; + unsigned int bufsize; int ret; ret = tegra_ccm_crypt_init(req, se, rctx); @@ -1210,14 +1211,15 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) rctx->key_id = ctx->key_id; /* Allocate buffers required */ - rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100; - rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size, + bufsize = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100; + rctx->inbuf.size = bufsize; + rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, bufsize, &rctx->inbuf.addr, GFP_KERNEL); if (!rctx->inbuf.buf) goto out_finalize; - rctx->outbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100; - rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->outbuf.size, + rctx->outbuf.size = bufsize; + rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, bufsize, &rctx->outbuf.addr, GFP_KERNEL); if (!rctx->outbuf.buf) { ret = -ENOMEM; @@ -1254,11 +1256,11 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) } out: - dma_free_coherent(ctx->se->dev, rctx->inbuf.size, + dma_free_coherent(ctx->se->dev, bufsize, rctx->outbuf.buf, rctx->outbuf.addr); out_free_inbuf: - dma_free_coherent(ctx->se->dev, rctx->outbuf.size, + dma_free_coherent(ctx->se->dev, bufsize, rctx->inbuf.buf, rctx->inbuf.addr); if (tegra_key_is_reserved(rctx->key_id)) @@ -1278,6 +1280,7 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm); struct tegra_aead_reqctx *rctx = aead_request_ctx(req); + unsigned int bufsize; int ret; rctx->src_sg = req->src; @@ -1296,16 +1299,17 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) rctx->key_id = ctx->key_id; /* Allocate buffers required */ - rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen; - rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size, + bufsize = rctx->assoclen + rctx->authsize + rctx->cryptlen; + rctx->inbuf.size = bufsize; + rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, bufsize, &rctx->inbuf.addr, GFP_KERNEL); if (!rctx->inbuf.buf) { ret = -ENOMEM; goto out_finalize; } - rctx->outbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen; - rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->outbuf.size, + rctx->outbuf.size = bufsize; + rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, bufsize, &rctx->outbuf.addr, GFP_KERNEL); if (!rctx->outbuf.buf) { ret = -ENOMEM; @@ -1342,11 +1346,11 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) ret = tegra_gcm_do_verify(ctx->se, rctx); out: - dma_free_coherent(ctx->se->dev, rctx->outbuf.size, + dma_free_coherent(ctx->se->dev, bufsize, rctx->outbuf.buf, rctx->outbuf.addr); out_free_inbuf: - dma_free_coherent(ctx->se->dev, rctx->inbuf.size, + dma_free_coherent(ctx->se->dev, bufsize, rctx->inbuf.buf, rctx->inbuf.addr); if (tegra_key_is_reserved(rctx->key_id)) From 370d6c3d411af8d34fcc227c244f4926fc743da7 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 19 May 2026 10:36:32 +0200 Subject: [PATCH 420/655] crypto: ecrdsa - remove empty sig_alg exit callback ecrdsa_exit_tfm() is empty, and sig_alg .exit is optional. The corresponding .init callback is not set either, so there is nothing to release in .exit. Remove the empty function and leave .exit unset. Signed-off-by: Thorsten Blum Reviewed-by: Lukas Wunner Signed-off-by: Herbert Xu --- crypto/ecrdsa.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crypto/ecrdsa.c b/crypto/ecrdsa.c index 0cd7eb367604..93c9e7d76792 100644 --- a/crypto/ecrdsa.c +++ b/crypto/ecrdsa.c @@ -259,16 +259,11 @@ static unsigned int ecrdsa_max_size(struct crypto_sig *tfm) return 2 * ctx->pub_key.ndigits * sizeof(u64); } -static void ecrdsa_exit_tfm(struct crypto_sig *tfm) -{ -} - static struct sig_alg ecrdsa_alg = { .verify = ecrdsa_verify, .set_pub_key = ecrdsa_set_pub_key, .key_size = ecrdsa_key_size, .max_size = ecrdsa_max_size, - .exit = ecrdsa_exit_tfm, .base = { .cra_name = "ecrdsa", .cra_driver_name = "ecrdsa-generic", From 690a5f9e5c972a580565ce544ed1627ccf1e84de Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 20 May 2026 10:51:14 +0800 Subject: [PATCH 421/655] crypto: tegra - Return ENOMEM when input buffer allocation fails for ccm Ensure the ENOMEM error value is set when the input buffer allocation fails in tegra_ccm_do_one_req. Fixes: 1e245948ca0c ("crypto: tegra - finalize crypto req on error") Reported-by: Vladislav Dronov Signed-off-by: Herbert Xu Reviewed-by: Vladislav Dronov Signed-off-by: Herbert Xu --- drivers/crypto/tegra/tegra-se-aes.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c index 5086e7f140c3..9094c03e991f 100644 --- a/drivers/crypto/tegra/tegra-se-aes.c +++ b/drivers/crypto/tegra/tegra-se-aes.c @@ -1215,16 +1215,15 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) rctx->inbuf.size = bufsize; rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, bufsize, &rctx->inbuf.addr, GFP_KERNEL); + ret = -ENOMEM; if (!rctx->inbuf.buf) goto out_finalize; rctx->outbuf.size = bufsize; rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, bufsize, &rctx->outbuf.addr, GFP_KERNEL); - if (!rctx->outbuf.buf) { - ret = -ENOMEM; + if (!rctx->outbuf.buf) goto out_free_inbuf; - } if (!ctx->key_id) { ret = tegra_key_submit_reserved_aes(ctx->se, ctx->key, From 5ec1a676301ad1adab10e6200ead363e5efb4e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 20 May 2026 09:01:28 +0200 Subject: [PATCH 422/655] crypto: atmel-sha204a - Drop of_device_id data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver binds to i2c devices only and thus in the absence of an assignment for .data in the of_device_id array i2c_get_match_data() falls back to .driver_data from the i2c_device_id array. So only provide &atsha204_quality once to reduce duplication. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha204a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index 12eb85b57380..a51e1f1e0088 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -209,8 +209,8 @@ static void atmel_sha204a_remove(struct i2c_client *client) } static const struct of_device_id atmel_sha204a_dt_ids[] = { - { .compatible = "atmel,atsha204", .data = &atsha204_quality }, - { .compatible = "atmel,atsha204a", }, + { .compatible = "atmel,atsha204" }, + { .compatible = "atmel,atsha204a" }, { } }; MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); From 42a58f08b70a7a320c168a1ce15e3fcfc8568708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 20 May 2026 09:01:29 +0200 Subject: [PATCH 423/655] crypto: atmel-sha204a - Use named initializers for struct i2c_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. This patch doesn't modify the compiled array, only its representation in source form benefits. The former was confirmed with x86 and arm64 builds. For consistency also assign .driver_data for the array item that the driver relies on i2c_get_match_data() returning NULL for. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha204a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index a51e1f1e0088..4c9af737b33a 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -216,8 +216,8 @@ static const struct of_device_id atmel_sha204a_dt_ids[] = { MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); static const struct i2c_device_id atmel_sha204a_id[] = { - { "atsha204", (kernel_ulong_t)&atsha204_quality }, - { "atsha204a" }, + { .name = "atsha204", .driver_data = (kernel_ulong_t)&atsha204_quality }, + { .name = "atsha204a", .driver_data = (kernel_ulong_t)NULL }, { } }; MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id); From 59f61b242400939084fe644e4e0cb7f141279ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 20 May 2026 09:01:30 +0200 Subject: [PATCH 424/655] crypto: atmel-ecc - Use named initializers for struct i2c_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. This patch doesn't modify the compiled array, only its representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Herbert Xu --- drivers/crypto/atmel-ecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 9660f6426a84..0ca02995a1de 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -376,8 +376,8 @@ static const struct of_device_id atmel_ecc_dt_ids[] = { MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids); static const struct i2c_device_id atmel_ecc_id[] = { - { "atecc508a" }, - { "atecc608b" }, + { .name = "atecc508a" }, + { .name = "atecc608b" }, { } }; MODULE_DEVICE_TABLE(i2c, atmel_ecc_id); From a43b47340b6bf809f282db8639fc4deea0180208 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 20 May 2026 12:00:30 +0200 Subject: [PATCH 425/655] crypto: octeontx - use strscpy_pad in ucode_load_store Instead of zero-initializing the temporary buffer and then copying into it with strscpy(), use strscpy_pad() to copy the string and zero-pad any trailing bytes. Drop the explicit size argument to further simplify the code since strscpy_pad() can determine it automatically when the destination buffer has a fixed length. Also use strscpy_pad() to check for string truncation instead of the hard-coded OTX_CPT_UCODE_NAME_LENGTH. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c index e0f38d32bc93..205579a6ba2b 100644 --- a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c +++ b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c @@ -1318,7 +1318,7 @@ static ssize_t ucode_load_store(struct device *dev, { struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = { {0} }; char *ucode_filename[OTX_CPT_MAX_ETYPES_PER_GRP]; - char tmp_buf[OTX_CPT_UCODE_NAME_LENGTH] = { 0 }; + char tmp_buf[OTX_CPT_UCODE_NAME_LENGTH]; char *start, *val, *err_msg, *tmp; struct otx_cpt_eng_grps *eng_grps; int grp_idx = 0, ret = -EINVAL; @@ -1326,12 +1326,11 @@ static ssize_t ucode_load_store(struct device *dev, int del_grp_idx = -1; int ucode_idx = 0; - if (count >= OTX_CPT_UCODE_NAME_LENGTH) + if (strscpy_pad(tmp_buf, buf) < 0) return -EINVAL; eng_grps = container_of(attr, struct otx_cpt_eng_grps, ucode_load_attr); err_msg = "Invalid engine group format"; - strscpy(tmp_buf, buf, OTX_CPT_UCODE_NAME_LENGTH); start = tmp_buf; has_se = has_ie = has_ae = false; From 7d3ed20f7e46b3e991936fedd7a28f3ff4aec8d2 Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 20 May 2026 13:33:00 +0100 Subject: [PATCH 426/655] crypto: qat - fix restarting state leak on allocation failure In adf_dev_aer_schedule_reset(), ADF_STATUS_RESTARTING is set before allocating reset_data. If the allocation fails, the function returns -ENOMEM without queuing reset work, so nothing ever clears the bit. This leaves the device permanently stuck in the restarting state, causing all subsequent reset attempts to be silently skipped. Fix this by using test_and_set_bit() to atomically claim the RESTARTING state, preventing duplicate reset scheduling races under concurrent fatal error reporting. If the subsequent allocation fails, clear the bit to restore clean state so future reset attempts can proceed. Cc: stable@vger.kernel.org Fixes: d8cba25d2c68 ("crypto: qat - Intel(R) QAT driver framework") Signed-off-by: Ahsan Atta Co-developed-by: Maksim Lukoshkov Signed-off-by: Maksim Lukoshkov Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index af028488e660..3fc7d13e882c 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -207,13 +207,14 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev, struct adf_reset_dev_data *reset_data; if (!adf_dev_started(accel_dev) || - test_bit(ADF_STATUS_RESTARTING, &accel_dev->status)) + test_and_set_bit(ADF_STATUS_RESTARTING, &accel_dev->status)) return 0; - set_bit(ADF_STATUS_RESTARTING, &accel_dev->status); reset_data = kzalloc_obj(*reset_data); - if (!reset_data) + if (!reset_data) { + clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); return -ENOMEM; + } reset_data->accel_dev = accel_dev; init_completion(&reset_data->compl); reset_data->mode = mode; From 5c6f845e77ec35f9b7b047cc8f9789bf397cdd3e Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 20 May 2026 13:41:55 +0100 Subject: [PATCH 427/655] crypto: qat - protect service table iterations with service_lock The service_table list is protected by service_lock when entries are added or removed (in adf_service_add() and adf_service_remove()), but several functions iterate over the list without holding this lock. A concurrent adf_service_register() or adf_service_unregister() call could modify the list during traversal, leading to list corruption or a use-after-free. Fix this by holding service_lock across all list_for_each_entry() iterations of service_table in adf_dev_init(), adf_dev_start(), adf_dev_stop(), adf_dev_shutdown(), adf_dev_restarting_notify(), adf_dev_restarted_notify(), and adf_error_notifier(). The lock ordering is safe: callers of the static helpers (adf_dev_up() and adf_dev_down()) acquire state_lock before service_lock, and no event_hld callback or service_lock holder ever acquires state_lock in the reverse order. Cc: stable@vger.kernel.org Fixes: d8cba25d2c68 ("crypto: qat - Intel(R) QAT driver framework") Signed-off-by: Ahsan Atta Co-developed-by: Maksim Lukoshkov Signed-off-by: Maksim Lukoshkov Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_init.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c index f9f5696ed476..1c7f9e49914d 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_init.c +++ b/drivers/crypto/intel/qat/qat_common/adf_init.c @@ -155,15 +155,18 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev) * This is to facilitate any ordering dependencies between services * prior to starting any of the accelerators. */ + mutex_lock(&service_lock); list_for_each_entry(service, &service_table, list) { if (service->event_hld(accel_dev, ADF_EVENT_INIT)) { dev_err(&GET_DEV(accel_dev), "Failed to initialise service %s\n", service->name); + mutex_unlock(&service_lock); return -EFAULT; } set_bit(accel_dev->accel_id, service->init_status); } + mutex_unlock(&service_lock); return 0; } @@ -233,15 +236,18 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev) if (ret && ret != -EOPNOTSUPP) return ret; + mutex_lock(&service_lock); list_for_each_entry(service, &service_table, list) { if (service->event_hld(accel_dev, ADF_EVENT_START)) { dev_err(&GET_DEV(accel_dev), "Failed to start service %s\n", service->name); + mutex_unlock(&service_lock); return -EFAULT; } set_bit(accel_dev->accel_id, service->start_status); } + mutex_unlock(&service_lock); clear_bit(ADF_STATUS_STARTING, &accel_dev->status); set_bit(ADF_STATUS_STARTED, &accel_dev->status); @@ -315,6 +321,7 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev) qat_comp_algs_unregister(hw_data->accel_capabilities_ext_mask); clear_bit(ADF_STATUS_COMP_ALGS_REGISTERED, &accel_dev->status); + mutex_lock(&service_lock); list_for_each_entry(service, &service_table, list) { if (!test_bit(accel_dev->accel_id, service->start_status)) continue; @@ -326,6 +333,7 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev) clear_bit(accel_dev->accel_id, service->start_status); } } + mutex_unlock(&service_lock); if (hw_data->stop_timer) hw_data->stop_timer(accel_dev); @@ -375,6 +383,7 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev) &accel_dev->status); } + mutex_lock(&service_lock); list_for_each_entry(service, &service_table, list) { if (!test_bit(accel_dev->accel_id, service->init_status)) continue; @@ -385,6 +394,7 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev) else clear_bit(accel_dev->accel_id, service->init_status); } + mutex_unlock(&service_lock); adf_rl_exit(accel_dev); @@ -419,12 +429,14 @@ int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev) { struct service_hndl *service; + mutex_lock(&service_lock); list_for_each_entry(service, &service_table, list) { if (service->event_hld(accel_dev, ADF_EVENT_RESTARTING)) dev_err(&GET_DEV(accel_dev), "Failed to restart service %s.\n", service->name); } + mutex_unlock(&service_lock); return 0; } @@ -432,12 +444,14 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev) { struct service_hndl *service; + mutex_lock(&service_lock); list_for_each_entry(service, &service_table, list) { if (service->event_hld(accel_dev, ADF_EVENT_RESTARTED)) dev_err(&GET_DEV(accel_dev), "Failed to restart service %s.\n", service->name); } + mutex_unlock(&service_lock); return 0; } @@ -445,12 +459,14 @@ void adf_error_notifier(struct adf_accel_dev *accel_dev) { struct service_hndl *service; + mutex_lock(&service_lock); list_for_each_entry(service, &service_table, list) { if (service->event_hld(accel_dev, ADF_EVENT_FATAL_ERROR)) dev_err(&GET_DEV(accel_dev), "Failed to send error event to %s.\n", service->name); } + mutex_unlock(&service_lock); } int adf_dev_down(struct adf_accel_dev *accel_dev) From 90fe909ed6956a8bcc627cbefe6e225ad4cbcd4b Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Wed, 20 May 2026 13:51:50 +0100 Subject: [PATCH 428/655] crypto: qat - use pci logging variants for PCI-specific messages Replace dev_err(&pdev->dev, ...), dev_info(&pdev->dev, ...) and dev_dbg(&pdev->dev, ...) with pci_err(), pci_info() and pci_dbg() where the log message relates to a PCI subsystem operation such as device enable, BAR mapping, PCI region requests, PCI state save/restore, and SR-IOV management. Messages about driver-level logic (NUMA topology, device matching, accelerator units, capabilities, configuration, DMA) are intentionally left as dev_err() even when a struct pci_dev pointer is in scope, since those concern the device or driver rather than the PCI bus. No functional change. Suggested-by: Andy Shevchenko Signed-off-by: Ahsan Atta Reviewed-by: Giovanni Cabiddu Reviewed-by: Andy Shevchenko Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_420xx/adf_drv.c | 8 +++---- drivers/crypto/intel/qat/qat_4xxx/adf_drv.c | 8 +++---- drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c | 4 ++-- .../crypto/intel/qat/qat_c3xxxvf/adf_drv.c | 2 +- drivers/crypto/intel/qat/qat_c62x/adf_drv.c | 4 ++-- drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c | 2 +- drivers/crypto/intel/qat/qat_common/adf_aer.c | 21 +++++++++---------- .../crypto/intel/qat/qat_common/adf_sriov.c | 2 +- .../crypto/intel/qat/qat_dh895xcc/adf_drv.c | 4 ++-- .../crypto/intel/qat/qat_dh895xccvf/adf_drv.c | 2 +- 10 files changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c index 265bd52778c5..0f0827e2b0bd 100644 --- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c @@ -101,7 +101,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Enable PCI device */ ret = pcim_enable_device(pdev); if (ret) { - dev_err(&pdev->dev, "Can't enable PCI device.\n"); + pci_err(pdev, "Can't enable PCI device.\n"); goto out_err; } @@ -131,7 +131,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ret = pcim_request_all_regions(pdev, pci_name(pdev)); if (ret) { - dev_err(&pdev->dev, "Failed to request PCI regions.\n"); + pci_err(pdev, "Failed to request PCI regions.\n"); goto out_err; } @@ -140,14 +140,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar = &accel_pci_dev->pci_bars[i++]; bar->virt_addr = pcim_iomap(pdev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to ioremap PCI region.\n"); + pci_err(pdev, "Failed to ioremap PCI region.\n"); ret = -ENOMEM; goto out_err; } } if (pci_save_state(pdev)) { - dev_err(&pdev->dev, "Failed to save pci state.\n"); + pci_err(pdev, "Failed to save pci state.\n"); ret = -ENOMEM; goto out_err; } diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c index 681c4dd8f3d2..aa95f762cb4b 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c @@ -103,7 +103,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Enable PCI device */ ret = pcim_enable_device(pdev); if (ret) { - dev_err(&pdev->dev, "Can't enable PCI device.\n"); + pci_err(pdev, "Can't enable PCI device.\n"); goto out_err; } @@ -133,7 +133,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ret = pcim_request_all_regions(pdev, pci_name(pdev)); if (ret) { - dev_err(&pdev->dev, "Failed to request PCI regions.\n"); + pci_err(pdev, "Failed to request PCI regions.\n"); goto out_err; } @@ -142,14 +142,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar = &accel_pci_dev->pci_bars[i++]; bar->virt_addr = pcim_iomap(pdev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to ioremap PCI region.\n"); + pci_err(pdev, "Failed to ioremap PCI region.\n"); ret = -ENOMEM; goto out_err; } } if (pci_save_state(pdev)) { - dev_err(&pdev->dev, "Failed to save pci state.\n"); + pci_err(pdev, "Failed to save pci state.\n"); ret = -ENOMEM; goto out_err; } diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c index ded52744b4fc..e816cc00632f 100644 --- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c @@ -162,14 +162,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar->size = pci_resource_len(pdev, bar_nr); bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); + pci_err(pdev, "Failed to map BAR %d\n", bar_nr); ret = -EFAULT; goto out_err_free_reg; } } if (pci_save_state(pdev)) { - dev_err(&pdev->dev, "Failed to save pci state\n"); + pci_err(pdev, "Failed to save pci state\n"); ret = -ENOMEM; goto out_err_free_reg; } diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c index e7600d284ed3..1c77f0a1882b 100644 --- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c @@ -158,7 +158,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar->size = pci_resource_len(pdev, bar_nr); bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); + pci_err(pdev, "Failed to map BAR %d\n", bar_nr); ret = -EFAULT; goto out_err_free_reg; } diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c index 2ebff5855b01..f48f3b437545 100644 --- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c @@ -162,14 +162,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar->size = pci_resource_len(pdev, bar_nr); bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); + pci_err(pdev, "Failed to map BAR %d\n", bar_nr); ret = -EFAULT; goto out_err_free_reg; } } if (pci_save_state(pdev)) { - dev_err(&pdev->dev, "Failed to save pci state\n"); + pci_err(pdev, "Failed to save pci state\n"); ret = -ENOMEM; goto out_err_free_reg; } diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c index 91e148bb4870..b96f19e31d05 100644 --- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c @@ -158,7 +158,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar->size = pci_resource_len(pdev, bar_nr); bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); + pci_err(pdev, "Failed to map BAR %d\n", bar_nr); ret = -EFAULT; goto out_err_free_reg; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 3fc7d13e882c..d58cd7fbf707 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -22,7 +22,7 @@ static pci_ers_result_t reset_prepare(struct pci_dev *pdev) struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); if (!accel_dev) { - dev_err(&pdev->dev, "Can't find acceleration device\n"); + pci_err(pdev, "Can't find acceleration device\n"); return PCI_ERS_RESULT_DISCONNECT; } @@ -46,7 +46,7 @@ static pci_ers_result_t reset_done(struct pci_dev *pdev) int res; if (!accel_dev) { - dev_err(&pdev->dev, "Can't find acceleration device\n"); + pci_err(pdev, "Can't find acceleration device\n"); return PCI_ERS_RESULT_DISCONNECT; } @@ -64,7 +64,7 @@ static pci_ers_result_t reset_done(struct pci_dev *pdev) clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); reset_complete: - dev_info(&pdev->dev, "Device reset completed successfully\n"); + pci_info(pdev, "Device reset completed successfully\n"); return PCI_ERS_RESULT_RECOVERED; } @@ -74,14 +74,14 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, { struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); - dev_info(&pdev->dev, "Acceleration driver hardware error detected.\n"); + pci_info(pdev, "Acceleration driver hardware error detected.\n"); if (!accel_dev) { - dev_err(&pdev->dev, "Can't find acceleration device\n"); + pci_err(pdev, "Can't find acceleration device\n"); return PCI_ERS_RESULT_DISCONNECT; } if (state == pci_channel_io_perm_failure) { - dev_err(&pdev->dev, "Can't recover from device error\n"); + pci_err(pdev, "Can't recover from device error\n"); return PCI_ERS_RESULT_DISCONNECT; } @@ -116,10 +116,9 @@ void adf_reset_sbr(struct adf_accel_dev *accel_dev) parent = pdev; if (!pci_wait_for_pending_transaction(pdev)) - dev_info(&GET_DEV(accel_dev), - "Transaction still in progress. Proceeding\n"); + pci_info(pdev, "Transaction still in progress. Proceeding\n"); - dev_info(&GET_DEV(accel_dev), "Secondary bus reset\n"); + pci_info(pdev, "Secondary bus reset\n"); pci_read_config_word(parent, PCI_BRIDGE_CONTROL, &bridge_ctl); bridge_ctl |= PCI_BRIDGE_CTL_BUS_RESET; @@ -247,8 +246,8 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev) static void adf_resume(struct pci_dev *pdev) { - dev_info(&pdev->dev, "Acceleration driver reset completed\n"); - dev_info(&pdev->dev, "Device is up and running\n"); + pci_info(pdev, "Acceleration driver reset completed\n"); + pci_info(pdev, "Device is up and running\n"); } static void adf_reset_prepare(struct pci_dev *pdev) diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c index f2011300a929..f45ca2eecc00 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c @@ -240,7 +240,7 @@ void adf_reenable_sriov(struct adf_accel_dev *accel_dev) if (adf_add_sriov_configuration(accel_dev)) return; - dev_dbg(&pdev->dev, "Re-enabling SRIOV\n"); + pci_dbg(pdev, "Re-enabling SRIOV\n"); adf_enable_sriov(accel_dev); } diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c index 97ad53eef38f..571f302edea3 100644 --- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c @@ -162,14 +162,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar->size = pci_resource_len(pdev, bar_nr); bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); + pci_err(pdev, "Failed to map BAR %d\n", bar_nr); ret = -EFAULT; goto out_err_free_reg; } } if (pci_save_state(pdev)) { - dev_err(&pdev->dev, "Failed to save pci state\n"); + pci_err(pdev, "Failed to save pci state\n"); ret = -ENOMEM; goto out_err_free_reg; } diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c index a5edda8bad32..481551a08708 100644 --- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c @@ -158,7 +158,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bar->size = pci_resource_len(pdev, bar_nr); bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); + pci_err(pdev, "Failed to map BAR %d\n", bar_nr); ret = -EFAULT; goto out_err_free_reg; } From 50e506201bab875545c7a9443bd7e1c71804e553 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 21 May 2026 17:43:01 +1000 Subject: [PATCH 429/655] crypto: ccp/tsm - Enable the root port after the endpoint The PCIe r7.0, chapter "6.33.8 Other IDE Rules" mandates if selective IDE is enabled for config requersts, a stream must be enabled on the endpoint before enabling it on the rootport: === For Selective IDE, the Stream must not be used until it has been enabled in both Partner Ports. For cases where one of the Partner Ports is a Root Port and Selective IDE for Configuration Requests is enabled, the other Partner Port must be enabled prior to the Root Port. For other scenarios, the mechanisms to satisfy this requirement are implementation-specific. === Do what the spec says. Fixes: 4be423572da1 ("crypto/ccp: Implement SEV-TIO PCIe IDE (phase1)") Signed-off-by: Alexey Kardashevskiy Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev-tsm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev-tsm.c b/drivers/crypto/ccp/sev-dev-tsm.c index f303d8f55991..46f2539d2d5a 100644 --- a/drivers/crypto/ccp/sev-dev-tsm.c +++ b/drivers/crypto/ccp/sev-dev-tsm.c @@ -58,13 +58,13 @@ static int stream_enable(struct pci_ide *ide) struct pci_dev *rp = pcie_find_root_port(ide->pdev); int ret; - ret = pci_ide_stream_enable(rp, ide); - if (ret) + ret = pci_ide_stream_enable(ide->pdev, ide); + if (ret && ret != -ENXIO) return ret; - ret = pci_ide_stream_enable(ide->pdev, ide); - if (ret) - pci_ide_stream_disable(rp, ide); + ret = pci_ide_stream_enable(rp, ide); + if (ret && ret != -ENXIO) + pci_ide_stream_disable(ide->pdev, ide); return ret; } From 4c600ab0d8cfc9d75b92f3426dbcb2ad85eac91d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 21 May 2026 21:25:25 -0500 Subject: [PATCH 430/655] crypto: loongson - Select CRYPTO_RNG This driver registers a rng_alg, so it requires CRYPTO_RNG. Fixes: 766b2d724c8d ("crypto: loongson - add Loongson RNG driver support") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605201622.qWOiiZTV-lkp@intel.com/ Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Reviewed-by: Huacai Chen Signed-off-by: Herbert Xu --- drivers/crypto/loongson/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/loongson/Kconfig b/drivers/crypto/loongson/Kconfig index 15475da8fc11..f4e1544ffbb4 100644 --- a/drivers/crypto/loongson/Kconfig +++ b/drivers/crypto/loongson/Kconfig @@ -1,5 +1,6 @@ config CRYPTO_DEV_LOONGSON_RNG tristate "Support for Loongson RNG Driver" depends on MFD_LOONGSON_SE + select CRYPTO_RNG help Support for Loongson RNG Driver. From fcc77d33a34cf271702e8daafb6c593e4626776d Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Sat, 23 May 2026 15:43:02 -0400 Subject: [PATCH 431/655] net: Remove support for AIO on sockets The only user of msg->msg_iocb was AF_ALG, but that's deprecated. It can be removed entirely at the cost of only supporting synchronous operations. This doesn't break userspace, which will silently block (for a bounded amount of time) in io_submit instead of operating asynchronously. This also makes struct msghdr smaller, helping every other caller of sendmsg(). Signed-off-by: Demi Marie Obenour Acked-by: Jakub Kicinski Signed-off-by: Herbert Xu --- crypto/af_alg.c | 33 +--------- crypto/algif_aead.c | 39 +++--------- crypto/algif_skcipher.c | 62 ++++--------------- include/crypto/if_alg.h | 5 +- include/linux/socket.h | 1 - io_uring/net.c | 1 - net/compat.c | 1 - net/socket.c | 7 +-- .../perf/trace/beauty/include/linux/socket.h | 1 - 9 files changed, 25 insertions(+), 125 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 48c53f488e0f..8ccf7a737cd6 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1085,35 +1085,6 @@ void af_alg_free_resources(struct af_alg_async_req *areq) } EXPORT_SYMBOL_GPL(af_alg_free_resources); -/** - * af_alg_async_cb - AIO callback handler - * @data: async request completion data - * @err: if non-zero, error result to be returned via ki_complete(); - * otherwise return the AIO output length via ki_complete(). - * - * This handler cleans up the struct af_alg_async_req upon completion of the - * AIO operation. - * - * The number of bytes to be generated with the AIO operation must be set - * in areq->outlen before the AIO callback handler is invoked. - */ -void af_alg_async_cb(void *data, int err) -{ - struct af_alg_async_req *areq = data; - struct sock *sk = areq->sk; - struct kiocb *iocb = areq->iocb; - unsigned int resultlen; - - /* Buffer size written by crypto operation. */ - resultlen = areq->outlen; - - af_alg_free_resources(areq); - sock_put(sk); - - iocb->ki_complete(iocb, err ? err : (int)resultlen); -} -EXPORT_SYMBOL_GPL(af_alg_async_cb); - /** * af_alg_poll - poll system call handler * @file: file pointer @@ -1154,8 +1125,8 @@ struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, struct af_alg_ctx *ctx = alg_sk(sk)->private; struct af_alg_async_req *areq; - /* Only one AIO request can be in flight. */ - if (ctx->inflight) + /* Only one request can be in flight. */ + if (WARN_ON_ONCE(ctx->inflight)) return ERR_PTR(-EBUSY); areq = sock_kmalloc(sk, areqlen, GFP_KERNEL); diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index c6c2ce21895d..60f06597cb0b 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -197,37 +197,14 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); aead_request_set_tfm(&areq->cra_u.aead_req, tfm); - if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { - /* AIO operation */ - sock_hold(sk); - areq->iocb = msg->msg_iocb; - - /* Remember output size that will be generated. */ - areq->outlen = outlen; - - aead_request_set_callback(&areq->cra_u.aead_req, - CRYPTO_TFM_REQ_MAY_SLEEP, - af_alg_async_cb, areq); - err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) : - crypto_aead_decrypt(&areq->cra_u.aead_req); - - /* AIO operation in progress */ - if (err == -EINPROGRESS) - return -EIOCBQUEUED; - - sock_put(sk); - } else { - /* Synchronous operation */ - aead_request_set_callback(&areq->cra_u.aead_req, - CRYPTO_TFM_REQ_MAY_SLEEP | - CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, &ctx->wait); - err = crypto_wait_req(ctx->enc ? - crypto_aead_encrypt(&areq->cra_u.aead_req) : - crypto_aead_decrypt(&areq->cra_u.aead_req), - &ctx->wait); - } - + aead_request_set_callback(&areq->cra_u.aead_req, + CRYPTO_TFM_REQ_MAY_SLEEP | + CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_req_done, &ctx->wait); + err = crypto_wait_req(ctx->enc ? + crypto_aead_encrypt(&areq->cra_u.aead_req) : + crypto_aead_decrypt(&areq->cra_u.aead_req), + &ctx->wait); free: af_alg_free_resources(areq); diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index ba0a17fd95ac..9dbccabd87b1 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -79,20 +79,6 @@ static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req) return err; } -static void algif_skcipher_done(void *data, int err) -{ - struct af_alg_async_req *areq = data; - struct sock *sk = areq->sk; - - if (err) - goto out; - - err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); - -out: - af_alg_async_cb(data, err); -} - static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -171,43 +157,19 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, cflags |= CRYPTO_SKCIPHER_REQ_CONT; } - if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { - /* AIO operation */ - sock_hold(sk); - areq->iocb = msg->msg_iocb; + skcipher_request_set_callback(&areq->cra_u.skcipher_req, + cflags | + CRYPTO_TFM_REQ_MAY_SLEEP | + CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_req_done, &ctx->wait); + err = crypto_wait_req(ctx->enc ? + crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : + crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), + &ctx->wait); - /* Remember output size that will be generated. */ - areq->outlen = len; - - skcipher_request_set_callback(&areq->cra_u.skcipher_req, - cflags | - CRYPTO_TFM_REQ_MAY_SLEEP, - algif_skcipher_done, areq); - err = ctx->enc ? - crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : - crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); - - /* AIO operation in progress */ - if (err == -EINPROGRESS) - return -EIOCBQUEUED; - - sock_put(sk); - } else { - /* Synchronous operation */ - skcipher_request_set_callback(&areq->cra_u.skcipher_req, - cflags | - CRYPTO_TFM_REQ_MAY_SLEEP | - CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, &ctx->wait); - err = crypto_wait_req(ctx->enc ? - crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : - crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), - &ctx->wait); - - if (!err) - err = algif_skcipher_export( - sk, &areq->cra_u.skcipher_req); - } + if (!err) + err = algif_skcipher_export( + sk, &areq->cra_u.skcipher_req); free: af_alg_free_resources(areq); diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 0cc8fa749f68..62867daca47d 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -80,7 +80,6 @@ struct af_alg_rsgl { /** * struct af_alg_async_req - definition of crypto request - * @iocb: IOCB for AIO operations * @sk: Socket the request is associated with * @first_rsgl: First RX SG * @last_rsgl: Pointer to last RX SG @@ -92,7 +91,6 @@ struct af_alg_rsgl { * @cra_u: Cipher request */ struct af_alg_async_req { - struct kiocb *iocb; struct sock *sk; struct af_alg_rsgl first_rsgl; @@ -138,7 +136,7 @@ struct af_alg_async_req { * @write: True if we are in the middle of a write. * @init: True if metadata has been sent. * @len: Length of memory allocated for this data structure. - * @inflight: Non-zero when AIO requests are in flight. + * @inflight: Non-zero when requests are in flight, for debugging only. */ struct af_alg_ctx { struct list_head tsgl_list; @@ -237,7 +235,6 @@ int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, unsigned int ivsize); void af_alg_free_resources(struct af_alg_async_req *areq); -void af_alg_async_cb(void *data, int err); __poll_t af_alg_poll(struct file *file, struct socket *sock, poll_table *wait); struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, diff --git a/include/linux/socket.h b/include/linux/socket.h index ec4a0a025793..3ffdfe184b23 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -89,7 +89,6 @@ struct msghdr { bool msg_get_inq : 1;/* return INQ after receive */ unsigned int msg_flags; /* flags on received message */ __kernel_size_t msg_controllen; /* ancillary data buffer length */ - struct kiocb *msg_iocb; /* ptr to iocb for async requests */ struct ubuf_info *msg_ubuf; int (*sg_from_iter)(struct sk_buff *skb, struct iov_iter *from, size_t length); diff --git a/io_uring/net.c b/io_uring/net.c index 30cd22c0b934..22100933966a 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -771,7 +771,6 @@ static int io_recvmsg_prep_setup(struct io_kiocb *req) kmsg->msg.msg_control = NULL; kmsg->msg.msg_get_inq = 1; kmsg->msg.msg_controllen = 0; - kmsg->msg.msg_iocb = NULL; kmsg->msg.msg_ubuf = NULL; if (req->flags & REQ_F_BUFFER_SELECT) diff --git a/net/compat.c b/net/compat.c index 2c9bd0edac99..d68cf9c3aad5 100644 --- a/net/compat.c +++ b/net/compat.c @@ -75,7 +75,6 @@ int __get_compat_msghdr(struct msghdr *kmsg, if (msg->msg_iovlen > UIO_MAXIOV) return -EMSGSIZE; - kmsg->msg_iocb = NULL; kmsg->msg_ubuf = NULL; return 0; } diff --git a/net/socket.c b/net/socket.c index 22a412fdec07..9785363858ce 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1213,8 +1213,7 @@ static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct file *file = iocb->ki_filp; struct socket *sock = file->private_data; - struct msghdr msg = {.msg_iter = *to, - .msg_iocb = iocb}; + struct msghdr msg = {.msg_iter = *to}; ssize_t res; if (file->f_flags & O_NONBLOCK || (iocb->ki_flags & IOCB_NOWAIT)) @@ -1235,8 +1234,7 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct socket *sock = file->private_data; - struct msghdr msg = {.msg_iter = *from, - .msg_iocb = iocb}; + struct msghdr msg = {.msg_iter = *from}; ssize_t res; if (iocb->ki_pos != 0) @@ -2612,7 +2610,6 @@ int __copy_msghdr(struct msghdr *kmsg, if (msg->msg_iovlen > UIO_MAXIOV) return -EMSGSIZE; - kmsg->msg_iocb = NULL; kmsg->msg_ubuf = NULL; return 0; } diff --git a/tools/perf/trace/beauty/include/linux/socket.h b/tools/perf/trace/beauty/include/linux/socket.h index ec715ad4bf25..2a0a50fd66f4 100644 --- a/tools/perf/trace/beauty/include/linux/socket.h +++ b/tools/perf/trace/beauty/include/linux/socket.h @@ -89,7 +89,6 @@ struct msghdr { bool msg_get_inq : 1;/* return INQ after receive */ unsigned int msg_flags; /* flags on received message */ __kernel_size_t msg_controllen; /* ancillary data buffer length */ - struct kiocb *msg_iocb; /* ptr to iocb for async requests */ struct ubuf_info *msg_ubuf; int (*sg_from_iter)(struct sk_buff *skb, struct iov_iter *from, size_t length); From 7524070f26d8d347c26787dc297fb844baa26abf Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Sat, 23 May 2026 15:43:03 -0400 Subject: [PATCH 432/655] crypto: af_alg - Drop support for off-CPU cryptography AF_ALG is deprecated and exposed to unprivileged userspace. Only use the least buggy algorithm implementations: the pure software ones. This removes one of the main advantages of AF_ALG, which is the ability to use it with off-CPU accelerators. However, using off-CPU accelerators has huge overheads, both in performance and attack surface. I have yet to see real-world, performance-critical workloads where using an accelerator via AF_ALG is actually a win over doing cryptography in userspace. If using an off-CPU accelerator really does turn out to be a win, a new API should be developed that is actually a good fit for it. Signed-off-by: Demi Marie Obenour Signed-off-by: Herbert Xu --- Documentation/crypto/userspace-if.rst | 7 ++++++- crypto/af_alg.c | 2 +- crypto/algif_aead.c | 4 ++-- crypto/algif_hash.c | 4 ++-- crypto/algif_rng.c | 4 ++-- crypto/algif_skcipher.c | 4 ++-- include/crypto/if_alg.h | 14 +++++++++++++- 7 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst index ea1b1b3f4049..b31117d4415d 100644 --- a/Documentation/crypto/userspace-if.rst +++ b/Documentation/crypto/userspace-if.rst @@ -9,7 +9,8 @@ symmetric cipher, AEAD, and RNG algorithms that are implemented in kernel-mode code. AF_ALG is insecure and is deprecated. Originally added to the kernel in 2010, -most kernel developers now consider it to be a mistake. +most kernel developers now consider it to be a mistake. Support for hardware +accelerators, which was the original purpose of AF_ALG, has been removed. AF_ALG continues to be supported only for backwards compatibility. On systems where no programs using AF_ALG remain, the support for it should be disabled by @@ -59,6 +60,10 @@ Some of the examples include: - CVE-2013-7421 - CVE-2011-4081 +Hardware accelerator drivers are frequently buggy. To reduce attack surface, +AF_ALG now only provides access to algorithms implemented in software. This +means that AF_ALG no longer fulfills its original purpose. + It is recommended that, whenever possible, userspace programs be migrated to userspace crypto code (which again, is what is normally used anyway) and ``CONFIG_CRYPTO_USER_API_*`` be disabled. On systems that use SELinux, SELinux diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 8ccf7a737cd6..cce000e8590e 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -181,7 +181,7 @@ static int alg_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int add if (IS_ERR(type)) return PTR_ERR(type); - private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask); + private = type->bind(sa->salg_name); if (IS_ERR(private)) { module_put(type->owner); return PTR_ERR(private); diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 60f06597cb0b..787aac8aeb24 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -342,9 +342,9 @@ static struct proto_ops algif_aead_ops_nokey = { .poll = af_alg_poll, }; -static void *aead_bind(const char *name, u32 type, u32 mask) +static void *aead_bind(const char *name) { - return crypto_alloc_aead(name, type, mask); + return crypto_alloc_aead(name, 0, AF_ALG_CRYPTOAPI_MASK); } static void aead_release(void *private) diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 4d3dfc60a16a..5452ad6c1506 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -380,9 +380,9 @@ static struct proto_ops algif_hash_ops_nokey = { .accept = hash_accept_nokey, }; -static void *hash_bind(const char *name, u32 type, u32 mask) +static void *hash_bind(const char *name) { - return crypto_alloc_ahash(name, type, mask); + return crypto_alloc_ahash(name, 0, AF_ALG_CRYPTOAPI_MASK); } static void hash_release(void *private) diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c index a9fb492e929a..4dfe7899f8fa 100644 --- a/crypto/algif_rng.c +++ b/crypto/algif_rng.c @@ -197,7 +197,7 @@ static struct proto_ops __maybe_unused algif_rng_test_ops = { .sendmsg = rng_test_sendmsg, }; -static void *rng_bind(const char *name, u32 type, u32 mask) +static void *rng_bind(const char *name) { struct rng_parent_ctx *pctx; struct crypto_rng *rng; @@ -206,7 +206,7 @@ static void *rng_bind(const char *name, u32 type, u32 mask) if (!pctx) return ERR_PTR(-ENOMEM); - rng = crypto_alloc_rng(name, type, mask); + rng = crypto_alloc_rng(name, 0, AF_ALG_CRYPTOAPI_MASK); if (IS_ERR(rng)) { kfree(pctx); return ERR_CAST(rng); diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 9dbccabd87b1..df20bdfe1f1f 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -307,9 +307,9 @@ static struct proto_ops algif_skcipher_ops_nokey = { .poll = af_alg_poll, }; -static void *skcipher_bind(const char *name, u32 type, u32 mask) +static void *skcipher_bind(const char *name) { - return crypto_alloc_skcipher(name, type, mask); + return crypto_alloc_skcipher(name, 0, AF_ALG_CRYPTOAPI_MASK); } static void skcipher_release(void *private) diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 62867daca47d..7643ba954125 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -41,7 +41,7 @@ struct af_alg_control { }; struct af_alg_type { - void *(*bind)(const char *name, u32 type, u32 mask); + void *(*bind)(const char *name); void (*release)(void *private); int (*setkey)(void *private, const u8 *key, unsigned int keylen); int (*setentropy)(void *private, sockptr_t entropy, unsigned int len); @@ -243,4 +243,16 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, struct af_alg_async_req *areq, size_t maxsize, size_t *outlen); +/* + * Mask used to disable unsupported algorithm implementations. + * + * This is the same as FSCRYPT_CRYPTOAPI_MASK in fs/crypto/fscrypt_private.h. + * In additions to the motivations there, this API is exposed to userspace + * that might not be fully trusted. + */ +#define AF_ALG_CRYPTOAPI_MASK \ + (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \ + CRYPTO_ALG_KERN_DRIVER_ONLY) + + #endif /* _CRYPTO_IF_ALG_H */ From 5624ea54f3ba5c83d2e5503411a31a8be0278c1e Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Sat, 23 May 2026 15:43:04 -0400 Subject: [PATCH 433/655] crypto: af_alg - Document that it is *always* slower Without support for zero-copy or off-CPU offloads, AF_ALG is always slower than software cryptography. Its only advantage is that it might save code size. However, this is largely mitigated by lightweight userspace cryptographic libraries. Signed-off-by: Demi Marie Obenour Signed-off-by: Herbert Xu --- Documentation/crypto/userspace-if.rst | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst index b31117d4415d..ab93300c8e04 100644 --- a/Documentation/crypto/userspace-if.rst +++ b/Documentation/crypto/userspace-if.rst @@ -28,8 +28,8 @@ functionality than that. It actually provides access to all software algorithms. This includes arbitrary compositions of different algorithms created via a complex template system, as well as algorithms that only make sense as internal -implementation details of other algorithms. It also includes full zero-copy -support, which is difficult for the kernel to implement securely. +implementation details of other algorithms. In the past, it also included full +zero-copy support, which was difficult for the kernel to implement securely. Ultimately, these algorithms are just math computations. They use the same instructions that userspace programs already have access to, just accessed in a @@ -38,6 +38,21 @@ much more convoluted and less efficient way. Indeed, userspace code is nearly always what is being used anyway. These same algorithms are widely implemented in userspace crypto libraries. +Even when zero-copy and off-CPU accelerators were supported, AF_ALG was usually +much slower than optimized software cryptography in userspace. This was +especially true for the small message sizes usually seen in performance-critical +workloads. While it was possible to demonstrate performance wins for hashing +large files on embedded devices, it is hard to imagine a situation where this +would be performance-critical. + +Nowadays, AF_ALG no longer supports zero-copy or off-CPU accelerators. +Therefore, it is *always* slower than an optimized userspace implementation, +even for large messages. The only possible advantage left is that it avoids +duplicating code between kernel and userspace. However, userspace +implementations, especially hardware-accelerated ones, do not need to be large. +Just because OpenSSL is huge does not mean that all userspace cryptography +libraries are. + Meanwhile, AF_ALG hasn't been withstanding modern vulnerability discovery tools such as syzbot and large language models. It receives a steady stream of CVEs. Some of the examples include: From 49e2a3d8566688ef6fe49bb4dfc0a4eb418869e7 Mon Sep 17 00:00:00 2001 From: "Vlastimil Babka (SUSE)" Date: Mon, 25 May 2026 09:26:39 +0200 Subject: [PATCH 434/655] MAINTAINERS: add slab-related scripts and tools to SLAB ALLOCATOR Make sure the maintainers and reviewers are CC'd on changes to the scripts and tools that depend on slab internals. Link: https://patch.msgid.link/20260525-maint-slab-tools-v1-1-d66b69f1412a@kernel.org Acked-by: Harry Yoo (Oracle) Acked-by: SeongJae Park Signed-off-by: Vlastimil Babka (SUSE) --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b2040011a386..03f66faebd30 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24612,6 +24612,12 @@ F: mm/mempool.c F: mm/slab.h F: mm/slab_common.c F: mm/slub.c +F: scripts/gdb/linux/slab.py +F: tools/cgroup/memcg_slabinfo.py +F: tools/include/linux/slab.h +F: tools/lib/slab.c +F: tools/mm/slabinfo-gnuplot.sh +F: tools/mm/slabinfo.c SLCAN CAN NETWORK DRIVER M: Dario Binacchi From 235ab68d67eadbef1fdbfb771f21f5bacc77a2ae Mon Sep 17 00:00:00 2001 From: Xuewen Wang Date: Mon, 18 May 2026 14:21:57 +0800 Subject: [PATCH 435/655] tools/mm/slabinfo: Fix trace disable logic inversion The disable trace path in slab_debug() had a logic error where it would set trace=1 instead of trace=0. This made trace functionality permanently enabled once turned on for any slab cache. Fixes: a87615b8f9e2 ("SLUB: slabinfo upgrade") Cc: stable@vger.kernel.org Reviewed-by: SeongJae Park Signed-off-by: Xuewen Wang WARNING: From:/Signed-off-by: email address mismatch: 'From: wangxuewen <18810879172@163.com>' != 'Signed-off-by: wangxuewen ' Link: https://patch.msgid.link/20260518062159.80664-2-wangxuewen@kylinos.cn Signed-off-by: Vlastimil Babka (SUSE) --- tools/mm/slabinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c index 54c7265ab52d..39f7eae7eecd 100644 --- a/tools/mm/slabinfo.c +++ b/tools/mm/slabinfo.c @@ -798,7 +798,7 @@ static void slab_debug(struct slabinfo *s) fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name); } if (!tracing && s->trace) - set_obj(s, "trace", 1); + set_obj(s, "trace", 0); } static void totals(void) From 76c2db064bc11dd13b0a6c078414b0a62b8128f5 Mon Sep 17 00:00:00 2001 From: Xuewen Wang Date: Mon, 18 May 2026 14:21:58 +0800 Subject: [PATCH 436/655] tools/mm/slabinfo: remove dead assignment in get_obj_and_str() The assignment `x = NULL` sets the local parameter variable instead of `*x`, which is a no-op since `*x` was already set to NULL on the line above. Remove the dead assignment. Signed-off-by: Xuewen Wang Reviewed-by: SeongJae Park Link: https://patch.msgid.link/20260518062159.80664-3-wangxuewen@kylinos.cn Signed-off-by: Vlastimil Babka (SUSE) --- tools/mm/slabinfo.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c index 39f7eae7eecd..685bcdd03568 100644 --- a/tools/mm/slabinfo.c +++ b/tools/mm/slabinfo.c @@ -193,10 +193,9 @@ static unsigned long get_obj_and_str(const char *name, char **x) *x = NULL; - if (!read_obj(name)) { - x = NULL; + if (!read_obj(name)) return 0; - } + result = strtoul(buffer, &p, 10); while (*p == ' ') p++; From 2b685ac24aede39cb37fa29f44ffc133b19bfe81 Mon Sep 17 00:00:00 2001 From: Xuewen Wang Date: Mon, 18 May 2026 14:21:59 +0800 Subject: [PATCH 437/655] tools/mm/slabinfo: remove redundant slab->partial assignment slab->partial is assigned by get_obj("partial") and then immediately overwritten by get_obj_and_str("partial", &t). Remove the first redundant assignment. Reviewed-by: SeongJae Park Signed-off-by: Xuewen Wang Link: https://patch.msgid.link/20260518062159.80664-4-wangxuewen@kylinos.cn Signed-off-by: Vlastimil Babka (SUSE) --- tools/mm/slabinfo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c index 685bcdd03568..87570c22b151 100644 --- a/tools/mm/slabinfo.c +++ b/tools/mm/slabinfo.c @@ -1265,7 +1265,6 @@ static void read_slab_dir(void) slab->objects_total = get_obj("objects_total"); slab->objs_per_slab = get_obj("objs_per_slab"); slab->order = get_obj("order"); - slab->partial = get_obj("partial"); slab->partial = get_obj_and_str("partial", &t); decode_numa_list(slab->numa_partial, t); free(t); From 4401e07263896cf992c5cd080315f46d4621aec4 Mon Sep 17 00:00:00 2001 From: Monish Chunara Date: Fri, 8 May 2026 15:45:44 +0530 Subject: [PATCH 438/655] dt-bindings: mmc: sdhci-msm: Document the Shikra compatible Document the Shikra-specific SDHCI compatible in the sdhci-msm binding. Use "qcom,sdhci-msm-v5" as the fallback compatible for the MSM SDHCI v5 controller used on Shikra. Signed-off-by: Monish Chunara Acked-by: Rob Herring (Arm) Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-msm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 695a95e8f35d..60dc6b0caa21 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -62,6 +62,7 @@ properties: - qcom,sdx55-sdhci - qcom,sdx65-sdhci - qcom,sdx75-sdhci + - qcom,shikra-sdhci - qcom,sm6115-sdhci - qcom,sm6125-sdhci - qcom,sm6350-sdhci From d04e0151d316edbdb4f0397a9b92a1936e4a1421 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Sun, 10 May 2026 18:29:39 +0200 Subject: [PATCH 439/655] mmc: davinci: fix mmc_add_host order in probe mmc_add_host() makes the host visible to the MMC core. Register the interrupt handlers and advertise MMC_CAP_SDIO_IRQ before that, so the core cannot start using the host before IRQ handling is set up. Signed-off-by: Osama Abdelkader Signed-off-by: Ulf Hansson --- drivers/mmc/host/davinci_mmc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 42ad87aa48f5..cdb9fa94b56d 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1294,14 +1294,10 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) goto cpu_freq_fail; } - ret = mmc_add_host(mmc); - if (ret < 0) - goto mmc_add_host_fail; - ret = devm_request_irq(&pdev->dev, irq, mmc_davinci_irq, 0, mmc_hostname(mmc), host); if (ret) - goto request_irq_fail; + goto mmc_add_host_fail; if (host->sdio_irq >= 0) { ret = devm_request_irq(&pdev->dev, host->sdio_irq, @@ -1311,6 +1307,10 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_SDIO_IRQ; } + ret = mmc_add_host(mmc); + if (ret < 0) + goto mmc_add_host_fail; + rename_region(mem, mmc_hostname(mmc)); if (mmc->caps & MMC_CAP_8_BIT_DATA) @@ -1324,8 +1324,6 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) return 0; -request_irq_fail: - mmc_remove_host(mmc); mmc_add_host_fail: mmc_davinci_cpufreq_deregister(host); cpu_freq_fail: From cb4b9aeb3a84149cf9c38942877093bdd8a611bc Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 13 May 2026 14:19:37 +0300 Subject: [PATCH 440/655] dt-bindings: mmc: sdhci-msm: Add Eliza compatible Document the compatible string for the SDHCI controller on the Eliza platform. Signed-off-by: Abel Vesa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-msm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 60dc6b0caa21..0762403d4c8b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -37,6 +37,7 @@ properties: - const: qcom,sdhci-msm-v4 # for sdcc versions less than 5.0 - items: - enum: + - qcom,eliza-sdhci - qcom,ipq5018-sdhci - qcom,ipq5210-sdhci - qcom,ipq5332-sdhci From 5ce500d31a1625d8fe7ede950201b8df076bdd48 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 19 May 2026 14:53:41 +0100 Subject: [PATCH 441/655] mmc: renesas_sdhi: Add OF entry for RZ/G2N SoC The RZ/G2N (R8A774B1) SoC was previously handled via the generic "renesas,rcar-gen3-sdhi" fallback compatible string. However, because the SDHI IP on RZ/G2N is identical with the R-Car M3-N (R8A77965), it requires the specific quirks and configuration defined in `of_r8a77965_compatible` rather than the generic Gen3 data. Add the explicit "renesas,sdhi-r8a774b1" match entry to map it correctly. Note that the DT binding file renesas,sdhi.yaml does not need an update as the entry for this SoC is already present. Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 1d3cd4c3da1f..93470aea21df 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -279,6 +279,7 @@ static const struct renesas_sdhi_of_data_with_quirks of_rza2_compatible = { static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, }, { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, }, + { .compatible = "renesas,sdhi-r8a774b1", .data = &of_r8a77965_compatible, }, { .compatible = "renesas,sdhi-r8a774e1", .data = &of_r8a7795_compatible, }, { .compatible = "renesas,sdhi-r8a7795", .data = &of_r8a7795_compatible, }, { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, }, From ebf7f2198ac4817bd2929cf83c697cefa8bf36a9 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 19 May 2026 14:53:42 +0100 Subject: [PATCH 442/655] mmc: renesas_sdhi: Add OF entry for RZ/G2E SoC The RZ/G2E (R8A774C0) SoC was previously handled via the generic "renesas,rcar-gen3-sdhi" fallback compatible string. However, because the SDHI IP on RZ/G2E is identical with the R-Car E3 (R8A77990), it requires the specific quirks and configuration defined in `of_r8a77990_compatible` rather than the generic Gen3 data. Add the explicit "renesas,sdhi-r8a774c0" match entry to map it correctly. Note that the DT binding file renesas,sdhi.yaml does not need an update as the entry for this SoC is already present. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 93470aea21df..024edc4e5fe6 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -280,6 +280,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, }, { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a774b1", .data = &of_r8a77965_compatible, }, + { .compatible = "renesas,sdhi-r8a774c0", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,sdhi-r8a774e1", .data = &of_r8a7795_compatible, }, { .compatible = "renesas,sdhi-r8a7795", .data = &of_r8a7795_compatible, }, { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, }, From 906d715cae80593470926f9fe1105d7d4a1ce14b Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Wed, 20 May 2026 13:24:45 +0530 Subject: [PATCH 443/655] dt-bindings: mmc: sdhci-msm: qcom: Add Hawi compatible Document the compatible string for the SDHCI controller on the Qualcomm Hawi platform. Signed-off-by: Nitin Rawat Signed-off-by: Mukesh Ojha Reviewed-by: Manivannan Sadhasivam Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-msm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 0762403d4c8b..df81b6accc72 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -38,6 +38,7 @@ properties: - items: - enum: - qcom,eliza-sdhci + - qcom,hawi-sdhci - qcom,ipq5018-sdhci - qcom,ipq5210-sdhci - qcom,ipq5332-sdhci From 423ab671bb921206bab25ffe61adc5da98a64e6c Mon Sep 17 00:00:00 2001 From: Artem Shimko Date: Fri, 22 May 2026 10:31:31 +0300 Subject: [PATCH 444/655] mmc: sdhci-of-dwcmshc: remove redundant IS_ERR() check The clk_disable_unprepare() function has internal protection against ERR_PTR and NULL pointers (IS_ERR_OR_NULL). Remove the redundant IS_ERR() check for bus_clk in dwcmshc_suspend() and in the error path of dwcmshc_resume() to simplify the code. Note that the clk_prepare_enable() call in dwcmshc_resume() must retain its IS_ERR() check because clk_prepare() only handles NULL pointers, not ERR_PTR. No functional change intended. Acked-by: Adrian Hunter Signed-off-by: Artem Shimko Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-dwcmshc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index b9ecd91f44ad..0786304e7a2f 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -2564,8 +2564,7 @@ static int dwcmshc_suspend(struct device *dev) return ret; clk_disable_unprepare(pltfm_host->clk); - if (!IS_ERR(priv->bus_clk)) - clk_disable_unprepare(priv->bus_clk); + clk_disable_unprepare(priv->bus_clk); clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); @@ -2608,8 +2607,7 @@ static int dwcmshc_resume(struct device *dev) disable_other_clks: clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); disable_bus_clk: - if (!IS_ERR(priv->bus_clk)) - clk_disable_unprepare(priv->bus_clk); + clk_disable_unprepare(priv->bus_clk); disable_clk: clk_disable_unprepare(pltfm_host->clk); return ret; From 23d4f4316a71e04c34c7c5e03a662cc59f9ccb80 Mon Sep 17 00:00:00 2001 From: Artem Shimko Date: Fri, 22 May 2026 10:31:32 +0300 Subject: [PATCH 445/655] mmc: sdhci-of-dwcmshc: use dev_err_probe() to simplify error paths Replace common pattern of dev_err() + return with dev_err_probe() in probe functions and their callees. This macro provides standardized error message format with symbolic error names and adds deferred probe debugging information. The conversion makes the code more compact and ensures consistent error logging across all initialization paths. Acked-by: Adrian Hunter Signed-off-by: Artem Shimko Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-dwcmshc.c | 30 +++++++++++------------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 0786304e7a2f..eef53455b8ee 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -918,11 +918,9 @@ static int dwcmshc_rk35xx_init(struct device *dev, struct sdhci_host *host, return -ENOMEM; priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc)); - if (IS_ERR(priv->reset)) { - err = PTR_ERR(priv->reset); - dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err); - return err; - } + if (IS_ERR(priv->reset)) + return dev_err_probe(mmc_dev(host->mmc), PTR_ERR(priv->reset), + "failed to get reset control\n"); err = dwcmshc_get_enable_other_clks(mmc_dev(host->mmc), dwc_priv, ARRAY_SIZE(clk_ids), clk_ids); @@ -1779,10 +1777,8 @@ static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcm dwc_priv->priv = priv; ret = sdhci_eic7700_reset_init(dev, dwc_priv->priv); - if (ret) { - dev_err(dev, "failed to reset\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to reset\n"); ret = dwcmshc_get_enable_other_clks(mmc_dev(host->mmc), dwc_priv, ARRAY_SIZE(clk_ids), clk_ids); @@ -1790,16 +1786,14 @@ static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcm return ret; ret = of_parse_phandle_with_fixed_args(dev->of_node, "eswin,hsp-sp-csr", 2, 0, &args); - if (ret) { - dev_err(dev, "Fail to parse 'eswin,hsp-sp-csr' phandle (%d)\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Fail to parse 'eswin,hsp-sp-csr' phandle\n"); hsp_regmap = syscon_node_to_regmap(args.np); if (IS_ERR(hsp_regmap)) { - dev_err(dev, "Failed to get regmap for 'eswin,hsp-sp-csr'\n"); of_node_put(args.np); - return PTR_ERR(hsp_regmap); + return dev_err_probe(dev, PTR_ERR(hsp_regmap), + "Failed to get regmap for 'eswin,hsp-sp-csr'\n"); } hsp_int_status = args.args[0]; hsp_pwr_ctrl = args.args[1]; @@ -2408,10 +2402,8 @@ static int dwcmshc_probe(struct platform_device *pdev) u32 extra, caps; pltfm_data = device_get_match_data(&pdev->dev); - if (!pltfm_data) { - dev_err(&pdev->dev, "Error: No device match data found\n"); - return -ENODEV; - } + if (!pltfm_data) + return dev_err_probe(&pdev->dev, -ENODEV, "No device match data found\n"); host = sdhci_pltfm_init(pdev, &pltfm_data->pdata, sizeof(struct dwcmshc_priv)); From 94044acc20cdb99a0429723bcca5e1d828dbf47f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 28 May 2026 15:53:42 +0200 Subject: [PATCH 446/655] dt-bindings: mmc: sdhci-msm: Rename the binding to include 'qcom' prefix This is the only Qcom binding that doesn't have 'qcom' prefix in the bindings name. This doesn't match with the regex in MAINTAINERS file and the 'get_maintainer.pl' script fails to list the 'linux-arm-msm' list: Ulf Hansson (maintainer:MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND...) Rob Herring (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Krzysztof Kozlowski (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Conor Dooley (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) Bjorn Andersson (in file) Konrad Dybcio (in file) linux-mmc@vger.kernel.org (open list:MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND...) devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS) linux-kernel@vger.kernel.org (open list) Hence, rename the binding to include 'qcom' prefix so that the regex matches correctly. Reported-by: Mukesh Ojha Closes: https://lore.kernel.org/all/20260526151003.p4kn2vek3hpv4gzv@hu-mojha-hyd.qualcomm.com Signed-off-by: Manivannan Sadhasivam Signed-off-by: Ulf Hansson --- .../bindings/mmc/{sdhci-msm.yaml => qcom,sdhci-msm.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Documentation/devicetree/bindings/mmc/{sdhci-msm.yaml => qcom,sdhci-msm.yaml} (99%) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/qcom,sdhci-msm.yaml similarity index 99% rename from Documentation/devicetree/bindings/mmc/sdhci-msm.yaml rename to Documentation/devicetree/bindings/mmc/qcom,sdhci-msm.yaml index df81b6accc72..bd558a11b792 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/qcom,sdhci-msm.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/mmc/sdhci-msm.yaml# +$id: http://devicetree.org/schemas/mmc/qcom,sdhci-msm.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm SDHCI controller (sdhci-msm) From b99062da21a3988c6b8f1ed0730bf3587cdc7844 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 29 May 2026 09:17:39 +0800 Subject: [PATCH 447/655] mmc: dw_mmc: Add desc_num field for clarity The ring_size field in struct dw_mci is misleadingly named. Despite its name, it does not represent the size of the descriptor ring buffer in bytes, but rather the number of descriptors allocated within the fixed-size ring buffer. The actual ring buffer size is fixed at PAGE_SIZE (or DESC_RING_BUF_SZ, which equals PAGE_SIZE). Within this buffer, we allocate either struct idmac_desc or struct idmac_desc_64addr descriptors, and ring_size stores the count of these descriptors. This naming has caused confusion, as it's also used to set mmc->max_segs (the maximum number of scatter-gather segments), which logically corresponds to the number of descriptors, not a size in bytes. No functional change is introduced by this naming-only patch. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 16 ++++++++-------- drivers/mmc/host/dw_mmc.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 3b4157f34d11..d734d010444d 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -490,12 +490,12 @@ static int dw_mci_idmac_init(struct dw_mci *host) if (host->dma_64bit_address == 1) { struct idmac_desc_64addr *p; - /* Number of descriptors in the ring buffer */ - host->ring_size = + + host->desc_num = DESC_RING_BUF_SZ / sizeof(struct idmac_desc_64addr); /* Forward link the descriptor list */ - for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; + for (i = 0, p = host->sg_cpu; i < host->desc_num - 1; i++, p++) { p->des6 = (host->sg_dma + (sizeof(struct idmac_desc_64addr) * @@ -518,13 +518,13 @@ static int dw_mci_idmac_init(struct dw_mci *host) } else { struct idmac_desc *p; - /* Number of descriptors in the ring buffer */ - host->ring_size = + + host->desc_num = DESC_RING_BUF_SZ / sizeof(struct idmac_desc); /* Forward link the descriptor list */ for (i = 0, p = host->sg_cpu; - i < host->ring_size - 1; + i < host->desc_num - 1; i++, p++) { p->des3 = cpu_to_le32(host->sg_dma + (sizeof(struct idmac_desc) * (i + 1))); @@ -2857,10 +2857,10 @@ static int dw_mci_init_host(struct dw_mci *host) /* Useful defaults if platform data is unset. */ if (host->use_dma == TRANS_MODE_IDMAC) { - mmc->max_segs = host->ring_size; + mmc->max_segs = host->desc_num; mmc->max_blk_size = 65535; mmc->max_seg_size = 0x1000; - mmc->max_req_size = mmc->max_seg_size * host->ring_size; + mmc->max_req_size = mmc->max_seg_size * host->desc_num; mmc->max_blk_count = mmc->max_req_size / 512; } else if (host->use_dma == TRANS_MODE_EDMAC) { mmc->max_segs = 64; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 2ce8585e2c1e..9ffcd3946cff 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -79,7 +79,7 @@ struct dw_mci_dma_slave { * @dma_ops: Pointer to DMA callbacks. * @cmd_status: Snapshot of SR taken upon completion of the current * command. Only valid when EVENT_CMD_COMPLETE is pending. - * @ring_size: Buffer size for idma descriptors. + * @desc_num: Number of idmac descriptors available. * @dms: structure of slave-dma private data. * @phy_regs: physical address of controller's register map * @data_status: Snapshot of SR taken upon completion of the current @@ -186,7 +186,7 @@ struct dw_mci { void *sg_cpu; const struct dw_mci_dma_ops *dma_ops; /* For idmac */ - unsigned int ring_size; + unsigned short desc_num; /* For edmac */ struct dw_mci_dma_slave *dms; From e562904fc1731f4a1d9a190f78b4218303ab2ced Mon Sep 17 00:00:00 2001 From: Shengming Hu Date: Thu, 28 May 2026 19:35:37 +0800 Subject: [PATCH 448/655] mm/slub: use empty sheaf helpers for oversized sheaves Oversized prefilled sheaves are allocated separately because their capacity can be larger than the cache's regular sheaf capacity. After they are flushed, however, they are empty sheaves as well, and should be released through the same empty-sheaf helper. Allocate oversized prefilled sheaves with __alloc_empty_sheaf() and free them with free_empty_sheaf() after a failed prefill or after they are returned and flushed. This keeps the oversized and pfmemalloc return paths consistent, including the SLAB_KMALLOC-specific __GFP_NO_OBJ_EXT and mark_obj_codetag_empty() handling. Keep the caller-GFP filtering in alloc_empty_sheaf() instead of __alloc_empty_sheaf(). In particular, do not clear OBJCGS_CLEAR_MASK in the raw helper, so the oversized prefill path does not unexpectedly drop caller-provided flags such as __GFP_NOFAIL. The SLAB_KMALLOC-specific addition of __GFP_NO_OBJ_EXT remains in __alloc_empty_sheaf(), matching the free_empty_sheaf() assumption. Since oversized sheaves are now allocated and freed through the empty sheaf helpers, SHEAF_ALLOC and SHEAF_FREE also account for oversized sheaves. Update the stat comments accordingly. Keep the capacity initialization in the oversized prefill path, since capacity is currently only used for prefilled sheaves Signed-off-by: Shengming Hu Link: https://patch.msgid.link/20260528193537623nAo-xYBNYBysGKSBjREuO@zte.com.cn Reviewed-by: Harry Yoo (Oracle) Reviewed-by: Hao Li Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index fad0d2b6a33d..cbf6636a3dad 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -362,8 +362,8 @@ enum stat_item { CMPXCHG_DOUBLE_FAIL, /* Failures of slab freelist update */ SHEAF_FLUSH, /* Objects flushed from a sheaf */ SHEAF_REFILL, /* Objects refilled to a sheaf */ - SHEAF_ALLOC, /* Allocation of an empty sheaf */ - SHEAF_FREE, /* Freeing of an empty sheaf */ + SHEAF_ALLOC, /* Allocation of an empty sheaf including oversized ones */ + SHEAF_FREE, /* Freeing of an empty sheaf including oversized ones */ BARN_GET, /* Got full sheaf from barn */ BARN_GET_FAIL, /* Failed to get full sheaf from barn */ BARN_PUT, /* Put full sheaf to barn */ @@ -2762,11 +2762,6 @@ static struct slab_sheaf *__alloc_empty_sheaf(struct kmem_cache *s, gfp_t gfp, struct slab_sheaf *sheaf; size_t sheaf_size; - if (gfp & __GFP_NO_OBJ_EXT) - return NULL; - - gfp &= ~OBJCGS_CLEAR_MASK; - /* * Prevent recursion to the same cache, or a deep stack of kmallocs of * varying sizes (sheaf capacity might differ for each kmalloc size @@ -2791,6 +2786,11 @@ static struct slab_sheaf *__alloc_empty_sheaf(struct kmem_cache *s, gfp_t gfp, static inline struct slab_sheaf *alloc_empty_sheaf(struct kmem_cache *s, gfp_t gfp) { + if (gfp & __GFP_NO_OBJ_EXT) + return NULL; + + gfp &= ~OBJCGS_CLEAR_MASK; + return __alloc_empty_sheaf(s, gfp, s->sheaf_capacity); } @@ -5014,12 +5014,11 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size) if (unlikely(size > s->sheaf_capacity)) { - sheaf = kzalloc_flex(*sheaf, objects, size, gfp); + sheaf = __alloc_empty_sheaf(s, gfp, size); if (!sheaf) return NULL; stat(s, SHEAF_PREFILL_OVERSIZE); - sheaf->cache = s; sheaf->capacity = size; /* @@ -5028,7 +5027,7 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size) */ if (!__kmem_cache_alloc_bulk(s, gfp, size, &sheaf->objects[0])) { - kfree(sheaf); + free_empty_sheaf(s, sheaf); return NULL; } @@ -5096,7 +5095,7 @@ void kmem_cache_return_sheaf(struct kmem_cache *s, gfp_t gfp, if (unlikely((sheaf->capacity != s->sheaf_capacity) || sheaf->pfmemalloc)) { sheaf_flush_unused(s, sheaf); - kfree(sheaf); + free_empty_sheaf(s, sheaf); return; } From 7e230738746ce9a7a57c55cbde0c48668a891334 Mon Sep 17 00:00:00 2001 From: Hao Li Date: Fri, 29 May 2026 11:50:51 +0800 Subject: [PATCH 449/655] mm/slub: introduce helpers for node partial slab state Wrap partial slab count inc/dec and flag set/clear into helper functions to reduce code duplication. Note that __add_partial() is called locklessly in early_kmem_cache_node_alloc(), but since there is no such use case for removal, __remove_partial() does not exist. Suggested-by: Harry Yoo Signed-off-by: Hao Li Link: https://patch.msgid.link/20260529035120.81304-2-hao.li@linux.dev Reviewed-by: Harry Yoo (Oracle) Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index cbf6636a3dad..f9a4da536356 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3521,15 +3521,21 @@ static inline void slab_clear_node_partial(struct slab *slab) /* * Management of partially allocated slabs. */ +static inline void set_node_partial_state(struct kmem_cache_node *n, + struct slab *slab) +{ + slab_set_node_partial(slab); + n->nr_partial++; +} + static inline void __add_partial(struct kmem_cache_node *n, struct slab *slab, enum add_mode mode) { - n->nr_partial++; if (mode == ADD_TO_TAIL) list_add_tail(&slab->slab_list, &n->partial); else list_add(&slab->slab_list, &n->partial); - slab_set_node_partial(slab); + set_node_partial_state(n, slab); } static inline void add_partial(struct kmem_cache_node *n, @@ -3539,13 +3545,19 @@ static inline void add_partial(struct kmem_cache_node *n, __add_partial(n, slab, mode); } +static inline void clear_node_partial_state(struct kmem_cache_node *n, + struct slab *slab) +{ + slab_clear_node_partial(slab); + n->nr_partial--; +} + static inline void remove_partial(struct kmem_cache_node *n, struct slab *slab) { lockdep_assert_held(&n->list_lock); list_del(&slab->slab_list); - slab_clear_node_partial(slab); - n->nr_partial--; + clear_node_partial_state(n, slab); } /* @@ -8266,8 +8278,7 @@ static int __kmem_cache_do_shrink(struct kmem_cache *s) if (free == slab->objects) { list_move(&slab->slab_list, &discard); - slab_clear_node_partial(slab); - n->nr_partial--; + clear_node_partial_state(n, slab); dec_slabs_node(s, node, slab->objects); } else if (free <= SHRINK_PROMOTE_MAX) list_move(&slab->slab_list, promote + free - 1); From 0fc52deec1068ea3cc8eaa6e045c96fbf73f20e2 Mon Sep 17 00:00:00 2001 From: Hao Li Date: Fri, 29 May 2026 11:50:52 +0800 Subject: [PATCH 450/655] mm/slub: detach and reattach partial slabs in batch get_partial_node_bulk() moves each selected slab from the node's partial list to the local pc->slabs list using a remove_partial() and list_add() pair. In practice, the loop often detaches several adjacent slabs. Doing this individually repeatedly manipulates list pointers while holding n->list_lock, which causes unnecessary churn. To demonstrate this, the counts below show how often single vs. multiple consecutive slabs are retrieved during a will-it-scale mmap stress test: consecutive_slabs_count frequency = 1 277345324 = 2 335238023 = 3 175717884 >= 4 88862337 The data confirms that retrieving multiple contiguous slabs is highly frequent. To optimize this, track contiguous runs of matching slabs and move each run in a single operation using list_bulk_move_tail(). This reduces list pointer churn inside the lock critical section. Apply the same optimization to __refill_objects_node() when reattaching leftover partial slabs back to the node's partial list. The will-it-scale mmap benchmark shows a 2% ~ 5% performance improvement after applying this patch. Signed-off-by: Hao Li Link: https://patch.msgid.link/20260529035120.81304-3-hao.li@linux.dev Reviewed-by: Harry Yoo (Oracle) Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index f9a4da536356..492128ae3af9 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3751,6 +3751,7 @@ static bool get_partial_node_bulk(struct kmem_cache *s, bool allow_spin) { struct slab *slab, *slab2; + struct slab *first = NULL, *last = NULL; unsigned int total_free = 0; unsigned long flags; @@ -3769,8 +3770,15 @@ static bool get_partial_node_bulk(struct kmem_cache *s, struct freelist_counters flc; unsigned int slab_free; - if (!pfmemalloc_match(slab, pc->flags)) + if (!pfmemalloc_match(slab, pc->flags)) { + if (first) { + list_bulk_move_tail(&pc->slabs, + &first->slab_list, + &last->slab_list); + first = NULL; + } continue; + } /* * determine the number of free objects in the slab racily @@ -3787,15 +3795,20 @@ static bool get_partial_node_bulk(struct kmem_cache *s, && total_free + slab_free > pc->max_objects) break; - remove_partial(n, slab); - - list_add(&slab->slab_list, &pc->slabs); + if (!first) + first = slab; + last = slab; + clear_node_partial_state(n, slab); total_free += slab_free; if (total_free >= pc->max_objects) break; } + if (first) + list_bulk_move_tail(&pc->slabs, &first->slab_list, + &last->slab_list); + spin_unlock_irqrestore(&n->list_lock, flags); return total_free > 0; } @@ -7205,11 +7218,10 @@ __refill_objects_node(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int mi if (!list_empty(&pc.slabs)) { spin_lock_irqsave(&n->list_lock, flags); - list_for_each_entry_safe(slab, slab2, &pc.slabs, slab_list) { + list_for_each_entry(slab, &pc.slabs, slab_list) + set_node_partial_state(n, slab); - list_del(&slab->slab_list); - add_partial(n, slab, ADD_TO_TAIL); - } + list_splice_tail(&pc.slabs, &n->partial); spin_unlock_irqrestore(&n->list_lock, flags); } From bd7e9843ec95bffe2643c901dd625f0bab32e639 Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Fri, 22 May 2026 20:40:48 +0800 Subject: [PATCH 451/655] spi: atmel: fix DMA channel and bounce buffer leaks The original code set use_dma to false when dma_alloc_coherent() for bounce buffers failed, but DMA channels acquired earlier via atmel_spi_configure_dma() were never freed. When devm_request_irq() or clk_prepare_enable() failed later in probe, the driver also did not release DMA channels or bounce buffers already allocated. The out_free_dma error path released DMA channels but did not free the bounce buffers. Fix by moving bounce buffer allocation into atmel_spi_configure_dma() and registering the devres cleanup for DMA channels and bounce buffers. Fixes: a9889ed62d06 ("spi: atmel: Implements transfers with bounce buffer") Signed-off-by: Felix Gu Link: https://patch.msgid.link/20260522-atmel-v3-1-23f8c6e6aa43@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 133 ++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 25aa294631c8..c8012c82c3a7 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -559,6 +559,38 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word) return err; } +static void atmel_spi_release_dma(void *data) +{ + struct spi_controller *host = data; + struct atmel_spi *as = spi_controller_get_devdata(host); + struct device *dev = &as->pdev->dev; + + if (host->dma_tx) { + dma_release_channel(host->dma_tx); + host->dma_tx = NULL; + } + + if (host->dma_rx) { + dma_release_channel(host->dma_rx); + host->dma_rx = NULL; + } + + if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { + if (as->addr_tx_bbuf) { + dma_free_coherent(dev, SPI_MAX_DMA_XFER, + as->addr_tx_bbuf, + as->dma_addr_tx_bbuf); + as->addr_tx_bbuf = NULL; + } + if (as->addr_rx_bbuf) { + dma_free_coherent(dev, SPI_MAX_DMA_XFER, + as->addr_rx_bbuf, + as->dma_addr_rx_bbuf); + as->addr_rx_bbuf = NULL; + } + } +} + static int atmel_spi_configure_dma(struct spi_controller *host, struct atmel_spi *as) { @@ -569,7 +601,8 @@ static int atmel_spi_configure_dma(struct spi_controller *host, if (IS_ERR(host->dma_tx)) { err = PTR_ERR(host->dma_tx); dev_dbg(dev, "No TX DMA channel, DMA is disabled\n"); - goto error_clear; + host->dma_tx = NULL; + return err; } host->dma_rx = dma_request_chan(dev, "rx"); @@ -580,26 +613,45 @@ static int atmel_spi_configure_dma(struct spi_controller *host, * requested tx channel. */ dev_dbg(dev, "No RX DMA channel, DMA is disabled\n"); - goto error; + host->dma_rx = NULL; + goto err_release_dma; } err = atmel_spi_dma_slave_config(as, 8); if (err) - goto error; + goto err_release_dma; + + if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { + as->addr_tx_bbuf = dma_alloc_coherent(dev, SPI_MAX_DMA_XFER, + &as->dma_addr_tx_bbuf, + GFP_KERNEL | GFP_DMA); + if (!as->addr_tx_bbuf) { + err = -ENOMEM; + goto err_release_dma; + } + + as->addr_rx_bbuf = dma_alloc_coherent(dev, SPI_MAX_DMA_XFER, + &as->dma_addr_rx_bbuf, + GFP_KERNEL | GFP_DMA); + if (!as->addr_rx_bbuf) { + err = -ENOMEM; + goto err_release_dma; + } + } + + err = devm_add_action_or_reset(dev, atmel_spi_release_dma, host); + if (err) + return err; dev_info(&as->pdev->dev, - "Using %s (tx) and %s (rx) for DMA transfers\n", - dma_chan_name(host->dma_tx), - dma_chan_name(host->dma_rx)); + "Using %s (tx) and %s (rx) for DMA transfers\n", + dma_chan_name(host->dma_tx), dma_chan_name(host->dma_rx)); return 0; -error: - if (!IS_ERR(host->dma_rx)) - dma_release_channel(host->dma_rx); - if (!IS_ERR(host->dma_tx)) - dma_release_channel(host->dma_tx); -error_clear: - host->dma_tx = host->dma_rx = NULL; + +err_release_dma: + atmel_spi_release_dma(host); + return err; } @@ -611,18 +663,6 @@ static void atmel_spi_stop_dma(struct spi_controller *host) dmaengine_terminate_all(host->dma_tx); } -static void atmel_spi_release_dma(struct spi_controller *host) -{ - if (host->dma_rx) { - dma_release_channel(host->dma_rx); - host->dma_rx = NULL; - } - if (host->dma_tx) { - dma_release_channel(host->dma_tx); - host->dma_tx = NULL; - } -} - /* This function is called by the DMA driver from tasklet context */ static void dma_callback(void *data) { @@ -1581,30 +1621,6 @@ static int atmel_spi_probe(struct platform_device *pdev) as->use_pdc = true; } - if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { - as->addr_rx_bbuf = dma_alloc_coherent(&pdev->dev, - SPI_MAX_DMA_XFER, - &as->dma_addr_rx_bbuf, - GFP_KERNEL | GFP_DMA); - if (!as->addr_rx_bbuf) { - as->use_dma = false; - } else { - as->addr_tx_bbuf = dma_alloc_coherent(&pdev->dev, - SPI_MAX_DMA_XFER, - &as->dma_addr_tx_bbuf, - GFP_KERNEL | GFP_DMA); - if (!as->addr_tx_bbuf) { - as->use_dma = false; - dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER, - as->addr_rx_bbuf, - as->dma_addr_rx_bbuf); - } - } - if (!as->use_dma) - dev_info(host->dev.parent, - " can not allocate dma coherent memory\n"); - } - if (as->caps.has_dma_support && !as->use_dma) dev_info(&pdev->dev, "Atmel SPI Controller using PIO only\n"); @@ -1664,13 +1680,10 @@ static int atmel_spi_probe(struct platform_device *pdev) out_free_dma: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - - if (as->use_dma) - atmel_spi_release_dma(host); - spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ - clk_disable_unprepare(as->gclk); + if (as->gclk) + clk_disable_unprepare(as->gclk); out_disable_clk: clk_disable_unprepare(clk); @@ -1687,18 +1700,8 @@ static void atmel_spi_remove(struct platform_device *pdev) spi_unregister_controller(host); /* reset the hardware and block queue progress */ - if (as->use_dma) { + if (as->use_dma) atmel_spi_stop_dma(host); - atmel_spi_release_dma(host); - if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { - dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER, - as->addr_tx_bbuf, - as->dma_addr_tx_bbuf); - dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER, - as->addr_rx_bbuf, - as->dma_addr_rx_bbuf); - } - } spin_lock_irq(&as->lock); spi_writel(as, CR, SPI_BIT(SWRST)); From e703ce47691b967fe9b4057fb1d062273211afa9 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Mon, 25 May 2026 14:23:56 +0800 Subject: [PATCH 452/655] spi: fsl-lpspi: replace dmaengine_terminate_all() with dmaengine_terminate_sync() dmaengine_terminate_all() has been deprecated, so replace it with dmaengine_terminate_sync(). Fixes: 09c04466ce7e ("spi: lpspi: add dma mode support") Cc: stable@vger.kernel.org Signed-off-by: Carlos Song Link: https://patch.msgid.link/20260525062357.3191349-2-carlos.song@oss.nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index e201309f8aae..1a94a42fac31 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -647,7 +647,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, tx->sgl, tx->nents, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { - dmaengine_terminate_all(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_tx); return -EINVAL; } @@ -668,8 +668,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, transfer_timeout); if (!time_left) { dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n"); - dmaengine_terminate_all(controller->dma_tx); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_rx); fsl_lpspi_reset(fsl_lpspi); return -ETIMEDOUT; } @@ -678,8 +678,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, transfer_timeout); if (!time_left) { dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n"); - dmaengine_terminate_all(controller->dma_tx); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_rx); fsl_lpspi_reset(fsl_lpspi); return -ETIMEDOUT; } @@ -688,8 +688,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, fsl_lpspi->target_aborted) { dev_dbg(fsl_lpspi->dev, "I/O Error in DMA TX interrupted\n"); - dmaengine_terminate_all(controller->dma_tx); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_rx); fsl_lpspi_reset(fsl_lpspi); return -EINTR; } @@ -698,8 +698,8 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, fsl_lpspi->target_aborted) { dev_dbg(fsl_lpspi->dev, "I/O Error in DMA RX interrupted\n"); - dmaengine_terminate_all(controller->dma_tx); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_rx); fsl_lpspi_reset(fsl_lpspi); return -EINTR; } From 01980b5da56e573d62798d0ff6c86bcaa2b22cbe Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Mon, 25 May 2026 14:23:57 +0800 Subject: [PATCH 453/655] spi: fsl-lpspi: terminate the RX channel on TX prepare failure path When dmaengine_prep_slave_sg() fails for the TX channel, the error path terminates the TX DMA channel but leaves the RX channel running. Since the RX channel was already submitted and issued prior to preparing the TX descriptor, returning -EINVAL causes the SPI core to unmap the DMA buffers while the RX DMA engine continues writing to them, leading to potential memory corruption or use-after-free. Terminate the RX channel before returning on the TX prepare failure path. Fixes: 09c04466ce7e ("spi: lpspi: add dma mode support") Cc: stable@vger.kernel.org Signed-off-by: Carlos Song Link: https://patch.msgid.link/20260525062357.3191349-3-carlos.song@oss.nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 1a94a42fac31..e14753144e19 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -647,7 +647,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, tx->sgl, tx->nents, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { - dmaengine_terminate_sync(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_rx); return -EINVAL; } From 4503b2fe761c2bfd33ed043d9b9deec0d1eb40e0 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Mon, 25 May 2026 14:29:28 +0800 Subject: [PATCH 454/655] spi: imx: replace dmaengine_terminate_all() with dmaengine_terminate_sync() dmaengine_terminate_all() has been deprecated, so replace it with dmaengine_terminate_sync(). Fixes: ba9b28652c75 ("spi: imx: enable DMA mode for target operation") Fixes: a450c8b77f92 ("spi: imx: handle DMA submission errors with dma_submit_error()") Signed-off-by: Carlos Song Link: https://patch.msgid.link/20260525062928.3191821-1-carlos.song@oss.nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 480d1e8b281f..ae9912905c67 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1774,8 +1774,8 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx, transfer_timeout); if (!time_left) { dev_err(spi_imx->dev, "I/O Error in DMA TX\n"); - dmaengine_terminate_all(controller->dma_tx); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_rx); return -ETIMEDOUT; } @@ -1784,7 +1784,7 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx, if (!time_left) { dev_err(&controller->dev, "I/O Error in DMA RX\n"); spi_imx->devtype_data->reset(spi_imx); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_rx); return -ETIMEDOUT; } } else { @@ -1793,15 +1793,15 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx, if (wait_for_completion_interruptible(&spi_imx->dma_tx_completion) || READ_ONCE(spi_imx->target_aborted)) { dev_dbg(spi_imx->dev, "I/O Error in DMA TX interrupted\n"); - dmaengine_terminate_all(controller->dma_tx); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_rx); return -EINTR; } if (wait_for_completion_interruptible(&spi_imx->dma_rx_completion) || READ_ONCE(spi_imx->target_aborted)) { dev_dbg(spi_imx->dev, "I/O Error in DMA RX interrupted\n"); - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_rx); return -EINTR; } @@ -1818,9 +1818,9 @@ static int spi_imx_dma_submit(struct spi_imx_data *spi_imx, return 0; dmaengine_terminate_tx: - dmaengine_terminate_all(controller->dma_tx); + dmaengine_terminate_sync(controller->dma_tx); dmaengine_terminate_rx: - dmaengine_terminate_all(controller->dma_rx); + dmaengine_terminate_sync(controller->dma_rx); return -EINVAL; } From f469138a77ac5ab685dfe15dfed7dccb9d5c33e5 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Mon, 25 May 2026 01:47:44 -0500 Subject: [PATCH 455/655] spi: tegra210-quad: Allocate DMA memory for DMA engine When the SPI controllers are running in DMA mode, it is the DMA engine that performs the memory accesses rather than the SPI controller. Pass the DMA engine's struct device pointer to the DMA API to make sure the correct DMA operations are used. Suggested-by: Thierry Reding Signed-off-by: Aaron Kling Link: https://patch.msgid.link/20260525-tegra194-qspi-iommu-v2-1-a11c53f804b2@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index db28dd556484..588a929a9785 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -226,11 +226,13 @@ struct tegra_qspi { struct completion xfer_completion; struct spi_transfer *curr_xfer; + struct device *rx_dma_dev; struct dma_chan *rx_dma_chan; u32 *rx_dma_buf; dma_addr_t rx_dma_phys; struct dma_async_tx_descriptor *rx_dma_desc; + struct device *tx_dma_dev; struct dma_chan *tx_dma_chan; u32 *tx_dma_buf; dma_addr_t tx_dma_phys; @@ -574,15 +576,15 @@ static int tegra_qspi_dma_map_xfer(struct tegra_qspi *tqspi, struct spi_transfer len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4; if (t->tx_buf) { - t->tx_dma = dma_map_single(tqspi->dev, (void *)tx_buf, len, DMA_TO_DEVICE); - if (dma_mapping_error(tqspi->dev, t->tx_dma)) + t->tx_dma = dma_map_single(tqspi->tx_dma_dev, (void *)tx_buf, len, DMA_TO_DEVICE); + if (dma_mapping_error(tqspi->tx_dma_dev, t->tx_dma)) return -ENOMEM; } if (t->rx_buf) { - t->rx_dma = dma_map_single(tqspi->dev, (void *)rx_buf, len, DMA_FROM_DEVICE); - if (dma_mapping_error(tqspi->dev, t->rx_dma)) { - dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE); + t->rx_dma = dma_map_single(tqspi->rx_dma_dev, (void *)rx_buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(tqspi->rx_dma_dev, t->rx_dma)) { + dma_unmap_single(tqspi->tx_dma_dev, t->tx_dma, len, DMA_TO_DEVICE); return -ENOMEM; } } @@ -597,9 +599,9 @@ static void tegra_qspi_dma_unmap_xfer(struct tegra_qspi *tqspi, struct spi_trans len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4; if (t->tx_buf) - dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE); + dma_unmap_single(tqspi->tx_dma_dev, t->tx_dma, len, DMA_TO_DEVICE); if (t->rx_buf) - dma_unmap_single(tqspi->dev, t->rx_dma, len, DMA_FROM_DEVICE); + dma_unmap_single(tqspi->rx_dma_dev, t->rx_dma, len, DMA_FROM_DEVICE); } static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct spi_transfer *t) @@ -745,7 +747,7 @@ static int tegra_qspi_start_cpu_based_transfer(struct tegra_qspi *qspi, struct s static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi) { if (tqspi->tx_dma_buf) { - dma_free_coherent(tqspi->dev, tqspi->dma_buf_size, + dma_free_coherent(tqspi->tx_dma_dev, tqspi->dma_buf_size, tqspi->tx_dma_buf, tqspi->tx_dma_phys); tqspi->tx_dma_buf = NULL; } @@ -756,7 +758,7 @@ static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi) } if (tqspi->rx_dma_buf) { - dma_free_coherent(tqspi->dev, tqspi->dma_buf_size, + dma_free_coherent(tqspi->rx_dma_dev, tqspi->dma_buf_size, tqspi->rx_dma_buf, tqspi->rx_dma_phys); tqspi->rx_dma_buf = NULL; } @@ -782,6 +784,7 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi) } tqspi->rx_dma_chan = dma_chan; + tqspi->rx_dma_dev = dmaengine_get_dma_device(tqspi->rx_dma_chan); dma_chan = dma_request_chan(tqspi->dev, "tx"); if (IS_ERR(dma_chan)) { @@ -790,15 +793,19 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi) } tqspi->tx_dma_chan = dma_chan; + tqspi->tx_dma_dev = dmaengine_get_dma_device(tqspi->tx_dma_chan); } else { if (!device_iommu_mapped(tqspi->dev)) { dev_warn(tqspi->dev, "IOMMU not enabled in device-tree, falling back to PIO mode\n"); return 0; } + + tqspi->rx_dma_dev = tqspi->dev; + tqspi->tx_dma_dev = tqspi->dev; } - dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL); + dma_buf = dma_alloc_coherent(tqspi->rx_dma_dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL); if (!dma_buf) { err = -ENOMEM; goto err_out; @@ -807,7 +814,7 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi) tqspi->rx_dma_buf = dma_buf; tqspi->rx_dma_phys = dma_phys; - dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL); + dma_buf = dma_alloc_coherent(tqspi->tx_dma_dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL); if (!dma_buf) { err = -ENOMEM; goto err_out; From 73cfdd6800b27bc7fabdcbeb177823e2226d9e7c Mon Sep 17 00:00:00 2001 From: Daniel Pereira Date: Wed, 27 May 2026 12:53:44 -0300 Subject: [PATCH 456/655] docs: pt_BR: add translation for kernel development process guides Add the Brazilian Portuguese (pt_BR) translation for the 'development-process.rst' and '2.process.rst' files under the 'process/' directory. The main 'index.rst' file is also updated to include references to the newly translated documents in the toctree. Signed-off-by: Daniel Pereira Signed-off-by: Jonathan Corbet Message-ID: <20260527155350.202569-1-danielmaraboo@gmail.com> --- Documentation/translations/pt_BR/index.rst | 1 + .../translations/pt_BR/process/2.Process.rst | 520 ++++++++++++++++++ .../pt_BR/process/development-process.rst | 21 + 3 files changed, 542 insertions(+) create mode 100644 Documentation/translations/pt_BR/process/2.Process.rst create mode 100644 Documentation/translations/pt_BR/process/development-process.rst diff --git a/Documentation/translations/pt_BR/index.rst b/Documentation/translations/pt_BR/index.rst index 76936710b06e..7a488f662a1e 100644 --- a/Documentation/translations/pt_BR/index.rst +++ b/Documentation/translations/pt_BR/index.rst @@ -67,6 +67,7 @@ kernel e sobre como ver seu trabalho integrado. :maxdepth: 1 Introdução + Guia do Processo de Desenvolvimento Index de documentos do Kernel Regras de licenciamento Como começar diff --git a/Documentation/translations/pt_BR/process/2.Process.rst b/Documentation/translations/pt_BR/process/2.Process.rst new file mode 100644 index 000000000000..5ff35f10aac7 --- /dev/null +++ b/Documentation/translations/pt_BR/process/2.Process.rst @@ -0,0 +1,520 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Como funciona o processo de desenvolvimento +=========================================== + +O desenvolvimento do kernel Linux no início dos anos 1990 era uma +atividade bastante informal, envolvendo um número relativamente pequeno de +usuários e desenvolvedores. Com uma base de usuários atualmente na casa +dos milhões e com cerca de 2.000 desenvolvedores envolvidos ao longo de +um ano, o kernel desde então teve que evoluir uma série de processos +para manter o desenvolvimento acontecendo de forma fluida. Uma +compreensão sólida de como o processo funciona é necessária para ser uma +parte eficaz dele. + +A Visão Geral +------------- + +O kernel Linux usa um modelo de desenvolvimento de lançamento contínuo +(*rolling release*), vagamente baseado em tempo. Um novo lançamento de +versão principal do kernel (que chamaremos, como exemplo, de 9.x) [1]_ +ocorre a cada dois ou três meses, trazendo novos recursos, alterações em +APIs internas e muito mais. Um lançamento típico pode conter cerca de +13.000 conjuntos de alterações (*changesets*) com modificações em várias +centenas de milhares de linhas de código. Lançamentos recentes, +juntamente com suas datas, podem ser encontrados na `Wikipedia +`_. + +.. [1] Rigorosamente falando, o kernel Linux não utiliza o esquema de + numeração de versionamento semântico, mas, em vez disso, o par + 9.x identifica a versão de lançamento principal como um número + inteiro. Para cada lançamento, x é incrementado, mas o 9 é + incrementado apenas se x for considerado grande o suficiente + (por exemplo, o Linux 5.0 foi lançado após o Linux 4.20). + +O processo de integração (*merging*) de patches segue um fluxo simples a +cada lançamento. No início de cada ciclo de desenvolvimento, abre-se a +**"janela de integração" (*merge window*)**. Durante esse período, todo +código considerado estável e aprovado pela comunidade é unificado ao +kernel principal (*mainline*). A maior parte das novidades e todas as +grandes mudanças estruturais — entra obrigatoriamente nessa fase, em um +ritmo frenético que chega a **1.000 patches (ou conjuntos de alterações) +por dia**. + +(Como observação secundária, vale destacar que as mudanças integradas durante +a janela de integração não surgem do nada; elas foram coletadas, testadas e +organizadas com antecedência. Como esse processo funciona será descrito em +detalhes mais adiante). + +A janela de integração dura aproximadamente duas semanas. Ao final desse +período, Linus Torvalds declarará que a janela está fechada e lançará o +primeiro dos kernels "rc". Para o kernel que está destinado a ser o 9.x, +por exemplo, o lançamento que ocorre ao final da janela de integração será +chamado de 9.x-rc1. O lançamento -rc1 é o sinal de que o prazo para integrar +novos recursos terminou e que o período para estabilizar o próximo kernel +começou. + +Ao longo das próximas seis a dez semanas, apenas patches que corrijam +problemas devem ser submetidos ao kernel principal. Ocasionalmente, uma +mudança mais significativa será permitida, mas esses casos são raros; +desenvolvedores que tentam integrar novos recursos fora da janela de +integração costumam receber uma recepção pouco amigável. Como regra geral, +se você perder a janela de integração para um determinado recurso, o melhor +a fazer é esperar pelo próximo ciclo de desenvolvimento. (Abre-se uma +exceção ocasional para drivers de hardware que antes não eram suportados; +se eles não modificarem nenhum código já existente na árvore, não podem +causar regressões e deve ser seguro adicioná-los a qualquer momento). + +À medida que as correções são integradas ao kernel principal, o ritmo de +envio de patches diminui com o tempo. Linus lança novos kernels -rc cerca +de uma vez por semana; uma série normal chega a algo entre -rc6 e -rc9 antes +que o kernel seja considerado suficientemente estável e o lançamento final +seja realizado. Nesse ponto, todo o processo recomeça. + +Como exemplo, veja como ocorreu o ciclo de desenvolvimento da versão 5.4 +(todas as datas são de 2019): + + ============== =============================== + Setembro 15 5.3 Lançamento estável do 5.3 + Setembro 30 5.4-rc1, fechamento da janela de integração + Outubro 6 5.4-rc2 + Outubro 13 5.4-rc3 + Outubro 20 5.4-rc4 + October 27 5.4-rc5 + Novembro 3 5.4-rc6 + Novembro 10 5.4-rc7 + Novembro 17 5.4-rc8 + Novembro 24 5.4 Lançamento estável do 5.4 + ============== =============================== + +Como os desenvolvedores decidem quando encerrar o ciclo de desenvolvimento +e criar o lançamento estável? A métrica mais significativa utilizada é a +lista de regressões de lançamentos anteriores. Nenhum bug é bem-vindo, mas +aqueles que quebram sistemas que funcionavam no passado são considerados +especialmente graves. Por esta razão, patches que causam regressões são +vistos de forma desfavorável e têm grande probabilidade de serem revertidos +durante o período de estabilização. + +O objetivo dos desenvolvedores é corrigir todas as regressões conhecidas +antes que o lançamento estável seja feito. No mundo real, esse tipo de +perfeição é difícil de alcançar; há simplesmente variáveis demais em um +projeto deste tamanho. Chega um ponto em que adiar o lançamento final apenas +torna o problema pior; o volume de mudanças esperando pela próxima janela de +integração crescerá ainda mais, criando ainda mais regressões no ciclo +seguinte. Portanto, a maioria dos kernels é lançada com um pequeno número de +regressões conhecidas, embora, felizmente, nenhuma delas seja grave. + +Assim que um lançamento estável é feito, sua manutenção contínua é passada +para a "equipe estável" (*stable team*), atualmente composta por Greg +Kroah-Hartman e Sasha Levin. A equipe estável lançará atualizações ocasionais +para a versão estável utilizando o esquema de numeração 9.x.y. + +Para ser considerado para um lançamento de atualização, um patch deve (1) +corrigir um bug significativo e (2) já estar integrado ao kernel principal +(*mainline*) para o próximo kernel de desenvolvimento. Os kernels normalmente +receberão atualizações estáveis por um pouco mais de um ciclo de +desenvolvimento após o seu lançamento inicial. Assim, por exemplo, o histórico +do kernel 5.2 ocorreu da seguinte forma (todas as datas são de 2019): + + ============== =============================== + 7 de Julho Lançamento estável do 5.2 + 14 de Julho 5.2.1 + 21 de Julho 5.2.2 + 26 de Julho 5.2.3 + 28 de Julho 5.2.4 + 31 de Julho 5.2.5 + ... ... + 11 de Outubro 5.2.21 + ============== =============================== + +A versão 5.2.21 foi a última atualização estável do lançamento 5.2. + +Alguns kernels são designados como kernels de "longo prazo" (*long term*); +eles receberão suporte por um período mais longo. Por favor, consulte o +seguinte link para obter a lista de versões ativas do kernel de longo prazo +e seus respectivos mantenedores: + + https://www.kernel.org/category/releases.html + +A seleção de um kernel para suporte de longo prazo é puramente uma questão +de um mantenedor ter a necessidade e o tempo para manter esse lançamento. +Não há planos conhecidos para suporte de longo prazo para nenhum lançamento +futuro específico. + + +O Ciclo de Vida de um Patch +--------------------------- + +Os patches não vão diretamente do teclado do desenvolvedor para o kernel +principal. Em vez disso, existe um processo um tanto complexo (embora um +tanto informal) projetado para garantir que cada patch seja revisado quanto +à sua qualidade e que cada patch implemente uma mudança que seja desejável +ter no mainline. Esse processo pode acontecer rapidamente para correções +menores ou, no caso de mudanças grandes e controversas, arrastar-se por +anos. Grande parte da frustração dos desenvolvedores vem da falta de +compreensão desse processo ou de tentativas de burlá-lo. + +Com a esperança de reduzir essa frustração, este documento descreverá como +um patch entra no kernel. O que se segue abaixo é uma introdução que +descreve o processo de uma forma um tanto idealizada. Um tratamento muito +mais detalhado virá nas seções posteriores. + +As etapas pelas quais um patch passa são, geralmente: + + - Design. É aqui que os requisitos reais para o patch e a forma + como esses requisitos serão atendidos são definidos. O trabalho de + design geralmente é feito sem envolver a comunidade, mas é melhor realizar + esse trabalho abertamente, se possível; isso pode economizar muito tempo + evitando ter que refazer o projeto mais tarde. + + - Revisão inicial. Os patches são postados na lista de + discussão relevante, e os desenvolvedores dessa lista respondem com os + comentários que tiverem. Se tudo correr bem, esse processo deve apontar + qualquer problema grave no patch. + + - Revisão ampla. Quando o patch estiver próximo de estar + pronto para inclusão no mainline, ele deve ser aceito por um mantenedor de + subsistema relevante — embora essa aceitação não seja uma garantia de que + o patch chegará até o kernel principal. O patch aparecerá na árvore de + subsistema do mantenedor e nas árvores -next. Quando o processo funciona, + esta etapa leva a uma revisão mais ampla do patch e à descoberta de + quaisquer problemas resultantes da integração deste patch com o trabalho + que está sendo feito por outros. + + - Por favor, note que a maioria dos mantenedores também tem seus empregos + regulares, portanto, integrar o seu patch pode não ser a maior prioridade + deles. Se o seu patch estiver recebendo feedback sobre alterações que são + necessárias, você deve fazer essas alterações ou justificar por que elas + não devem ser feitas. Se o seu patch não tiver nenhuma objeção de revisão, + mas não estiver sendo integrado pelo mantenedor do subsistema ou driver + adequado, você deve ser persistente em atualizar o patch para o kernel + atual (garantindo que ele seja aplicado de forma limpa) e continuar + enviando-o para revisão e integração. + + - Integração no mainline. Eventualmente, um + patch bem-sucedido será integrado ao repositório principal (*mainline*) + gerenciado por Linus Torvalds. Mais comentários e/ou problemas podem surgir + neste momento; é importante que o desenvolvedor seja responsivo a eles e + corrija quaisquer problemas que venham a aparecer. + + - Lançamento estável. O número de usuários potencialmente + afetados pelo patch agora é grande, portanto, mais uma vez, novos + problemas podem surgir. + + - Manutenção de longo prazo. Embora seja perfeitamente + possível para um desenvolvedor esquecer o código após integrá-lo, esse + tipo de comportamento tende a deixar uma má impressão na comunidade de + desenvolvimento. Integrar o código elimina parte do fardo de manutenção, + já que outros corrigirão problemas causados por mudanças de API. No entanto, + o desenvolvedor original deve continuar assumindo a responsabilidade pelo + código se ele quiser que este permaneça útil no longo prazo. + +Um dos maiores erros cometidos por desenvolvedores do kernel (ou por seus +empregadores) é tentar reduzir todo o processo a uma única etapa de +"integração no mainline". Essa abordagem invariavelmente leva à frustração +de todos os envolvidos. + +Como os patches entram no Kernel +-------------------------------- + +Existe exatamente uma pessoa que pode integrar patches no repositório do +kernel principal: Linus Torvalds. Mas, por exemplo, dos mais de 9.500 patches +que entraram no kernel 2.6.38, apenas 112 (cerca de 1,3%) foram escolhidos +diretamente pelo próprio Linus. O projeto do kernel há muito tempo cresceu +para um tamanho onde nenhum desenvolvedor sozinho conseguiria inspecionar e +selecionar cada patch sem ajuda. A maneira como os desenvolvedores do kernel +lidaram com esse crescimento foi através do uso de um sistema de "tenentes" +(*lieutenant system*) construído em torno de uma cadeia de confiança. + +A base de código do kernel é logicamente dividida em um conjunto de +subsistemas: rede, suporte a arquiteturas específicas, +gerenciamento de memória, dispositivos de vídeo, etc. A maioria dos +subsistemas possui um mantenedor designado, um desenvolvedor que tem a +responsabilidade geral pelo código dentro daquele subsistema. Esses +mantenedores de subsistemas são os guardiões (de forma flexível) +da parte do kernel que gerenciam; são eles que (geralmente) aceitarão um +patch para inclusão no kernel principal. + +Cada um dos mantenedores de subsistemas gerencia sua própria versão da árvore +de fontes do kernel, geralmente (mas certamente nem sempre) usando a +ferramenta de gerenciamento de código-fonte Git. Ferramentas como o Git +(e ferramentas relacionadas como o quilt ou mercurial) permitem que os +mantenedores acompanhem uma lista de patches, incluindo informações de +autoria e outros metadados. A qualquer momento, o mantenedor pode identificar +quais patches em seu repositório não são encontrados no mainline. + +Quando a janela de integração se abre, os mantenedores de +alto nível pedirão a Linus para realizar o pull de seus repositórios os patches +que selecionaram para integração. Se Linus concordar, o fluxo de patches +subirá para o seu repositório, tornando-se parte do kernel principal. A +quantidade de atenção que Linus dedica a patches específicos +recebidos em uma operação de pull varia. Está claro que, às vezes, ele os +examina bem de perto. Mas, como regra geral, Linus confia que os mantenedores +de subsistemas não enviarão patches ruins para o upstream. + +Os mantenedores de subsistemas, por sua vez, podem realizar o pull dos patches +de outros mantenedores. Por exemplo, a árvore de rede é +construída a partir de patches que se acumularam primeiro em árvores dedicadas +a drivers de dispositivos de rede, rede sem fio, etc. Essa cadeia +de repositórios pode ser arbitrariamente longa, embora raramente exceda dois +ou três elos. Como cada mantenedor na cadeia confia naqueles que gerenciam as +árvores de nível inferior, esse processo é conhecido como a "cadeia de +confiança". + +Claramente, em um sistema como este, colocar patches no kernel depende de +encontrar o mantenedor correto. Enviar patches diretamente para Linus +normalmente não é o caminho certo a seguir. + + +Árvore -next +------------- + +A cadeia de árvores de subsistemas orienta o fluxo de patches para o kernel, +mas também levanta uma questão interessante: e se alguém quiser dar uma +olhada em todos os patches que estão sendo preparados para a próxima janela +de integração? Os desenvolvedores estarão interessados em saber quais outras +mudanças estão pendentes para ver se há conflitos com os quais se preocupar; um +patch que altera o protótipo de uma função central do kernel, por exemplo, +entrará em conflito com quaisquer outros patches que usem a forma mais antiga +dessa função. Revisores e testadores querem ter acesso às mudanças em sua forma +integrada antes que todas essas alterações cheguem ao kernel principal. Seria +possível realizar o pull das mudanças de todas as árvores de subsistemas +interessantes, mas isso seria um trabalho enorme e propenso a erros. + +A resposta vem na forma das árvores -next, onde as árvores de subsistemas +são coletadas para testes e revisão. A mais antiga dessas árvores, mantida +por Andrew Morton, é chamada de "-mm" (de *memory management*, gerenciamento +de memória, que foi como ela começou). A árvore -mm integra patches de uma +longa lista de árvores de subsistemas; ela também possui alguns patches +destinados a ajudar na depuração (*debugging*). + +Além disso, a árvore -mm contém uma coleção significativa de patches que +foram selecionados diretamente por Andrew. Esses patches podem ter sido +postados em uma lista de discussão ou podem se aplicar a uma parte do kernel +para a qual não existe uma árvore de subsistema designada. Como resultado, a +-mm opera como uma espécie de árvore de subsistema de "último recurso"; se +não houver outro caminho óbvio para um patch entrar no mainline, é provável +que ele acabe na -mm. Patches diversos que se acumulam na +-mm eventualmente serão encaminhados para uma árvore de subsistema adequada +ou enviados diretamente para Linus. Em um ciclo de desenvolvimento típico, +aproximadamente 5% a 10% do total de patches que entram no mainline chegam +lá por meio da -mm. + +O patch -mm atual está disponível no diretório "mmotm" (*-mm of the moment*) +em: + + https://www.ozlabs.org/~akpm/mmotm/ + +O uso da árvore MMOTM, no entanto, provavelmente será uma experiência +frustrante; existe uma chance real de que ela sequer compile. + +A árvore primária para a integração de patches do próximo ciclo é a +linux-next, mantida por Mark Brown. A árvore linux-next é, por design, um +snapshot do que se espera que o mainline se pareça após o +fechamento da próxima janela de integração. As árvores +linux-next são anunciadas nas listas de discussão linux-kernel e linux-next +quando são montadas; elas podem ser baixadas em: + + https://www.kernel.org/pub/linux/kernel/next/ + +A linux-next tornou-se uma parte integrante do processo de desenvolvimento +do kernel; todos os patches integrados durante uma determinada janela de +integração devem, idealmente, ter encontrado seu caminho para a linux-next algum +tempo antes da abertura da janela de integração. + + +Árvores de laboratório +---------------------- + +A árvore de fontes do kernel contém o diretório drivers/staging/, onde residem +muitos subdiretórios para drivers ou sistemas de arquivos que estão a caminho +de serem adicionados à árvore do kernel. Eles permanecem em drivers/staging/ +enquanto ainda precisam de mais trabalho; uma vez concluídos, podem ser movidos +para o kernel proper Esta é uma maneira de acompanhar drivers que não estão à +altura dos padrões de codificação ou de qualidade do kernel Linux, mas que as +pessoas podem querer usar e acompanhar o desenvolvimento. + +Greg Kroah-Hartman atualmente mantém a árvore de staging. Os drivers que +ainda precisam de trabalho são enviados a ele, com cada driver tendo seu +próprio subdiretório em drivers/staging/. Junto com os arquivos de código-fonte +do driver, um arquivo TODO também deve estar presente no diretório. O arquivo +TODO lista o trabalho pendente que o driver precisa para ser aceito no kernel +propriamente dito, bem como uma lista de pessoas que devem receber cópia +(*Cc'd*) em quaisquer patches para o driver. As regras atuais exigem que os +drivers contribuídos para o staging devem, no mínimo, compilar corretamente. + +O staging pode ser uma maneira relativamente fácil de colocar novos drivers +no mainline onde, com sorte, eles chamarão a atenção de outros desenvolvedores +e melhorarão rapidamente. No entanto, a entrada no staging não é o fim da +história; o código no staging que não apresentar progresso regular será, +eventualmente, removido. Os distribuidores também tendem a ser relativamente +relutantes em habilitar drivers do staging. Portanto, o staging é, na melhor +das hipóteses, uma parada no caminho para se tornar um driver mainline adequado. + + +Ferramentas +----------- + +Como pode ser visto no texto acima, o processo de desenvolvimento do kernel +depende fortemente da capacidade de guiar coleções de patches em várias +direções. Todo esse sistema não funcionaria nem de longe tão bem quanto +funciona sem ferramentas adequadamente poderosas. Tutoriais sobre como usar +essas ferramentas estão muito além do escopo deste documento, mas há espaço +para algumas indicações. + +De longe, o sistema de gerenciamento de código-fonte dominante usado pela +comunidade do kernel é o Git. O Git é um entre vários sistemas de controle +de versão distribuídos desenvolvidos na comunidade de software livre. Ele é +bem sintonizado para o desenvolvimento do kernel, uma vez que apresenta um +excelente desempenho ao lidar com grandes repositórios e grandes volumes de +patches. Ele também tem a reputação de ser difícil de aprender e usar, embora +tenha melhorado ao longo do tempo. Algum tipo de familiaridade com o Git é +quase um requisito para os desenvolvedores do kernel; mesmo que não o usem +em seu próprio trabalho, eles precisarão do Git para acompanhar o que outros +desenvolvedores (e o mainline) estão fazendo. + +O Git agora é empacotado por quase todas as distribuições Linux. Existe uma +página inicial em: + + https://git-scm.com/ + +Essa página possui indicações para documentações e tutoriais. + +Entre os desenvolvedores do kernel que não usam o Git, a escolha mais popular +é, quase certamente, o Mercurial: + + https://www.selenic.com/mercurial/ + +O Mercurial compartilha muitos recursos com o Git, mas oferece uma interface +que muitos consideram mais fácil de usar. + +A outra ferramenta que vale a pena conhecer é o Quilt: + + https://savannah.nongnu.org/projects/quilt/ + +O Quilt é um sistema de gerenciamento de patches, em vez de um sistema de +gerenciamento de código-fonte. Ele não rastreia o histórico ao longo do +tempo; em vez disso, ele é orientado a rastrear um conjunto específico de +alterações em relação a uma base de código em evolução. Alguns mantenedores +de grandes subsistemas usam o Quilt para gerenciar patches destinados a ir +para o upstream. Para o gerenciamento de certos tipos de árvores (-mm, por +exemplo), o Quilt é a melhor ferramenta para o trabalho. + + +Listas de discussão +------------------- + +Uma grande parte do trabalho de desenvolvimento do kernel Linux é realizada por +meio de listas de discussão. É difícil ser um membro plenamente ativo da +comunidade sem se inscrever em pelo menos uma lista em algum lugar. No entanto, +as listas de discussão do Linux também representam um risco potencial para os +desenvolvedores, que correm o risco de serem soterrados por uma avalanche de +e-mails, de violar as convenções utilizadas nas listas do Linux, ou ambos. + +A maioria das listas de discussão do kernel é hospedada no kernel.org; a +lista mestre pode ser encontrada em: + + https://subspace.kernel.org + +Existem listas hospedadas em outros locais; por favor, verifique o arquivo +MAINTAINERS para encontrar a lista relevante para qualquer subsistema específico. + +A lista de discussão central para o desenvolvimento do kernel é, naturalmente, +a linux-kernel. Esta lista é um lugar intimidador para se estar; o volume pode +atingir 500 mensagens por dia, a quantidade de ruído é alta, a conversa pode +ser severamente técnica e os participantes nem sempre estão preocupados em +demonstrar um alto grau de polidez. No entanto, não há outro lugar onde a +comunidade de desenvolvimento do kernel se reúna como um todo; desenvolvedores +que evitam esta lista perderão informações importantes. + +Existem algumas dicas que podem ajudar na sobrevivência na lista linux-kernel: + +- Faça com que a lista seja entregue em uma pasta separada, em vez de na sua + caixa de entrada principal. É preciso ser capaz de ignorar o fluxo de e-mails + por períodos prolongados de tempo. + +- Não tente acompanhar cada conversa ninguém mais faz isso. É importante + filtrar tanto pelo tópico de interesse (embora note que conversas longas + podem se desviar do assunto original sem que a linha de assunto do e-mail + seja alterada) quanto pelas pessoas que estão participando. + +- Não alimente os trolls. Se alguém estiver tentando provocar uma resposta + irada, ignore-o. + +- Ao responder a um e-mail da lista linux-kernel (o mesmo valendo para outras + listas), preserve o cabeçalho Cc: para todos os envolvidos. Na ausência de um + motivo forte (como uma solicitação explícita), você nunca deve remover + destinatários. Sempre certifique-se de que a pessoa a quem você está + respondendo esteja na lista de Cc:. Essa convenção também torna desnecessário + solicitar explicitamente ser copiado em respostas às suas postagens. + +- Pesquise nos arquivos da lista (e na internet como um todo) antes de fazer + perguntas. Alguns desenvolvedores podem ficar impacientes com pessoas que + claramente não fizeram sua lição de casa. + +- Use respostas intercaladas, o que torna sua resposta mais fácil + de ler. (ou seja, evite o "top-posting" — a prática de colocar sua resposta + acima do texto citado ao qual você está respondendo). Para mais detalhes, veja + :ref:`Documentation/process/submitting-patches.rst `. + +- Pergunte na lista de discussão correta. A lista linux-kernel pode até ser o + ponto de encontro geral, mas não é o melhor lugar para encontrar desenvolvedores + de todos os subsistemas. + +O último ponto, encontrar a lista de discussão correta é um lugar comum +onde os desenvolvedores iniciantes costumam errar. Alguém que faça uma pergunta +relacionada a redes na lista linux-kernel quase certamente receberá uma +sugestão educada para perguntar na lista netdev em seu lugar, já que essa é a +lista frequentada pela maioria dos desenvolvedores de redes. Existem outras +listas para os subsistemas SCSI, video4linux, IDE, filesystem (sistemas de +arquivos), etc. O melhor lugar para procurar por listas de discussão é no +arquivo MAINTAINERS empacotado junto com o código-fonte do kernel. + + +Começando com o desenvolvimento do kernel +----------------------------------------- + +Perguntas sobre como começar com o processo de desenvolvimento do kernel são +comuns — tanto por parte de indivíduos quanto de empresas. Igualmente comuns +são os passos em falso que tornam o início do relacionamento mais difícil do +que precisa ser. + +As empresas frequentemente buscam contratar desenvolvedores bem conhecidos para +dar o pontapé inicial em um grupo de desenvolvimento. Esta pode, de fato, ser +uma técnica eficaz. No entanto, ela também tende a ser cara e não faz muito para +expandir o grupo de desenvolvedores de kernel experientes. É possível capacitar +desenvolvedores internos no desenvolvimento do kernel Linux, desde que haja o +investimento de um pouco de tempo. Dedicar esse tempo pode dotar um empregador +de um grupo de desenvolvedores que entendem tanto o kernel quanto a própria +empresa, e que também podem ajudar a treinar outros. A médio prazo, esta é +frequentemente a abordagem mais lucrativa. + +Desenvolvedores individuais frequentemente, e de forma compreensível, ficam sem +saber por onde começar. Iniciar com um grande projeto pode ser intimidante; +muitas vezes deseja-se testar o terreno com algo menor primeiro. Este é o ponto +onde alguns desenvolvedores saltam para a criação de patches que corrigem erros +de ortografia ou pequenos problemas de estilo de código. Infelizmente, tais +patches criam um nível de ruído que distrai a comunidade de desenvolvimento +como um todo, por isso, cada vez mais, eles são vistos com desdém. Novos +desenvolvedores que desejam se apresentar à comunidade não receberão o tipo de +recepção que desejam por esses meios. + +Andrew Morton dá este conselho para aspirantes a desenvolvedores do kernel: + +:: + + "O projeto número um para todos os iniciantes no kernel certamente deveria + ser 'certificar-se de que o kernel funcione perfeitamente o tempo todo em + todas as máquinas em que você conseguir colocar as mãos'. Normalmente, a + maneira de fazer isso é trabalhar com outros para resolver as coisas (isso + pode exigir persistência!), mas tudo bem — isso é parte do desenvolvimento + do kernel." + +(https://lwn.net/Articles/283982/). + +Na ausência de problemas óbvios para corrigir, os desenvolvedores são +aconselhados a olhar para as listas atuais de regressões e bugs abertos em +geral. Nunca há escassez de problemas que precisam de correção; ao abordar +esses problemas, os desenvolvedores ganharão experiência com o processo +enquanto, ao mesmo tempo, constroem respeito com o restante da comunidade de +desenvolvimento. diff --git a/Documentation/translations/pt_BR/process/development-process.rst b/Documentation/translations/pt_BR/process/development-process.rst new file mode 100644 index 000000000000..737fdcdffd4a --- /dev/null +++ b/Documentation/translations/pt_BR/process/development-process.rst @@ -0,0 +1,21 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Guia para o Processo de Desenvolvimento do Kernel +================================================= + +O objetivo deste documento é ajudar desenvolvedores (e seus gerentes) +a trabalhar com a comunidade de desenvolvimento com o mínimo de frustração. +É uma tentativa de documentar como esta comunidade funciona de uma forma +que seja acessível àqueles que não estão intimamente familiarizados com o +desenvolvimento do kernel Linux (ou, de fato, com o desenvolvimento de +software livre em geral). Embora haja algum material técnico aqui, esta +é fundamentalmente uma discussão orientada ao processo, que não requer um +conhecimento profundo de programação de kernel para ser compreendida. + +.. toctree:: + :caption: Contents + :numbered: + :maxdepth: 2 + + 1.Intro + 2.Process From 344cc3d79494935e5ed1c5b2f2359022ff34fedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amanda=20Corr=C3=AAa?= Date: Thu, 28 May 2026 01:19:58 -0300 Subject: [PATCH 457/655] docs: pt_BR: update maintainer-handbooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the content of the maintainer-handbooks documentation to Brazilian Portuguese. Signed-off-by: Amanda Corrêa Acked-by: Daniel Pereira Signed-off-by: Jonathan Corbet Message-ID: <20260528041958.57231-1-amandacorreasilvax@gmail.com> --- .../pt_BR/process/maintainer-handbooks.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Documentation/translations/pt_BR/process/maintainer-handbooks.rst b/Documentation/translations/pt_BR/process/maintainer-handbooks.rst index bf7a381472e2..b7aab788ffdb 100644 --- a/Documentation/translations/pt_BR/process/maintainer-handbooks.rst +++ b/Documentation/translations/pt_BR/process/maintainer-handbooks.rst @@ -6,14 +6,17 @@ Notas sobre o processo de desenvolvimento de subsistemas e mantenedores O propósito deste documento é fornecer informações específicas de subsistemas que são suplementares ao manual geral do processo de desenvolvimento. +:ref:`Documentation/process `. -Conteúdos: +Para desenvolvedores, veja abaixo todos os guias específicos de +subsistemas conhecidos. Se o subsistema para o qual você está +contribuindo não tiver um guia listado aqui, é recomendável buscar +esclarecimentos sobre as questões levantadas em +Documentation/maintainer/maintainer-entry-profile.rst. -.. toctree:: - :numbered: - :maxdepth: 2 +Para mantenedores, considere documentar requisitos adicionais e +expectativas caso as submissões frequentemente deixem de atender +a critérios específicos de submissão. Veja +Documentation/maintainer/maintainer-entry-profile.rst. - maintainer-netdev - maintainer-soc - maintainer-soc-clean-dts - maintainer-kvm-x86 +.. maintainers-profile-toc:: From 323fa4b9608b1c277ca7f97f81172aa56da76074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 May 2026 10:10:05 +0200 Subject: [PATCH 458/655] Documentation: Fix syntax of kmalloc_objs example in coding style doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first parameter should match the variable that the allocated memory is assigned to. Fix the example accordingly, the one for kmalloc_obj got it right already. Fixes: 7c6d969d5349 ("Documentation: adopt new coding style of type-aware kmalloc-family") Signed-off-by: Uwe Kleine-König Reviewed-by: Geert Uytterhoeven Signed-off-by: Jonathan Corbet Message-ID: <20260529081006.2019687-2-ukleinek@kernel.org> --- Documentation/process/coding-style.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/process/coding-style.rst b/Documentation/process/coding-style.rst index a3bf75dc7c88..a8336582f60b 100644 --- a/Documentation/process/coding-style.rst +++ b/Documentation/process/coding-style.rst @@ -959,13 +959,13 @@ The preferred form for allocating an array is the following: .. code-block:: c - p = kmalloc_objs(*ptr, n, ...); + p = kmalloc_objs(*p, n, ...); The preferred form for allocating a zeroed array is the following: .. code-block:: c - p = kzalloc_objs(*ptr, n, ...); + p = kzalloc_objs(*p, n, ...); Both forms check for overflow on the allocation size n * sizeof(...), and return NULL if that occurred. From 2c1ccd9a1d786503086e83fe83e5c3b3c953b70e Mon Sep 17 00:00:00 2001 From: Zhan Xusheng Date: Tue, 26 May 2026 10:20:33 +0800 Subject: [PATCH 459/655] docs: changes.rst: restore pahole 1.26 minimum (regressed by sort) Commit 9edd04c4189e ("docs: Raise minimum pahole version to 1.26 for KF_IMPLICIT_ARGS kfuncs") raised the minimum required pahole version from 1.22 to 1.26 in the requirements table and added a paragraph explaining the failure mode for distributions still shipping pahole v1.25 (e.g. Ubuntu 24.04 LTS). The next day, commit ece7e57afd51 ("docs: changes.rst and ver_linux: sort the lists") came through a different tree (docs vs sched_ext) and re-flowed the table alphabetically, but its base did not include 9edd04c4189e. When the two commits met in mainline, the textual rewrite of the table won and the version bump was lost. The added "Since Linux 7.0..." paragraph also disappeared. The result is that changes.rst on master (v7.1-rc5) lists pahole 1.22 again, even though sched_ext kfuncs annotated with KF_IMPLICIT_ARGS genuinely require v1.26 to produce a correct vmlinux BTF. Users on distributions with pahole v1.25 hit "func_proto incompatible with vmlinux" when loading any sched_ext BPF program (scx_simple, scx_qmap, ...) and have no documentation pointing them at the version gap. Restore both changes from 9edd04c4189e. Fixes: ece7e57afd51 ("docs: changes.rst and ver_linux: sort the lists") Signed-off-by: Zhan Xusheng Signed-off-by: Jonathan Corbet Message-ID: <20260526022033.1301884-1-zhanxusheng@xiaomi.com> --- Documentation/process/changes.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 9a99037270ff..a4db8f7b3afb 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -53,7 +53,7 @@ mcelog 0.6 mcelog --version mkimage (optional) 2017.01 mkimage --version nfs-utils 1.0.5 showmount --version openssl & libcrypto 1.0.0 openssl version -pahole 1.22 pahole --version +pahole 1.26 pahole --version pcmciautils 004 pccardctl -V PPP 2.4.0 pppd --version procps 3.2.0 ps --version @@ -147,6 +147,11 @@ Since Linux 5.2, if CONFIG_DEBUG_INFO_BTF is selected, the build system generates BTF (BPF Type Format) from DWARF in vmlinux, a bit later from kernel modules as well. This requires pahole v1.22 or later. +Since Linux 7.0, kfuncs annotated with KF_IMPLICIT_ARGS require pahole v1.26 +or later. Without it, such kfuncs will have incorrect BTF prototypes in +vmlinux, causing BPF programs to fail to load with a "func_proto incompatible +with vmlinux" error. Many sched_ext kfuncs are affected. + It is found in the 'dwarves' or 'pahole' distro packages or from https://fedorapeople.org/~acme/dwarves/. From af794e79d803e509eef130765b049f6c9c61e8c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Mart=C3=ADn=20Gil?= Date: Mon, 25 May 2026 23:45:53 +0200 Subject: [PATCH 460/655] docs: md: fix grammar in speed_limit description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 'This are' with 'These are' in the md sysfs speed limit section to correct grammar and improve readability. Signed-off-by: Miguel Martín Gil Signed-off-by: Jonathan Corbet Message-ID: <20260525214554.2196-1-miguel.martin.gil.uni@gmail.com> --- Documentation/admin-guide/md.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/md.rst b/Documentation/admin-guide/md.rst index dc7eab191caa..003fd34f73bc 100644 --- a/Documentation/admin-guide/md.rst +++ b/Documentation/admin-guide/md.rst @@ -734,7 +734,7 @@ also have They should be scaled by the bitmap_chunksize. sync_speed_min, sync_speed_max - This are similar to ``/proc/sys/dev/raid/speed_limit_{min,max}`` + These are similar to ``/proc/sys/dev/raid/speed_limit_{min,max}`` however they only apply to the particular array. If no value has been written to these, or if the word ``system`` From a41ac48a164a2e8b85cc819b206cc7e87fe3f43b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 27 May 2026 22:46:11 -0700 Subject: [PATCH 461/655] iommu: Documentation: rearrange, update kernel-parameters Add text for some undescribed iommu= parameters (merge, nomerge, biomerge, panic, nopanic, pt, nopt). Add "usedac" and its description. Add that iommu=pt is equivalent to iommu.passthrough=1 and that iommu=nopt is equivalent to iommu.passthrough=0. Move the PPC/POWERNV heading & its option "nobypass" to a separate area since the current "iommu=" applies only to X86 (according to its heading). Unindent the AMD GART IOMMU options heading to make it stand out. Also add its kconfig symbol name to be explicit about what these options apply to. Make sure that the IOMMU options that are listed under AMD Gart HW IOMMU-specific options are only for that product; i.e., add "force" there and move "merge", "nomerge", and "panic" to the general IOMMU options area. Signed-off-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260528054611.1524937-1-rdunlap@infradead.org> --- .../admin-guide/kernel-parameters.txt | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 8c22943e51c0..f2fff89bc7bb 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2580,23 +2580,41 @@ Kernel parameters Don't force hardware IOMMU usage when it is not needed. (default). - biomerge - panic - nopanic merge + Do scatter-gather (SG) merging. Implies "force" + (experimental). + nomerge + Don't do scatter-gather (SG) merging. + + biomerge + Do scatter-gather (SG) merging. Implies "force" + (experimental). [same as "merge"] + + panic + Always panic when IOMMU overflows. + + nopanic + Don't panic on IOMMU overflows. + + pt + Use passththrough mode by default + (Equivalent to iommu.passthrough=1) + + nopt + Use translated mode for DMA by default + (Equivalent to iommu.passthrough=0) soft Use software bounce buffering (SWIOTLB) (default for Intel machines). This can be used to prevent the usage of an available hardware IOMMU. - pt - nopt - nobypass [PPC/POWERNV] - Disable IOMMU bypass, using IOMMU for PCI devices. + usedac + Use the DAC on VIA PCI bridge + (default: disable the VIA PCI bridge DAC) - AMD Gart HW IOMMU-specific options: + AMD Gart HW IOMMU-specific options: (CONFIG_GART_IOMMU) Set the size of the remapping area in bytes. @@ -2604,6 +2622,9 @@ Kernel parameters allowed Overwrite iommu off workarounds for specific chipsets + force + Overwrite iommu off workarounds for specific chipsets + fullflush Flush IOMMU on each allocation (default). @@ -2614,21 +2635,16 @@ Kernel parameters Allocate an own aperture over RAM with size 32MB< Date: Sun, 31 May 2026 16:54:50 +0300 Subject: [PATCH 462/655] docs: kernel-parameters: Remove sa1100ir IrDA parameter The sa1100ir parameter referenced drivers/net/irda/sa1100_ir.c, which was removed along with the entire IrDA stack in commit d64c2a76123f ("staging: irda: remove the irda network stack and drivers"). Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260531135455.4113157-1-costa.shul@redhat.com> --- Documentation/admin-guide/kernel-parameters.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index f2fff89bc7bb..a0704bfef72c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6786,8 +6786,6 @@ Kernel parameters restrictions other than those given by hardware at the cost of significant additional memory use for tables. - sa1100ir [NET] - See drivers/net/irda/sa1100_ir.c. sched_proxy_exec= [KNL] Enables or disables "proxy execution" style From 11d309f63357da45de026f5ac2e5e6afdd547800 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sun, 31 May 2026 16:58:48 +0300 Subject: [PATCH 463/655] docs: sonypi: Fix stale header file path The sonypi.h header was moved from drivers/char/ to include/linux/. Update the reference. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Signed-off-by: Jonathan Corbet Message-ID: <20260531135850.4113774-1-costa.shul@redhat.com> --- Documentation/admin-guide/laptops/sonypi.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/laptops/sonypi.rst b/Documentation/admin-guide/laptops/sonypi.rst index 7541f56e0007..fb8f4a30ddce 100644 --- a/Documentation/admin-guide/laptops/sonypi.rst +++ b/Documentation/admin-guide/laptops/sonypi.rst @@ -89,7 +89,7 @@ statically linked into the kernel). Those options are: set to 0xffffffff, meaning that all possible events will be tried. You can use the following bits to construct your own event mask (from - drivers/char/sonypi.h):: + include/linux/sonypi.h):: SONYPI_JOGGER_MASK 0x0001 SONYPI_CAPTURE_MASK 0x0002 From ef4c0f7aee482459205149e52a8ab770e85b7f63 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sun, 31 May 2026 17:02:07 +0300 Subject: [PATCH 464/655] docs: kgdb: Fix stale source file paths Update two file paths that became stale when kgdb/kdb sources were reorganized: - kernel/debugger/debug_core.c -> kernel/debug/debug_core.c - drivers/char/kdb_keyboard.c -> kernel/debug/kdb/kdb_keyboard.c Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Signed-off-by: Jonathan Corbet Message-ID: <20260531140207.4114764-1-costa.shul@redhat.com> --- Documentation/process/debugging/kgdb.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/process/debugging/kgdb.rst b/Documentation/process/debugging/kgdb.rst index dd6a103073fa..c4d0a9121d52 100644 --- a/Documentation/process/debugging/kgdb.rst +++ b/Documentation/process/debugging/kgdb.rst @@ -696,7 +696,7 @@ The kernel debugger is organized into a number of components: 1. The debug core - The debug core is found in ``kernel/debugger/debug_core.c``. It + The debug core is found in ``kernel/debug/debug_core.c``. It contains: - A generic OS exception handler which includes sync'ing the @@ -877,7 +877,7 @@ attached keyboard. The keyboard infrastructure is only compiled into the kernel when ``CONFIG_KDB_KEYBOARD=y`` is set in the kernel configuration. The core polled keyboard driver for PS/2 type keyboards is in -``drivers/char/kdb_keyboard.c``. This driver is hooked into the debug core +``kernel/debug/kdb/kdb_keyboard.c``. This driver is hooked into the debug core when kgdboc populates the callback in the array called :c:expr:`kdb_poll_funcs[]`. The kdb_get_kbd_char() is the top-level function which polls hardware for single character input. From 2d5e755b0698572c6564567645c31385055e1f5c Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sun, 31 May 2026 17:18:22 +0300 Subject: [PATCH 465/655] docs: real-time: Fix duplicated sched(7) text The man page reference appeared twice - once as plain text and once as a hyperlink. Remove the plain text duplicate. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Reviewed-by: Sebastian Andrzej Siewior Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260531141823.4118954-1-costa.shul@redhat.com> --- Documentation/core-api/real-time/theory.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/core-api/real-time/theory.rst b/Documentation/core-api/real-time/theory.rst index 43d0120737f8..92de5654163d 100644 --- a/Documentation/core-api/real-time/theory.rst +++ b/Documentation/core-api/real-time/theory.rst @@ -25,7 +25,7 @@ Scheduling ========== The core principles of Linux scheduling and the associated user-space API are -documented in the man page sched(7) +documented in the man page `sched(7) `_. By default, the Linux kernel uses the SCHED_OTHER scheduling policy. Under this policy, a task is preempted when the scheduler determines that it has From 3c2edee3a40ee5fe0bb219c7401fa9ff57009334 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sun, 31 May 2026 17:05:37 +0300 Subject: [PATCH 466/655] docs: kernel-parameters: Fix stale sticore file paths Update file paths for sticore references that became stale when drivers were reorganized: - drivers/video/console/sticore.c -> drivers/video/ Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Costa Shulyupin Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Message-ID: <20260531140541.4115641-1-costa.shul@redhat.com> --- Documentation/admin-guide/kernel-parameters.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a0704bfef72c..f3bba3cc173e 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7420,10 +7420,10 @@ Kernel parameters Set the STI (builtin display/keyboard on the HP-PARISC machines) console (graphic card) which should be used as the initial boot-console. - See also comment in drivers/video/console/sticore.c. + See also comment in drivers/video/sticore.c. sti_font= [HW] - See comment in drivers/video/console/sticore.c. + See comment in drivers/video/sticore.c. stifb= [HW] Format: bpp:[:[:...]] From c76934b3f4c8ed075971d171892895deb506667b Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Sat, 2 May 2026 17:32:55 -0600 Subject: [PATCH 467/655] docs/dyndbg: update examples \012 to \n commit 47ea6f99d06e ("dyndbg: use ESCAPE_SPACE for cat control") changed the control-file to display format strings with "\n" rather than "\012". Update the docs to match the new reality. Reviewed-by: Louis Chauvet Tested-by: Louis Chauvet Signed-off-by: Jim Cromie Signed-off-by: Jonathan Corbet Message-ID: <20260502-dyndbg-doc-v1-1-67cc4a93a77e@gmail.com> --- .../admin-guide/dynamic-debug-howto.rst | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 095a63892257..4b14d9fd0300 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -38,12 +38,12 @@ You can view the currently configured behaviour in the *prdbg* catalog:: :#> head -n7 /proc/dynamic_debug/control # filename:lineno [module]function flags format - init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\012 - init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\012" - init/main.c:1424 [main]run_init_process =_ " with arguments:\012" - init/main.c:1426 [main]run_init_process =_ " %s\012" - init/main.c:1427 [main]run_init_process =_ " with environment:\012" - init/main.c:1429 [main]run_init_process =_ " %s\012" + init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\n" + init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\n" + init/main.c:1424 [main]run_init_process =_ " with arguments:\n" + init/main.c:1426 [main]run_init_process =_ " %s\n" + init/main.c:1427 [main]run_init_process =_ " with environment:\n" + init/main.c:1429 [main]run_init_process =_ " %s\n" The 3rd space-delimited column shows the current flags, preceded by a ``=`` for easy use with grep/cut. ``=p`` shows enabled callsites. @@ -59,10 +59,10 @@ query/commands to the control file. Example:: :#> ddcmd '-p; module main func run* +p' :#> grep =p /proc/dynamic_debug/control - init/main.c:1424 [main]run_init_process =p " with arguments:\012" - init/main.c:1426 [main]run_init_process =p " %s\012" - init/main.c:1427 [main]run_init_process =p " with environment:\012" - init/main.c:1429 [main]run_init_process =p " %s\012" + init/main.c:1424 [main]run_init_process =p " with arguments:\n" + init/main.c:1426 [main]run_init_process =p " %s\n" + init/main.c:1427 [main]run_init_process =p " with environment:\n" + init/main.c:1429 [main]run_init_process =p " %s\n" Error messages go to console/syslog:: From 5c48ecedf7769f67c1e5592c1ef5202a4a967a34 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Sat, 2 May 2026 17:32:56 -0600 Subject: [PATCH 468/655] docs/dyndbg: explain flags parse 1st When writing queries to >control, flags are parsed 1st, since they are the only required field, and they require specific compositions. So if the flags draw an error (on those specifics), then keyword errors aren't reported. This can be mildly confusing/annoying, so explain it instead. cc: linux-doc@vger.kernel.org Reviewed-by: Louis Chauvet Signed-off-by: Jim Cromie Signed-off-by: Jonathan Corbet Message-ID: <20260502-dyndbg-doc-v1-2-67cc4a93a77e@gmail.com> --- Documentation/admin-guide/dynamic-debug-howto.rst | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 4b14d9fd0300..9c2f096ed1d8 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -109,10 +109,19 @@ The match-spec's select *prdbgs* from the catalog, upon which to apply the flags-spec, all constraints are ANDed together. An absent keyword is the same as keyword "*". +Note that since the match-spec can be empty, the flags are checked 1st, +then the pairs of keyword and value. Flag errs will hide keyword errs:: -A match specification is a keyword, which selects the attribute of -the callsite to be compared, and a value to compare against. Possible -keywords are::: + bash-5.2# ddcmd mod bar +foo + dyndbg: read 13 bytes from userspace + dyndbg: query 0: "mod bar +foo" mod:* + dyndbg: unknown flag 'o' + dyndbg: flags parse failed + dyndbg: processed 1 queries, with 0 matches, 1 errs + +So a match-spec is a keyword, which selects the attribute of the +callsite to be compared, and a value to compare against. Possible +keywords are:: match-spec ::= 'func' string | 'file' string | From fa11039d6cdff84584a3ef8cc1f5e1b56e045da2 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 27 May 2026 10:48:50 +0000 Subject: [PATCH 469/655] regulator: scmi: fix of_node refcount leak in scmi_regulator_probe() scmi_regulator_probe() calls of_find_node_by_name() which takes a reference on the returned device node. On the error path where process_scmi_regulator_of_node() fails, the function returns without calling of_node_put() on the child node, leaking the reference. Add of_node_put(np) on the error path to properly release the reference. Cc: stable@vger.kernel.org Fixes: 0fbeae70ee7c ("regulator: add SCMI driver") Signed-off-by: Wentao Liang Link: https://patch.msgid.link/20260527104850.872415-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/regulator/scmi-regulator.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c index 6d609c42e479..c005e65ba0ec 100644 --- a/drivers/regulator/scmi-regulator.c +++ b/drivers/regulator/scmi-regulator.c @@ -345,8 +345,10 @@ static int scmi_regulator_probe(struct scmi_device *sdev) for_each_child_of_node_scoped(np, child) { ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo); /* abort on any mem issue */ - if (ret == -ENOMEM) + if (ret == -ENOMEM) { + of_node_put(np); return ret; + } } of_node_put(np); /* From 4079e9d91b4031a0f28335385a67b1be9b286ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 27 May 2026 12:47:44 +0200 Subject: [PATCH 470/655] regulator: Drop unused assignment of platform_device_id driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several drivers explicitly set the .driver_data member of struct platform_device_id to zero without relying on that value. Drop these unused assignments. While touching these arrays unify spacing, usage of commas and use named initializers for .name. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/613cd1bed263c2bf562ee714595f6d57f442804d.1779878004.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/regulator/88pm8607.c | 4 +--- drivers/regulator/max77686-regulator.c | 4 ++-- drivers/regulator/max77802-regulator.c | 4 ++-- drivers/regulator/max8997-regulator.c | 4 ++-- drivers/regulator/mt6323-regulator.c | 4 ++-- drivers/regulator/mt6331-regulator.c | 4 ++-- drivers/regulator/mt6332-regulator.c | 4 ++-- drivers/regulator/mt6358-regulator.c | 4 ++-- drivers/regulator/mt6359-regulator.c | 4 ++-- drivers/regulator/mt6360-regulator.c | 4 ++-- drivers/regulator/mt6370-regulator.c | 4 ++-- drivers/regulator/mt6380-regulator.c | 4 ++-- drivers/regulator/mt6397-regulator.c | 4 ++-- drivers/regulator/rt4831-regulator.c | 4 ++-- drivers/regulator/rt5120-regulator.c | 4 ++-- drivers/regulator/s2mpa01.c | 4 ++-- drivers/regulator/s5m8767.c | 4 ++-- 17 files changed, 33 insertions(+), 35 deletions(-) diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index e6c436955e25..969554725a67 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -371,12 +371,10 @@ static int pm8607_regulator_probe(struct platform_device *pdev) static const struct platform_device_id pm8607_regulator_driver_ids[] = { { .name = "88pm860x-regulator", - .driver_data = 0, }, { .name = "88pm860x-preg", - .driver_data = 0, }, - { }, + { } }; MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids); diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index c7b270fd9e0c..3a0156f4d6e7 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -517,8 +517,8 @@ static int max77686_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id max77686_pmic_id[] = { - {"max77686-pmic", 0}, - { }, + { .name = "max77686-pmic" }, + { } }; MODULE_DEVICE_TABLE(platform, max77686_pmic_id); diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index b2e87642bec4..4c05cc9c4bd2 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -546,8 +546,8 @@ static int max77802_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id max77802_pmic_id[] = { - {"max77802-pmic", 0}, - { }, + { .name = "max77802-pmic" }, + { } }; MODULE_DEVICE_TABLE(platform, max77802_pmic_id); diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index e77621b6466c..e48ba694a906 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -1152,8 +1152,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id max8997_pmic_id[] = { - { "max8997-pmic", 0}, - { }, + { .name = "max8997-pmic" }, + { } }; MODULE_DEVICE_TABLE(platform, max8997_pmic_id); diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c index b43da848a06e..bac226812b0b 100644 --- a/drivers/regulator/mt6323-regulator.c +++ b/drivers/regulator/mt6323-regulator.c @@ -401,8 +401,8 @@ static int mt6323_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6323_platform_ids[] = { - {"mt6323-regulator", 0}, - { /* sentinel */ }, + { .name = "mt6323-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6323_platform_ids); diff --git a/drivers/regulator/mt6331-regulator.c b/drivers/regulator/mt6331-regulator.c index 0059f88c6fd7..eed9dda0481f 100644 --- a/drivers/regulator/mt6331-regulator.c +++ b/drivers/regulator/mt6331-regulator.c @@ -487,8 +487,8 @@ static int mt6331_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6331_platform_ids[] = { - {"mt6331-regulator", 0}, - { /* sentinel */ }, + { .name = "mt6331-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6331_platform_ids); diff --git a/drivers/regulator/mt6332-regulator.c b/drivers/regulator/mt6332-regulator.c index 8d8331a2aca5..949fde37617c 100644 --- a/drivers/regulator/mt6332-regulator.c +++ b/drivers/regulator/mt6332-regulator.c @@ -402,8 +402,8 @@ static int mt6332_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6332_platform_ids[] = { - {"mt6332-regulator", 0}, - { /* sentinel */ }, + { .name = "mt6332-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6332_platform_ids); diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c index 2604f674be49..f2bb3c1523ca 100644 --- a/drivers/regulator/mt6358-regulator.c +++ b/drivers/regulator/mt6358-regulator.c @@ -724,8 +724,8 @@ static int mt6358_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6358_platform_ids[] = { - {"mt6358-regulator", 0}, - { /* sentinel */ }, + { .name = "mt6358-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6358_platform_ids); diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c index c8a788858824..4a1e1bdd0e9a 100644 --- a/drivers/regulator/mt6359-regulator.c +++ b/drivers/regulator/mt6359-regulator.c @@ -977,8 +977,8 @@ static int mt6359_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6359_platform_ids[] = { - {"mt6359-regulator", 0}, - { /* sentinel */ }, + { .name = "mt6359-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6359_platform_ids); diff --git a/drivers/regulator/mt6360-regulator.c b/drivers/regulator/mt6360-regulator.c index 24cc9fc94e90..ed25e9603b2b 100644 --- a/drivers/regulator/mt6360-regulator.c +++ b/drivers/regulator/mt6360-regulator.c @@ -446,8 +446,8 @@ static int mt6360_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6360_regulator_id_table[] = { - { "mt6360-regulator", 0 }, - {}, + { .name = "mt6360-regulator" }, + { } }; MODULE_DEVICE_TABLE(platform, mt6360_regulator_id_table); diff --git a/drivers/regulator/mt6370-regulator.c b/drivers/regulator/mt6370-regulator.c index c2cea904b0ca..a4ac4a42c108 100644 --- a/drivers/regulator/mt6370-regulator.c +++ b/drivers/regulator/mt6370-regulator.c @@ -371,8 +371,8 @@ static int mt6370_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6370_devid_table[] = { - { "mt6370-regulator", 0}, - {} + { .name = "mt6370-regulator" }, + { } }; MODULE_DEVICE_TABLE(platform, mt6370_devid_table); diff --git a/drivers/regulator/mt6380-regulator.c b/drivers/regulator/mt6380-regulator.c index 83e50df7f7c3..da901a75137a 100644 --- a/drivers/regulator/mt6380-regulator.c +++ b/drivers/regulator/mt6380-regulator.c @@ -314,8 +314,8 @@ static int mt6380_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6380_platform_ids[] = { - {"mt6380-regulator", 0}, - { /* sentinel */ }, + { .name = "mt6380-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6380_platform_ids); diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c index 92a2d92f84f9..e68df86ca4d9 100644 --- a/drivers/regulator/mt6397-regulator.c +++ b/drivers/regulator/mt6397-regulator.c @@ -392,8 +392,8 @@ static int mt6397_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6397_platform_ids[] = { - {"mt6397-regulator", 0}, - { /* sentinel */ }, + { .name = "mt6397-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6397_platform_ids); diff --git a/drivers/regulator/rt4831-regulator.c b/drivers/regulator/rt4831-regulator.c index dfc868a24056..5c47fd57fdef 100644 --- a/drivers/regulator/rt4831-regulator.c +++ b/drivers/regulator/rt4831-regulator.c @@ -186,8 +186,8 @@ static int rt4831_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id rt4831_regulator_match[] = { - { "rt4831-regulator", 0 }, - {} + { .name = "rt4831-regulator" }, + { } }; MODULE_DEVICE_TABLE(platform, rt4831_regulator_match); diff --git a/drivers/regulator/rt5120-regulator.c b/drivers/regulator/rt5120-regulator.c index f0d3efd160d4..a2a13ce2e67b 100644 --- a/drivers/regulator/rt5120-regulator.c +++ b/drivers/regulator/rt5120-regulator.c @@ -401,8 +401,8 @@ static int rt5120_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id rt5120_regulator_dev_table[] = { - { "rt5120-regulator", 0 }, - {} + { .name = "rt5120-regulator" }, + { } }; MODULE_DEVICE_TABLE(platform, rt5120_regulator_dev_table); diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index c22fdde67f9c..8171503861c1 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -367,8 +367,8 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id s2mpa01_pmic_id[] = { - { "s2mpa01-pmic", 0}, - { }, + { .name = "s2mpa01-pmic" }, + { } }; MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id); diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index fe2631378ccd..2794245d4042 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -916,8 +916,8 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id s5m8767_pmic_id[] = { - { "s5m8767-pmic", 0}, - { }, + { .name = "s5m8767-pmic" }, + { } }; MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id); From d35028340d751c352234438bfa9a9c58ead74853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 27 May 2026 12:47:45 +0200 Subject: [PATCH 471/655] regulator: Use named initializers for platform_device_id arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Named initializers are better readable and more robust to changes of the struct definition. This robustness is relevant for a planned change to struct platform_device_id replacing .driver_data by an anonymous unit. While touching these arrays unify spacing and usage of commas. Signed-off-by: Uwe Kleine-König (The Capable Hub) Acked-by: Karel Balej Reviewed-by: Matti Vaittinen Link: https://patch.msgid.link/d02f55dfd5bdd743ae5cd76f2a5af0d346226a68.1779878004.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/regulator/88pm886-regulator.c | 2 +- drivers/regulator/bd71815-regulator.c | 4 ++-- drivers/regulator/bd71828-regulator.c | 6 +++--- drivers/regulator/bd718x7-regulator.c | 6 +++--- drivers/regulator/bd9571mwv-regulator.c | 4 ++-- drivers/regulator/bd9576-regulator.c | 6 +++--- drivers/regulator/bd96801-regulator.c | 10 +++++----- drivers/regulator/lp873x-regulator.c | 2 +- drivers/regulator/lp87565-regulator.c | 4 ++-- drivers/regulator/max14577-regulator.c | 4 ++-- drivers/regulator/max77541-regulator.c | 4 ++-- drivers/regulator/max77693-regulator.c | 6 +++--- drivers/regulator/max8998.c | 4 ++-- drivers/regulator/mt6357-regulator.c | 4 ++-- drivers/regulator/pf1550-regulator.c | 2 +- drivers/regulator/qcom-pm8008-regulator.c | 2 +- drivers/regulator/rt5033-regulator.c | 2 +- drivers/regulator/s2dos05-regulator.c | 4 ++-- drivers/regulator/s2mps11.c | 18 +++++++++--------- drivers/regulator/sy7636a-regulator.c | 2 +- drivers/regulator/tps65086-regulator.c | 2 +- drivers/regulator/tps65218-regulator.c | 2 +- drivers/regulator/tps65219-regulator.c | 6 +++--- drivers/regulator/tps65912-regulator.c | 2 +- 24 files changed, 54 insertions(+), 54 deletions(-) diff --git a/drivers/regulator/88pm886-regulator.c b/drivers/regulator/88pm886-regulator.c index a38bd4f312b7..7328cd1cf265 100644 --- a/drivers/regulator/88pm886-regulator.c +++ b/drivers/regulator/88pm886-regulator.c @@ -373,7 +373,7 @@ static int pm886_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id pm886_regulator_id_table[] = { - { "88pm886-regulator", }, + { .name = "88pm886-regulator" }, { } }; MODULE_DEVICE_TABLE(platform, pm886_regulator_id_table); diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c index 668714f35464..4c2b20d1b284 100644 --- a/drivers/regulator/bd71815-regulator.c +++ b/drivers/regulator/bd71815-regulator.c @@ -607,8 +607,8 @@ static int bd7181x_probe(struct platform_device *pdev) } static const struct platform_device_id bd7181x_pmic_id[] = { - { "bd71815-pmic", ROHM_CHIP_TYPE_BD71815 }, - { }, + { .name = "bd71815-pmic", .driver_data = ROHM_CHIP_TYPE_BD71815 }, + { } }; MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id); diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c index 473beb4399d9..bd61caa8284a 100644 --- a/drivers/regulator/bd71828-regulator.c +++ b/drivers/regulator/bd71828-regulator.c @@ -1691,9 +1691,9 @@ static int bd71828_probe(struct platform_device *pdev) } static const struct platform_device_id bd71828_pmic_id[] = { - { "bd71828-pmic", ROHM_CHIP_TYPE_BD71828 }, - { "bd72720-pmic", ROHM_CHIP_TYPE_BD72720 }, - { }, + { .name = "bd71828-pmic", .driver_data = ROHM_CHIP_TYPE_BD71828 }, + { .name = "bd72720-pmic", .driver_data = ROHM_CHIP_TYPE_BD72720 }, + { } }; MODULE_DEVICE_TABLE(platform, bd71828_pmic_id); diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index 1b5997c8482e..9cc29b9409d0 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -1816,9 +1816,9 @@ static int bd718xx_probe(struct platform_device *pdev) } static const struct platform_device_id bd718x7_pmic_id[] = { - { "bd71837-pmic", ROHM_CHIP_TYPE_BD71837 }, - { "bd71847-pmic", ROHM_CHIP_TYPE_BD71847 }, - { }, + { .name = "bd71837-pmic", .driver_data = ROHM_CHIP_TYPE_BD71837 }, + { .name = "bd71847-pmic", .driver_data = ROHM_CHIP_TYPE_BD71847 }, + { } }; MODULE_DEVICE_TABLE(platform, bd718x7_pmic_id); diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index f4de24a281b1..5bf02dc0d20e 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -344,8 +344,8 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id bd9571mwv_regulator_id_table[] = { - { "bd9571mwv-regulator", ROHM_CHIP_TYPE_BD9571 }, - { "bd9574mwf-regulator", ROHM_CHIP_TYPE_BD9574 }, + { .name = "bd9571mwv-regulator", .driver_data = ROHM_CHIP_TYPE_BD9571 }, + { .name = "bd9574mwf-regulator", .driver_data = ROHM_CHIP_TYPE_BD9574 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table); diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c index bf5f9c3f2c97..fcdaaa56e356 100644 --- a/drivers/regulator/bd9576-regulator.c +++ b/drivers/regulator/bd9576-regulator.c @@ -1117,9 +1117,9 @@ static int bd957x_probe(struct platform_device *pdev) } static const struct platform_device_id bd957x_pmic_id[] = { - { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 }, - { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 }, - { }, + { .name = "bd9573-regulator", .driver_data = ROHM_CHIP_TYPE_BD9573 }, + { .name = "bd9576-regulator", .driver_data = ROHM_CHIP_TYPE_BD9576 }, + { } }; MODULE_DEVICE_TABLE(platform, bd957x_pmic_id); diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c index 129b20c33bad..308279b31fd3 100644 --- a/drivers/regulator/bd96801-regulator.c +++ b/drivers/regulator/bd96801-regulator.c @@ -1329,11 +1329,11 @@ static int bd96801_probe(struct platform_device *pdev) } static const struct platform_device_id bd96801_pmic_id[] = { - { "bd96801-regulator", (kernel_ulong_t)&bd96801_data }, - { "bd96802-regulator", (kernel_ulong_t)&bd96802_data }, - { "bd96805-regulator", (kernel_ulong_t)&bd96805_data }, - { "bd96806-regulator", (kernel_ulong_t)&bd96806_data }, - { }, + { .name = "bd96801-regulator", .driver_data = (kernel_ulong_t)&bd96801_data }, + { .name = "bd96802-regulator", .driver_data = (kernel_ulong_t)&bd96802_data }, + { .name = "bd96805-regulator", .driver_data = (kernel_ulong_t)&bd96805_data }, + { .name = "bd96806-regulator", .driver_data = (kernel_ulong_t)&bd96806_data }, + { } }; MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c index 84a134cfcd9c..7e837ddfa236 100644 --- a/drivers/regulator/lp873x-regulator.c +++ b/drivers/regulator/lp873x-regulator.c @@ -180,7 +180,7 @@ static int lp873x_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id lp873x_regulator_id_table[] = { - { "lp873x-regulator", }, + { .name = "lp873x-regulator" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, lp873x_regulator_id_table); diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index 1259b5d20153..34e7a5d323d7 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -229,8 +229,8 @@ static int lp87565_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id lp87565_regulator_id_table[] = { - { "lp87565-regulator", }, - { "lp87565-q1-regulator", }, + { .name = "lp87565-regulator" }, + { .name = "lp87565-q1-regulator" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, lp87565_regulator_id_table); diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c index 41fd15adfd1f..c9d8d5e31cbd 100644 --- a/drivers/regulator/max14577-regulator.c +++ b/drivers/regulator/max14577-regulator.c @@ -235,8 +235,8 @@ static int max14577_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id max14577_regulator_id[] = { - { "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, }, - { "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, }, + { .name = "max14577-regulator", .driver_data = MAXIM_DEVICE_TYPE_MAX14577 }, + { .name = "max77836-regulator", .driver_data = MAXIM_DEVICE_TYPE_MAX77836 }, { } }; MODULE_DEVICE_TABLE(platform, max14577_regulator_id); diff --git a/drivers/regulator/max77541-regulator.c b/drivers/regulator/max77541-regulator.c index e6b3d9147c37..f2365930e9a9 100644 --- a/drivers/regulator/max77541-regulator.c +++ b/drivers/regulator/max77541-regulator.c @@ -133,8 +133,8 @@ static int max77541_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id max77541_regulator_platform_id[] = { - { "max77540-regulator" }, - { "max77541-regulator" }, + { .name = "max77540-regulator" }, + { .name = "max77541-regulator" }, { } }; MODULE_DEVICE_TABLE(platform, max77541_regulator_platform_id); diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c index 72a67d0c5f1e..a8b3a2058d34 100644 --- a/drivers/regulator/max77693-regulator.c +++ b/drivers/regulator/max77693-regulator.c @@ -271,9 +271,9 @@ static int max77693_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id max77693_pmic_id[] = { - { "max77693-pmic", TYPE_MAX77693 }, - { "max77843-regulator", TYPE_MAX77843 }, - {}, + { .name = "max77693-pmic", .driver_data = TYPE_MAX77693 }, + { .name = "max77843-regulator", .driver_data = TYPE_MAX77843 }, + { } }; MODULE_DEVICE_TABLE(platform, max77693_pmic_id); diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 254a77887f66..cc85fbe8b77c 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -752,8 +752,8 @@ static int max8998_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id max8998_pmic_id[] = { - { "max8998-pmic", TYPE_MAX8998 }, - { "lp3974-pmic", TYPE_LP3974 }, + { .name = "max8998-pmic", .driver_data = TYPE_MAX8998 }, + { .name = "lp3974-pmic", .driver_data = TYPE_LP3974 }, { } }; MODULE_DEVICE_TABLE(platform, max8998_pmic_id); diff --git a/drivers/regulator/mt6357-regulator.c b/drivers/regulator/mt6357-regulator.c index 09feb454ab6b..815ef7d3e5be 100644 --- a/drivers/regulator/mt6357-regulator.c +++ b/drivers/regulator/mt6357-regulator.c @@ -431,8 +431,8 @@ static int mt6357_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id mt6357_platform_ids[] = { - { "mt6357-regulator" }, - { /* sentinel */ }, + { .name = "mt6357-regulator" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6357_platform_ids); diff --git a/drivers/regulator/pf1550-regulator.c b/drivers/regulator/pf1550-regulator.c index 1d1726528460..610eac9bb9cb 100644 --- a/drivers/regulator/pf1550-regulator.c +++ b/drivers/regulator/pf1550-regulator.c @@ -409,7 +409,7 @@ static int pf1550_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id pf1550_regulator_id[] = { - { "pf1550-regulator", }, + { .name = "pf1550-regulator" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, pf1550_regulator_id); diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c index 90c78ee1c37b..9c9b8be2e15a 100644 --- a/drivers/regulator/qcom-pm8008-regulator.c +++ b/drivers/regulator/qcom-pm8008-regulator.c @@ -180,7 +180,7 @@ static int pm8008_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id pm8008_regulator_id_table[] = { - { "pm8008-regulator" }, + { .name = "pm8008-regulator" }, { } }; MODULE_DEVICE_TABLE(platform, pm8008_regulator_id_table); diff --git a/drivers/regulator/rt5033-regulator.c b/drivers/regulator/rt5033-regulator.c index 2ba74f205543..3aeab9a57871 100644 --- a/drivers/regulator/rt5033-regulator.c +++ b/drivers/regulator/rt5033-regulator.c @@ -116,7 +116,7 @@ static int rt5033_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id rt5033_regulator_id[] = { - { "rt5033-regulator", }, + { .name = "rt5033-regulator" }, { } }; MODULE_DEVICE_TABLE(platform, rt5033_regulator_id); diff --git a/drivers/regulator/s2dos05-regulator.c b/drivers/regulator/s2dos05-regulator.c index a1c394ddbaff..6e25f663496a 100644 --- a/drivers/regulator/s2dos05-regulator.c +++ b/drivers/regulator/s2dos05-regulator.c @@ -146,8 +146,8 @@ static int s2dos05_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id s2dos05_pmic_id[] = { - { "s2dos05-regulator" }, - { }, + { .name = "s2dos05-regulator" }, + { } }; MODULE_DEVICE_TABLE(platform, s2dos05_pmic_id); diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 81cfd60460f8..0fb54617b8a7 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -2266,15 +2266,15 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id s2mps11_pmic_id[] = { - { "s2mpg10-regulator", S2MPG10}, - { "s2mpg11-regulator", S2MPG11}, - { "s2mps11-regulator", S2MPS11X}, - { "s2mps13-regulator", S2MPS13X}, - { "s2mps14-regulator", S2MPS14X}, - { "s2mps15-regulator", S2MPS15X}, - { "s2mpu02-regulator", S2MPU02}, - { "s2mpu05-regulator", S2MPU05}, - { }, + { .name = "s2mpg10-regulator", .driver_data = S2MPG10 }, + { .name = "s2mpg11-regulator", .driver_data = S2MPG11 }, + { .name = "s2mps11-regulator", .driver_data = S2MPS11X }, + { .name = "s2mps13-regulator", .driver_data = S2MPS13X }, + { .name = "s2mps14-regulator", .driver_data = S2MPS14X }, + { .name = "s2mps15-regulator", .driver_data = S2MPS15X }, + { .name = "s2mpu02-regulator", .driver_data = S2MPU02 }, + { .name = "s2mpu05-regulator", .driver_data = S2MPU05 }, + { } }; MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id); diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c index 551647bc1052..c44c445ea139 100644 --- a/drivers/regulator/sy7636a-regulator.c +++ b/drivers/regulator/sy7636a-regulator.c @@ -147,7 +147,7 @@ static int sy7636a_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id sy7636a_regulator_id_table[] = { - { "sy7636a-regulator", }, + { .name = "sy7636a-regulator" }, { } }; MODULE_DEVICE_TABLE(platform, sy7636a_regulator_id_table); diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c index 2d284c64eeb7..94bf96856d10 100644 --- a/drivers/regulator/tps65086-regulator.c +++ b/drivers/regulator/tps65086-regulator.c @@ -399,7 +399,7 @@ static int tps65086_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id tps65086_regulator_id_table[] = { - { "tps65086-regulator", }, + { .name = "tps65086-regulator" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, tps65086_regulator_id_table); diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index f44b5767099c..8df81ceeb845 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -341,7 +341,7 @@ static int tps65218_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id tps65218_regulator_id_table[] = { - { "tps65218-regulator", }, + { .name = "tps65218-regulator" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, tps65218_regulator_id_table); diff --git a/drivers/regulator/tps65219-regulator.c b/drivers/regulator/tps65219-regulator.c index 324c3a33af8a..a667c3f44bb7 100644 --- a/drivers/regulator/tps65219-regulator.c +++ b/drivers/regulator/tps65219-regulator.c @@ -541,9 +541,9 @@ static int tps65219_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id tps65219_regulator_id_table[] = { - { "tps65214-regulator", TPS65214 }, - { "tps65215-regulator", TPS65215 }, - { "tps65219-regulator", TPS65219 }, + { .name = "tps65214-regulator", .driver_data = TPS65214 }, + { .name = "tps65215-regulator", .driver_data = TPS65215 }, + { .name = "tps65219-regulator", .driver_data = TPS65219 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, tps65219_regulator_id_table); diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 7ff7877a2e09..4317ec62f18f 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -142,7 +142,7 @@ static int tps65912_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id tps65912_regulator_id_table[] = { - { "tps65912-regulator", }, + { .name = "tps65912-regulator" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, tps65912_regulator_id_table); From 0eb17367814a3b7d3ad75a9f5c25cfd9976993e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 27 May 2026 12:47:46 +0200 Subject: [PATCH 472/655] regulator: Unify usage of space and comma in platform_device_id arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After converting all these arrays to use named initializers and fixing coding style en passant, adapt the coding style also for those drivers that already used named initializers before for consistency. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/a3a2736ebfcfa5a228dcebfbfefc14960dcce314.1779878004.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- drivers/regulator/hi6421-regulator.c | 2 +- drivers/regulator/hi6421v530-regulator.c | 2 +- drivers/regulator/hi6421v600-regulator.c | 2 +- drivers/regulator/hi655x-regulator.c | 2 +- drivers/regulator/max77620-regulator.c | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c index cd06030c3587..3373c4fdbddf 100644 --- a/drivers/regulator/hi6421-regulator.c +++ b/drivers/regulator/hi6421-regulator.c @@ -571,7 +571,7 @@ static int hi6421_regulator_probe(struct platform_device *pdev) static const struct platform_device_id hi6421_regulator_table[] = { { .name = "hi6421-regulator" }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, hi6421_regulator_table); diff --git a/drivers/regulator/hi6421v530-regulator.c b/drivers/regulator/hi6421v530-regulator.c index 1822f5daf6ce..7f4fc7175bbb 100644 --- a/drivers/regulator/hi6421v530-regulator.c +++ b/drivers/regulator/hi6421v530-regulator.c @@ -187,7 +187,7 @@ static int hi6421v530_regulator_probe(struct platform_device *pdev) static const struct platform_device_id hi6421v530_regulator_table[] = { { .name = "hi6421v530-regulator" }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, hi6421v530_regulator_table); diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c index e7c8bc10cf24..c42858c93b47 100644 --- a/drivers/regulator/hi6421v600-regulator.c +++ b/drivers/regulator/hi6421v600-regulator.c @@ -276,7 +276,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) static const struct platform_device_id hi6421_spmi_regulator_table[] = { { .name = "hi6421v600-regulator" }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, hi6421_spmi_regulator_table); diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c index 1d8211f635b7..b2b454b6a18c 100644 --- a/drivers/regulator/hi655x-regulator.c +++ b/drivers/regulator/hi655x-regulator.c @@ -198,7 +198,7 @@ static int hi655x_regulator_probe(struct platform_device *pdev) static const struct platform_device_id hi655x_regulator_table[] = { { .name = "hi655x-regulator" }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, hi655x_regulator_table); diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 57c54472ec5b..5099c372eea5 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -902,10 +902,10 @@ static const struct dev_pm_ops max77620_regulator_pm_ops = { }; static const struct platform_device_id max77620_regulator_devtype[] = { - { .name = "max77620-pmic", }, - { .name = "max20024-pmic", }, - { .name = "max77663-pmic", }, - {}, + { .name = "max77620-pmic" }, + { .name = "max20024-pmic" }, + { .name = "max77663-pmic" }, + { } }; MODULE_DEVICE_TABLE(platform, max77620_regulator_devtype); From 6bb0009862c5f0e89a6e4afc09b499a02576c7da Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 28 May 2026 11:34:32 +0200 Subject: [PATCH 473/655] mm/slab: improve kmem_cache_alloc_bulk The kmem_cache_alloc_bulk return value is weird. It returns the number of allocated objects, but that must always be 0 or the requested number based on the implementations and the handling in the callers, but that assumption is not actually documented anywhere, which confuses automated review tools. Fix this by returning a bool if the allocation succeeded and adding a kerneldoc comment explaining the API. [rob.clark@oss.qualcomm.com: fixups in msm_iommu_pagetable_prealloc_allocate() ] Signed-off-by: Christoph Hellwig Reviewed-by: Alexander Lobakin # skbuff Link: https://patch.msgid.link/20260528093437.2519248-2-hch@lst.de Signed-off-by: Vlastimil Babka (SUSE) --- drivers/gpu/drm/msm/msm_iommu.c | 13 +++--- drivers/gpu/drm/panthor/panthor_mmu.c | 13 +++--- include/linux/slab.h | 6 ++- io_uring/io_uring.c | 23 ++++------ lib/test_meminit.c | 23 +++++----- mm/kasan/kasan_test_c.c | 5 +-- mm/kfence/kfence_test.c | 9 ++-- mm/slub.c | 64 ++++++++++++++------------- net/bpf/test_run.c | 7 ++- net/core/skbuff.c | 24 +++++----- tools/include/linux/slab.h | 2 +- tools/testing/shared/linux.c | 19 ++++---- 12 files changed, 104 insertions(+), 104 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 7d449e5202c5..35dd43e3ef43 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -330,17 +330,20 @@ static int msm_iommu_pagetable_prealloc_allocate(struct msm_mmu *mmu, struct msm_mmu_prealloc *p) { struct kmem_cache *pt_cache = get_pt_cache(mmu); - int ret; + + if (!p->count) { + p->pages = NULL; + return 0; + } p->pages = kvmalloc_objs(*p->pages, p->count); if (!p->pages) return -ENOMEM; - ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, p->count, p->pages); - if (ret != p->count) { - kfree(p->pages); + if (!kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, p->count, p->pages)) { + kvfree(p->pages); p->pages = NULL; - p->count = ret; + p->count = 0; return -ENOMEM; } diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 75d98dad7b1d..b12c641af46c 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1274,13 +1274,13 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, goto err_cleanup; } - ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, - op_ctx->rsvd_page_tables.pages); - op_ctx->rsvd_page_tables.count = ret; - if (ret != pt_count) { + if (!kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, + op_ctx->rsvd_page_tables.pages)) { + op_ctx->rsvd_page_tables.count = 0; ret = -ENOMEM; goto err_cleanup; } + op_ctx->rsvd_page_tables.count = pt_count; /* Insert BO into the extobj list last, when we know nothing can fail. */ dma_resv_lock(panthor_vm_resv(vm), NULL); @@ -1328,9 +1328,8 @@ static int panthor_vm_prepare_unmap_op_ctx(struct panthor_vm_op_ctx *op_ctx, goto err_cleanup; } - ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, - op_ctx->rsvd_page_tables.pages); - if (ret != pt_count) { + if (!kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, + op_ctx->rsvd_page_tables.pages)) { ret = -ENOMEM; goto err_cleanup; } diff --git a/include/linux/slab.h b/include/linux/slab.h index 15a60b501b95..24b244e63ba9 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -815,8 +815,10 @@ kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags, */ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p); -int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size, void **p); -#define kmem_cache_alloc_bulk(...) alloc_hooks(kmem_cache_alloc_bulk_noprof(__VA_ARGS__)) +bool kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, + size_t size, void **p); +#define kmem_cache_alloc_bulk(...) \ + alloc_hooks(kmem_cache_alloc_bulk_noprof(__VA_ARGS__)) static __always_inline void kfree_bulk(size_t size, void **p) { diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 4ed998d60c09..b46d038400ff 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -966,29 +966,24 @@ __cold bool __io_alloc_req_refill(struct io_ring_ctx *ctx) { gfp_t gfp = GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO; void *reqs[IO_REQ_ALLOC_BATCH]; - int ret; - - ret = kmem_cache_alloc_bulk(req_cachep, gfp, ARRAY_SIZE(reqs), reqs); + int nr_reqs = ARRAY_SIZE(reqs); /* - * Bulk alloc is all-or-nothing. If we fail to get a batch, - * retry single alloc to be on the safe side. + * Bulk alloc is all-or-nothing. If we fail to get a batch, retry a + * single allocation to be on the safe side. */ - if (unlikely(ret <= 0)) { + if (!kmem_cache_alloc_bulk(req_cachep, gfp, nr_reqs, reqs)) { reqs[0] = kmem_cache_alloc(req_cachep, gfp); if (!reqs[0]) return false; - ret = 1; + nr_reqs = 1; } - percpu_ref_get_many(&ctx->refs, ret); - ctx->nr_req_allocated += ret; + percpu_ref_get_many(&ctx->refs, nr_reqs); + ctx->nr_req_allocated += nr_reqs; - while (ret--) { - struct io_kiocb *req = reqs[ret]; - - io_req_add_to_cache(req, ctx); - } + while (nr_reqs--) + io_req_add_to_cache(reqs[nr_reqs], ctx); return true; } diff --git a/lib/test_meminit.c b/lib/test_meminit.c index 6298f66c964b..e106a0c0601a 100644 --- a/lib/test_meminit.c +++ b/lib/test_meminit.c @@ -229,16 +229,14 @@ static int __init do_kmem_cache_size(size_t size, bool want_ctor, for (iter = 0; iter < 10; iter++) { /* Do a test of bulk allocations */ if (!want_rcu && !want_ctor) { - int ret; - - ret = kmem_cache_alloc_bulk(c, alloc_mask, BULK_SIZE, bulk_array); - if (!ret) { + if (!kmem_cache_alloc_bulk(c, alloc_mask, BULK_SIZE, + bulk_array)) { fail = true; } else { int i; - for (i = 0; i < ret; i++) + for (i = 0; i < BULK_SIZE; i++) fail |= check_buf(bulk_array[i], size, want_ctor, want_rcu, want_zero); - kmem_cache_free_bulk(c, ret, bulk_array); + kmem_cache_free_bulk(c, BULK_SIZE, bulk_array); } } @@ -348,23 +346,24 @@ static int __init do_kmem_cache_size_bulk(int size, int *total_failures) { struct kmem_cache *c; int i, iter, maxiter = 1024; - int num, bytes; + int bytes; bool fail = false; void *objects[10]; c = kmem_cache_create("test_cache", size, size, 0, NULL); for (iter = 0; (iter < maxiter) && !fail; iter++) { - num = kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects), - objects); - for (i = 0; i < num; i++) { + if (!kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects), + objects)) + continue; + + for (i = 0; i < ARRAY_SIZE(objects); i++) { bytes = count_nonzero_bytes(objects[i], size); if (bytes) fail = true; fill_with_garbage(objects[i], size); } - if (num) - kmem_cache_free_bulk(c, num, objects); + kmem_cache_free_bulk(c, ARRAY_SIZE(objects), objects); } kmem_cache_destroy(c); *total_failures += fail; diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c index 32d06cbf6a31..e41ba69592ef 100644 --- a/mm/kasan/kasan_test_c.c +++ b/mm/kasan/kasan_test_c.c @@ -1215,14 +1215,13 @@ static void kmem_cache_bulk(struct kunit *test) struct kmem_cache *cache; size_t size = 200; char *p[10]; - bool ret; int i; cache = kmem_cache_create("test_cache", size, 0, 0, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache); - ret = kmem_cache_alloc_bulk(cache, GFP_KERNEL, ARRAY_SIZE(p), (void **)&p); - if (!ret) { + if (!kmem_cache_alloc_bulk(cache, GFP_KERNEL, ARRAY_SIZE(p), + (void **)&p)) { kunit_err(test, "Allocation failed: %s\n", __func__); kmem_cache_destroy(cache); return; diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c index 5725a367246d..bac6f2aff101 100644 --- a/mm/kfence/kfence_test.c +++ b/mm/kfence/kfence_test.c @@ -761,9 +761,10 @@ static void test_memcache_alloc_bulk(struct kunit *test) timeout = jiffies + msecs_to_jiffies(100 * kfence_sample_interval); do { void *objects[100]; - int i, num = kmem_cache_alloc_bulk(test_cache, GFP_ATOMIC, ARRAY_SIZE(objects), - objects); - if (!num) + int i; + + if (!kmem_cache_alloc_bulk(test_cache, GFP_ATOMIC, + ARRAY_SIZE(objects), objects)) continue; for (i = 0; i < ARRAY_SIZE(objects); i++) { if (is_kfence_address(objects[i])) { @@ -771,7 +772,7 @@ static void test_memcache_alloc_bulk(struct kunit *test) break; } } - kmem_cache_free_bulk(test_cache, num, objects); + kmem_cache_free_bulk(test_cache, ARRAY_SIZE(objects), objects); /* * kmem_cache_alloc_bulk() disables interrupts, and calling it * in a tight loop may not give KFENCE a chance to switch the diff --git a/mm/slub.c b/mm/slub.c index 0baa906f39ab..711df528c9a6 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -4980,8 +4980,8 @@ static int __prefill_sheaf_pfmemalloc(struct kmem_cache *s, return ret; } -static int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, - size_t size, void **p); +static bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, + size_t size, void **p); /* * returns a sheaf that has at least the requested size @@ -5153,9 +5153,8 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp, return __prefill_sheaf_pfmemalloc(s, sheaf, gfp); if (!__kmem_cache_alloc_bulk(s, gfp, sheaf->capacity - sheaf->size, - &sheaf->objects[sheaf->size])) { + &sheaf->objects[sheaf->size])) return -ENOMEM; - } sheaf->size = sheaf->capacity; return 0; @@ -7272,9 +7271,8 @@ out: return refilled; } -static inline -int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - void **p) +static bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, + size_t size, void **p) { int i; @@ -7295,30 +7293,43 @@ int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, stat_add(s, ALLOC_SLOWPATH, i); } - return i; + return true; error: __kmem_cache_free_bulk(s, i, p); - return 0; - + return false; } -/* - * Note that interrupts must be enabled when calling this function and gfp - * flags must allow spinning. +/** + * kmem_cache_alloc_bulk - Allocate multiple objects + * @s: The cache to allocate from + * @flags: GFP_* flags. See kmalloc(). + * @size: Number of objects to allocate + * @p: Array of allocated objects + * + * Allocate @size objects from @s and places them into @p. @size must be larger + * than 0. + * + * Interrupts must be enabled when calling this function and @flags must allow + * spinning. + * + * Unlike alloc_pages_bulk(), this function does not check for already allocated + * objects in @p, and thus the caller does not need to zero it. + * + * Return: %true if the allocation succeeded, or %false if it failed. */ -int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size, - void **p) +bool kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, + size_t size, void **p) { unsigned int i = 0; void *kfence_obj; if (!size) - return 0; + return false; s = slab_pre_alloc_hook(s, flags); if (unlikely(!s)) - return 0; + return false; /* * to make things simpler, only assume at most once kfence allocated @@ -7335,18 +7346,18 @@ int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size, } i = alloc_from_pcs_bulk(s, flags, size, p); - if (i < size) { /* * If we ran out of memory, don't bother with freeing back to * the percpu sheaves, we have bigger problems. */ - if (unlikely(__kmem_cache_alloc_bulk(s, flags, size - i, p + i) == 0)) { + if (unlikely(!__kmem_cache_alloc_bulk(s, flags, size - i, + p + i))) { if (i > 0) __kmem_cache_free_bulk(s, i, p); if (kfence_obj) __kfence_free(kfence_obj); - return 0; + return false; } } @@ -7361,16 +7372,9 @@ int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size, } out: - /* - * memcg and kmem_cache debug support and memory initialization. - * Done outside of the IRQ disabled fastpath loop. - */ - if (unlikely(!slab_post_alloc_hook(s, NULL, flags, size, p, - slab_want_init_on_alloc(flags, s), s->object_size))) { - return 0; - } - - return size; + /* memcg and kmem_cache debug support and memory initialization */ + return likely(slab_post_alloc_hook(s, NULL, flags, size, p, + slab_want_init_on_alloc(flags, s), s->object_size)); } EXPORT_SYMBOL(kmem_cache_alloc_bulk_noprof); diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 2bc04feadfab..dbf0d8eae8d8 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -243,12 +243,11 @@ static int xdp_recv_frames(struct xdp_frame **frames, int nframes, struct net_device *dev) { gfp_t gfp = __GFP_ZERO | GFP_ATOMIC; - int i, n; + int i; LIST_HEAD(list); - n = kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, gfp, nframes, - (void **)skbs); - if (unlikely(n == 0)) { + if (unlikely(!kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, gfp, + nframes, (void **)skbs))) { for (i = 0; i < nframes; i++) xdp_return_frame(frames[i]); return -ENOMEM; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7dad68e3b518..74f32c581403 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -288,11 +288,11 @@ static inline struct sk_buff *napi_skb_cache_get(bool alloc) local_lock_nested_bh(&napi_alloc_cache.bh_lock); if (unlikely(!nc->skb_count)) { - if (alloc) - nc->skb_count = kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, - GFP_ATOMIC | __GFP_NOWARN, - NAPI_SKB_CACHE_BULK, - nc->skb_cache); + if (alloc && kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, + GFP_ATOMIC | __GFP_NOWARN, + NAPI_SKB_CACHE_BULK, + nc->skb_cache)) + nc->skb_count = NAPI_SKB_CACHE_BULK; if (unlikely(!nc->skb_count)) { local_unlock_nested_bh(&napi_alloc_cache.bh_lock); return NULL; @@ -353,16 +353,18 @@ u32 napi_skb_cache_get_bulk(void **skbs, u32 n) /* No enough cached skbs. Try refilling the cache first */ bulk = min(NAPI_SKB_CACHE_SIZE - nc->skb_count, NAPI_SKB_CACHE_BULK); - nc->skb_count += kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, - GFP_ATOMIC | __GFP_NOWARN, bulk, - &nc->skb_cache[nc->skb_count]); + if (kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, + GFP_ATOMIC | __GFP_NOWARN, bulk, + &nc->skb_cache[nc->skb_count])) + nc->skb_count += bulk; if (likely(nc->skb_count >= n)) goto get; /* Still not enough. Bulk-allocate the missing part directly, zeroed */ - n -= kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, - GFP_ATOMIC | __GFP_ZERO | __GFP_NOWARN, - n - nc->skb_count, &skbs[nc->skb_count]); + if (kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, + GFP_ATOMIC | __GFP_ZERO | __GFP_NOWARN, + n - nc->skb_count, &skbs[nc->skb_count])) + n = nc->skb_count; if (likely(nc->skb_count >= n)) goto get; diff --git a/tools/include/linux/slab.h b/tools/include/linux/slab.h index 6d8e9413d5a4..2e63c2e726aa 100644 --- a/tools/include/linux/slab.h +++ b/tools/include/linux/slab.h @@ -183,7 +183,7 @@ __kmem_cache_create(const char *name, unsigned int size, unsigned int align, default: __kmem_cache_create)(__name, __object_size, __args, __VA_ARGS__) void kmem_cache_free_bulk(struct kmem_cache *cachep, size_t size, void **list); -int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, +bool kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, void **list); struct slab_sheaf * kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size); diff --git a/tools/testing/shared/linux.c b/tools/testing/shared/linux.c index 8c7257155958..e0a0693df08f 100644 --- a/tools/testing/shared/linux.c +++ b/tools/testing/shared/linux.c @@ -154,7 +154,7 @@ void kmem_cache_shrink(struct kmem_cache *cachep) { } -int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, +bool kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, void **p) { size_t i; @@ -213,7 +213,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, pthread_mutex_unlock(&cachep->lock); if (cachep->callback) cachep->exec_callback = true; - return 0; + return false; } for (i = 0; i < size; i++) { @@ -224,7 +224,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, printf("Allocating %p from slab\n", p[i]); } - return size; + return true; } struct kmem_cache * @@ -271,8 +271,8 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size) sheaf->cache = s; sheaf->capacity = capacity; - sheaf->size = kmem_cache_alloc_bulk(s, gfp, size, sheaf->objects); - if (!sheaf->size) { + sheaf->size = size; + if (!kmem_cache_alloc_bulk(s, gfp, size, sheaf->objects)) { free(sheaf); return NULL; } @@ -284,7 +284,6 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp, struct slab_sheaf **sheafp, unsigned int size) { struct slab_sheaf *sheaf = *sheafp; - int refill; if (sheaf->size >= size) return 0; @@ -299,12 +298,10 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp, return 0; } - refill = kmem_cache_alloc_bulk(s, gfp, size - sheaf->size, - &sheaf->objects[sheaf->size]); - if (!refill) + if (!kmem_cache_alloc_bulk(s, gfp, size - sheaf->size, + &sheaf->objects[sheaf->size])) return -ENOMEM; - - sheaf->size += refill; + sheaf->size = size; return 0; } From be6e0a533d4f42f87e5fe1190d742478e4184f86 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 2 Jun 2026 18:00:38 +0200 Subject: [PATCH 474/655] mm: simplify the mempool_alloc_bulk API The mempool_alloc_bulk was modelled after the alloc_pages_bulk API, including some misunderstanding of it. Remove checking for NULL slots in the array, as alloc_pages_bulk and kmem_cache_alloc_bulk always fill the array from the beginning and thus we know the offset of the first failing allocation. This removes support for working well with alloc_pages_bulk used to refill page arrays that might have an entry removed from in the middle, but that is only used by sunrpc and hopefully on it's way out. Also remove the allocated parameter as it is redundant because the caller can simply specific and offset into the entries array. Signed-off-by: Christoph Hellwig Link: https://patch.msgid.link/20260602160038.3976341-1-hch@lst.de Signed-off-by: Vlastimil Babka (SUSE) --- block/blk-crypto-fallback.c | 9 +++++---- include/linux/mempool.h | 2 +- mm/mempool.c | 27 ++++++++++----------------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c index 61f595410832..ab6924fba280 100644 --- a/block/blk-crypto-fallback.c +++ b/block/blk-crypto-fallback.c @@ -199,8 +199,8 @@ static struct bio *blk_crypto_alloc_enc_bio(struct bio *bio_src, pages += nr_segs * (PAGE_PTRS_PER_BVEC - 1); /* - * Try a bulk allocation first. This could leave random pages in the - * array unallocated, but we'll fix that up later in mempool_alloc_bulk. + * Try a bulk allocation first. This might not fill all allocated + * pages, but we'll fix that up later in mempool_alloc_bulk. * * Note: alloc_pages_bulk needs the array to be zeroed, as it assumes * any non-zero slot already contains a valid allocation. @@ -208,8 +208,9 @@ static struct bio *blk_crypto_alloc_enc_bio(struct bio *bio_src, memset(pages, 0, sizeof(struct page *) * nr_segs); nr_allocated = alloc_pages_bulk(GFP_KERNEL, nr_segs, pages); if (nr_allocated < nr_segs) - mempool_alloc_bulk(blk_crypto_bounce_page_pool, (void **)pages, - nr_segs, nr_allocated); + mempool_alloc_bulk(blk_crypto_bounce_page_pool, + (void **)pages + nr_allocated, + nr_segs - nr_allocated); memalloc_noio_restore(memflags); *pages_ret = pages; return bio; diff --git a/include/linux/mempool.h b/include/linux/mempool.h index e8e440e04a06..a0fa6d43e0dc 100644 --- a/include/linux/mempool.h +++ b/include/linux/mempool.h @@ -66,7 +66,7 @@ void *mempool_alloc_noprof(struct mempool *pool, gfp_t gfp_mask) __malloc; #define mempool_alloc(...) \ alloc_hooks(mempool_alloc_noprof(__VA_ARGS__)) int mempool_alloc_bulk_noprof(struct mempool *pool, void **elem, - unsigned int count, unsigned int allocated); + unsigned int count); #define mempool_alloc_bulk(...) \ alloc_hooks(mempool_alloc_bulk_noprof(__VA_ARGS__)) diff --git a/mm/mempool.c b/mm/mempool.c index db23e0eef652..473a029fa31f 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -419,12 +419,8 @@ static unsigned int mempool_alloc_from_pool(struct mempool *pool, void **elems, spin_lock_irqsave(&pool->lock, flags); if (unlikely(pool->curr_nr < count - allocated)) goto fail; - for (i = 0; i < count; i++) { - if (!elems[i]) { - elems[i] = remove_element(pool); - allocated++; - } - } + while (allocated < count) + elems[allocated++] = remove_element(pool); spin_unlock_irqrestore(&pool->lock, flags); /* Paired with rmb in mempool_free(), read comment there. */ @@ -479,22 +475,21 @@ static inline gfp_t mempool_adjust_gfp(gfp_t *gfp_mask) * @pool: pointer to the memory pool * @elems: partially or fully populated elements array * @count: number of entries in @elem that need to be allocated - * @allocated: number of entries in @elem already allocated * - * Allocate elements for each slot in @elem that is non-%NULL. This is done by - * first calling into the alloc_fn supplied at pool initialization time, and - * dipping into the reserved pool when alloc_fn fails to allocate an element. + * Allocate @count elements into @elems. This is done by first calling into the + * alloc_fn supplied at pool initialization time, and dipping into the reserved + * pool when alloc_fn fails to allocate an element. * * On return all @count elements in @elems will be populated. * * Return: Always 0. If it wasn't for %$#^$ alloc tags, it would return void. */ int mempool_alloc_bulk_noprof(struct mempool *pool, void **elems, - unsigned int count, unsigned int allocated) + unsigned int count) { gfp_t gfp_mask = GFP_KERNEL; gfp_t gfp_temp = mempool_adjust_gfp(&gfp_mask); - unsigned int i = 0; + unsigned int allocated = 0; VM_WARN_ON_ONCE(count > pool->min_nr); might_alloc(gfp_mask); @@ -514,11 +509,9 @@ repeat_alloc: * Try to allocate the elements using the allocation callback first as * that might succeed even when the caller's bulk allocation did not. */ - for (i = 0; i < count; i++) { - if (elems[i]) - continue; - elems[i] = pool->alloc(gfp_temp, pool->pool_data); - if (unlikely(!elems[i])) + while (allocated < count) { + elems[allocated] = pool->alloc(gfp_temp, pool->pool_data); + if (unlikely(!elems[allocated])) goto use_pool; allocated++; } From 4954d4eca469419339452cb5fea26dd0fc678c54 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Wed, 3 Jun 2026 07:58:25 +0800 Subject: [PATCH 475/655] spi: cadence-xspi: Support 32bit and 64bit slave dma interface The cdns xspi controller slave dma interface may support wider data width. Wider I/O width can benefit performance. We can know the width by checking the CTRL_FEATURES_REG's DMA_DATA_WIDTH bit, 0 means 32bit 1 means 64bit. A simple test with QSPI nor flash on one arm64 platform: Use 8bit slave dma data width (now): # dd if=/dev/mtdblock0 of=/dev/null bs=8192 count=1000 1000+0 records in 1000+0 records out 8192000 bytes (7.8MB) copied, 1.368735 seconds, 5.7MB/s Use 32bit slave dma data width: # dd if=/dev/mtdblock0 of=/dev/null bs=8192 count=1000 1000+0 records in 1000+0 records out 8192000 bytes (7.8MB) copied, 1.088787 seconds, 7.2MB/s Improved by 26.3%! Use 64bit slave dma data width: # dd if=/dev/mtdblock0 of=/dev/null bs=8192 count=1000 1000+0 records in 1000+0 records out 8192000 bytes (7.8MB) copied, 0.831104 seconds, 9.4MB/s Improved by 64.9%! Signed-off-by: Jisheng Zhang Link: https://patch.msgid.link/20260602235825.28614-1-jszhang@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-xspi.c | 53 +++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index c45b29c043bf..e2bfb0c78b82 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -373,6 +373,8 @@ struct cdns_xspi_dev { void *in_buffer; const void *out_buffer; + /* Slave DMA data width in bytes (4 or 8). */ + u8 dma_data_width; u8 hw_num_banks; @@ -576,11 +578,56 @@ static int cdns_xspi_controller_init(struct cdns_xspi_dev *cdns_xspi) ctrl_features = readl(cdns_xspi->iobase + CDNS_XSPI_CTRL_FEATURES_REG); cdns_xspi->hw_num_banks = FIELD_GET(CDNS_XSPI_NUM_BANKS, ctrl_features); + cdns_xspi->dma_data_width = (ctrl_features & CDNS_XSPI_DMA_DATA_WIDTH) ? 8 : 4; cdns_xspi->set_interrupts_handler(cdns_xspi, false); return 0; } +static inline void cdns_xspi_sdma_read(struct cdns_xspi_dev *cdns_xspi, size_t len) +{ + void __iomem *src = cdns_xspi->sdmabase; + void *buf = cdns_xspi->in_buffer; + size_t offset = 0; + + if (cdns_xspi->dma_data_width == 4) { + if (IS_ALIGNED((uintptr_t)src, 4) && IS_ALIGNED((uintptr_t)buf, 4)) { + ioread32_rep(src, buf, len >> 2); + offset = len & ~0x3; + len -= offset; + } + } else { + if (IS_ALIGNED((uintptr_t)src, 8) && IS_ALIGNED((uintptr_t)buf, 8)) { + readsq(src, buf, len >> 3); + offset = len & ~0x7; + len -= offset; + } + } + ioread8_rep(src, (u8 *)buf + offset, len); +} + +static inline void cdns_xspi_sdma_write(struct cdns_xspi_dev *cdns_xspi, size_t len) +{ + void __iomem *dst = cdns_xspi->sdmabase; + const void *buf = cdns_xspi->out_buffer; + size_t offset = 0; + + if (cdns_xspi->dma_data_width == 4) { + if (IS_ALIGNED((uintptr_t)dst, 4) && IS_ALIGNED((uintptr_t)buf, 4)) { + iowrite32_rep(dst, buf, len >> 2); + offset = len & ~0x3; + len -= offset; + } + } else { + if (IS_ALIGNED((uintptr_t)dst, 8) && IS_ALIGNED((uintptr_t)buf, 8)) { + writesq(dst, buf, len >> 3); + offset = len & ~0x7; + len -= offset; + } + } + iowrite8_rep(dst, (const u8 *)buf + offset, len); +} + static void cdns_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi) { u32 sdma_size, sdma_trd_info; @@ -592,13 +639,11 @@ static void cdns_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi) switch (sdma_dir) { case CDNS_XSPI_SDMA_DIR_READ: - ioread8_rep(cdns_xspi->sdmabase, - cdns_xspi->in_buffer, sdma_size); + cdns_xspi_sdma_read(cdns_xspi, sdma_size); break; case CDNS_XSPI_SDMA_DIR_WRITE: - iowrite8_rep(cdns_xspi->sdmabase, - cdns_xspi->out_buffer, sdma_size); + cdns_xspi_sdma_write(cdns_xspi, sdma_size); break; } } From e727fe9be1738ebc0caa5cc901f0299404b6bbe6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 4 Jun 2026 13:59:12 +0200 Subject: [PATCH 476/655] regulator: bq257xx: drop confusing configuration of_node The driver reuses the OF node of the parent multi-function device but still sets the of_node field of the regulator configuration to any prior OF node. Since the MFD child device does not have an OF node set until probe is called, this field is set to NULL on first probe and to the reused OF node if the driver is later rebound. As the device_set_of_node_from_dev() helper drops a reference to any prior OF node before taking a reference to the new one this can apparently also confuse LLMs like Sashiko which flags it as a potential use-after-free (which it is not). Drop the confusing and redundant configuration of_node assignment. Link: https://sashiko.dev/#/patchset/20260408073055.5183-1-johan%40kernel.org Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20260604115912.2734074-1-johan@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/bq257xx-regulator.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c index 09c466052c04..577b277efd7f 100644 --- a/drivers/regulator/bq257xx-regulator.c +++ b/drivers/regulator/bq257xx-regulator.c @@ -143,7 +143,6 @@ static int bq257xx_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct bq257xx_reg_data *pdata; - struct device_node *np = dev->of_node; struct regulator_config cfg = {}; device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); @@ -159,7 +158,6 @@ static int bq257xx_regulator_probe(struct platform_device *pdev) cfg.dev = &pdev->dev; cfg.driver_data = pdata; - cfg.of_node = np; cfg.regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!cfg.regmap) return -ENODEV; From 214f94e56423f4097bb62692fe63d217d02a443d Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 21 May 2026 12:36:20 +0000 Subject: [PATCH 477/655] dt-bindings: crypto: qcom,prng: Document Hawi TRNG Hawi SoC has the True Random Number Generator (TRNG) which is compatible with the baseline IP "qcom,trng". Hence, document the compatible as such. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Acked-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/crypto/qcom,prng.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml index d054cc114707..dc270c8aedf3 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml @@ -18,6 +18,7 @@ properties: - items: - enum: - qcom,glymur-trng + - qcom,hawi-trng - qcom,ipq5332-trng - qcom,ipq5424-trng - qcom,ipq9574-trng From d273b258d8d582626f2270809874b94c71a27bf5 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 21 May 2026 12:36:21 +0000 Subject: [PATCH 478/655] dt-bindings: crypto: qcom,inline-crypto-engine: Document Hawi ICE The Inline Crypto Engine found in Hawi SoC is compatible with the common baseline IP 'qcom,inline-crypto-engine'. Hence, document the compatible as such. Signed-off-by: Manivannan Sadhasivam Acked-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml index 876bf90ed96e..2a183b07b03a 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml @@ -14,6 +14,7 @@ properties: items: - enum: - qcom,eliza-inline-crypto-engine + - qcom,hawi-inline-crypto-engine - qcom,kaanapali-inline-crypto-engine - qcom,milos-inline-crypto-engine - qcom,qcs8300-inline-crypto-engine From 4e67f504ee9ded15e256b64f4fde150e917381d7 Mon Sep 17 00:00:00 2001 From: Sam James Date: Mon, 25 May 2026 08:56:19 +0100 Subject: [PATCH 479/655] crypto: nx - fix nx_crypto_ctx_exit argument nx_crypto_ctx_shash_exit calls nx_crypto_ctx_exit with crypto_shash_ctx(...) but crypto_shash_ctx gives a nx_crypto_ctx *, not a crypto_tfm *. Fix the type in nx_crypto_ctx_exit and drop the bogus crypto_tfm_ctx call. This fixes the following oops: BUG: Unable to handle kernel data access at 0xc0403effffffffc8 Faulting instruction address: 0xc000000000396cb4 Oops: Kernel access of bad area, sig: 11 [#15] Call Trace: nx_crypto_ctx_shash_exit+0x24/0x60 crypto_shash_exit_tfm+0x28/0x40 crypto_destroy_tfm+0x98/0x140 crypto_exit_ahash_using_shash+0x20/0x40 crypto_destroy_tfm+0x98/0x140 hash_release+0x1c/0x30 alg_sock_destruct+0x38/0x60 __sk_destruct+0x48/0x2b0 af_alg_release+0x58/0xb0 __sock_release+0x68/0x150 sock_close+0x20/0x40 __fput+0x110/0x3a0 sys_close+0x48/0xa0 system_call_exception+0x140/0x2d0 system_call_common+0xf4/0x258 .. which came from hardlink(1) opportunistically using AF_ALG. The same problem exists with nx_crypto_ctx_skcipher_exit getting a context it wasn't expecting, but apparently nobody hit that for years. Cc: Eric Biggers Cc: stable@vger.kernel.org Fixes: bfd9efddf990 ("crypto: nx - convert AES-ECB to skcipher API") Fixes: 9420e628e7d8 ("crypto: nx - Use API partial block handling") Acked-by: Breno Leitao Reviewed-by: Eric Biggers Reported-by: Calvin Buckley Tested-by: Calvin Buckley Suggested-by: Brad Spengler Signed-off-by: Sam James Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx.c | 6 ++---- drivers/crypto/nx/nx.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 78135fb13f5c..1b7509e2ce44 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -714,15 +714,13 @@ int nx_crypto_ctx_aes_xcbc_init(struct crypto_shash *tfm) /** * nx_crypto_ctx_exit - destroy a crypto api context * - * @tfm: the crypto transform pointer for the context + * @nx_ctx: the crypto api context * * As crypto API contexts are destroyed, this exit hook is called to free the * memory associated with it. */ -void nx_crypto_ctx_exit(struct crypto_tfm *tfm) +void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm); - kfree_sensitive(nx_ctx->kmem); nx_ctx->csbcpb = NULL; nx_ctx->csbcpb_aead = NULL; diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h index 36974f08490a..6dfabfbf8192 100644 --- a/drivers/crypto/nx/nx.h +++ b/drivers/crypto/nx/nx.h @@ -153,7 +153,7 @@ int nx_crypto_ctx_aes_ctr_init(struct crypto_skcipher *tfm); int nx_crypto_ctx_aes_cbc_init(struct crypto_skcipher *tfm); int nx_crypto_ctx_aes_ecb_init(struct crypto_skcipher *tfm); int nx_crypto_ctx_sha_init(struct crypto_shash *tfm); -void nx_crypto_ctx_exit(struct crypto_tfm *tfm); +void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx); void nx_crypto_ctx_skcipher_exit(struct crypto_skcipher *tfm); void nx_crypto_ctx_aead_exit(struct crypto_aead *tfm); void nx_crypto_ctx_shash_exit(struct crypto_shash *tfm); From ed459fe319376e876de433d12b6c6772e612ca36 Mon Sep 17 00:00:00 2001 From: Ruijie Li Date: Mon, 25 May 2026 19:45:21 +0800 Subject: [PATCH 480/655] crypto: pcrypt - restore callback for non-parallel fallback pcrypt installs pcrypt_aead_done() on the child AEAD request before trying to submit it through padata. If padata_do_parallel() returns -EBUSY, pcrypt falls back to calling the child AEAD directly. That fallback must not keep the padata completion callback. Otherwise an asynchronous completion runs pcrypt_aead_done() even though the request was never enrolled in padata. Restore the original request callback and callback data before calling the child AEAD directly. This keeps the fallback path aligned with a direct AEAD request while leaving the parallel path unchanged. Fixes: 662f2f13e66d ("crypto: pcrypt - Call crypto layer directly when padata_do_parallel() return -EBUSY") Cc: stable@kernel.org Reported-by: Yuan Tan Reported-by: Yifan Wu Reported-by: Juefei Pu Reported-by: Zhengchuan Liang Reported-by: Xin Liu Assisted-by: Codex:gpt-5.4 Signed-off-by: Ruijie Li Signed-off-by: Ren Wei Signed-off-by: Herbert Xu --- crypto/pcrypt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index ed0feaba2383..9f372442981e 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -122,6 +122,8 @@ static int pcrypt_aead_encrypt(struct aead_request *req) return -EINPROGRESS; if (err == -EBUSY) { /* try non-parallel mode */ + aead_request_set_callback(creq, flags, req->base.complete, + req->base.data); return crypto_aead_encrypt(creq); } @@ -173,6 +175,8 @@ static int pcrypt_aead_decrypt(struct aead_request *req) return -EINPROGRESS; if (err == -EBUSY) { /* try non-parallel mode */ + aead_request_set_callback(creq, flags, req->base.complete, + req->base.data); return crypto_aead_decrypt(creq); } From fb98254a5eb9c5ddd22e9bffdd8ae709769bee9f Mon Sep 17 00:00:00 2001 From: Junyuan Wang Date: Tue, 26 May 2026 09:28:39 +0000 Subject: [PATCH 481/655] crypto: qat - add KPT support for GEN6 devices Add support for Intel Key Protection Technology (KPT) on QAT GEN6 devices. KPT protects private keys from exposure by keeping them wrapped (encrypted) while in use, in-flight, and at rest. Keys remain in wrapped form and are not exposed in plaintext in host memory. This feature operates outside of the Linux crypto framework and kernel keyring. Extend the firmware admin interface to enable and configure KPT. During device initialisation, if KPT is enabled, the driver sends an admin message to firmware to enable KPT mode and configure parameters such as the maximum number of SWK (Symmetric Wrapping Key) slots and the SWK time-to-live (TTL). Expose KPT configuration via a new sysfs attribute group, "qat_kpt", and add ABI documentation. Co-developed-by: Nitesh Venkatesh Signed-off-by: Nitesh Venkatesh Signed-off-by: Junyuan Wang Reviewed-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Signed-off-by: Herbert Xu --- .../ABI/testing/sysfs-driver-qat_kpt | 97 ++++++ .../intel/qat/qat_6xxx/adf_6xxx_hw_data.c | 21 +- .../intel/qat/qat_6xxx/adf_6xxx_hw_data.h | 9 + drivers/crypto/intel/qat/qat_6xxx/adf_drv.c | 6 + drivers/crypto/intel/qat/qat_common/Makefile | 2 + .../intel/qat/qat_common/adf_accel_devices.h | 2 + .../crypto/intel/qat/qat_common/adf_admin.c | 39 +++ .../crypto/intel/qat/qat_common/adf_admin.h | 2 + .../crypto/intel/qat/qat_common/adf_init.c | 8 + drivers/crypto/intel/qat/qat_common/adf_kpt.c | 56 ++++ drivers/crypto/intel/qat/qat_common/adf_kpt.h | 29 ++ .../intel/qat/qat_common/adf_sysfs_kpt.c | 296 ++++++++++++++++++ .../intel/qat/qat_common/adf_sysfs_kpt.h | 10 + .../qat/qat_common/icp_qat_fw_init_admin.h | 8 + .../crypto/intel/qat/qat_common/icp_qat_hw.h | 3 +- 15 files changed, 586 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-qat_kpt create mode 100644 drivers/crypto/intel/qat/qat_common/adf_kpt.c create mode 100644 drivers/crypto/intel/qat/qat_common/adf_kpt.h create mode 100644 drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.c create mode 100644 drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.h diff --git a/Documentation/ABI/testing/sysfs-driver-qat_kpt b/Documentation/ABI/testing/sysfs-driver-qat_kpt new file mode 100644 index 000000000000..c6480ea1fa4f --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-qat_kpt @@ -0,0 +1,97 @@ +What: /sys/bus/pci/devices//qat_kpt/ +Date: August 2026 +KernelVersion: 7.2 +Contact: qat-linux@intel.com +Description: + Directory containing attributes related to the QAT Key Protection + Technology (KPT) feature. KPT allows cryptographic keys to be used + by the accelerator without being exposed in plaintext to the host. + +What: /sys/bus/pci/devices//qat_kpt/enable +Date: August 2026 +KernelVersion: 7.2 +Contact: qat-linux@intel.com +Description: + (RW) Enables or disables Key Protection Technology (KPT). + + Write 1 to enable KPT, or 0 to disable it. + + Example usage:: + + # cat /sys/bus/pci/devices//qat_kpt/enable + 0 + # echo 1 > /sys/bus/pci/devices//qat_kpt/enable + + This attribute is only available on devices that support KPT. + +What: /sys/bus/pci/devices//qat_kpt/swk_cnt_per_fn +Date: August 2026 +KernelVersion: 7.2 +Contact: qat-linux@intel.com +Description: + (RW) Configures the maximum number of KPT symmetric wrapping keys + (SWKs) that a Virtual Function (VF) may be associated with. + + Valid values range from 0 to 128. A value of 0 indicates no limit. + + Example usage:: + + # cat /sys/bus/pci/devices//qat_kpt/swk_cnt_per_fn + 128 + # echo 128 > /sys/bus/pci/devices//qat_kpt/swk_cnt_per_fn + + This attribute is only available on devices that support KPT. + +What: /sys/bus/pci/devices//qat_kpt/swk_cnt_per_pasid +Date: August 2026 +KernelVersion: 7.2 +Contact: qat-linux@intel.com +Description: + (RW) Configures the maximum number of KPT symmetric wrapping keys + (SWKs) per Process Address Space ID (PASID). + + Valid values range from 0 to 128. A value of 0 indicates no limit. + + Example usage:: + + # cat /sys/bus/pci/devices//qat_kpt/swk_cnt_per_pasid + 128 + # echo 128 > /sys/bus/pci/devices//qat_kpt/swk_cnt_per_pasid + + This attribute is only available on devices that support KPT. + +What: /sys/bus/pci/devices//qat_kpt/swk_max_ttl +Date: August 2026 +KernelVersion: 7.2 +Contact: qat-linux@intel.com +Description: + (RW) Configures the maximum Time To Live (TTL) for KPT symmetric + wrapping keys (SWK). + + Valid values range from 0 to 31536000 seconds. A value of 0 + indicates that the SWK TTL is unlimited. + + Example usage:: + + # cat /sys/bus/pci/devices//qat_kpt/swk_max_ttl + 1000 + # echo 1000 > /sys/bus/pci/devices//qat_kpt/swk_max_ttl + + This attribute is only available on devices that support KPT. + +What: /sys/bus/pci/devices//qat_kpt/swk_shared +Date: August 2026 +KernelVersion: 7.2 +Contact: qat-linux@intel.com +Description: + (RW) Controls shared mode for KPT symmetric wrapping keys (SWK). + + Write 1 to enable shared mode, or 0 to disable it (non-shared mode). + + Example usage:: + + # cat /sys/bus/pci/devices//qat_kpt/swk_shared + 0 + # echo 1 > /sys/bus/pci/devices//qat_kpt/swk_shared + + This attribute is only available on devices that support KPT. diff --git a/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.c b/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.c index 205680797e2c..388087e64540 100644 --- a/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.c @@ -752,10 +752,12 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) unsigned long mask; u32 caps = 0; u32 fusectl1; + u32 fusectl0; if (adf_6xxx_is_wcy(GET_HW_DATA(accel_dev))) return get_accel_cap_wcy(accel_dev); + fusectl0 = GET_HW_DATA(accel_dev)->fuses[ADF_FUSECTL0]; fusectl1 = GET_HW_DATA(accel_dev)->fuses[ADF_FUSECTL1]; /* Read accelerator capabilities mask */ @@ -785,7 +787,8 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) capabilities_asym = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC | ICP_ACCEL_CAPABILITIES_SM2 | - ICP_ACCEL_CAPABILITIES_ECEDMONT; + ICP_ACCEL_CAPABILITIES_ECEDMONT | + ICP_ACCEL_CAPABILITIES_KPT; if (fusectl1 & ICP_ACCEL_GEN6_MASK_PKE_SLICE) { capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC; @@ -793,6 +796,9 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_ECEDMONT; } + if (fusectl0 & ADF_GEN6_KPT_FUSE_BIT) + capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_KPT; + capabilities_dc = ICP_ACCEL_CAPABILITIES_COMPRESSION | ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION | ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION | @@ -960,6 +966,18 @@ static int dev_config(struct adf_accel_dev *accel_dev) return ret; } +static void adf_gen6_init_kpt(struct adf_kpt_hw_data *kpt_data) +{ + kpt_data->max_swk_cnt_per_fn_pasid = ADF_6XXX_KPT_MAX_SWK_COUNT_PER_FNPASID; + kpt_data->max_swk_ttl = ADF_6XXX_KPT_MAX_SWK_TTL; + + kpt_data->user_input.enable = false; + kpt_data->user_input.swk_shared = ADF_6XXX_KPT_DEFAULT_SWK_SHARED_MODE; + kpt_data->user_input.swk_max_ttl = ADF_6XXX_KPT_DEFAULT_SWK_TTL; + kpt_data->user_input.swk_cnt_per_fn = ADF_6XXX_KPT_DEFAULT_SWK_CNT_PER_FN; + kpt_data->user_input.swk_cnt_per_pasid = ADF_6XXX_KPT_DEFAULT_SWK_CNT_PER_PASID; +} + static void adf_gen6_init_rl_data(struct adf_rl_hw_data *rl_data) { rl_data->pciout_tb_offset = ADF_GEN6_RL_TOKEN_PCIEOUT_BUCKET_OFFSET; @@ -1057,6 +1075,7 @@ void adf_init_hw_data_6xxx(struct adf_hw_device_data *hw_data) adf_gen6_init_tl_data(&hw_data->tl_data); adf_gen6_init_rl_data(&hw_data->rl_data); adf_gen6_init_anti_rb(&hw_data->anti_rb_data); + adf_gen6_init_kpt(&hw_data->kpt_data); } void adf_clean_hw_data_6xxx(struct adf_hw_device_data *hw_data) diff --git a/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.h b/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.h index e4d433bdd379..2719ddbc1e05 100644 --- a/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.h +++ b/drivers/crypto/intel/qat/qat_6xxx/adf_6xxx_hw_data.h @@ -58,6 +58,7 @@ /* Fuse bits */ #define ADF_GEN6_ANTI_RB_FUSE_BIT BIT(24) +#define ADF_GEN6_KPT_FUSE_BIT BIT(16) /* * Watchdog timers @@ -164,6 +165,14 @@ /* Clock frequency */ #define ADF_6XXX_AE_FREQ (1000 * HZ_PER_MHZ) +/* KPT */ +#define ADF_6XXX_KPT_MAX_SWK_COUNT_PER_FNPASID 128 +#define ADF_6XXX_KPT_MAX_SWK_TTL 31536000 +#define ADF_6XXX_KPT_DEFAULT_SWK_SHARED_MODE 1 +#define ADF_6XXX_KPT_DEFAULT_SWK_TTL 0 +#define ADF_6XXX_KPT_DEFAULT_SWK_CNT_PER_FN 0 +#define ADF_6XXX_KPT_DEFAULT_SWK_CNT_PER_PASID 0 + enum icp_qat_gen6_slice_mask { ICP_ACCEL_GEN6_MASK_UCS_SLICE = BIT(0), ICP_ACCEL_GEN6_MASK_AUTH_SLICE = BIT(1), diff --git a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c index ab62b91ecb51..319b4251ad46 100644 --- a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "adf_gen6_shared.h" #include "adf_6xxx_hw_data.h" @@ -217,6 +218,11 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; ret = adf_sysfs_init(accel_dev); + if (ret) + return ret; + + if (!(hw_data->fuses[ADF_FUSECTL0] & ADF_GEN6_KPT_FUSE_BIT)) + ret = adf_sysfs_init_kpt(accel_dev); return ret; } diff --git a/drivers/crypto/intel/qat/qat_common/Makefile b/drivers/crypto/intel/qat/qat_common/Makefile index 2b1649001518..306ec71bb6fa 100644 --- a/drivers/crypto/intel/qat/qat_common/Makefile +++ b/drivers/crypto/intel/qat/qat_common/Makefile @@ -25,12 +25,14 @@ intel_qat-y := adf_accel_engine.o \ adf_hw_arbiter.o \ adf_init.o \ adf_isr.o \ + adf_kpt.o \ adf_module.o \ adf_mstate_mgr.o \ adf_rl_admin.o \ adf_rl.o \ adf_sysfs.o \ adf_sysfs_anti_rb.o \ + adf_sysfs_kpt.o \ adf_sysfs_ras_counters.o \ adf_sysfs_rl.o \ adf_timer.o \ diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h index d9b2a1cf474e..f2d70641c377 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h @@ -14,6 +14,7 @@ #include "adf_anti_rb.h" #include "adf_cfg_common.h" #include "adf_dc.h" +#include "adf_kpt.h" #include "adf_rl.h" #include "adf_telemetry.h" #include "adf_pfvf_msg.h" @@ -335,6 +336,7 @@ struct adf_hw_device_data { struct adf_rl_hw_data rl_data; struct adf_tl_hw_data tl_data; struct adf_anti_rb_hw_data anti_rb_data; + struct adf_kpt_hw_data kpt_data; struct qat_migdev_ops vfmig_ops; const char *fw_name; const char *fw_mmp_name; diff --git a/drivers/crypto/intel/qat/qat_common/adf_admin.c b/drivers/crypto/intel/qat/qat_common/adf_admin.c index 841aa802c79e..1eea74c2a8a5 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_admin.c +++ b/drivers/crypto/intel/qat/qat_common/adf_admin.c @@ -13,6 +13,7 @@ #include "adf_common_drv.h" #include "adf_cfg.h" #include "adf_heartbeat.h" +#include "adf_kpt.h" #include "icp_qat_fw_init_admin.h" #define ADF_ADMIN_MAILBOX_STRIDE 0x1000 @@ -606,6 +607,44 @@ int adf_send_admin_arb_commit(struct adf_accel_dev *accel_dev) return adf_send_admin_svn(accel_dev, ICP_QAT_FW_SVN_COMMIT, &resp); } +static_assert(sizeof(struct icp_qat_fw_init_admin_kpt_cfg) < PAGE_SIZE); + +static void adf_cfg_kpt_config(struct adf_accel_dev *accel_dev, + struct icp_qat_fw_init_admin_kpt_cfg *kpt_config) +{ + struct adf_kpt_interface_data *user_data = GET_KPT_USER_DATA(accel_dev); + + kpt_config->swk_cnt_per_fn = user_data->swk_cnt_per_fn; + kpt_config->swk_cnt_per_pasid = user_data->swk_cnt_per_pasid; + kpt_config->swk_ttl_in_secs = user_data->swk_max_ttl; + kpt_config->swk_shared_disable = !user_data->swk_shared; +} + +int adf_send_admin_kpt_init(struct adf_accel_dev *accel_dev, void *init_cfg, + size_t init_cfg_sz, dma_addr_t init_ptr) +{ + struct icp_qat_fw_init_admin_kpt_cfg *kpt_config = init_cfg; + u32 ae_mask = GET_HW_DATA(accel_dev)->admin_ae_mask; + struct icp_qat_fw_init_admin_resp resp = { }; + struct icp_qat_fw_init_admin_req req = { }; + int ret; + + if (!kpt_config || init_cfg_sz < sizeof(*kpt_config)) + return -EINVAL; + + adf_cfg_kpt_config(accel_dev, kpt_config); + + req.cmd_id = ICP_QAT_FW_KPT_ENABLE; + req.init_cfg_ptr = init_ptr; + req.init_cfg_sz = sizeof(*kpt_config); + + ret = adf_send_admin(accel_dev, &req, &resp, ae_mask); + if (ret) + dev_err(&GET_DEV(accel_dev), "Failed to send KPT init admin message\n"); + + return ret; +} + int adf_init_admin_comms(struct adf_accel_dev *accel_dev) { struct adf_admin_comms *admin; diff --git a/drivers/crypto/intel/qat/qat_common/adf_admin.h b/drivers/crypto/intel/qat/qat_common/adf_admin.h index 9704219f2eb7..44eb6dc92e45 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_admin.h +++ b/drivers/crypto/intel/qat/qat_common/adf_admin.h @@ -29,5 +29,7 @@ int adf_send_admin_tl_start(struct adf_accel_dev *accel_dev, int adf_send_admin_tl_stop(struct adf_accel_dev *accel_dev); int adf_send_admin_arb_query(struct adf_accel_dev *accel_dev, int cmd, u8 *svn); int adf_send_admin_arb_commit(struct adf_accel_dev *accel_dev); +int adf_send_admin_kpt_init(struct adf_accel_dev *accel_dev, void *init_cfg, + size_t init_cfg_sz, dma_addr_t init_ptr); #endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c index 1c7f9e49914d..3e39c53814de 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_init.c +++ b/drivers/crypto/intel/qat/qat_common/adf_init.c @@ -10,6 +10,7 @@ #include "adf_dbgfs.h" #include "adf_heartbeat.h" #include "adf_rl.h" +#include "adf_kpt.h" #include "adf_sysfs_anti_rb.h" #include "adf_sysfs_ras_counters.h" #include "adf_telemetry.h" @@ -219,6 +220,13 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev) return -EFAULT; } + /* Enable Key Protection Technology (KPT) */ + ret = adf_enable_kpt(accel_dev); + if (ret) { + dev_err(&GET_DEV(accel_dev), "Failed to enable KPT\n"); + return ret; + } + if (hw_data->start_timer) { ret = hw_data->start_timer(accel_dev); if (ret) { diff --git a/drivers/crypto/intel/qat/qat_common/adf_kpt.c b/drivers/crypto/intel/qat/qat_common/adf_kpt.c new file mode 100644 index 000000000000..a0430141ea0e --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_kpt.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2026 Intel Corporation */ +#include + +#include "adf_admin.h" +#include "adf_cfg_services.h" +#include "adf_common_drv.h" +#include "adf_kpt.h" + +static bool adf_kpt_supported(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + + return hw_data->accel_capabilities_mask & ICP_ACCEL_CAPABILITIES_KPT; +} + +int adf_enable_kpt(struct adf_accel_dev *accel_dev) +{ + struct adf_kpt_interface_data *user_data = GET_KPT_USER_DATA(accel_dev); + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + dma_addr_t paddr; + void *vaddr; + int ret; + int svc; + + /* Return 0 if KPT is not supported by the hardware */ + if (!adf_kpt_supported(accel_dev)) + return 0; + + if (!user_data->enable) { + /* Disable KPT capability if user has not enabled it */ + hw_data->accel_capabilities_mask &= ~ICP_ACCEL_CAPABILITIES_KPT; + return 0; + } + + svc = adf_get_service_enabled(accel_dev); + if (svc < 0) + return svc; + + if (svc != SVC_ASYM) { + dev_err(&GET_DEV(accel_dev), + "KPT can only be enabled when service is configured as 'asym'\n"); + return -EINVAL; + } + + vaddr = dma_alloc_coherent(&GET_DEV(accel_dev), PAGE_SIZE, &paddr, + GFP_KERNEL); + if (!vaddr) + return -ENOMEM; + + ret = adf_send_admin_kpt_init(accel_dev, vaddr, PAGE_SIZE, paddr); + + dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE, vaddr, paddr); + + return ret; +} diff --git a/drivers/crypto/intel/qat/qat_common/adf_kpt.h b/drivers/crypto/intel/qat/qat_common/adf_kpt.h new file mode 100644 index 000000000000..17d07d24a319 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_kpt.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright(c) 2026 Intel Corporation */ +#ifndef ADF_KPT_H_ +#define ADF_KPT_H_ + +#include + +#define GET_KPT_CFG_DATA(accel_dev) (&(accel_dev)->hw_device->kpt_data) +#define GET_KPT_USER_DATA(accel_dev) (&(accel_dev)->hw_device->kpt_data.user_input) + +struct adf_accel_dev; + +struct adf_kpt_interface_data { + bool enable; + bool swk_shared; + unsigned int swk_cnt_per_fn; + unsigned int swk_cnt_per_pasid; + unsigned int swk_max_ttl; +}; + +struct adf_kpt_hw_data { + unsigned int max_swk_cnt_per_fn_pasid; + unsigned int max_swk_ttl; + struct adf_kpt_interface_data user_input; +}; + +int adf_enable_kpt(struct adf_accel_dev *accel_dev); + +#endif /* ADF_KPT_H_ */ diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.c new file mode 100644 index 000000000000..1f733ae80bdf --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2026 Intel Corporation */ +#include +#include + +#include "adf_cfg.h" +#include "adf_cfg_services.h" +#include "adf_common_drv.h" +#include "adf_kpt.h" +#include "adf_sysfs_kpt.h" + +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adf_kpt_interface_data *user_data; + struct adf_accel_dev *accel_dev; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + user_data = GET_KPT_USER_DATA(accel_dev); + + return sysfs_emit(buf, "%d\n", user_data->enable); +} + +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adf_kpt_interface_data *user_data; + struct adf_hw_device_data *hw_data; + struct adf_accel_dev *accel_dev; + bool enable; + int ret; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + if (adf_dev_started(accel_dev)) { + dev_info(dev, "Device qat_dev%d must be down before enabling KPT\n", + accel_dev->accel_id); + return -EINVAL; + } + + if (adf_get_service_enabled(accel_dev) != SVC_ASYM) { + dev_info(dev, "KPT can only be enabled when the asymmetric service is enabled\n"); + return -EINVAL; + } + + hw_data = GET_HW_DATA(accel_dev); + + /* + * Restore the KPT capability bit in the device's capabilities mask + * before processing user input, as the bit may have been cleared if + * KPT was previously disabled by the user. + */ + hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev); + if (!hw_data->accel_capabilities_mask) + return -EINVAL; + + ret = kstrtobool(buf, &enable); + if (ret) + return ret; + + user_data = GET_KPT_USER_DATA(accel_dev); + user_data->enable = enable; + + return count; +} +static DEVICE_ATTR_RW(enable); + +static ssize_t swk_shared_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adf_kpt_interface_data *user_data; + struct adf_accel_dev *accel_dev; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + user_data = GET_KPT_USER_DATA(accel_dev); + + return sysfs_emit(buf, "%d\n", user_data->swk_shared); +} + +static ssize_t swk_shared_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adf_kpt_interface_data *user_data; + struct adf_accel_dev *accel_dev; + bool swk_shared; + int ret; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + if (adf_dev_started(accel_dev)) { + dev_info(dev, "Device qat_dev%d must be down before setting swk_shared\n", + accel_dev->accel_id); + return -EINVAL; + } + + ret = kstrtobool(buf, &swk_shared); + if (ret) + return ret; + + user_data = GET_KPT_USER_DATA(accel_dev); + user_data->swk_shared = swk_shared; + + return count; +} +static DEVICE_ATTR_RW(swk_shared); + +static ssize_t swk_max_ttl_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adf_kpt_interface_data *user_data; + struct adf_accel_dev *accel_dev; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + user_data = GET_KPT_USER_DATA(accel_dev); + + return sysfs_emit(buf, "%u\n", user_data->swk_max_ttl); +} + +static ssize_t swk_max_ttl_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adf_kpt_hw_data *kpt_data; + struct adf_accel_dev *accel_dev; + unsigned int swk_max_ttl; + int ret; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + if (adf_dev_started(accel_dev)) { + dev_info(dev, "Device qat_dev%d must be down before setting swk_max_ttl\n", + accel_dev->accel_id); + return -EINVAL; + } + + ret = kstrtouint(buf, 10, &swk_max_ttl); + if (ret) + return ret; + + kpt_data = GET_KPT_CFG_DATA(accel_dev); + + if (swk_max_ttl > kpt_data->max_swk_ttl) { + dev_info(dev, "Configuration value is out of range (%u - %u)\n", + 0, kpt_data->max_swk_ttl); + return -EINVAL; + } + + kpt_data->user_input.swk_max_ttl = swk_max_ttl; + + return count; +} +static DEVICE_ATTR_RW(swk_max_ttl); + +static ssize_t swk_cnt_per_fn_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adf_kpt_interface_data *user_data; + struct adf_accel_dev *accel_dev; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + user_data = GET_KPT_USER_DATA(accel_dev); + + return sysfs_emit(buf, "%u\n", user_data->swk_cnt_per_fn); +} + +static ssize_t swk_cnt_per_fn_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adf_kpt_hw_data *kpt_data; + struct adf_accel_dev *accel_dev; + unsigned int swk_cnt_per_fn; + int ret; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + if (adf_dev_started(accel_dev)) { + dev_info(dev, "Device qat_dev%d must be down before setting swk_cnt_per_fn\n", + accel_dev->accel_id); + return -EINVAL; + } + + ret = kstrtouint(buf, 10, &swk_cnt_per_fn); + if (ret) + return ret; + + kpt_data = GET_KPT_CFG_DATA(accel_dev); + + if (swk_cnt_per_fn > kpt_data->max_swk_cnt_per_fn_pasid) { + dev_info(dev, "swk_cnt_per_fn: value out of range (0 - %u)\n", + kpt_data->max_swk_cnt_per_fn_pasid); + return -EINVAL; + } + + kpt_data->user_input.swk_cnt_per_fn = swk_cnt_per_fn; + + return count; +} +static DEVICE_ATTR_RW(swk_cnt_per_fn); + +static ssize_t swk_cnt_per_pasid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adf_kpt_interface_data *user_data; + struct adf_accel_dev *accel_dev; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + user_data = GET_KPT_USER_DATA(accel_dev); + + return sysfs_emit(buf, "%u\n", user_data->swk_cnt_per_pasid); +} + +static ssize_t swk_cnt_per_pasid_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adf_kpt_hw_data *kpt_data; + struct adf_accel_dev *accel_dev; + unsigned int swk_cnt_per_pasid; + int ret; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + if (adf_dev_started(accel_dev)) { + dev_info(dev, "Device qat_dev%d must be down before setting swk_cnt_per_pasid\n", + accel_dev->accel_id); + return -EINVAL; + } + + ret = kstrtouint(buf, 10, &swk_cnt_per_pasid); + if (ret) + return ret; + + kpt_data = GET_KPT_CFG_DATA(accel_dev); + + if (swk_cnt_per_pasid > kpt_data->max_swk_cnt_per_fn_pasid) { + dev_info(dev, "swk_cnt_per_pasid: value out of range (0 - %u)\n", + kpt_data->max_swk_cnt_per_fn_pasid); + return -EINVAL; + } + + kpt_data->user_input.swk_cnt_per_pasid = swk_cnt_per_pasid; + + return count; +} +static DEVICE_ATTR_RW(swk_cnt_per_pasid); + +static struct attribute *qat_kpt_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_swk_shared.attr, + &dev_attr_swk_max_ttl.attr, + &dev_attr_swk_cnt_per_fn.attr, + &dev_attr_swk_cnt_per_pasid.attr, + NULL, +}; + +static const struct attribute_group qat_kpt_group = { + .attrs = qat_kpt_attrs, + .name = "qat_kpt", +}; + +int adf_sysfs_init_kpt(struct adf_accel_dev *accel_dev) +{ + int ret; + + ret = devm_device_add_group(&GET_DEV(accel_dev), &qat_kpt_group); + if (ret) { + dev_err(&GET_DEV(accel_dev), "Failed to create qat_kpt attribute group\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(adf_sysfs_init_kpt); diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.h b/drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.h new file mode 100644 index 000000000000..d9d065f75114 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_kpt.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright(c) 2026 Intel Corporation */ +#ifndef ADF_SYSFS_KPT_H_ +#define ADF_SYSFS_KPT_H_ + +struct adf_accel_dev; + +int adf_sysfs_init_kpt(struct adf_accel_dev *accel_dev); + +#endif /* ADF_SYSFS_KPT_H_ */ diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h index 6b0f0d100cb9..95f7f514cb63 100644 --- a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h +++ b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h @@ -31,6 +31,7 @@ enum icp_qat_fw_init_admin_cmd_id { ICP_QAT_FW_RL_REMOVE = 136, ICP_QAT_FW_TL_START = 137, ICP_QAT_FW_TL_STOP = 138, + ICP_QAT_FW_KPT_ENABLE = 144, ICP_QAT_FW_SVN_READ = 146, ICP_QAT_FW_SVN_COMMIT = 147, }; @@ -212,4 +213,11 @@ struct icp_qat_fw_init_admin_pm_info { __u32 resvrd3[6]; }; +struct icp_qat_fw_init_admin_kpt_cfg { + __u32 swk_cnt_per_fn; + __u32 swk_cnt_per_pasid; + __u32 swk_ttl_in_secs; + __u32 swk_shared_disable; +}; + #endif diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h index 16ef6d98fa42..e38115d3cd75 100644 --- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h +++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h @@ -114,7 +114,8 @@ enum icp_qat_capabilities_mask { ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION = BIT(24), ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION = BIT(25), ICP_ACCEL_CAPABILITIES_AES_V2 = BIT(26), - /* Bits 27-28 are currently reserved */ + ICP_ACCEL_CAPABILITIES_KPT = BIT(27), + /* Bit 28 is currently reserved */ ICP_ACCEL_CAPABILITIES_ZUC_256 = BIT(29), ICP_ACCEL_CAPABILITIES_WIRELESS_CRYPTO_EXT = BIT(30), }; From 265b861bece38318b8e0fc8fac0643d4ef906d31 Mon Sep 17 00:00:00 2001 From: Xiaonan Zhao Date: Tue, 26 May 2026 18:11:43 +0800 Subject: [PATCH 482/655] crypto: chacha20poly1305 - validate poly1305 template argument chachapoly_create() still accepts the compatibility poly1305 parameter in the template name, but it assumes the second template argument is always present and immediately passes it to strcmp(). When the argument is missing, crypto_attr_alg_name() returns an error pointer. Check for that before comparing the name so malformed template instantiations fail with an error instead of dereferencing the error pointer in strcmp(). This matches the surrounding Crypto API template pattern where crypto_attr_alg_name() results are validated before string-specific use. Fixes: a298765e28ad ("crypto: chacha20poly1305 - Use lib/crypto poly1305") Cc: stable@kernel.org Reported-by: Yuan Tan Reported-by: Zhengchuan Liang Reported-by: Xin Liu Co-developed-by: Luxing Yin Signed-off-by: Luxing Yin Signed-off-by: Xiaonan Zhao Signed-off-by: Ren Wei Signed-off-by: Herbert Xu --- crypto/chacha20poly1305.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c index b4b5a7198d84..27df9e1eb058 100644 --- a/crypto/chacha20poly1305.c +++ b/crypto/chacha20poly1305.c @@ -375,6 +375,7 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, struct aead_instance *inst; struct chachapoly_instance_ctx *ctx; struct skcipher_alg_common *chacha; + const char *poly_name; int err; if (ivsize > CHACHAPOLY_IV_SIZE) @@ -396,9 +397,15 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, goto err_free_inst; chacha = crypto_spawn_skcipher_alg_common(&ctx->chacha); + poly_name = crypto_attr_alg_name(tb[2]); + if (IS_ERR(poly_name)) { + err = PTR_ERR(poly_name); + goto err_free_inst; + } + err = -EINVAL; - if (strcmp(crypto_attr_alg_name(tb[2]), "poly1305") && - strcmp(crypto_attr_alg_name(tb[2]), "poly1305-generic")) + if (strcmp(poly_name, "poly1305") && + strcmp(poly_name, "poly1305-generic")) goto err_free_inst; /* Need 16-byte IV size, including Initial Block Counter value */ if (chacha->ivsize != CHACHA_IV_SIZE) From b2b24a98863fee9a495c8afb602fe75b964a1a84 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 27 May 2026 16:11:47 +0200 Subject: [PATCH 483/655] crypto: powerpc/aes - use min in ppc_{ecb,cbc,ctr,xts}_crypt Replace min_t() with the simpler min() macro since the values are unsigned and compatible. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes-spe-glue.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/crypto/aes-spe-glue.c b/arch/powerpc/crypto/aes-spe-glue.c index 7d2827e65240..e038488087e6 100644 --- a/arch/powerpc/crypto/aes-spe-glue.c +++ b/arch/powerpc/crypto/aes-spe-glue.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -140,7 +141,7 @@ static int ppc_ecb_crypt(struct skcipher_request *req, bool enc) err = skcipher_walk_virt(&walk, req, false); while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); nbytes = round_down(nbytes, AES_BLOCK_SIZE); spe_begin(); @@ -179,7 +180,7 @@ static int ppc_cbc_crypt(struct skcipher_request *req, bool enc) err = skcipher_walk_virt(&walk, req, false); while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); nbytes = round_down(nbytes, AES_BLOCK_SIZE); spe_begin(); @@ -220,7 +221,7 @@ static int ppc_ctr_crypt(struct skcipher_request *req) err = skcipher_walk_virt(&walk, req, false); while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); if (nbytes < walk.total) nbytes = round_down(nbytes, AES_BLOCK_SIZE); @@ -248,7 +249,7 @@ static int ppc_xts_crypt(struct skcipher_request *req, bool enc) twk = ctx->key_twk; while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); nbytes = round_down(nbytes, AES_BLOCK_SIZE); spe_begin(); From 79bbe453e5bfa6e1c6aa2e8329bfc8f152b81c9b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 27 May 2026 19:46:55 +0200 Subject: [PATCH 484/655] crypto: qat - simplify adf_service_mask_to_string helper Use a single scnprintf() for each set bit and drop the offset in the else branch to simplify adf_service_mask_to_string(). Signed-off-by: Thorsten Blum Acked-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_cfg_services.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c index 7d00bcb41ce7..1af6da8b263f 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c @@ -94,10 +94,9 @@ static int adf_service_mask_to_string(unsigned long mask, char *buf, size_t len) for_each_set_bit(bit, &mask, SVC_COUNT) { if (offset) offset += scnprintf(buf + offset, len - offset, - ADF_SERVICES_DELIMITER); - - offset += scnprintf(buf + offset, len - offset, "%s", - adf_cfg_services[bit]); + ADF_SERVICES_DELIMITER "%s", adf_cfg_services[bit]); + else + offset += scnprintf(buf, len, "%s", adf_cfg_services[bit]); } return 0; From 19b206b9534a85266efa78febeb4ae185e75bccd Mon Sep 17 00:00:00 2001 From: Shengming Hu Date: Thu, 4 Jun 2026 20:27:32 +0800 Subject: [PATCH 485/655] mm/slub: preserve original size in _kmalloc_nolock_noprof retry path _kmalloc_nolock_noprof() retries from the next kmalloc bucket when the initial allocation fails. The retry currently reuses `size` as the bucket selector and overwrites it with s->object_size + 1. That value is later passed as the original allocation size to __slab_alloc_node(), slab_post_alloc_hook() and kasan_kmalloc(). On a successful retry this makes KASAN/slub-debug observe the retry bucket selector rather than the caller requested size, potentially widening the valid kmalloc range and hiding overflows. Keep the caller requested size separately as orig_size and pass it to the allocation/debug/KASAN paths. Continue using `size` as the retry cache selector. Fixes: af92793e52c3 ("slab: Introduce kmalloc_nolock() and kfree_nolock()") Signed-off-by: Shengming Hu Reviewed-by: Harry Yoo (Oracle) Reviewed-by: Hao Li Link: https://patch.msgid.link/202606042027323804pk3MRY42Jy7y42OHAhQZ@zte.com.cn Signed-off-by: Vlastimil Babka (SUSE) --- mm/slub.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 492128ae3af9..ff83345d7f95 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5359,6 +5359,7 @@ EXPORT_SYMBOL(__kmalloc_noprof); void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) { gfp_t alloc_gfp = __GFP_NOWARN | __GFP_NOMEMALLOC | gfp_flags; + size_t orig_size = size; struct kmem_cache *s; bool can_retry = true; void *ret; @@ -5407,7 +5408,7 @@ retry: * kfence_alloc. Hence call __slab_alloc_node() (at most twice) * and slab_post_alloc_hook() directly. */ - ret = __slab_alloc_node(s, alloc_gfp, node, _RET_IP_, size); + ret = __slab_alloc_node(s, alloc_gfp, node, _RET_IP_, orig_size); /* * It's possible we failed due to trylock as we preempted someone with @@ -5431,9 +5432,9 @@ retry: success: maybe_wipe_obj_freeptr(s, ret); slab_post_alloc_hook(s, NULL, alloc_gfp, 1, &ret, - slab_want_init_on_alloc(alloc_gfp, s), size); + slab_want_init_on_alloc(alloc_gfp, s), orig_size); - ret = kasan_kmalloc(s, ret, size, alloc_gfp); + ret = kasan_kmalloc(s, ret, orig_size, alloc_gfp); return ret; } EXPORT_SYMBOL_GPL(kmalloc_nolock_noprof); From 608a9fe171a770b62bf34aaa1f4992061c9dcdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 May 2026 18:08:08 +0200 Subject: [PATCH 486/655] fbdev: matroxfb/ssd1307fb: Use named initializers for struct i2c_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. While touching all these arrays, unify usage of whitespace in the list terminator. This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Helge Deller --- drivers/video/fbdev/matrox/matroxfb_maven.c | 2 +- drivers/video/fbdev/ssd1307fb.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/matrox/matroxfb_maven.c b/drivers/video/fbdev/matrox/matroxfb_maven.c index 2ea65da6075c..fe057a0b57ec 100644 --- a/drivers/video/fbdev/matrox/matroxfb_maven.c +++ b/drivers/video/fbdev/matrox/matroxfb_maven.c @@ -1282,7 +1282,7 @@ static void maven_remove(struct i2c_client *client) } static const struct i2c_device_id maven_id[] = { - { "maven" }, + { .name = "maven" }, { } }; MODULE_DEVICE_TABLE(i2c, maven_id); diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 83dd31fa1fab..644b8d97b381 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -784,10 +784,10 @@ static void ssd1307fb_remove(struct i2c_client *client) } static const struct i2c_device_id ssd1307fb_i2c_id[] = { - { "ssd1305fb" }, - { "ssd1306fb" }, - { "ssd1307fb" }, - { "ssd1309fb" }, + { .name = "ssd1305fb" }, + { .name = "ssd1306fb" }, + { .name = "ssd1307fb" }, + { .name = "ssd1309fb" }, { } }; MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id); From e840a232a4a017ff61faedf715083fa1785dfde7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 30 Apr 2026 13:16:36 +0200 Subject: [PATCH 487/655] fbdev: Consistently define pci_device_ids using named initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... and PCI device helpers. The various struct pci_device_id arrays were initialized mostly by list expressions. This isn't easily readable if you're not into PCI. Using named initializers is more explicit and thus easier to parse. Also use PCI_DEVICE* helper macros to assign .vendor, .device, .subvendor and .subdevice where appropriate and skip explicit assignments of 0 (which the compiler takes care of). The secret plan is to make struct pci_device_id::driver_data an anonymous union (similar to https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/) and that requires named initializers. But it's also a nice cleanup on its own. While touching all these arrays, unify usage of whitespace and comma in a few drivers. This change doesn't introduce changes to the compiled pci_device_id array. Tested on x86 and arm64. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Helge Deller --- drivers/video/fbdev/arkfb.c | 4 +- drivers/video/fbdev/aty/aty128fb.c | 143 +++++++------------ drivers/video/fbdev/aty/radeon_base.c | 2 +- drivers/video/fbdev/carminefb.c | 5 +- drivers/video/fbdev/cirrusfb.c | 2 +- drivers/video/fbdev/cyber2000fb.c | 24 ++-- drivers/video/fbdev/geode/gx1fb_core.c | 10 +- drivers/video/fbdev/kyro/fbdev.c | 5 +- drivers/video/fbdev/matrox/matroxfb_base.c | 40 ++---- drivers/video/fbdev/neofb.c | 29 ++-- drivers/video/fbdev/nvidia/nvidia.c | 9 +- drivers/video/fbdev/pm2fb.c | 11 +- drivers/video/fbdev/pm3fb.c | 5 +- drivers/video/fbdev/pvr2fb.c | 5 +- drivers/video/fbdev/riva/fbdev.c | 128 ++++++----------- drivers/video/fbdev/s3fb.c | 32 ++--- drivers/video/fbdev/savage/savagefb_driver.c | 140 +++++++++--------- drivers/video/fbdev/sis/sis_main.h | 26 ++-- drivers/video/fbdev/tdfxfb.c | 21 +-- drivers/video/fbdev/tridentfb.c | 44 +++--- drivers/video/fbdev/vt8623fb.c | 4 +- 21 files changed, 293 insertions(+), 396 deletions(-) diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c index 866c1165704e..195dbf4a5142 100644 --- a/drivers/video/fbdev/arkfb.c +++ b/drivers/video/fbdev/arkfb.c @@ -1167,8 +1167,8 @@ static const struct dev_pm_ops ark_pci_pm_ops = { /* List of boards that we are trying to support */ static const struct pci_device_id ark_devices[] = { - {PCI_DEVICE(0xEDD8, 0xA099)}, - {0, 0, 0, 0, 0, 0, 0} + { PCI_DEVICE(0xEDD8, 0xA099) }, + { } }; diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index f55b4c7609a8..bcb10e66221c 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -180,101 +180,54 @@ static const struct dev_pm_ops aty128_pci_pm_ops = { /* supported Rage128 chipsets */ static const struct pci_device_id aty128_pci_tbl[] = { - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, - { 0, } + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_LE), .driver_data = rage_M3_pci }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_LF), .driver_data = rage_M3 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_MF), .driver_data = rage_M4 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_ML), .driver_data = rage_M4 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PA), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PB), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PC), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PD), .driver_data = rage_128_pro_pci }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PE), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PF), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PG), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PH), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PI), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PK), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PL), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PM), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PN), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PO), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PP), .driver_data = rage_128_pro_pci }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PR), .driver_data = rage_128_pro_pci }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PS), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PT), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PU), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PV), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PW), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_PX), .driver_data = rage_128_pro }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_RE), .driver_data = rage_128_pci }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_RF), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_RG), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_RK), .driver_data = rage_128_pci }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_RL), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SE), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SF), .driver_data = rage_128_pci }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SG), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SH), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SK), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SL), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SM), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_SN), .driver_data = rage_128 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_TF), .driver_data = rage_128_ultra }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_TL), .driver_data = rage_128_ultra }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_TR), .driver_data = rage_128_ultra }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_TS), .driver_data = rage_128_ultra }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_TT), .driver_data = rage_128_ultra }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_RAGE128_TU), .driver_data = rage_128_ultra }, + { } }; MODULE_DEVICE_TABLE(pci, aty128_pci_tbl); diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index cb006484831b..adb03489bedf 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -95,7 +95,7 @@ #define MIN_MAPPED_VRAM (1024*768*1) #define CHIP_DEF(id, family, flags) \ - { PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) } + { PCI_DEVICE(PCI_VENDOR_ID_ATI, id), .driver_data = (flags) | (CHIP_FAMILY_##family) } static const struct pci_device_id radeonfb_pci_table[] = { /* Radeon Xpress 200m */ diff --git a/drivers/video/fbdev/carminefb.c b/drivers/video/fbdev/carminefb.c index bd4bff6a2484..5f13f1cc79d3 100644 --- a/drivers/video/fbdev/carminefb.c +++ b/drivers/video/fbdev/carminefb.c @@ -753,9 +753,8 @@ static void carminefb_remove(struct pci_dev *dev) #define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf static struct pci_device_id carmine_devices[] = { -{ - PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)}, - {0, 0, 0, 0, 0, 0, 0} + { PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b) }, + { } }; MODULE_DEVICE_TABLE(pci, carmine_devices); diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c index e29217e476ea..2693b5cc053f 100644 --- a/drivers/video/fbdev/cirrusfb.c +++ b/drivers/video/fbdev/cirrusfb.c @@ -253,7 +253,7 @@ static const struct cirrusfb_board_info_rec { #ifdef CONFIG_PCI #define CHIP(id, btype) \ - { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } + { PCI_VDEVICE(CIRRUS, id), .driver_data = (btype) } static struct pci_device_id cirrusfb_pci_table[] = { CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE), diff --git a/drivers/video/fbdev/cyber2000fb.c b/drivers/video/fbdev/cyber2000fb.c index 2d12f8e96c7e..3daba94c6c13 100644 --- a/drivers/video/fbdev/cyber2000fb.c +++ b/drivers/video/fbdev/cyber2000fb.c @@ -1796,16 +1796,22 @@ static int __maybe_unused cyberpro_pci_resume(struct device *dev) static struct pci_device_id cyberpro_pci_table[] = { /* Not yet - * { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, - * PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 }, + * { + * PCI_VDEVICE(INTERG, PCI_DEVICE_ID_INTERG_1682), + * .driver_data = ID_IGA_1682, + * }, */ - { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 }, - { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 }, - { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 }, - { 0, } + { + PCI_VDEVICE(INTERG, PCI_DEVICE_ID_INTERG_2000), + .driver_data = ID_CYBERPRO_2000, + }, { + PCI_VDEVICE(INTERG, PCI_DEVICE_ID_INTERG_2010), + .driver_data = ID_CYBERPRO_2010, + }, { + PCI_VDEVICE(INTERG, PCI_DEVICE_ID_INTERG_5000), + .driver_data = ID_CYBERPRO_5000, + }, + { } }; MODULE_DEVICE_TABLE(pci, cyberpro_pci_table); diff --git a/drivers/video/fbdev/geode/gx1fb_core.c b/drivers/video/fbdev/geode/gx1fb_core.c index a1919c1934ac..7cca46891aef 100644 --- a/drivers/video/fbdev/geode/gx1fb_core.c +++ b/drivers/video/fbdev/geode/gx1fb_core.c @@ -423,10 +423,12 @@ static void __init gx1fb_setup(char *options) #endif static struct pci_device_id gx1fb_id_table[] = { - { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_VIDEO, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, - { 0, } + { + PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_VIDEO), + .class = PCI_BASE_CLASS_DISPLAY << 16, + .class_mask = 0xff0000, + }, + { } }; MODULE_DEVICE_TABLE(pci, gx1fb_id_table); diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c index c8b1dfa456a3..d756b3603fa6 100644 --- a/drivers/video/fbdev/kyro/fbdev.c +++ b/drivers/video/fbdev/kyro/fbdev.c @@ -645,9 +645,8 @@ static int kyrofb_ioctl(struct fb_info *info, } static const struct pci_device_id kyrofb_pci_tbl[] = { - { PCI_VENDOR_ID_ST, PCI_DEVICE_ID_STG4000, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } + { PCI_DEVICE(PCI_VENDOR_ID_ST, PCI_DEVICE_ID_STG4000) }, + { } }; MODULE_DEVICE_TABLE(pci, kyrofb_pci_tbl); diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index e1a4bc7c2318..ac04a19b6849 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -1642,8 +1642,8 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b) int err; static const struct pci_device_id intel_82437[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) }, - { }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82437) }, + { } }; DBG(__func__) @@ -2135,35 +2135,23 @@ static void pci_remove_matrox(struct pci_dev* pdev) { static const struct pci_device_id matroxfb_devices[] = { #ifdef CONFIG_FB_MATROX_MILLENIUM - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_MIL) }, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_MIL_2) }, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP) }, #endif #ifdef CONFIG_FB_MATROX_MYSTIQUE - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_MYS) }, #endif #ifdef CONFIG_FB_MATROX_G - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, 0x0532, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_G100_MM) }, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_G100_AGP) }, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_G200_PCI) }, + { PCI_VDEVICE(MATROX, 0x0532) }, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_G200_AGP) }, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_G400) }, + { PCI_VDEVICE(MATROX, PCI_DEVICE_ID_MATROX_G550) }, #endif - {0, 0, - 0, 0, 0, 0, 0} + { } }; MODULE_DEVICE_TABLE(pci, matroxfb_devices); diff --git a/drivers/video/fbdev/neofb.c b/drivers/video/fbdev/neofb.c index c1cd028b8991..e0b8d4d6ce79 100644 --- a/drivers/video/fbdev/neofb.c +++ b/drivers/video/fbdev/neofb.c @@ -2126,34 +2126,25 @@ static void neofb_remove(struct pci_dev *dev) } static const struct pci_device_id neofb_devices[] = { - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2070), .driver_data = FB_ACCEL_NEOMAGIC_NM2070 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2090), .driver_data = FB_ACCEL_NEOMAGIC_NM2090 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2093), .driver_data = FB_ACCEL_NEOMAGIC_NM2093 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2097), .driver_data = FB_ACCEL_NEOMAGIC_NM2097 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2160), .driver_data = FB_ACCEL_NEOMAGIC_NM2160 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2200), .driver_data = FB_ACCEL_NEOMAGIC_NM2200 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2230), .driver_data = FB_ACCEL_NEOMAGIC_NM2230 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2360), .driver_data = FB_ACCEL_NEOMAGIC_NM2360 }, - {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380}, + { PCI_VDEVICE(NEOMAGIC, PCI_CHIP_NM2380), .driver_data = FB_ACCEL_NEOMAGIC_NM2380 }, - {0, 0, 0, 0, 0, 0, 0} + { } }; MODULE_DEVICE_TABLE(pci, neofb_devices); diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index 72b85f475605..da2d486022e8 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -58,9 +58,12 @@ #define MAX_CURS 32 static const struct pci_device_id nvidiafb_pci_tbl[] = { - {PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0}, - { 0, } + { + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), + .class = PCI_BASE_CLASS_DISPLAY << 16, + .class_mask = 0xff0000 + }, + { } }; MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); diff --git a/drivers/video/fbdev/pm2fb.c b/drivers/video/fbdev/pm2fb.c index f34429829b7d..412ff249b5c7 100644 --- a/drivers/video/fbdev/pm2fb.c +++ b/drivers/video/fbdev/pm2fb.c @@ -1748,13 +1748,10 @@ static void pm2fb_remove(struct pci_dev *pdev) } static const struct pci_device_id pm2fb_id_table[] = { - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } + { PCI_VDEVICE(TI, PCI_DEVICE_ID_TI_TVP4020) }, + { PCI_VDEVICE(3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2) }, + { PCI_VDEVICE(3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V) }, + { } }; static struct pci_driver pm2fb_driver = { diff --git a/drivers/video/fbdev/pm3fb.c b/drivers/video/fbdev/pm3fb.c index 6e55e42514d6..6f552ae36219 100644 --- a/drivers/video/fbdev/pm3fb.c +++ b/drivers/video/fbdev/pm3fb.c @@ -1486,9 +1486,8 @@ static void pm3fb_remove(struct pci_dev *dev) } static const struct pci_device_id pm3fb_id_table[] = { - { PCI_VENDOR_ID_3DLABS, 0x0a, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } + { PCI_VDEVICE(3DLABS, 0x000a) }, + { } }; /* For PCI drivers */ diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index 3f6384e631b1..9428716e2dc4 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -993,9 +993,8 @@ static void pvr2fb_pci_remove(struct pci_dev *pdev) } static const struct pci_device_id pvr2fb_pci_tbl[] = { - { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NEON250, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, }, + { PCI_VDEVICE(NEC, PCI_DEVICE_ID_NEC_NEON250) }, + { } }; MODULE_DEVICE_TABLE(pci, pvr2fb_pci_tbl); diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index 1e377b2ec089..2268fea4d807 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -103,92 +103,50 @@ static int rivafb_blank(int blank, struct fb_info *info); * ------------------------------------------------------------------------- */ static const struct pci_device_id rivafb_pci_tbl[] = { - { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440) }, // NF2/IGP version, GeForce 4 MX, NV18 - { PCI_VENDOR_ID_NVIDIA, 0x01f0, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } /* terminate list */ + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x01f0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200) }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index ba30e5568cab..831e9e6861b1 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -1563,24 +1563,24 @@ static const struct dev_pm_ops s3_pci_pm_ops = { /* List of boards that we are trying to support */ static const struct pci_device_id s3_devices[] = { - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8810), .driver_data = CHIP_XXX_TRIO}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8811), .driver_data = CHIP_XXX_TRIO}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8812), .driver_data = CHIP_M65_AURORA64VP}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8814), .driver_data = CHIP_767_TRIO64UVP}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8901), .driver_data = CHIP_XXX_TRIO64V2_DXGX}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8902), .driver_data = CHIP_551_PLATO_PX}, + { PCI_VDEVICE(S3, 0x8810), .driver_data = CHIP_XXX_TRIO }, + { PCI_VDEVICE(S3, 0x8811), .driver_data = CHIP_XXX_TRIO }, + { PCI_VDEVICE(S3, 0x8812), .driver_data = CHIP_M65_AURORA64VP }, + { PCI_VDEVICE(S3, 0x8814), .driver_data = CHIP_767_TRIO64UVP }, + { PCI_VDEVICE(S3, 0x8901), .driver_data = CHIP_XXX_TRIO64V2_DXGX }, + { PCI_VDEVICE(S3, 0x8902), .driver_data = CHIP_551_PLATO_PX }, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x5631), .driver_data = CHIP_325_VIRGE}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x883D), .driver_data = CHIP_988_VIRGE_VX}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A01), .driver_data = CHIP_XXX_VIRGE_DXGX}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_357_VIRGE_GX2}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_359_VIRGE_GX2P}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8C01), .driver_data = CHIP_260_VIRGE_MX}, + { PCI_VDEVICE(S3, 0x5631), .driver_data = CHIP_325_VIRGE }, + { PCI_VDEVICE(S3, 0x883D), .driver_data = CHIP_988_VIRGE_VX }, + { PCI_VDEVICE(S3, 0x8A01), .driver_data = CHIP_XXX_VIRGE_DXGX }, + { PCI_VDEVICE(S3, 0x8A10), .driver_data = CHIP_357_VIRGE_GX2 }, + { PCI_VDEVICE(S3, 0x8A11), .driver_data = CHIP_359_VIRGE_GX2P }, + { PCI_VDEVICE(S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P }, + { PCI_VDEVICE(S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X }, + { PCI_VDEVICE(S3, 0x8904), .driver_data = CHIP_365_TRIO3D }, + { PCI_VDEVICE(S3, 0x8C01), .driver_data = CHIP_260_VIRGE_MX }, - {0, 0, 0, 0, 0, 0, 0} + { } }; diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c index c2f79357c8da..7789196d2eb5 100644 --- a/drivers/video/fbdev/savage/savagefb_driver.c +++ b/drivers/video/fbdev/savage/savagefb_driver.c @@ -2449,76 +2449,78 @@ static const struct dev_pm_ops savagefb_pm_ops = { }; static const struct pci_device_id savagefb_devices[] = { - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, + { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_MX128), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_MX64), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_MX64C), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_IX128SDR), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_IX128DDR), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_IX64SDR), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_IX64DDR), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_IXCSDR), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SUPSAV_IXCDDR), + .driver_data = FB_ACCEL_SUPERSAVAGE, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE4), + .driver_data = FB_ACCEL_SAVAGE4, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE3D), + .driver_data = FB_ACCEL_SAVAGE3D, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE3D_MV), + .driver_data = FB_ACCEL_SAVAGE3D_MV, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE2000), + .driver_data = FB_ACCEL_SAVAGE2000, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE_MX_MV), + .driver_data = FB_ACCEL_SAVAGE_MX_MV, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE_MX), + .driver_data = FB_ACCEL_SAVAGE_MX, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE_IX_MV), + .driver_data = FB_ACCEL_SAVAGE_IX_MV, + }, { + PCI_VDEVICE(S3, PCI_CHIP_SAVAGE_IX), + .driver_data = FB_ACCEL_SAVAGE_IX, + }, { + PCI_VDEVICE(S3, PCI_CHIP_PROSAVAGE_PM), + .driver_data = FB_ACCEL_PROSAVAGE_PM, + }, { + PCI_VDEVICE(S3, PCI_CHIP_PROSAVAGE_KM), + .driver_data = FB_ACCEL_PROSAVAGE_KM, + }, { + PCI_VDEVICE(S3, PCI_CHIP_S3TWISTER_P), + .driver_data = FB_ACCEL_S3TWISTER_P, + }, { + PCI_VDEVICE(S3, PCI_CHIP_S3TWISTER_K), + .driver_data = FB_ACCEL_S3TWISTER_K, + }, { + PCI_VDEVICE(S3, PCI_CHIP_PROSAVAGE_DDR), + .driver_data = FB_ACCEL_PROSAVAGE_DDR, + }, { + PCI_VDEVICE(S3, PCI_CHIP_PROSAVAGE_DDRK), + .driver_data = FB_ACCEL_PROSAVAGE_DDRK, + }, - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR}, - - {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK}, - - {0, 0, 0, 0, 0, 0, 0} + { } }; MODULE_DEVICE_TABLE(pci, savagefb_devices); diff --git a/drivers/video/fbdev/sis/sis_main.h b/drivers/video/fbdev/sis/sis_main.h index 0965db9fad6a..4ca487f48205 100644 --- a/drivers/video/fbdev/sis/sis_main.h +++ b/drivers/video/fbdev/sis/sis_main.h @@ -102,22 +102,22 @@ static struct sisfb_chip_info { static struct pci_device_id sisfb_pci_table[] = { #ifdef CONFIG_FB_SIS_300 - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_300), .driver_data = 0 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_540_VGA), .driver_data = 1 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_630_VGA), .driver_data = 2 }, #endif #ifdef CONFIG_FB_SIS_315 - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, - { PCI_VENDOR_ID_XGI,PCI_DEVICE_ID_XGI_20, PCI_ANY_ID, PCI_ANY_ID, 0, 0,10}, - { PCI_VENDOR_ID_XGI,PCI_DEVICE_ID_XGI_40, PCI_ANY_ID, PCI_ANY_ID, 0, 0,11}, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_315H), .driver_data = 3 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_315), .driver_data = 4 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_315PRO), .driver_data = 5 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_550_VGA), .driver_data = 6 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_650_VGA), .driver_data = 7 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_330), .driver_data = 8 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_660_VGA), .driver_data = 9 }, + { PCI_VDEVICE(XGI, PCI_DEVICE_ID_XGI_20), .driver_data = 10 }, + { PCI_VDEVICE(XGI, PCI_DEVICE_ID_XGI_40), .driver_data = 11 }, #endif - { 0 } + { } }; MODULE_DEVICE_TABLE(pci, sisfb_pci_table); diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c index 4c4e53aaea3a..a6b63c09b48f 100644 --- a/drivers/video/fbdev/tdfxfb.c +++ b/drivers/video/fbdev/tdfxfb.c @@ -124,16 +124,17 @@ static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void tdfxfb_remove(struct pci_dev *pdev); static const struct pci_device_id tdfxfb_id_table[] = { - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, - { 0, } + { + PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE), + .class = PCI_BASE_CLASS_DISPLAY << 16, .class_mask = 0xff0000, + }, { + PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3), + .class = PCI_BASE_CLASS_DISPLAY << 16, .class_mask = 0xff0000, + }, { + PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5), + .class = PCI_BASE_CLASS_DISPLAY << 16, .class_mask = 0xff0000, + }, + { } }; static struct pci_driver tdfxfb_driver = { diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 17b7253b8fbe..a8fdbae83a80 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -1736,28 +1736,28 @@ static void trident_pci_remove(struct pci_dev *dev) /* List of boards that we are trying to support */ static const struct pci_device_id trident_devices[] = { - {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, TGUI9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_VDEVICE(TRIDENT, BLADE3D) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEi7) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEi7D) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEi1) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEi1D) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEAi1) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEAi1D) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEE4) }, + { PCI_VDEVICE(TRIDENT, TGUI9440) }, + { PCI_VDEVICE(TRIDENT, TGUI9660) }, + { PCI_VDEVICE(TRIDENT, IMAGE975) }, + { PCI_VDEVICE(TRIDENT, IMAGE985) }, + { PCI_VDEVICE(TRIDENT, CYBER9320) }, + { PCI_VDEVICE(TRIDENT, CYBER9388) }, + { PCI_VDEVICE(TRIDENT, CYBER9520) }, + { PCI_VDEVICE(TRIDENT, CYBER9525DVD) }, + { PCI_VDEVICE(TRIDENT, CYBER9397) }, + { PCI_VDEVICE(TRIDENT, CYBER9397DVD) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEXPAi1) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEXPm8) }, + { PCI_VDEVICE(TRIDENT, CYBERBLADEXPm16) }, + { } }; MODULE_DEVICE_TABLE(pci, trident_devices); diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c index df984f3a7ff6..9708d968970a 100644 --- a/drivers/video/fbdev/vt8623fb.c +++ b/drivers/video/fbdev/vt8623fb.c @@ -900,8 +900,8 @@ static const struct dev_pm_ops vt8623_pci_pm_ops = { /* List of boards that we are trying to support */ static const struct pci_device_id vt8623_devices[] = { - {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)}, - {0, 0, 0, 0, 0, 0, 0} + { PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122) }, + { } }; MODULE_DEVICE_TABLE(pci, vt8623_devices); From 84202754fb1727dc3ee87f47104e4162ecc8ba3a Mon Sep 17 00:00:00 2001 From: Jiacheng Yu Date: Thu, 14 May 2026 17:19:18 +0800 Subject: [PATCH 488/655] fbcon: Use correct type for vc_resize() return value The return value of vc_resize() is int, but fbcon_set_disp() stores it in an unsigned long variable. While the !ret check happens to work correctly by coincidence (negative values become large positive values), the types should match. Use int instead. Eliminates the following W=3 warning: drivers/video/fbdev/core/fbcon.c: In function 'fbcon_set_disp': drivers/video/fbdev/core/fbcon.c:1494:14: warning: implicit conversion from 'int' to 'unsigned long' [-Wconversion] Fixes: af0db3c1f898 ("fbdev: Fix vmalloc out-of-bounds write in fast_imageblit") Cc: stable@vger.kernel.org # v6.17+ Signed-off-by: Jiacheng Yu Reviewed-by: Thomas Zimmermann Signed-off-by: Helge Deller --- drivers/video/fbdev/core/fbcon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index b0e3e765360d..641687a734d5 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1440,8 +1440,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, struct vc_data **default_mode, *vc; struct vc_data *svc; struct fbcon_par *par = info->fbcon_par; - int rows, cols; - unsigned long ret = 0; + int rows, cols, ret; p = &fb_display[unit]; From 3b069f0596e169bc1b1a991fbba64ffaefe8de75 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 18 May 2026 14:13:03 -0700 Subject: [PATCH 489/655] fbdev: imxfb: Use of_device_get_match_data() Use of_device_get_match_data() to fetch the platform ID entry directly instead of open-coding an of_match_device() lookup. No NULL check is needed as every compatible string has a corresponding data section. This also lets the driver drop the of_device.h include. Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev Signed-off-by: Helge Deller --- drivers/video/fbdev/imxfb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c index a077bf346bdf..7a021da0a32a 100644 --- a/drivers/video/fbdev/imxfb.c +++ b/drivers/video/fbdev/imxfb.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -880,7 +879,6 @@ static int imxfb_probe(struct platform_device *pdev) struct lcd_device *lcd; struct fb_info *info; struct imx_fb_videomode *m; - const struct of_device_id *of_id; struct device_node *display_np; int ret, i; int bytes_per_pixel; @@ -891,9 +889,7 @@ static int imxfb_probe(struct platform_device *pdev) if (ret < 0) return ret; - of_id = of_match_device(imxfb_of_dev_id, &pdev->dev); - if (of_id) - pdev->id_entry = of_id->data; + pdev->id_entry = of_device_get_match_data(&pdev->dev); info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev); if (!info) From 9402555579cf203151755f51b19ef0b4ecb9da71 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 18 May 2026 17:36:13 -0700 Subject: [PATCH 490/655] fbdev: atmel_lcdfb: Use of_device_get_match_data() Use of_device_get_match_data() to retrieve the driver match data instead of open-coding the OF match lookup and dereferencing match->data. This also removes the deprecated of_device.h include from the driver. No need for NULL check as every compatible has a corresponding data component. Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev Signed-off-by: Helge Deller --- drivers/video/fbdev/atmel_lcdfb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 9dfbc5310210..87406a5a2dcf 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -21,7 +21,6 @@ #include #include #include -#include #include